diff gcc/jit/jit-recording.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcc/jit/jit-recording.c	Fri Oct 27 22:46:09 2017 +0900
@@ -0,0 +1,6247 @@
+/* Internals of libgccjit: classes for recording calls made to the JIT API.
+   Copyright (C) 2013-2017 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.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 "tm.h"
+#include "pretty-print.h"
+#include "toplev.h"
+
+#include <pthread.h>
+
+#include "jit-builtins.h"
+#include "jit-recording.h"
+#include "jit-playback.h"
+
+namespace gcc {
+namespace jit {
+
+// class dump
+
+dump::dump (recording::context &ctxt,
+	    const char *filename,
+	    bool update_locations)
+: m_ctxt (ctxt),
+  m_filename (filename),
+  m_update_locations (update_locations),
+  m_line (0),
+  m_column (0)
+{
+  m_file = fopen (filename, "w");
+  if (!m_file)
+    ctxt.add_error (NULL,
+		    "error opening dump file %s for writing: %s",
+		    filename,
+		    xstrerror (errno));
+}
+
+dump::~dump ()
+{
+  if (m_file)
+    {
+      int err = fclose (m_file);
+      if (err)
+	m_ctxt.add_error (NULL,
+			  "error closing dump file %s: %s",
+			  m_filename,
+			  xstrerror (errno));
+    }
+}
+
+/* Write the given message to the dump, using printf-formatting
+   conventions, updating the line/column within the dump.
+
+   Emit an error on the context if a failure occurs.  */
+
+void
+dump::write (const char *fmt, ...)
+{
+  int len;
+  va_list ap;
+  char *buf;
+
+  /* If there was an error opening the file, we've already reported it.
+     Don't attempt further work.  */
+  if (!m_file)
+    return;
+
+  va_start (ap, fmt);
+  len = vasprintf (&buf, fmt, ap);
+  va_end (ap);
+
+  if (buf == NULL || len < 0)
+    {
+      m_ctxt.add_error (NULL, "malloc failure writing to dumpfile %s",
+			m_filename);
+      return;
+    }
+
+  if (fwrite (buf, strlen (buf), 1, m_file) != 1)
+    m_ctxt.add_error (NULL, "error writing to dump file %s",
+		      m_filename);
+
+  /* Flush after each line, to ease debugging crashes.  */
+  fflush (m_file);
+
+  /* Update line/column: */
+  for (const char *ptr = buf; *ptr; ptr++)
+    {
+      if ('\n' == *ptr)
+	{
+	  m_line++;
+	  m_column = 0;
+	}
+      else
+	m_column++;
+    }
+
+  free (buf);
+}
+
+/* Construct a gcc::jit::recording::location instance for the current
+   location within the dump.  */
+
+recording::location *
+dump::make_location () const
+{
+  return m_ctxt.new_location (m_filename, m_line, m_column,
+			      /* We need to flag such locations as *not*
+				 created by the user, so that
+				 reproducer::get_identifier can cope with
+				 them appearing *after* the memento that
+				 refers to them.  */
+			      false);
+}
+
+/* A collection of allocations, all of which can be released together, to
+   avoid needing to track and release them individually.  */
+
+class allocator
+{
+ public:
+  ~allocator ();
+
+  char *
+  xstrdup_printf (const char *, ...)
+    ATTRIBUTE_RETURNS_NONNULL
+    GNU_PRINTF(2, 3);
+
+  char *
+  xstrdup_printf_va (const char *, va_list ap)
+    ATTRIBUTE_RETURNS_NONNULL
+    GNU_PRINTF(2, 0);
+
+ private:
+  auto_vec <void *> m_buffers;
+};
+
+/* allocator's destructor.  Call "free" on all of the allocations.  */
+
+allocator::~allocator ()
+{
+  unsigned i;
+  void *buffer;
+  FOR_EACH_VEC_ELT (m_buffers, i, buffer)
+    free (buffer);
+}
+
+/* Formatted printing, allocating to a buffer (or exiting the process if
+   the allocation fails).
+
+   The buffer exists until the allocator is cleaned up, and is freed at
+   that point, so the caller doesn't need to track the result.  */
+
+char *
+allocator::xstrdup_printf (const char *fmt, ...)
+{
+  char *result;
+  va_list ap;
+  va_start (ap, fmt);
+  result = xstrdup_printf_va (fmt, ap);
+  va_end (ap);
+  return result;
+}
+
+/* Formatted printing, allocating to a buffer (or exiting the process if
+   the allocation fails).
+
+   The buffer exists until the allocator is cleaned up, and is freed at
+   that point, so the caller doesn't need to track the result.  */
+
+char *
+allocator::xstrdup_printf_va (const char *fmt, va_list ap)
+{
+  char *result = xvasprintf (fmt, ap);
+  m_buffers.safe_push (result);
+  return result;
+}
+
+/* gcc::jit::reproducer is a subclass of gcc::jit::dump, used for
+   implementing gcc_jit_context_dump_reproducer_to_file.  */
+
+class reproducer : public dump
+{
+ public:
+  reproducer (recording::context &ctxt,
+	      const char *filename);
+
+  void
+  write_params (const vec <recording::context *> &contexts);
+
+  void
+  write_args (const vec <recording::context *> &contexts);
+
+  const char *
+  make_identifier (recording::memento *m, const char *prefix);
+
+  const char *
+  make_tmp_identifier (const char *prefix, recording::memento *m);
+
+  const char *
+  get_identifier (recording::context *ctxt);
+
+  const char *
+  get_identifier (recording::memento *m);
+
+  const char *
+  get_identifier_as_rvalue (recording::rvalue *m);
+
+  const char *
+  get_identifier_as_lvalue (recording::lvalue *m);
+
+  const char *
+  get_identifier_as_type (recording::type *m);
+
+  char *
+  xstrdup_printf (const char *, ...)
+    ATTRIBUTE_RETURNS_NONNULL
+    GNU_PRINTF(2, 3);
+
+ private:
+  const char * ensure_identifier_is_unique (const char *candidate, void *ptr);
+
+ private:
+  hash_map<recording::memento *, const char *> m_map_memento_to_identifier;
+
+  struct hash_traits : public string_hash
+  {
+    static void remove (const char *) {}
+  };
+  hash_set<const char *, hash_traits> m_set_identifiers;
+  allocator m_allocator;
+};
+
+/* gcc::jit::reproducer's constructor.  */
+
+reproducer::reproducer (recording::context &ctxt,
+			const char *filename) :
+  dump (ctxt, filename, 0),
+  m_map_memento_to_identifier (),
+  m_set_identifiers (),
+  m_allocator ()
+{
+}
+
+/* Write out a list of contexts as a set of parameters within a
+   C function declaration.  */
+
+void
+reproducer::write_params (const vec <recording::context *> &contexts)
+{
+  unsigned i;
+  recording::context *ctxt;
+  FOR_EACH_VEC_ELT (contexts, i, ctxt)
+    {
+      write ("gcc_jit_context *%s",
+	     get_identifier (ctxt));
+      if (i < contexts.length () - 1)
+	write (",\n"
+	       "             ");
+    }
+}
+
+/* Write out a list of contexts as a set of arguments within a call
+   to a C function.  */
+
+void
+reproducer::write_args (const vec <recording::context *> &contexts)
+{
+  unsigned i;
+  recording::context *ctxt;
+  FOR_EACH_VEC_ELT (contexts, i, ctxt)
+    {
+      write ("%s",
+	     get_identifier (ctxt));
+      if (i < contexts.length () - 1)
+	write (",\n"
+	       "               ");
+    }
+}
+
+/* Ensure that STR is a valid C identifier by overwriting
+   any invalid chars in-place with underscores.
+
+   This doesn't special-case the first character.  */
+
+static void
+convert_to_identifier (char *str)
+{
+  for (char *p = str; *p; p++)
+    if (!ISALNUM (*p))
+      *p = '_';
+}
+
+/* Given CANDIDATE, a possible C identifier for use in a reproducer,
+   ensure that it is unique within the generated source file by
+   appending PTR to it if necessary.  Return the resulting string.
+
+   The reproducer will eventually clean up the buffer in its dtor.  */
+
+const char *
+reproducer::ensure_identifier_is_unique (const char *candidate, void *ptr)
+{
+  if (m_set_identifiers.contains (candidate))
+    candidate = m_allocator.xstrdup_printf ("%s_%p", candidate, ptr);
+  gcc_assert (!m_set_identifiers.contains (candidate));
+  m_set_identifiers.add (candidate);
+  return candidate;
+}
+
+/* Generate a C identifier for the given memento, associating the generated
+   buffer with the memento (for future calls to get_identifier et al).
+
+   The reproducer will eventually clean up the buffer in its dtor.  */
+const char *
+reproducer::make_identifier (recording::memento *m, const char *prefix)
+{
+  const char *result;
+  if (strlen (m->get_debug_string ()) < 100)
+    {
+      char *buf = m_allocator.xstrdup_printf ("%s_%s",
+					      prefix,
+					      m->get_debug_string ());
+      convert_to_identifier (buf);
+      result = buf;
+    }
+  else
+    result = m_allocator.xstrdup_printf ("%s_%p",
+					 prefix, (void *) m);
+  result = ensure_identifier_is_unique (result, m);
+  m_map_memento_to_identifier.put (m, result);
+  return result;
+}
+
+/* Generate a C identifier for a temporary variable.
+   The reproducer will eventually clean up the buffer in its dtor.  */
+
+const char *
+reproducer::make_tmp_identifier (const char *prefix, recording::memento *m)
+{
+  return m_allocator.xstrdup_printf ("%s_%s",
+				     prefix, get_identifier (m));
+}
+
+/* Generate a C identifier for the given context.
+   The reproducer will eventually clean up the buffer in its dtor.  */
+
+const char *
+reproducer::get_identifier (recording::context *ctxt)
+{
+  return m_allocator.xstrdup_printf ("ctxt_%p",
+				     (void *)ctxt);
+}
+
+/* Locate the C identifier for the given memento, which is assumed to
+   have already been created via make_identifier.  */
+
+const char *
+reproducer::get_identifier (recording::memento *m)
+{
+  if (!m)
+    return "NULL";
+
+  /* gcc_jit_context_dump_to_file (, , 1) generates and writes locations,
+     and hence these locations appear in the context's memento list
+     out-of-order: they appear in the context's memento list *after*
+     the memento that refers to them.  For this case, it's simplest to
+     pretend that they're NULL when writing out the code to recreate the
+     memento that uses them.  */
+  if (recording::location *loc = m->dyn_cast_location ())
+    if (!loc->created_by_user ())
+      return "NULL";
+
+  const char **slot = m_map_memento_to_identifier.get (m);
+  if (!slot)
+    {
+      get_context ().add_error (NULL,
+				"unable to find identifier for %p: %s",
+				(void *)m,
+				m->get_debug_string ());
+      gcc_unreachable ();
+    }
+  return *slot;
+}
+
+/* Locate the C identifier for the given rvalue, wrapping it within
+   a gcc_*_as_rvalue upcast if necessary.  */
+
+const char *
+reproducer::get_identifier_as_rvalue (recording::rvalue *m)
+{
+  return m->access_as_rvalue (*this);
+}
+
+/* Locate the C identifier for the given lvalue, wrapping it within
+   a gcc_*_as_lvalue upcast if necessary.  */
+
+const char *
+reproducer::get_identifier_as_lvalue (recording::lvalue *m)
+{
+  return m->access_as_lvalue (*this);
+}
+
+/* Locate the C identifier for the given type, wrapping it within
+   a gcc_*_as_type upcast if necessary.  */
+
+const char *
+reproducer::get_identifier_as_type (recording::type *m)
+{
+  return m->access_as_type (*this);
+}
+
+/* Formatted printing, allocating to a buffer (or exiting the process if
+   the allocation fails).
+
+   The buffer exists until the allocator is cleaned up, and is freed at
+   that point, so the caller doesn't need to track the result.
+
+   Note that we can't use ggc_printf since we're not within the compiler
+   proper (when within gcc_jit_context_dump_reproducer_to_file).  */
+
+char *
+reproducer::xstrdup_printf (const char *fmt, ...)
+{
+  char *result;
+  va_list ap;
+  va_start (ap, fmt);
+  result = m_allocator.xstrdup_printf_va (fmt, ap);
+  va_end (ap);
+  return result;
+}
+
+/* A helper class for implementing make_debug_string, for building
+   a temporary string from a vec of rvalues.  */
+
+class comma_separated_string
+{
+ public:
+  comma_separated_string (const auto_vec<recording::rvalue *> &rvalues,
+			  enum recording::precedence prec);
+  ~comma_separated_string ();
+
+  const char *as_char_ptr () const { return m_buf; }
+
+ private:
+  char *m_buf;
+};
+
+/* comma_separated_string's ctor
+   Build m_buf.  */
+
+comma_separated_string::comma_separated_string
+  (const auto_vec<recording::rvalue *> &rvalues,
+   enum recording::precedence prec)
+: m_buf (NULL)
+{
+  /* Calculate length of said buffer.  */
+  size_t sz = 1; /* nil terminator */
+  for (unsigned i = 0; i< rvalues.length (); i++)
+    {
+      sz += strlen (rvalues[i]->get_debug_string_parens (prec));
+      sz += 2; /* ", " separator */
+    }
+
+  /* Now allocate and populate the buffer.  */
+  m_buf = new char[sz];
+  size_t len = 0;
+
+  for (unsigned i = 0; i< rvalues.length (); i++)
+    {
+      strcpy (m_buf + len, rvalues[i]->get_debug_string_parens (prec));
+      len += strlen (rvalues[i]->get_debug_string_parens (prec));
+      if (i + 1 < rvalues.length ())
+	{
+	  strcpy (m_buf + len, ", ");
+	  len += 2;
+	}
+    }
+  m_buf[len] = '\0';
+}
+
+/* comma_separated_string's dtor.  */
+
+comma_separated_string::~comma_separated_string ()
+{
+  delete[] m_buf;
+}
+
+/**********************************************************************
+ Recording.
+ **********************************************************************/
+
+/* Get the playback::location for the given recording::location,
+   handling a NULL input with a NULL output.  */
+
+playback::location *
+recording::playback_location (replayer *r, recording::location *loc)
+{
+  if (loc)
+    return loc->playback_location (r);
+  else
+    return NULL;
+}
+
+/* Get a const char * for the given recording::string
+   handling a NULL input with a NULL output.  */
+
+const char *
+recording::playback_string (recording::string *str)
+{
+  if (str)
+    return str->c_str ();
+  else
+    return NULL;
+}
+
+/* Get the playback::block for the given recording::block,
+   handling a NULL input with a NULL output.  */
+
+playback::block *
+recording::playback_block (recording::block *b)
+{
+  if (b)
+    return b->playback_block ();
+  else
+    return NULL;
+}
+
+/* Methods of cc::jit::recording::context.  */
+
+/* The constructor for gcc::jit::recording::context, used by
+   gcc_jit_context_acquire and gcc_jit_context_new_child_context.  */
+
+recording::context::context (context *parent_ctxt)
+  : log_user (NULL),
+    m_parent_ctxt (parent_ctxt),
+    m_toplevel_ctxt (m_parent_ctxt ? m_parent_ctxt->m_toplevel_ctxt : this),
+    m_timer (NULL),
+    m_error_count (0),
+    m_first_error_str (NULL),
+    m_owns_first_error_str (false),
+    m_last_error_str (NULL),
+    m_owns_last_error_str (false),
+    m_mementos (),
+    m_compound_types (),
+    m_globals (),
+    m_functions (),
+    m_FILE_type (NULL),
+    m_builtins_manager(NULL)
+{
+  if (parent_ctxt)
+    {
+      /* Inherit options from parent.  */
+      for (unsigned i = 0;
+	   i < sizeof (m_str_options) / sizeof (m_str_options[0]);
+	   i++)
+	{
+	  const char *parent_opt = parent_ctxt->m_str_options[i];
+	  m_str_options[i] = parent_opt ? xstrdup (parent_opt) : NULL;
+	}
+      memcpy (m_int_options,
+	      parent_ctxt->m_int_options,
+	      sizeof (m_int_options));
+      memcpy (m_bool_options,
+	      parent_ctxt->m_bool_options,
+	      sizeof (m_bool_options));
+      memcpy (m_inner_bool_options,
+	      parent_ctxt->m_inner_bool_options,
+	      sizeof (m_inner_bool_options));
+      set_logger (parent_ctxt->get_logger ());
+    }
+  else
+    {
+      memset (m_str_options, 0, sizeof (m_str_options));
+      memset (m_int_options, 0, sizeof (m_int_options));
+      memset (m_bool_options, 0, sizeof (m_bool_options));
+      memset (m_inner_bool_options, 0, sizeof (m_inner_bool_options));
+    }
+
+  memset (m_basic_types, 0, sizeof (m_basic_types));
+}
+
+/* The destructor for gcc::jit::recording::context, implicitly used by
+   gcc_jit_context_release.  */
+
+recording::context::~context ()
+{
+  JIT_LOG_SCOPE (get_logger ());
+  int i;
+  memento *m;
+  FOR_EACH_VEC_ELT (m_mementos, i, m)
+    {
+      delete m;
+    }
+
+  for (i = 0; i < GCC_JIT_NUM_STR_OPTIONS; ++i)
+    free (m_str_options[i]);
+
+  char *optname;
+  FOR_EACH_VEC_ELT (m_command_line_options, i, optname)
+    free (optname);
+
+  if (m_builtins_manager)
+    delete m_builtins_manager;
+
+  if (m_owns_first_error_str)
+    free (m_first_error_str);
+
+  if (m_owns_last_error_str)
+    if (m_last_error_str != m_first_error_str)
+      free (m_last_error_str);
+}
+
+/* Add the given mememto to the list of those tracked by this
+   gcc::jit::recording::context, so that e.g. it can be deleted
+   when this context is released.  */
+
+void
+recording::context::record (memento *m)
+{
+  gcc_assert (m);
+
+  m_mementos.safe_push (m);
+}
+
+/* Replay this context (and any parents) into the given replayer.  */
+
+void
+recording::context::replay_into (replayer *r)
+{
+  JIT_LOG_SCOPE (get_logger ());
+  int i;
+  memento *m;
+
+  /* If we have a parent context, we must replay it.  This will
+     recursively walk backwards up the historical tree, then replay things
+     forwards "in historical order", starting with the ultimate parent
+     context, until we reach the "this" context.
+
+     Note that we fully replay the parent, then fully replay the child,
+     which means that inter-context references can only exist from child
+     to parent, not the other way around.
+
+     All of this replaying is suboptimal - it would be better to do the
+     work for the parent context *once*, rather than replaying the parent
+     every time we replay each child.  However, fixing this requires deep
+     surgery to lifetime-management: we'd need every context family tree
+     to have its own GC heap, and to initialize the GCC code to use that
+     heap (with a mutex on such a heap).  */
+  if (m_parent_ctxt)
+    m_parent_ctxt->replay_into (r);
+
+  if (r->errors_occurred ())
+    return;
+
+  /* Replay this context's saved operations into r.  */
+  FOR_EACH_VEC_ELT (m_mementos, i, m)
+    {
+      /* Disabled low-level debugging, here if we need it: print what
+	 we're replaying.
+	 Note that the calls to get_debug_string might lead to more
+	 mementos being created for the strings.
+	 This can also be used to exercise the debug_string
+	 machinery.  */
+      if (0)
+	printf ("context %p replaying (%p): %s\n",
+		(void *)this, (void *)m, m->get_debug_string ());
+
+      m->replay_into (r);
+
+      if (r->errors_occurred ())
+	return;
+    }
+}
+
+/* During a playback, we associate objects from the recording with
+   their counterparts during this playback.
+
+   For simplicity, we store this within the recording objects.
+
+   The following method cleans away these associations, to ensure that
+   we never have out-of-date associations lingering on subsequent
+   playbacks (the objects pointed to are GC-managed, but the
+   recording objects don't own refs to them).  */
+
+void
+recording::context::disassociate_from_playback ()
+{
+  JIT_LOG_SCOPE (get_logger ());
+  int i;
+  memento *m;
+
+  if (m_parent_ctxt)
+    m_parent_ctxt->disassociate_from_playback ();
+
+  FOR_EACH_VEC_ELT (m_mementos, i, m)
+    {
+      m->set_playback_obj (NULL);
+    }
+}
+
+/* Create a recording::string instance and add it to this context's list
+   of mementos.
+
+   This creates a fresh copy of the given 0-terminated buffer.  */
+
+recording::string *
+recording::context::new_string (const char *text)
+{
+  if (!text)
+    return NULL;
+
+  recording::string *result = new string (this, text);
+  record (result);
+  return result;
+}
+
+/* Create a recording::location instance and add it to this context's
+   list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_location.  */
+
+recording::location *
+recording::context::new_location (const char *filename,
+				  int line,
+				  int column,
+				  bool created_by_user)
+{
+  recording::location *result =
+    new recording::location (this,
+			     new_string (filename),
+			     line, column,
+			     created_by_user);
+  record (result);
+  return result;
+}
+
+/* If we haven't seen this enum value yet, create a recording::type
+   instance and add it to this context's list of mementos.
+
+   If we have seen it before, reuse our cached value, so that repeated
+   calls on the context give the same object.
+
+   If we have a parent context, the cache is within the ultimate
+   ancestor context.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_get_type.  */
+
+recording::type *
+recording::context::get_type (enum gcc_jit_types kind)
+{
+  if (!m_basic_types[kind])
+    {
+      if (m_parent_ctxt)
+	m_basic_types[kind] = m_parent_ctxt->get_type (kind);
+      else
+	{
+	  recording::type *result = new memento_of_get_type (this, kind);
+	  record (result);
+	  m_basic_types[kind] = result;
+	}
+    }
+
+  return m_basic_types[kind];
+}
+
+/* Get a recording::type instance for the given size and signedness.
+   This is implemented in terms of recording::context::get_type
+   above.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_get_int_type.  */
+
+recording::type *
+recording::context::get_int_type (int num_bytes, int is_signed)
+{
+  /* We can't use a switch here since some of the values are macros affected
+     by options; e.g. i386.h has
+       #define LONG_TYPE_SIZE (TARGET_X32 ? 32 : BITS_PER_WORD)
+     Compare with tree.c's make_or_reuse_type.  Note that the _SIZE macros
+     are in bits, rather than bytes.
+  */
+  const int num_bits = num_bytes * 8;
+  if (num_bits == INT_TYPE_SIZE)
+    return get_type (is_signed
+		     ? GCC_JIT_TYPE_INT
+		     : GCC_JIT_TYPE_UNSIGNED_INT);
+  if (num_bits == CHAR_TYPE_SIZE)
+    return get_type (is_signed
+		     ? GCC_JIT_TYPE_SIGNED_CHAR
+		     : GCC_JIT_TYPE_UNSIGNED_CHAR);
+  if (num_bits == SHORT_TYPE_SIZE)
+    return get_type (is_signed
+		     ? GCC_JIT_TYPE_SHORT
+		     : GCC_JIT_TYPE_UNSIGNED_SHORT);
+  if (num_bits == LONG_TYPE_SIZE)
+    return get_type (is_signed
+		     ? GCC_JIT_TYPE_LONG
+		     : GCC_JIT_TYPE_UNSIGNED_LONG);
+  if (num_bits == LONG_LONG_TYPE_SIZE)
+    return get_type (is_signed
+		     ? GCC_JIT_TYPE_LONG_LONG
+		     : GCC_JIT_TYPE_UNSIGNED_LONG_LONG);
+
+  /* Some other size, not corresponding to the C int types.  */
+  /* To be written: support arbitrary other sizes, sharing by
+     memoizing at the recording::context level?  */
+  gcc_unreachable ();
+}
+
+/* Create a recording::type instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_array_type.  */
+
+recording::type *
+recording::context::new_array_type (recording::location *loc,
+				    recording::type *element_type,
+				    int num_elements)
+{
+  if (struct_ *s = element_type->dyn_cast_struct ())
+    if (!s->get_fields ())
+      {
+	add_error (NULL,
+		   "cannot create an array of type %s"
+		   " until the fields have been set",
+		   s->get_name ()->c_str ());
+	return NULL;
+      }
+  recording::type *result =
+    new recording::array_type (this, loc, element_type, num_elements);
+  record (result);
+  return result;
+}
+
+/* Create a recording::field instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_field.  */
+
+recording::field *
+recording::context::new_field (recording::location *loc,
+			       recording::type *type,
+			       const char *name)
+{
+  recording::field *result =
+    new recording::field (this, loc, type, new_string (name));
+  record (result);
+  return result;
+}
+
+/* Create a recording::struct_ instance and add it to this context's
+   list of mementos and list of compound types.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_struct_type.  */
+
+recording::struct_ *
+recording::context::new_struct_type (recording::location *loc,
+				     const char *name)
+{
+  recording::struct_ *result = new struct_ (this, loc, new_string (name));
+  record (result);
+  m_compound_types.safe_push (result);
+  return result;
+}
+
+/* Create a recording::union_ instance and add it to this context's
+   list of mementos and list of compound types.
+
+   Implements the first post-error-checking part of
+   gcc_jit_context_new_union_type.  */
+
+recording::union_ *
+recording::context::new_union_type (recording::location *loc,
+				    const char *name)
+{
+  recording::union_ *result = new union_ (this, loc, new_string (name));
+  record (result);
+  m_compound_types.safe_push (result);
+  return result;
+}
+
+/* Create a recording::function_type instance and add it to this context's
+   list of mementos.
+
+   Used by new_function_ptr_type and by builtins_manager::make_fn_type.  */
+
+recording::function_type *
+recording::context::new_function_type (recording::type *return_type,
+				       int num_params,
+				       recording::type **param_types,
+				       int is_variadic)
+{
+  recording::function_type *fn_type
+    = new function_type (this,
+			 return_type,
+			 num_params,
+			 param_types,
+			 is_variadic);
+  record (fn_type);
+  return fn_type;
+}
+
+/* Create a recording::type instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_function_ptr_type.  */
+
+recording::type *
+recording::context::new_function_ptr_type (recording::location *, /* unused loc */
+					   recording::type *return_type,
+					   int num_params,
+					   recording::type **param_types,
+					   int is_variadic)
+{
+  recording::function_type *fn_type
+    = new_function_type (return_type,
+			 num_params,
+			 param_types,
+			 is_variadic);
+
+  /* Return a pointer-type to the function type.  */
+  return fn_type->get_pointer ();
+}
+
+/* Create a recording::param instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_param.  */
+
+recording::param *
+recording::context::new_param (recording::location *loc,
+			       recording::type *type,
+			       const char *name)
+{
+  recording::param *result = new recording::param (this, loc, type, new_string (name));
+  record (result);
+  return result;
+}
+
+/* Create a recording::function instance and add it to this context's list
+   of mementos and list of functions.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_function.  */
+
+recording::function *
+recording::context::new_function (recording::location *loc,
+				  enum gcc_jit_function_kind kind,
+				  recording::type *return_type,
+				  const char *name,
+				  int num_params,
+				  recording::param **params,
+				  int is_variadic,
+				  enum built_in_function builtin_id)
+{
+  recording::function *result =
+    new recording::function (this,
+			     loc, kind, return_type,
+			     new_string (name),
+			     num_params, params, is_variadic,
+			     builtin_id);
+  record (result);
+  m_functions.safe_push (result);
+
+  return result;
+}
+
+/* Locate the builtins_manager (if any) for this family of contexts,
+   creating it if it doesn't exist already.
+
+   All of the recording contexts in a family share one builtins_manager:
+   if we have a child context, follow the parent links to get the
+   ultimate ancestor context, and look for it/store it there.  */
+
+builtins_manager *
+recording::context::get_builtins_manager ()
+{
+  if (m_parent_ctxt)
+    return m_parent_ctxt->get_builtins_manager ();
+
+  if (!m_builtins_manager)
+    m_builtins_manager = new builtins_manager (this);
+
+  return m_builtins_manager;
+}
+
+/* Get a recording::function instance, which is lazily-created and added
+   to the context's lists of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_get_builtin_function.  */
+
+recording::function *
+recording::context::get_builtin_function (const char *name)
+{
+  builtins_manager *bm = get_builtins_manager ();
+  return bm->get_builtin_function (name);
+}
+
+/* Create a recording::global instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_global.  */
+
+recording::lvalue *
+recording::context::new_global (recording::location *loc,
+				enum gcc_jit_global_kind kind,
+				recording::type *type,
+				const char *name)
+{
+  recording::global *result =
+    new recording::global (this, loc, kind, type, new_string (name));
+  record (result);
+  m_globals.safe_push (result);
+
+  return result;
+}
+
+/* Create a recording::memento_of_new_string_literal instance and add it
+   to this context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_string_literal.  */
+
+recording::rvalue *
+recording::context::new_string_literal (const char *value)
+{
+  recording::rvalue *result =
+    new memento_of_new_string_literal (this, NULL, new_string (value));
+  record (result);
+  return result;
+}
+
+/* Create a recording::memento_of_new_rvalue_from_vector instance and add it
+   to this context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_rvalue_from_vector.  */
+
+recording::rvalue *
+recording::context::new_rvalue_from_vector (location *loc,
+					    vector_type *type,
+					    rvalue **elements)
+{
+  recording::rvalue *result
+    = new memento_of_new_rvalue_from_vector (this, loc, type, elements);
+  record (result);
+  return result;
+}
+
+/* Create a recording::unary_op instance and add it to this context's
+   list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_unary_op.  */
+
+recording::rvalue *
+recording::context::new_unary_op (recording::location *loc,
+				  enum gcc_jit_unary_op op,
+				  recording::type *result_type,
+				  recording::rvalue *a)
+{
+  recording::rvalue *result =
+    new unary_op (this, loc, op, result_type, a);
+  record (result);
+  return result;
+}
+
+/* Create a recording::binary_op instance and add it to this context's
+   list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_binary_op.  */
+
+recording::rvalue *
+recording::context::new_binary_op (recording::location *loc,
+				   enum gcc_jit_binary_op op,
+				   recording::type *result_type,
+				   recording::rvalue *a,
+				   recording::rvalue *b)
+{
+  recording::rvalue *result =
+    new binary_op (this, loc, op, result_type, a, b);
+  record (result);
+  return result;
+}
+
+/* Create a recording::comparison instance and add it to this context's
+   list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_comparison.  */
+
+recording::rvalue *
+recording::context::new_comparison (recording::location *loc,
+				    enum gcc_jit_comparison op,
+				    recording::rvalue *a,
+				    recording::rvalue *b)
+{
+  recording::rvalue *result = new comparison (this, loc, op, a, b);
+  record (result);
+  return result;
+}
+
+/* Create a recording::cast instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_cast.  */
+
+recording::rvalue *
+recording::context::new_cast (recording::location *loc,
+			      recording::rvalue *expr,
+			      recording::type *type_)
+{
+  recording::rvalue *result = new cast (this, loc, expr, type_);
+  record (result);
+  return result;
+}
+
+/* Create a recording::call instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_call.  */
+
+recording::rvalue *
+recording::context::new_call (recording::location *loc,
+			      function *func,
+			      int numargs , recording::rvalue **args)
+{
+  recording::rvalue *result = new call (this, loc, func, numargs, args);
+  record (result);
+  return result;
+}
+
+/* Create a recording::call_through_ptr instance and add it to this
+   context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_call_through_ptr.  */
+
+recording::rvalue *
+recording::context::new_call_through_ptr (recording::location *loc,
+					  recording::rvalue *fn_ptr,
+					  int numargs,
+					  recording::rvalue **args)
+  {
+  recording::rvalue *result = new call_through_ptr (this, loc, fn_ptr, numargs, args);
+  record (result);
+  return result;
+}
+
+/* Create a recording::array_access instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_array_access.  */
+
+recording::lvalue *
+recording::context::new_array_access (recording::location *loc,
+				      recording::rvalue *ptr,
+				      recording::rvalue *index)
+{
+  recording::lvalue *result = new array_access (this, loc, ptr, index);
+  record (result);
+  return result;
+}
+
+/* Create a recording::case_ instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_case.  */
+
+recording::case_ *
+recording::context::new_case (recording::rvalue *min_value,
+			      recording::rvalue *max_value,
+			      recording::block *block)
+{
+  recording::case_ *result = new case_ (this, min_value, max_value, block);
+  record (result);
+  return result;
+}
+
+/* Set the given string option for this context, or add an error if
+   it's not recognized.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_set_str_option.  */
+
+void
+recording::context::set_str_option (enum gcc_jit_str_option opt,
+				    const char *value)
+{
+  if (opt < 0 || opt >= GCC_JIT_NUM_STR_OPTIONS)
+    {
+      add_error (NULL,
+		 "unrecognized (enum gcc_jit_str_option) value: %i", opt);
+      return;
+    }
+  free (m_str_options[opt]);
+  m_str_options[opt] = value ? xstrdup (value) : NULL;
+  log_str_option (opt);
+}
+
+/* Set the given integer option for this context, or add an error if
+   it's not recognized.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_set_int_option.  */
+
+void
+recording::context::set_int_option (enum gcc_jit_int_option opt,
+				    int value)
+{
+  if (opt < 0 || opt >= GCC_JIT_NUM_INT_OPTIONS)
+    {
+      add_error (NULL,
+		 "unrecognized (enum gcc_jit_int_option) value: %i", opt);
+      return;
+    }
+  m_int_options[opt] = value;
+  log_int_option (opt);
+}
+
+/* Set the given boolean option for this context, or add an error if
+   it's not recognized.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_set_bool_option.  */
+
+void
+recording::context::set_bool_option (enum gcc_jit_bool_option opt,
+				     int value)
+{
+  if (opt < 0 || opt >= GCC_JIT_NUM_BOOL_OPTIONS)
+    {
+      add_error (NULL,
+		 "unrecognized (enum gcc_jit_bool_option) value: %i", opt);
+      return;
+    }
+  m_bool_options[opt] = value ? true : false;
+  log_bool_option (opt);
+}
+
+void
+recording::context::set_inner_bool_option (enum inner_bool_option inner_opt,
+					   int value)
+{
+  gcc_assert (inner_opt >= 0 && inner_opt < NUM_INNER_BOOL_OPTIONS);
+  m_inner_bool_options[inner_opt] = value ? true : false;
+  log_inner_bool_option (inner_opt);
+}
+
+
+/* Add the given optname to this context's list of extra options.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_add_command_line_option.  */
+
+void
+recording::context::add_command_line_option (const char *optname)
+{
+  m_command_line_options.safe_push (xstrdup (optname));
+}
+
+/* Add any user-provided extra options, starting with any from
+   parent contexts.
+   Called by playback::context::make_fake_args.  */
+
+void
+recording::context::append_command_line_options (vec <char *> *argvec)
+{
+  if (m_parent_ctxt)
+    m_parent_ctxt->append_command_line_options (argvec);
+
+  int i;
+  char *optname;
+  FOR_EACH_VEC_ELT (m_command_line_options, i, optname)
+    argvec->safe_push (xstrdup (optname));
+}
+
+/* Add the given dumpname/out_ptr pair to this context's list of requested
+   dumps.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_enable_dump.  */
+
+void
+recording::context::enable_dump (const char *dumpname,
+				 char **out_ptr)
+{
+  requested_dump d;
+  gcc_assert (dumpname);
+  gcc_assert (out_ptr);
+
+  d.m_dumpname = dumpname;
+  d.m_out_ptr = out_ptr;
+  *out_ptr = NULL;
+  m_requested_dumps.safe_push (d);
+}
+
+/* Validate this context, and if it passes, compile it to memory
+   (within a mutex).
+
+   Implements the post-error-checking part of
+   gcc_jit_context_compile.  */
+
+result *
+recording::context::compile ()
+{
+  JIT_LOG_SCOPE (get_logger ());
+
+  log_all_options ();
+
+  validate ();
+
+  if (errors_occurred ())
+    return NULL;
+
+  /* Set up a compile_to_memory playback context.  */
+  ::gcc::jit::playback::compile_to_memory replayer (this);
+
+  /* Use it.  */
+  replayer.compile ();
+
+  /* Get the jit::result (or NULL) from the
+     compile_to_memory playback context.  */
+  return replayer.get_result_obj ();
+}
+
+/* Validate this context, and if it passes, compile it to a file
+   (within a mutex).
+
+   Implements the post-error-checking part of
+   gcc_jit_context_compile_to_file.  */
+
+void
+recording::context::compile_to_file (enum gcc_jit_output_kind output_kind,
+				     const char *output_path)
+{
+  JIT_LOG_SCOPE (get_logger ());
+
+  log_all_options ();
+
+  validate ();
+
+  if (errors_occurred ())
+    return;
+
+  /* Set up a compile_to_file playback context.  */
+  ::gcc::jit::playback::compile_to_file replayer (this,
+						  output_kind,
+						  output_path);
+
+  /* Use it.  */
+  replayer.compile ();
+}
+
+/* Format the given error using printf's conventions, print
+   it to stderr, and add it to the context.  */
+
+void
+recording::context::add_error (location *loc, const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  add_error_va (loc, fmt, ap);
+  va_end (ap);
+}
+
+/* Format the given error using printf's conventions, print
+   it to stderr, and add it to the context.  */
+
+void
+recording::context::add_error_va (location *loc, const char *fmt, va_list ap)
+{
+  int len;
+  char *malloced_msg;
+  const char *errmsg;
+  bool has_ownership;
+
+  JIT_LOG_SCOPE (get_logger ());
+
+  len = vasprintf (&malloced_msg, fmt, ap);
+  if (malloced_msg == NULL || len < 0)
+    {
+      errmsg = "out of memory generating error message";
+      has_ownership = false;
+    }
+  else
+    {
+      errmsg = malloced_msg;
+      has_ownership = true;
+    }
+  if (get_logger ())
+    get_logger ()->log ("error %i: %s", m_error_count, errmsg);
+
+  const char *ctxt_progname =
+    get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
+  if (!ctxt_progname)
+    ctxt_progname = "libgccjit.so";
+
+  if (loc)
+    fprintf (stderr, "%s: %s: error: %s\n",
+	     ctxt_progname,
+	     loc->get_debug_string (),
+	     errmsg);
+  else
+    fprintf (stderr, "%s: error: %s\n",
+	     ctxt_progname,
+	     errmsg);
+
+  if (!m_error_count)
+    {
+      m_first_error_str = const_cast <char *> (errmsg);
+      m_owns_first_error_str = has_ownership;
+    }
+
+  if (m_owns_last_error_str)
+    if (m_last_error_str != m_first_error_str)
+      free (m_last_error_str);
+  m_last_error_str = const_cast <char *> (errmsg);
+  m_owns_last_error_str = has_ownership;
+
+  m_error_count++;
+}
+
+/* Get the message for the first error that occurred on this context, or
+   NULL if no errors have occurred on it.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_get_first_error.  */
+
+const char *
+recording::context::get_first_error () const
+{
+  return m_first_error_str;
+}
+
+/* Get the message for the last error that occurred on this context, or
+   NULL if no errors have occurred on it.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_get_last_error.  */
+
+const char *
+recording::context::get_last_error () const
+{
+  return m_last_error_str;
+}
+
+/* Lazily generate and record a recording::type representing an opaque
+   struct named "FILE".
+
+   For use if client code tries to dereference the result of
+   get_type (GCC_JIT_TYPE_FILE_PTR).  */
+
+recording::type *
+recording::context::get_opaque_FILE_type ()
+{
+  if (!m_FILE_type)
+    m_FILE_type = new_struct_type (NULL, "FILE");
+  return m_FILE_type;
+}
+
+/* Dump a C-like representation of the given context to the given path.
+   If UPDATE_LOCATIONS is true, update the locations within the
+   context's mementos to point to the dumpfile.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_dump_to_file.  */
+
+void
+recording::context::dump_to_file (const char *path, bool update_locations)
+{
+  int i;
+  dump d (*this, path, update_locations);
+
+  /* Forward declaration of structs and unions.  */
+  compound_type *st;
+  FOR_EACH_VEC_ELT (m_compound_types, i, st)
+    {
+      d.write ("%s;\n\n", st->get_debug_string ());
+    }
+
+  /* Content of structs, where set.  */
+  FOR_EACH_VEC_ELT (m_compound_types, i, st)
+    if (st->get_fields ())
+      {
+	st->get_fields ()->write_to_dump (d);
+	d.write ("\n");
+      }
+
+  /* Globals.  */
+  global *g;
+  FOR_EACH_VEC_ELT (m_globals, i, g)
+    {
+      g->write_to_dump (d);
+    }
+  if (!m_globals.is_empty ())
+    d.write ("\n");
+
+  function *fn;
+  FOR_EACH_VEC_ELT (m_functions, i, fn)
+    {
+      fn->write_to_dump (d);
+    }
+}
+
+static const char * const
+ str_option_reproducer_strings[GCC_JIT_NUM_STR_OPTIONS] = {
+  "GCC_JIT_STR_OPTION_PROGNAME"
+};
+
+static const char * const
+ int_option_reproducer_strings[GCC_JIT_NUM_INT_OPTIONS] = {
+  "GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL"
+};
+
+static const char * const
+ bool_option_reproducer_strings[GCC_JIT_NUM_BOOL_OPTIONS] = {
+  "GCC_JIT_BOOL_OPTION_DEBUGINFO",
+  "GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE",
+  "GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE",
+  "GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE",
+  "GCC_JIT_BOOL_OPTION_DUMP_SUMMARY",
+  "GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING",
+  "GCC_JIT_BOOL_OPTION_SELFCHECK_GC",
+  "GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES"
+};
+
+static const char * const
+ inner_bool_option_reproducer_strings[NUM_INNER_BOOL_OPTIONS] = {
+  "gcc_jit_context_set_bool_allow_unreachable_blocks",
+  "gcc_jit_context_set_bool_use_external_driver"
+};
+
+/* Write the current value of all options to the log file (if any).  */
+
+void
+recording::context::log_all_options () const
+{
+  int opt_idx;
+
+  if (!get_logger ())
+    return;
+
+  for (opt_idx = 0; opt_idx < GCC_JIT_NUM_STR_OPTIONS; opt_idx++)
+    log_str_option ((enum gcc_jit_str_option)opt_idx);
+
+  for (opt_idx = 0; opt_idx < GCC_JIT_NUM_INT_OPTIONS; opt_idx++)
+    log_int_option ((enum gcc_jit_int_option)opt_idx);
+
+  for (opt_idx = 0; opt_idx < GCC_JIT_NUM_BOOL_OPTIONS; opt_idx++)
+    log_bool_option ((enum gcc_jit_bool_option)opt_idx);
+  for (opt_idx = 0; opt_idx < NUM_INNER_BOOL_OPTIONS; opt_idx++)
+    log_inner_bool_option ((enum inner_bool_option)opt_idx);
+}
+
+/* Write the current value of the given string option to the
+   log file (if any).  */
+
+void
+recording::context::log_str_option (enum gcc_jit_str_option opt) const
+{
+  gcc_assert (opt < GCC_JIT_NUM_STR_OPTIONS);
+  if (get_logger ())
+    {
+      if (m_str_options[opt])
+	log ("%s: \"%s\"",
+	     str_option_reproducer_strings[opt],
+	     m_str_options[opt]);
+      else
+	log ("%s: NULL",
+	     str_option_reproducer_strings[opt]);
+    }
+}
+
+/* Write the current value of the given int option to the
+   log file (if any).  */
+
+void
+recording::context::log_int_option (enum gcc_jit_int_option opt) const
+{
+  gcc_assert (opt < GCC_JIT_NUM_INT_OPTIONS);
+  if (get_logger ())
+    log ("%s: %i",
+	 int_option_reproducer_strings[opt],
+	 m_int_options[opt]);
+}
+
+/* Write the current value of the given bool option to the
+   log file (if any).  */
+
+void
+recording::context::log_bool_option (enum gcc_jit_bool_option opt) const
+{
+  gcc_assert (opt < GCC_JIT_NUM_BOOL_OPTIONS);
+  if (get_logger ())
+    log ("%s: %s",
+	 bool_option_reproducer_strings[opt],
+	 m_bool_options[opt] ? "true" : "false");
+}
+
+/* Write the current value of the given "inner" bool option to the
+   log file (if any).  */
+
+void
+recording::context::log_inner_bool_option (enum inner_bool_option opt) const
+{
+  gcc_assert (opt < NUM_INNER_BOOL_OPTIONS);
+  if (get_logger ())
+    log ("%s: %s",
+	 inner_bool_option_reproducer_strings[opt],
+	 m_inner_bool_options[opt] ? "true" : "false");
+}
+
+/* Write C source code to PATH that attempts to replay the API
+   calls made to this context (and its parents), for use in
+   minimizing test cases for libgccjit.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_dump_reproducer_to_file.  */
+
+void
+recording::context::dump_reproducer_to_file (const char *path)
+{
+  JIT_LOG_SCOPE (get_logger ());
+  reproducer r (*this, path);
+
+  /* Generate the "ancestry" of this context, as a list.  */
+  auto_vec <context *> ascending_contexts;
+  for (context *ctxt = this; ctxt; ctxt = ctxt->m_parent_ctxt)
+    ascending_contexts.safe_push (ctxt);
+
+  /* Reverse the list, giving a list of contexts from
+     top-most parent context down through to youngest child context.
+     We will use this list as the parameters of the functions in
+     our generated file.  */
+  unsigned num_ctxts = ascending_contexts.length ();
+  auto_vec <context *> contexts (num_ctxts);
+  for (unsigned i = 0; i < num_ctxts; i++)
+    contexts.safe_push (ascending_contexts[num_ctxts - (i + 1)]);
+
+  /* contexts[0] should be the top-level context.  */
+  gcc_assert (contexts[0]);
+  gcc_assert (contexts[0]->m_toplevel_ctxt == contexts[0]);
+
+  /* The final element in contexts should be "this".  */
+  gcc_assert (contexts[contexts.length () - 1] == this);
+  gcc_assert (contexts[contexts.length () - 1]->m_toplevel_ctxt
+	      == contexts[0]);
+
+  r.write ("/* This code was autogenerated by"
+	   " gcc_jit_context_dump_reproducer_to_file.\n\n");
+  print_version (r.get_file (), "  ", false);
+  r.write ("*/\n");
+  r.write ("#include <libgccjit.h>\n\n");
+  r.write ("#pragma GCC diagnostic ignored \"-Wunused-variable\"\n\n");
+  r.write ("static void\nset_options (");
+  r.write_params (contexts);
+  r.write (");\n\n");
+  r.write ("static void\ncreate_code (");
+  r.write_params (contexts);
+  r.write (");\n\n");
+  r.write ("int\nmain (int argc, const char **argv)\n");
+  r.write ("{\n");
+  for (unsigned i = 0; i < num_ctxts; i++)
+    r.write ("  gcc_jit_context *%s;\n",
+	     r.get_identifier (contexts[i]));
+  r.write ("  gcc_jit_result *result;\n"
+	   "\n");
+
+  /* Create the contexts.
+     The top-level context is acquired from a clean slate, the others as
+     children of the prior context.  */
+  r.write ("  %s = gcc_jit_context_acquire ();\n",
+	   r.get_identifier (contexts[0]));
+  for (unsigned i = 1; i < num_ctxts; i++)
+    r.write ("  %s = gcc_jit_context_new_child_context (%s);\n",
+	     r.get_identifier (contexts[i]),
+	     r.get_identifier (contexts[i - 1]));
+  r.write ("  set_options (");
+  r.write_args (contexts);
+  r.write (");\n");
+  r.write ("  create_code (");
+  r.write_args (contexts);
+  r.write (");\n");
+
+  r.write ("  result = gcc_jit_context_compile (%s);\n",
+	   r.get_identifier (this));
+
+  for (unsigned i = num_ctxts; i > 0; i--)
+    r.write ("  gcc_jit_context_release (%s);\n",
+	     r.get_identifier (contexts[i - 1]));
+
+  r.write ("  gcc_jit_result_release (result);\n"
+	   "  return 0;\n"
+	   "}\n\n");
+
+  /* Define (char *) variables for use in calls to
+     gcc_jit_context_enable_dump.  */
+  for (unsigned ctxt_idx = 0; ctxt_idx < num_ctxts; ctxt_idx++)
+    {
+      if (m_requested_dumps.length ())
+	{
+	  r.write ("/* Requested dumps for %s.  */\n",
+		   r.get_identifier (contexts[ctxt_idx]));
+	  for (unsigned i = 0; i < m_requested_dumps.length (); i++)
+	    r.write ("static char *dump_%p;\n",
+		     (void *)&m_requested_dumps[i]);
+	  r.write ("\n");
+	}
+    }
+
+  /* Write out values of options.  */
+  r.write ("static void\nset_options (");
+  r.write_params (contexts);
+  r.write (")\n{\n");
+  for (unsigned ctxt_idx = 0; ctxt_idx < num_ctxts; ctxt_idx++)
+    {
+      if (ctxt_idx > 0)
+	r.write ("\n");
+
+      r.write ("  /* Set options for %s.  */\n",
+	       r.get_identifier (contexts[ctxt_idx]));
+
+      r.write ("  /* String options.  */\n");
+      for (int opt_idx = 0; opt_idx < GCC_JIT_NUM_STR_OPTIONS; opt_idx++)
+	{
+	  r.write ("  gcc_jit_context_set_str_option (%s,\n"
+		   "                                  %s,\n",
+		   r.get_identifier (contexts[ctxt_idx]),
+		   str_option_reproducer_strings[opt_idx]);
+	  if (m_str_options[opt_idx])
+	    r.write ("                                  \"%s\");\n",
+		     m_str_options[opt_idx]);
+	  else
+	    r.write ("                                  NULL);\n");
+	}
+      r.write ("  /* Int options.  */\n");
+      for (int opt_idx = 0; opt_idx < GCC_JIT_NUM_INT_OPTIONS; opt_idx++)
+	r.write ("  gcc_jit_context_set_int_option (%s,\n"
+		 "                                  %s,\n"
+		 "                                  %i);\n",
+		 r.get_identifier (contexts[ctxt_idx]),
+		 int_option_reproducer_strings[opt_idx],
+		 m_int_options[opt_idx]);
+      r.write ("  /* Boolean options.  */\n");
+      for (int opt_idx = 0; opt_idx < GCC_JIT_NUM_BOOL_OPTIONS; opt_idx++)
+	r.write ("  gcc_jit_context_set_bool_option (%s,\n"
+		 "                                  %s,\n"
+		 "                                  %i);\n",
+		 r.get_identifier (contexts[ctxt_idx]),
+		 bool_option_reproducer_strings[opt_idx],
+		 m_bool_options[opt_idx]);
+      for (int opt_idx = 0; opt_idx < NUM_INNER_BOOL_OPTIONS; opt_idx++)
+	r.write ("  %s (%s, %i);\n",
+		 inner_bool_option_reproducer_strings[opt_idx],
+		 r.get_identifier (contexts[ctxt_idx]),
+		 m_inner_bool_options[opt_idx]);
+
+      if (!m_command_line_options.is_empty ())
+	{
+	  int i;
+	  char *optname;
+	  r.write ("  /* User-provided command-line options.  */\n");
+	  FOR_EACH_VEC_ELT (m_command_line_options, i, optname)
+	    r.write ("  gcc_jit_context_add_command_line_option (%s, \"%s\");\n",
+		     r.get_identifier (contexts[ctxt_idx]),
+		     optname);
+	}
+
+      if (m_requested_dumps.length ())
+	{
+	  r.write ("  /* Requested dumps.  */\n");
+	  /* Dumpfiles that were requested via gcc_jit_context_enable_dump.  */
+	  for (unsigned i = 0; i < m_requested_dumps.length (); i++)
+	    {
+	      r.write ("  gcc_jit_context_enable_dump (%s,\n"
+		       "                               \"%s\",\n"
+		       "                               &dump_%p);\n",
+		       r.get_identifier (contexts[ctxt_idx]),
+		       m_requested_dumps[i].m_dumpname,
+		       (void *)&m_requested_dumps[i]);
+	    }
+	}
+    }
+  r.write ("}\n\n");
+
+  r.write ("static void\ncreate_code (");
+  r.write_params (contexts);
+  r.write (")\n"
+	   "{\n");
+  for (unsigned ctxt_idx = 0; ctxt_idx < num_ctxts; ctxt_idx++)
+    {
+      memento *m;
+      int i;
+      if (ctxt_idx > 0)
+	r.write ("\n\n");
+
+      r.write ("  /* Replay of API calls for %s.  */\n",
+	       r.get_identifier (contexts[ctxt_idx]));
+      FOR_EACH_VEC_ELT (contexts[ctxt_idx]->m_mementos, i, m)
+	m->write_reproducer (r);
+    }
+  r.write ("}\n");
+}
+
+/* Copy the requested dumps within this context and all ancestors into
+   OUT. */
+
+void
+recording::context::get_all_requested_dumps (vec <recording::requested_dump> *out)
+{
+  if (m_parent_ctxt)
+    m_parent_ctxt->get_all_requested_dumps (out);
+
+  out->reserve (m_requested_dumps.length ());
+  out->splice (m_requested_dumps);
+}
+
+/* This is a pre-compilation check for the context (and any parents).
+
+   Detect errors within the context, adding errors if any are found.  */
+
+void
+recording::context::validate ()
+{
+  JIT_LOG_SCOPE (get_logger ());
+
+  if (m_parent_ctxt)
+    m_parent_ctxt->validate ();
+
+  int i;
+  function *fn;
+  FOR_EACH_VEC_ELT (m_functions, i, fn)
+    fn->validate ();
+}
+
+/* The implementation of class gcc::jit::recording::memento.  */
+
+/* Get a (const char *) debug description of the given memento, by
+   calling the pure-virtual make_debug_string hook, caching the
+   result.
+
+   It is intended that this should only be called in debugging and
+   error-handling paths, so this doesn't need to be particularly
+   optimized.  */
+
+const char *
+recording::memento::get_debug_string ()
+{
+  if (!m_debug_string)
+    m_debug_string = make_debug_string ();
+  return m_debug_string->c_str ();
+}
+
+/* Default implementation of recording::memento::write_to_dump, writing
+   an indented form of the memento's debug string to the dump.  */
+
+void
+recording::memento::write_to_dump (dump &d)
+{
+  d.write("  %s\n", get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::string.  */
+
+/* Constructor for gcc::jit::recording::string::string, allocating a
+   copy of the given text using new char[].  */
+
+recording::string::string (context *ctxt, const char *text)
+  : memento (ctxt)
+{
+  m_len = strlen (text);
+  m_buffer = new char[m_len + 1];
+  strcpy (m_buffer, text);
+}
+
+/* Destructor for gcc::jit::recording::string::string.  */
+
+recording::string::~string ()
+{
+  delete[] m_buffer;
+}
+
+/* Function for making gcc::jit::recording::string instances on a
+   context via printf-style formatting.
+
+   It is intended that this should only be called in debugging and
+   error-handling paths, so this doesn't need to be particularly
+   optimized, hence the double-copy of the string is acceptable.  */
+
+recording::string *
+recording::string::from_printf (context *ctxt, const char *fmt, ...)
+{
+  int len;
+  va_list ap;
+  char *buf;
+  recording::string *result;
+
+  va_start (ap, fmt);
+  len = vasprintf (&buf, fmt, ap);
+  va_end (ap);
+
+  if (buf == NULL || len < 0)
+    {
+      ctxt->add_error (NULL, "malloc failure");
+      return NULL;
+    }
+
+  result = ctxt->new_string (buf);
+  free (buf);
+  return result;
+}
+
+/* Implementation of recording::memento::make_debug_string for strings,
+   wrapping the given string in quotes and escaping as necessary.  */
+
+recording::string *
+recording::string::make_debug_string ()
+{
+  /* Hack to avoid infinite recursion into strings when logging all
+     mementos: don't re-escape strings:  */
+  if (m_buffer[0] == '"')
+    return this;
+
+  /* Wrap in quotes and do escaping etc */
+
+  size_t sz = (1 /* opening quote */
+	       + (m_len * 2) /* each char might get escaped */
+	       + 1 /* closing quote */
+	       + 1); /* nil termintator */
+  char *tmp = new char[sz];
+  size_t len = 0;
+
+#define APPEND(CH)  do { gcc_assert (len < sz); tmp[len++] = (CH); } while (0)
+  APPEND('"'); /* opening quote */
+  for (size_t i = 0; i < m_len ; i++)
+    {
+      char ch = m_buffer[i];
+      if (ch == '\t' || ch == '\n' || ch == '\\' || ch == '"')
+	APPEND('\\');
+      APPEND(ch);
+    }
+  APPEND('"'); /* closing quote */
+#undef APPEND
+  tmp[len] = '\0'; /* nil termintator */
+
+  string *result = m_ctxt->new_string (tmp);
+
+  delete[] tmp;
+  return result;
+}
+
+/* Implementation of recording::memento::write_reproducer for strings. */
+
+void
+recording::string::write_reproducer (reproducer &)
+{
+  /* Empty.  */
+}
+
+/* The implementation of class gcc::jit::recording::location.  */
+
+/* Implementation of recording::memento::replay_into for locations.
+
+   Create a new playback::location and store it into the
+   recording::location's m_playback_obj field.  */
+
+void
+recording::location::replay_into (replayer *r)
+{
+  m_playback_obj = r->new_location (this,
+				    m_filename->c_str (),
+				    m_line,
+				    m_column);
+}
+
+/* Implementation of recording::memento::make_debug_string for locations,
+   turning them into the usual form:
+     FILENAME:LINE:COLUMN
+   like we do when emitting diagnostics.  */
+
+recording::string *
+recording::location::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s:%i:%i",
+			      m_filename->c_str (), m_line, m_column);
+}
+
+/* Implementation of recording::memento::write_reproducer for locations. */
+
+void
+recording::location::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "loc");
+  r.write ("  gcc_jit_location *%s =\n"
+	   "    gcc_jit_context_new_location (%s, /* gcc_jit_context *ctxt */\n"
+	   "    %s, /* const char *filename */\n"
+	   "    %i, /* int line */\n"
+	   "    %i);/* int column */\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   m_filename->get_debug_string (),
+	   m_line, m_column);
+}
+
+/* The implementation of class gcc::jit::recording::type.  */
+
+/* Given a type T, get the type T*.
+
+   If this doesn't already exist, generate a new memento_of_get_pointer
+   instance and add it to this type's context's list of mementos.
+
+   Otherwise, use the cached type.
+
+   Implements the post-error-checking part of
+   gcc_jit_type_get_pointer.  */
+
+recording::type *
+recording::type::get_pointer ()
+{
+  if (!m_pointer_to_this_type)
+    {
+      m_pointer_to_this_type = new memento_of_get_pointer (this);
+      m_ctxt->record (m_pointer_to_this_type);
+    }
+  return m_pointer_to_this_type;
+}
+
+/* Given a type T, get the type const T.
+
+   Implements the post-error-checking part of
+   gcc_jit_type_get_const.  */
+
+recording::type *
+recording::type::get_const ()
+{
+  recording::type *result = new memento_of_get_const (this);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* Given a type T, get the type volatile T.
+
+   Implements the post-error-checking part of
+   gcc_jit_type_get_volatile.  */
+
+recording::type *
+recording::type::get_volatile ()
+{
+  recording::type *result = new memento_of_get_volatile (this);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* Given a type, get an aligned version of the type.
+
+   Implements the post-error-checking part of
+   gcc_jit_type_get_aligned.  */
+
+recording::type *
+recording::type::get_aligned (size_t alignment_in_bytes)
+{
+  recording::type *result
+    = new memento_of_get_aligned (this, alignment_in_bytes);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* Given a type, get a vector version of the type.
+
+   Implements the post-error-checking part of
+   gcc_jit_type_get_vector.  */
+
+recording::type *
+recording::type::get_vector (size_t num_units)
+{
+  recording::type *result
+    = new vector_type (this, num_units);
+  m_ctxt->record (result);
+  return result;
+}
+
+const char *
+recording::type::access_as_type (reproducer &r)
+{
+  return r.get_identifier (this);
+}
+
+/* Implementation of pure virtual hook recording::type::dereference for
+   recording::memento_of_get_type.  */
+
+recording::type *
+recording::memento_of_get_type::dereference ()
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+
+    case GCC_JIT_TYPE_VOID:
+      return NULL;
+
+    case GCC_JIT_TYPE_VOID_PTR:
+      return m_ctxt->get_type (GCC_JIT_TYPE_VOID);
+
+    case GCC_JIT_TYPE_BOOL:
+    case GCC_JIT_TYPE_CHAR:
+    case GCC_JIT_TYPE_SIGNED_CHAR:
+    case GCC_JIT_TYPE_UNSIGNED_CHAR:
+    case GCC_JIT_TYPE_SHORT:
+    case GCC_JIT_TYPE_UNSIGNED_SHORT:
+    case GCC_JIT_TYPE_INT:
+    case GCC_JIT_TYPE_UNSIGNED_INT:
+    case GCC_JIT_TYPE_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG:
+    case GCC_JIT_TYPE_LONG_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+    case GCC_JIT_TYPE_FLOAT:
+    case GCC_JIT_TYPE_DOUBLE:
+    case GCC_JIT_TYPE_LONG_DOUBLE:
+    case GCC_JIT_TYPE_COMPLEX_FLOAT:
+    case GCC_JIT_TYPE_COMPLEX_DOUBLE:
+    case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
+      /* Not a pointer: */
+      return NULL;
+
+    case GCC_JIT_TYPE_CONST_CHAR_PTR:
+      return m_ctxt->get_type (GCC_JIT_TYPE_CHAR)->get_const ();
+
+    case GCC_JIT_TYPE_SIZE_T:
+      /* Not a pointer: */
+      return NULL;
+
+    case GCC_JIT_TYPE_FILE_PTR:
+      /* Give the client code back an opaque "struct FILE".  */
+      return m_ctxt->get_opaque_FILE_type ();
+    }
+}
+
+/* Implementation of pure virtual hook recording::type::is_int for
+   recording::memento_of_get_type.  */
+
+bool
+recording::memento_of_get_type::is_int () const
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+
+    case GCC_JIT_TYPE_VOID:
+      return false;
+
+    case GCC_JIT_TYPE_VOID_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_BOOL:
+      return false;
+
+    case GCC_JIT_TYPE_CHAR:
+    case GCC_JIT_TYPE_SIGNED_CHAR:
+    case GCC_JIT_TYPE_UNSIGNED_CHAR:
+    case GCC_JIT_TYPE_SHORT:
+    case GCC_JIT_TYPE_UNSIGNED_SHORT:
+    case GCC_JIT_TYPE_INT:
+    case GCC_JIT_TYPE_UNSIGNED_INT:
+    case GCC_JIT_TYPE_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG:
+    case GCC_JIT_TYPE_LONG_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+      return true;
+
+    case GCC_JIT_TYPE_FLOAT:
+    case GCC_JIT_TYPE_DOUBLE:
+    case GCC_JIT_TYPE_LONG_DOUBLE:
+      return false;
+
+    case GCC_JIT_TYPE_CONST_CHAR_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_SIZE_T:
+      return true;
+
+    case GCC_JIT_TYPE_FILE_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_COMPLEX_FLOAT:
+    case GCC_JIT_TYPE_COMPLEX_DOUBLE:
+    case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
+      return false;
+    }
+}
+
+/* Implementation of pure virtual hook recording::type::is_float for
+   recording::memento_of_get_type.  */
+
+bool
+recording::memento_of_get_type::is_float () const
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+
+    case GCC_JIT_TYPE_VOID:
+      return false;
+
+    case GCC_JIT_TYPE_VOID_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_BOOL:
+      return false;
+
+    case GCC_JIT_TYPE_CHAR:
+    case GCC_JIT_TYPE_SIGNED_CHAR:
+    case GCC_JIT_TYPE_UNSIGNED_CHAR:
+    case GCC_JIT_TYPE_SHORT:
+    case GCC_JIT_TYPE_UNSIGNED_SHORT:
+    case GCC_JIT_TYPE_INT:
+    case GCC_JIT_TYPE_UNSIGNED_INT:
+    case GCC_JIT_TYPE_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG:
+    case GCC_JIT_TYPE_LONG_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+      return false;
+
+    case GCC_JIT_TYPE_FLOAT:
+    case GCC_JIT_TYPE_DOUBLE:
+    case GCC_JIT_TYPE_LONG_DOUBLE:
+      return true;
+
+    case GCC_JIT_TYPE_CONST_CHAR_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_SIZE_T:
+      return false;
+
+    case GCC_JIT_TYPE_FILE_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_COMPLEX_FLOAT:
+    case GCC_JIT_TYPE_COMPLEX_DOUBLE:
+    case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
+      return true;
+    }
+}
+
+/* Implementation of pure virtual hook recording::type::is_bool for
+   recording::memento_of_get_type.  */
+
+bool
+recording::memento_of_get_type::is_bool () const
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+
+    case GCC_JIT_TYPE_VOID:
+      return false;
+
+    case GCC_JIT_TYPE_VOID_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_BOOL:
+      return true;
+
+    case GCC_JIT_TYPE_CHAR:
+    case GCC_JIT_TYPE_SIGNED_CHAR:
+    case GCC_JIT_TYPE_UNSIGNED_CHAR:
+    case GCC_JIT_TYPE_SHORT:
+    case GCC_JIT_TYPE_UNSIGNED_SHORT:
+    case GCC_JIT_TYPE_INT:
+    case GCC_JIT_TYPE_UNSIGNED_INT:
+    case GCC_JIT_TYPE_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG:
+    case GCC_JIT_TYPE_LONG_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+      return false;
+
+    case GCC_JIT_TYPE_FLOAT:
+    case GCC_JIT_TYPE_DOUBLE:
+    case GCC_JIT_TYPE_LONG_DOUBLE:
+      return false;
+
+    case GCC_JIT_TYPE_CONST_CHAR_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_SIZE_T:
+      return false;
+
+    case GCC_JIT_TYPE_FILE_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_COMPLEX_FLOAT:
+    case GCC_JIT_TYPE_COMPLEX_DOUBLE:
+    case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
+      return false;
+    }
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_get_type.  */
+
+void
+recording::memento_of_get_type::replay_into (replayer *r)
+{
+  set_playback_obj (r->get_type (m_kind));
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_get_type.  */
+
+/* Descriptive strings for each of enum gcc_jit_types.  */
+
+static const char * const get_type_strings[] = {
+  "void",    /* GCC_JIT_TYPE_VOID */
+  "void *",  /* GCC_JIT_TYPE_VOID_PTR */
+
+  "bool",  /* GCC_JIT_TYPE_BOOL */
+
+  "char",           /* GCC_JIT_TYPE_CHAR */
+  "signed char",    /* GCC_JIT_TYPE_SIGNED_CHAR */
+  "unsigned char",  /* GCC_JIT_TYPE_UNSIGNED_CHAR */
+
+  "short",           /* GCC_JIT_TYPE_SHORT */
+  "unsigned short",  /* GCC_JIT_TYPE_UNSIGNED_SHORT */
+
+  "int",           /* GCC_JIT_TYPE_INT */
+  "unsigned int",  /* GCC_JIT_TYPE_UNSIGNED_INT */
+
+  "long",           /* GCC_JIT_TYPE_LONG  */
+  "unsigned long",  /* GCC_JIT_TYPE_UNSIGNED_LONG, */
+
+  "long long",           /* GCC_JIT_TYPE_LONG_LONG */
+  "unsigned long long",  /* GCC_JIT_TYPE_UNSIGNED_LONG_LONG */
+
+  "float",        /* GCC_JIT_TYPE_FLOAT */
+  "double",       /* GCC_JIT_TYPE_DOUBLE */
+  "long double",  /* GCC_JIT_TYPE_LONG_DOUBLE */
+
+  "const char *",  /* GCC_JIT_TYPE_CONST_CHAR_PTR */
+
+  "size_t",  /* GCC_JIT_TYPE_SIZE_T */
+
+  "FILE *",  /* GCC_JIT_TYPE_FILE_PTR */
+
+  "complex float", /* GCC_JIT_TYPE_COMPLEX_FLOAT */
+  "complex double", /* GCC_JIT_TYPE_COMPLEX_DOUBLE */
+  "complex long double"  /* GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE */
+
+};
+
+/* Implementation of recording::memento::make_debug_string for
+   results of get_type, using a simple table of type names.  */
+
+recording::string *
+recording::memento_of_get_type::make_debug_string ()
+{
+  return m_ctxt->new_string (get_type_strings[m_kind]);
+}
+
+static const char * const get_type_enum_strings[] = {
+  "GCC_JIT_TYPE_VOID",
+  "GCC_JIT_TYPE_VOID_PTR",
+  "GCC_JIT_TYPE_BOOL",
+  "GCC_JIT_TYPE_CHAR",
+  "GCC_JIT_TYPE_SIGNED_CHAR",
+  "GCC_JIT_TYPE_UNSIGNED_CHAR",
+  "GCC_JIT_TYPE_SHORT",
+  "GCC_JIT_TYPE_UNSIGNED_SHORT",
+  "GCC_JIT_TYPE_INT",
+  "GCC_JIT_TYPE_UNSIGNED_INT",
+  "GCC_JIT_TYPE_LONG",
+  "GCC_JIT_TYPE_UNSIGNED_LONG",
+  "GCC_JIT_TYPE_LONG_LONG",
+  "GCC_JIT_TYPE_UNSIGNED_LONG_LONG",
+  "GCC_JIT_TYPE_FLOAT",
+  "GCC_JIT_TYPE_DOUBLE",
+  "GCC_JIT_TYPE_LONG_DOUBLE",
+  "GCC_JIT_TYPE_CONST_CHAR_PTR",
+  "GCC_JIT_TYPE_SIZE_T",
+  "GCC_JIT_TYPE_FILE_PTR",
+  "GCC_JIT_TYPE_COMPLEX_FLOAT",
+  "GCC_JIT_TYPE_COMPLEX_DOUBLE",
+  "GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE"
+};
+
+void
+recording::memento_of_get_type::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "type");
+  r.write ("  gcc_jit_type *%s = gcc_jit_context_get_type (%s, %s);\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   get_type_enum_strings[m_kind]);
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_get_pointer.  */
+
+/* Override of default implementation of
+   recording::type::accepts_writes_from for get_pointer.
+
+   Require a pointer type, and allowing writes to
+   (const T *) from a (T*), but not the other way around.  */
+
+bool
+recording::memento_of_get_pointer::accepts_writes_from (type *rtype)
+{
+  /* Must be a pointer type: */
+  type *rtype_points_to = rtype->is_pointer ();
+  if (!rtype_points_to)
+    return false;
+
+  /* It's OK to assign to a (const T *) from a (T *).  */
+  return m_other_type->unqualified ()
+    ->accepts_writes_from (rtype_points_to);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_get_pointer.  */
+
+void
+recording::memento_of_get_pointer::replay_into (replayer *)
+{
+  set_playback_obj (m_other_type->playback_type ()->get_pointer ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of get_pointer, adding " *" to the underlying type,
+   with special-casing to handle function pointer types.  */
+
+recording::string *
+recording::memento_of_get_pointer::make_debug_string ()
+{
+  /* Special-case function pointer types, to put the "*" in parens between
+     the return type and the params (for one level of dereferencing, at
+     least).  */
+  if (function_type *fn_type = m_other_type->dyn_cast_function_type ())
+    return fn_type->make_debug_string_with_ptr ();
+
+  return string::from_printf (m_ctxt,
+			      "%s *", m_other_type->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for get_pointer.  */
+
+void
+recording::memento_of_get_pointer::write_reproducer (reproducer &r)
+{
+  /* We need to special-case function pointer types; see the notes in
+     recording::function_type::write_deferred_reproducer.  */
+  if (function_type *fn_type = m_other_type->dyn_cast_function_type ())
+    {
+      fn_type->write_deferred_reproducer (r, this);
+      return;
+    }
+
+  const char *id = r.make_identifier (this, "type");
+  r.write ("  gcc_jit_type *%s =\n"
+	   "    gcc_jit_type_get_pointer (%s);\n",
+	   id,
+	   r.get_identifier_as_type (m_other_type));
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_get_const.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_get_const.  */
+
+void
+recording::memento_of_get_const::replay_into (replayer *)
+{
+  set_playback_obj (m_other_type->playback_type ()->get_const ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of get_const, prepending "const ".  */
+
+recording::string *
+recording::memento_of_get_const::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "const %s", m_other_type->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for const types. */
+
+void
+recording::memento_of_get_const::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "type");
+  r.write ("  gcc_jit_type *%s =\n"
+	   "    gcc_jit_type_get_const (%s);\n",
+	   id,
+	   r.get_identifier_as_type (m_other_type));
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_get_volatile.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_get_volatile.  */
+
+void
+recording::memento_of_get_volatile::replay_into (replayer *)
+{
+  set_playback_obj (m_other_type->playback_type ()->get_volatile ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of get_volatile, prepending "volatile ".  */
+
+recording::string *
+recording::memento_of_get_volatile::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "volatile %s", m_other_type->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for volatile
+   types. */
+
+void
+recording::memento_of_get_volatile::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "type");
+  r.write ("  gcc_jit_type *%s =\n"
+	   "    gcc_jit_type_get_volatile (%s);\n",
+	   id,
+	   r.get_identifier_as_type (m_other_type));
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_get_aligned.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_get_aligned.  */
+
+void
+recording::memento_of_get_aligned::replay_into (replayer *)
+{
+  set_playback_obj
+    (m_other_type->playback_type ()->get_aligned (m_alignment_in_bytes));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of get_aligned.  */
+
+recording::string *
+recording::memento_of_get_aligned::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s  __attribute__((aligned(%zi)))",
+			      m_other_type->get_debug_string (),
+			      m_alignment_in_bytes);
+}
+
+/* Implementation of recording::memento::write_reproducer for aligned
+   types. */
+
+void
+recording::memento_of_get_aligned::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "type");
+  r.write ("  gcc_jit_type *%s =\n"
+	   "    gcc_jit_type_get_aligned (%s, %zi);\n",
+	   id,
+	   r.get_identifier_as_type (m_other_type),
+	   m_alignment_in_bytes);
+}
+
+/* The implementation of class gcc::jit::recording::vector_type.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::vector_type.  */
+
+void
+recording::vector_type::replay_into (replayer *)
+{
+  set_playback_obj
+    (m_other_type->playback_type ()->get_vector (m_num_units));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of get_vector.  */
+
+recording::string *
+recording::vector_type::make_debug_string ()
+{
+  return string::from_printf
+    (m_ctxt,
+     "%s  __attribute__((vector_size(sizeof (%s) * %zi)))",
+     m_other_type->get_debug_string (),
+     m_other_type->get_debug_string (),
+     m_num_units);
+}
+
+/* Implementation of recording::memento::write_reproducer for vector types. */
+
+void
+recording::vector_type::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "type");
+  r.write ("  gcc_jit_type *%s =\n"
+	   "    gcc_jit_type_get_vector (%s, %zi);\n",
+	   id,
+	   r.get_identifier_as_type (m_other_type),
+	   m_num_units);
+}
+
+/* The implementation of class gcc::jit::recording::array_type */
+
+/* Implementation of pure virtual hook recording::type::dereference for
+   recording::array_type.  */
+
+recording::type *
+recording::array_type::dereference ()
+{
+  return m_element_type;
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::array_type.  */
+
+void
+recording::array_type::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_array_type (playback_location (r, m_loc),
+				       m_element_type->playback_type (),
+				       m_num_elements));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of new_array_type.  */
+
+recording::string *
+recording::array_type::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s[%d]",
+			      m_element_type->get_debug_string (),
+			      m_num_elements);
+}
+
+/* Implementation of recording::memento::write_reproducer for array
+   types. */
+
+void
+recording::array_type::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "array_type");
+  r.write ("  gcc_jit_type *%s =\n"
+	   "    gcc_jit_context_new_array_type (%s,\n"
+	   "                                    %s, /* gcc_jit_location *loc */\n"
+	   "                                    %s, /* gcc_jit_type *element_type */\n"
+	   "                                    %i); /* int num_elements */\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   r.get_identifier (m_loc),
+	   r.get_identifier_as_type (m_element_type),
+	   m_num_elements);
+}
+
+/* The implementation of class gcc::jit::recording::function_type */
+
+/* Constructor for gcc::jit::recording::function_type.  */
+
+recording::function_type::function_type (context *ctxt,
+					 type *return_type,
+					 int num_params,
+					 type **param_types,
+					 int is_variadic)
+: type (ctxt),
+  m_return_type (return_type),
+  m_param_types (),
+  m_is_variadic (is_variadic)
+{
+  for (int i = 0; i< num_params; i++)
+    m_param_types.safe_push (param_types[i]);
+}
+
+/* Implementation of pure virtual hook recording::type::dereference for
+   recording::function_type.  */
+
+recording::type *
+recording::function_type::dereference ()
+{
+  return NULL;
+}
+
+/* Implementation of virtual hook recording::type::is_same_type_as for
+   recording::function_type.
+
+   We override this to avoid requiring identity of function pointer types,
+   so that if client code has obtained the same signature in
+   different ways (e.g. via gcc_jit_context_new_function_ptr_type
+   vs gcc_jit_function_get_address), the different function_type
+   instances are treated as compatible.
+
+   We can't use type::accepts_writes_from for this as we need a stronger
+   notion of "sameness": if we have a fn_ptr type that has args that are
+   themselves fn_ptr types, then those args still need to match exactly.
+
+   Alternatively, we could consolidate attempts to create identical
+   function_type instances so that pointer equality works, but that runs
+   into issues about the lifetimes of the cache (w.r.t. nested contexts).  */
+
+bool
+recording::function_type::is_same_type_as (type *other)
+{
+  gcc_assert (other);
+
+  function_type *other_fn_type = other->dyn_cast_function_type ();
+  if (!other_fn_type)
+    return false;
+
+  /* Everything must match.  */
+
+  if (!m_return_type->is_same_type_as (other_fn_type->m_return_type))
+    return false;
+
+  if (m_param_types.length () != other_fn_type->m_param_types.length ())
+    return false;
+
+  unsigned i;
+  type *param_type;
+  FOR_EACH_VEC_ELT (m_param_types, i, param_type)
+    if (!param_type->is_same_type_as (other_fn_type->m_param_types[i]))
+      return false;
+
+  if (m_is_variadic != other_fn_type->m_is_variadic)
+    return false;
+
+  /* Passed all tests.  */
+  return true;
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::function_type.  */
+
+void
+recording::function_type::replay_into (replayer *r)
+{
+  /* Convert m_param_types to a vec of playback type.  */
+  auto_vec <playback::type *> param_types;
+  int i;
+  recording::type *type;
+  param_types.create (m_param_types.length ());
+  FOR_EACH_VEC_ELT (m_param_types, i, type)
+    param_types.safe_push (type->playback_type ());
+
+  set_playback_obj (r->new_function_type (m_return_type->playback_type (),
+					  &param_types,
+					  m_is_variadic));
+}
+
+/* Special-casing for make_debug_string for get_pointer results for
+   handling (one level) of pointers to functions.  */
+
+recording::string *
+recording::function_type::make_debug_string_with_ptr ()
+{
+  return make_debug_string_with ("(*) ");
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of new_function_type.  */
+
+recording::string *
+recording::function_type::make_debug_string ()
+{
+  return make_debug_string_with ("");
+}
+
+/* Build a debug string representation of the form:
+
+     RESULT_TYPE INSERT (PARAM_TYPES)
+
+   for use when handling 0 and 1 level of indirection to this
+   function type.  */
+
+recording::string *
+recording::function_type::make_debug_string_with (const char *insert)
+{
+  /* First, build a buffer for the arguments.  */
+  /* Calculate length of said buffer.  */
+  size_t sz = 1; /* nil terminator */
+  for (unsigned i = 0; i< m_param_types.length (); i++)
+    {
+      sz += strlen (m_param_types[i]->get_debug_string ());
+      sz += 2; /* ", " separator */
+    }
+  if (m_is_variadic)
+    sz += 5; /* ", ..." separator and ellipsis */
+
+  /* Now allocate and populate the buffer.  */
+  char *argbuf = new char[sz];
+  size_t len = 0;
+
+  for (unsigned i = 0; i< m_param_types.length (); i++)
+    {
+      strcpy (argbuf + len, m_param_types[i]->get_debug_string ());
+      len += strlen (m_param_types[i]->get_debug_string ());
+      if (i + 1 < m_param_types.length ())
+	{
+	  strcpy (argbuf + len, ", ");
+	  len += 2;
+	}
+    }
+  if (m_is_variadic)
+    {
+      if (m_param_types.length ())
+	{
+	  strcpy (argbuf + len, ", ");
+	  len += 2;
+	}
+      strcpy (argbuf + len, "...");
+      len += 3;
+    }
+  argbuf[len] = '\0';
+
+  /* ...and use it to get the string for the call as a whole.  */
+  string *result = string::from_printf (m_ctxt,
+					"%s %s(%s)",
+					m_return_type->get_debug_string (),
+					insert,
+					argbuf);
+
+  delete[] argbuf;
+
+  return result;
+}
+
+/* Implementation of recording::memento::write_reproducer for function
+   types.  */
+
+void
+recording::function_type::write_reproducer (reproducer &)
+{
+  /* see notes below.  */
+}
+
+/* There's a get_pointer within context::new_function_ptr_type:
+   the type received by client code isn't the memento for the
+   function_type, but instead the result of get_pointer on it.
+
+   Hence we can't directly write a reproducer that gives function_type.
+   Instead we special-case things within get_pointer, detecting this
+   case, calling the following function.  */
+
+void
+recording::function_type::write_deferred_reproducer (reproducer &r,
+						     memento *ptr_type)
+{
+  gcc_assert (ptr_type);
+  r.make_identifier (this, "function_type");
+  const char *ptr_id = r.make_identifier (ptr_type, "ptr_to");
+  const char *param_types_id = r.make_tmp_identifier ("params_for", this);
+  r.write ("  gcc_jit_type *%s[%i] = {\n",
+	   param_types_id,
+	   m_param_types.length ());
+  int i;
+  type *param_type;
+  FOR_EACH_VEC_ELT (m_param_types, i, param_type)
+    r.write ("    %s,\n", r.get_identifier_as_type (param_type));
+  r.write ("  };\n");
+  r.write ("  gcc_jit_type *%s =\n"
+	   "    gcc_jit_context_new_function_ptr_type (%s, /* gcc_jit_context *ctxt */\n"
+	   "                                           %s, /* gcc_jit_location *loc */\n"
+	   "                                           %s, /* gcc_jit_type *return_type */\n"
+	   "                                           %i, /* int num_params */\n"
+	   "                                           %s, /* gcc_jit_type **param_types */\n"
+	   "                                           %i); /* int is_variadic */\n",
+	   ptr_id,
+	   r.get_identifier (get_context ()),
+	   "NULL", /* location is not stored */
+	   r.get_identifier_as_type (m_return_type),
+	   m_param_types.length (),
+	   param_types_id,
+	   m_is_variadic);
+}
+
+/* The implementation of class gcc::jit::recording::field.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::field.  */
+
+void
+recording::field::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_field (playback_location (r, m_loc),
+				  m_type->playback_type (),
+				  playback_string (m_name)));
+}
+
+/* Override the default implementation of
+   recording::memento::write_to_dump.  Dump each field
+   by dumping a line of the form:
+      TYPE NAME;
+   so that we can build up a struct/union field-byfield.  */
+
+void
+recording::field::write_to_dump (dump &d)
+{
+  d.write ("  %s %s;\n",
+	   m_type->get_debug_string (),
+	   m_name->c_str ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of new_field.  */
+
+recording::string *
+recording::field::make_debug_string ()
+{
+  return m_name;
+}
+
+/* Implementation of recording::memento::write_reproducer for fields.  */
+
+void
+recording::field::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "field");
+  r.write("  gcc_jit_field *%s =\n"
+	  "    gcc_jit_context_new_field (%s,\n"
+	  "                               %s, /* gcc_jit_location *loc */\n"
+	  "                               %s, /* gcc_jit_type *type, */\n"
+	  "                               %s); /* const char *name */\n",
+	  id,
+	  r.get_identifier (get_context ()),
+	  r.get_identifier (m_loc),
+	  r.get_identifier_as_type (m_type),
+	  m_name->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::compound_type */
+
+/* The constructor for gcc::jit::recording::compound_type.  */
+
+recording::compound_type::compound_type (context *ctxt,
+					 location *loc,
+					 string *name)
+: type (ctxt),
+  m_loc (loc),
+  m_name (name),
+  m_fields (NULL)
+{
+}
+
+/* Set the fields of a compound type.
+
+   Implements the post-error-checking part of
+   gcc_jit_struct_set_fields, and is also used by
+   gcc_jit_context_new_union_type.  */
+
+void
+recording::compound_type::set_fields (location *loc,
+				      int num_fields,
+				      field **field_array)
+{
+  m_loc = loc;
+  gcc_assert (NULL == m_fields);
+
+  m_fields = new fields (this, num_fields, field_array);
+  m_ctxt->record (m_fields);
+}
+
+/* Implementation of pure virtual hook recording::type::dereference for
+   recording::compound_type.  */
+
+recording::type *
+recording::compound_type::dereference ()
+{
+  return NULL; /* not a pointer */
+}
+
+/* The implementation of class gcc::jit::recording::struct_.  */
+
+/* The constructor for gcc::jit::recording::struct_.  */
+
+recording::struct_::struct_ (context *ctxt,
+			     location *loc,
+			     string *name)
+: compound_type (ctxt, loc, name)
+{
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::struct_.  */
+
+void
+recording::struct_::replay_into (replayer *r)
+{
+  set_playback_obj (
+    r->new_compound_type (playback_location (r, get_loc ()),
+			  get_name ()->c_str (),
+			  true /* is_struct */));
+}
+
+const char *
+recording::struct_::access_as_type (reproducer &r)
+{
+  return r.xstrdup_printf ("gcc_jit_struct_as_type (%s)",
+			   r.get_identifier (this));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   structs.  */
+
+recording::string *
+recording::struct_::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "struct %s", get_name ()->c_str ());
+}
+
+void
+recording::struct_::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "struct");
+  r.write ("  gcc_jit_struct *%s =\n"
+	   "    gcc_jit_context_new_opaque_struct (%s,\n"
+	   "                                       %s, /* gcc_jit_location *loc */\n"
+	   "                                       %s); /* const char *name */\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   r.get_identifier (get_loc ()),
+	   get_name ()->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::union_.  */
+
+/* The constructor for gcc::jit::recording::union_.  */
+
+recording::union_::union_ (context *ctxt,
+			   location *loc,
+			   string *name)
+: compound_type (ctxt, loc, name)
+{
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::union_.  */
+
+void
+recording::union_::replay_into (replayer *r)
+{
+  set_playback_obj (
+    r->new_compound_type (playback_location (r, get_loc ()),
+			  get_name ()->c_str (),
+			  false /* is_struct */));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   unions.  */
+
+recording::string *
+recording::union_::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "union %s", get_name ()->c_str ());
+}
+
+/* Implementation of recording::memento::write_reproducer for unions.  */
+
+void
+recording::union_::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "union");
+
+  const char *fields_id = r.make_tmp_identifier ("fields_for", this);
+  r.write ("  gcc_jit_field *%s[%i] = {\n",
+	   fields_id,
+	   get_fields ()->length ());
+  for (int i = 0; i < get_fields ()->length (); i++)
+    r.write ("    %s,\n", r.get_identifier (get_fields ()->get_field (i)));
+  r.write ("  };\n");
+
+  r.write ("  gcc_jit_type *%s =\n"
+	   "    gcc_jit_context_new_union_type (%s,\n"
+	   "                                    %s, /* gcc_jit_location *loc */\n"
+	   "                                    %s, /* const char *name */\n"
+	   "                                    %i, /* int num_fields */\n"
+	   "                                    %s); /* gcc_jit_field **fields */\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   r.get_identifier (get_loc ()),
+	   get_name ()->get_debug_string (),
+	   get_fields ()->length (),
+	   fields_id);
+}
+
+/* The implementation of class gcc::jit::recording::fields.  */
+
+/* The constructor for gcc::jit::recording::fields.  */
+
+recording::fields::fields (compound_type *struct_or_union,
+			   int num_fields,
+			   field **fields)
+: memento (struct_or_union->m_ctxt),
+  m_struct_or_union (struct_or_union),
+  m_fields ()
+{
+  for (int i = 0; i < num_fields; i++)
+    {
+      gcc_assert (fields[i]->get_container () == NULL);
+      fields[i]->set_container (m_struct_or_union);
+      m_fields.safe_push (fields[i]);
+    }
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::fields.  */
+
+void
+recording::fields::replay_into (replayer *)
+{
+  auto_vec<playback::field *> playback_fields;
+  playback_fields.create (m_fields.length ());
+  for (unsigned i = 0; i < m_fields.length (); i++)
+    playback_fields.safe_push (m_fields[i]->playback_field ());
+  m_struct_or_union->playback_compound_type ()->set_fields (&playback_fields);
+}
+
+/* Override the default implementation of
+   recording::memento::write_to_dump by writing a union/struct
+   declaration of this form:
+
+      struct/union NAME {
+	TYPE_1 NAME_1;
+	TYPE_2 NAME_2;
+	....
+	TYPE_N NAME_N;
+      };
+
+    to the dump.  */
+
+void
+recording::fields::write_to_dump (dump &d)
+{
+  int i;
+  field *f;
+
+  d.write ("%s\n{\n", m_struct_or_union->get_debug_string ());
+  FOR_EACH_VEC_ELT (m_fields, i, f)
+    f->write_to_dump (d);
+  d.write ("};\n");
+}
+
+/* Implementation of recording::memento::write_reproducer for the fields
+   subclass.  */
+
+void
+recording::fields::write_reproducer (reproducer &r)
+{
+  if (m_struct_or_union)
+    if (NULL == m_struct_or_union->dyn_cast_struct ())
+      /* We have a union; the fields have already been written by
+	 union::write_reproducer.  */
+      return;
+
+  const char *fields_id = r.make_identifier (this, "fields");
+  r.write ("  gcc_jit_field *%s[%i] = {\n",
+	   fields_id,
+	   m_fields.length ());
+  int i;
+  field *field;
+  FOR_EACH_VEC_ELT (m_fields, i, field)
+    r.write ("    %s,\n", r.get_identifier (field));
+  r.write ("  };\n");
+
+  r.write ("  gcc_jit_struct_set_fields (%s, /* gcc_jit_struct *struct_type */\n"
+	   "                             %s, /* gcc_jit_location *loc */\n"
+	   "                             %i, /* int num_fields */\n"
+	   "                             %s); /* gcc_jit_field **fields */\n",
+	   r.get_identifier (m_struct_or_union),
+	   r.get_identifier ((memento *)NULL),
+	   m_fields.length (),
+	   fields_id);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   field tables.  */
+
+recording::string *
+recording::fields::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "fields");
+}
+
+/* The implementation of class gcc::jit::recording::rvalue.  */
+
+/* Create a recording::access_field_rvalue instance and add it to
+   the rvalue's context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_rvalue_access_field.  */
+
+recording::rvalue *
+recording::rvalue::access_field (recording::location *loc,
+				 field *field)
+{
+  recording::rvalue *result =
+    new access_field_rvalue (m_ctxt, loc, this, field);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* Create a recording::dereference_field_rvalue instance and add it to
+   the rvalue's context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_rvalue_dereference_field.  */
+
+recording::lvalue *
+recording::rvalue::dereference_field (recording::location *loc,
+				      field *field)
+{
+  recording::lvalue *result =
+    new dereference_field_rvalue (m_ctxt, loc, this, field);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* Create a recording::dereference_rvalue instance and add it to the
+   rvalue's context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_rvalue_dereference.  */
+
+recording::lvalue *
+recording::rvalue::dereference (recording::location *loc)
+{
+  recording::lvalue *result =
+    new dereference_rvalue (m_ctxt, loc, this);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* An rvalue visitor, for validating that every rvalue within an expression
+   trees within "STMT" has the correct scope (e.g. no access to locals
+   of a different function).  */
+
+class rvalue_usage_validator : public recording::rvalue_visitor
+{
+ public:
+  rvalue_usage_validator (const char *api_funcname,
+			  recording::context *ctxt,
+			  recording::statement *stmt);
+
+  void
+  visit (recording::rvalue *rvalue) FINAL OVERRIDE;
+
+ private:
+  const char *m_api_funcname;
+  recording::context *m_ctxt;
+  recording::statement *m_stmt;
+};
+
+/* The trivial constructor for rvalue_usage_validator.  */
+
+rvalue_usage_validator::rvalue_usage_validator (const char *api_funcname,
+						recording::context *ctxt,
+						recording::statement *stmt)
+  : m_api_funcname (api_funcname),
+    m_ctxt (ctxt),
+    m_stmt (stmt)
+{
+}
+
+/* Verify that the given rvalue is in the correct scope.  */
+
+void
+rvalue_usage_validator::visit (recording::rvalue *rvalue)
+{
+  gcc_assert (m_stmt->get_block ());
+  recording::function *stmt_scope = m_stmt->get_block ()->get_function ();
+
+  /* Most rvalues don't have a scope (only locals and params).  */
+  if (rvalue->get_scope ())
+    {
+      if (rvalue->get_scope () != stmt_scope)
+	m_ctxt->add_error
+	  (rvalue->get_loc (),
+	   "%s:"
+	   " rvalue %s (type: %s)"
+	   " has scope limited to function %s"
+	   " but was used within function %s"
+	   " (in statement: %s)",
+	   m_api_funcname,
+	   rvalue->get_debug_string (),
+	   rvalue->get_type ()->get_debug_string (),
+	   rvalue->get_scope ()->get_debug_string (),
+	   stmt_scope->get_debug_string (),
+	   m_stmt->get_debug_string ());
+    }
+  else
+    {
+      if (rvalue->dyn_cast_param ())
+	m_ctxt->add_error
+	  (rvalue->get_loc (),
+	   "%s:"
+	   " param %s (type: %s)"
+	   " was used within function %s"
+	   " (in statement: %s)"
+	   " but is not associated with any function",
+	   m_api_funcname,
+	   rvalue->get_debug_string (),
+	   rvalue->get_type ()->get_debug_string (),
+	   stmt_scope->get_debug_string (),
+	   m_stmt->get_debug_string ());
+    }
+}
+
+/* Verify that it's valid to use this rvalue (and all expressions
+   in the tree below it) within the given statement.
+
+   For example, we must reject attempts to use a local from one
+   function within a different function here, or we'll get
+   an ICE deep inside toplev::main.  */
+
+void
+recording::rvalue::verify_valid_within_stmt (const char *api_funcname, statement *s)
+{
+  rvalue_usage_validator v (api_funcname,
+			    s->get_context (),
+			    s);
+
+  /* Verify that it's OK to use this rvalue within s.  */
+  v.visit (this);
+
+  /* Traverse the expression tree below "this", verifying all rvalues
+     within it.  */
+  visit_children (&v);
+}
+
+/* Set the scope of this rvalue to be the given function.  This can only
+   be done once on a given rvalue.  */
+
+void
+recording::rvalue::set_scope (function *scope)
+{
+  gcc_assert (scope);
+  gcc_assert (NULL == m_scope);
+  m_scope = scope;
+}
+
+
+/* Implementation of recording::rvalue::access_as_rvalue for rvalues
+   themselves.
+   Instances of rvalue don't need an upcast call.  */
+
+const char *
+recording::rvalue::access_as_rvalue (reproducer &r)
+{
+  return r.get_identifier (this);
+}
+
+/* Return a debug string for the given rvalue, wrapping it in parentheses
+   if needed to mimic C's precedence rules, i.e. if OUTER_PREC is of
+   stronger precedence that this rvalue's precedence.
+
+   For example, given:
+
+           MULT
+          /    \
+       PLUS     MINUS
+      /    \   /     \
+     A      B C       D
+
+   we want to emit:
+
+     (A + B) * (C - D)
+
+   since MULT has strong precedence than PLUS and MINUS, whereas for:
+
+           PLUS
+          /    \
+       MULT     DIVIDE
+      /    \   /      \
+     A      B C        D
+
+   we can simply emit:
+
+     A * B + C / D
+
+   since PLUS has weaker precedence than MULT and DIVIDE.  */
+
+const char *
+recording::rvalue::get_debug_string_parens (enum precedence outer_prec)
+{
+  enum precedence this_prec = get_precedence ();
+
+  /* If this_prec has stronger precedence than outer_prec, we don't
+     need to wrap this in parens within the outer debug string.
+     Stronger precedences occur earlier than weaker within the enum,
+     so this is a less than test.  Equal precedences don't need
+     parentheses.  */
+  if (this_prec <= outer_prec)
+    return get_debug_string();
+
+  /* Otherwise, we need parentheses.  */
+
+  /* Lazily-build and cache m_parenthesized_string.  */
+  if (!m_parenthesized_string)
+    {
+      const char *debug_string = get_debug_string ();
+      m_parenthesized_string = string::from_printf (get_context (),
+						    "(%s)",
+						    debug_string);
+    }
+  gcc_assert (m_parenthesized_string);
+  return m_parenthesized_string->c_str ();
+}
+
+
+/* The implementation of class gcc::jit::recording::lvalue.  */
+
+/* Create a recording::new_access_field_of_lvalue instance and add it to
+   the lvalue's context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_lvalue_access_field.  */
+
+recording::lvalue *
+recording::lvalue::access_field (recording::location *loc,
+				 field *field)
+{
+  recording::lvalue *result =
+    new access_field_of_lvalue (m_ctxt, loc, this, field);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* Implementation of recording::rvalue::access_as_rvalue for lvalues.
+   Instances of lvalue need to be wrapped in a gcc_jit_lvalue_as_rvalue
+   upcast call.  */
+
+const char *
+recording::lvalue::access_as_rvalue (reproducer &r)
+{
+  return r.xstrdup_printf ("gcc_jit_lvalue_as_rvalue (%s)",
+			   r.get_identifier (this));
+}
+
+/* Implementation of recording::lvalue::access_as_lvalue for lvalues.
+   Instances of lvalue don't need to be upcast.  */
+
+const char *
+recording::lvalue::access_as_lvalue (reproducer &r)
+{
+  return r.get_identifier (this);
+}
+
+/* Create a recording::get_address_of_lvalue instance and add it to
+   the lvalue's context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_lvalue_get_address.  */
+
+recording::rvalue *
+recording::lvalue::get_address (recording::location *loc)
+{
+  recording::rvalue *result =
+    new get_address_of_lvalue (m_ctxt, loc, this);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* The implementation of class gcc::jit::recording::param.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::param.  */
+
+void
+recording::param::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_param (playback_location (r, m_loc),
+				  m_type->playback_type (),
+				  m_name->c_str ()));
+}
+
+/* Implementation of recording::rvalue::access_as_rvalue for params.
+   Instances of param need to be wrapped in a gcc_jit_param_as_rvalue
+   upcast call.  */
+
+const char *
+recording::param::access_as_rvalue (reproducer &r)
+{
+  return r.xstrdup_printf ("gcc_jit_param_as_rvalue (%s)",
+			   r.get_identifier (this));
+}
+
+/* Implementation of recording::lvalue::access_as_lvalue for params.
+   Instances of param need to be wrapped in a gcc_jit_param_as_lvalue
+   upcast call.  */
+
+const char *
+recording::param::access_as_lvalue (reproducer &r)
+{
+  return r.xstrdup_printf ("gcc_jit_param_as_lvalue (%s)",
+			   r.get_identifier (this));
+}
+
+/* Implementation of recording::memento::write_reproducer for params. */
+
+void
+recording::param::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "param");
+  r.write ("  gcc_jit_param *%s =\n"
+	   "    gcc_jit_context_new_param (%s,\n"
+	   "                               %s, /* gcc_jit_location *loc */\n"
+	   "                               %s, /*gcc_jit_type *type */\n"
+	   "                               %s); /* const char *name */\n",
+	   id,
+    r.get_identifier (get_context ()),
+	   r.get_identifier (m_loc),
+	   r.get_identifier_as_type (m_type),
+	   m_name->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::function.  */
+
+/* gcc::jit::recording::function's constructor.  */
+
+recording::function::function (context *ctxt,
+			       recording::location *loc,
+			       enum gcc_jit_function_kind kind,
+			       type *return_type,
+			       recording::string *name,
+			       int num_params,
+			       recording::param **params,
+			       int is_variadic,
+			       enum built_in_function builtin_id)
+: memento (ctxt),
+  m_loc (loc),
+  m_kind (kind),
+  m_return_type (return_type),
+  m_name (name),
+  m_params (),
+  m_is_variadic (is_variadic),
+  m_builtin_id (builtin_id),
+  m_locals (),
+  m_blocks (),
+  m_fn_ptr_type (NULL)
+{
+  for (int i = 0; i< num_params; i++)
+    {
+      param *param = params[i];
+      gcc_assert (param);
+
+      /* Associate each param with this function.
+
+	 Verify that the param doesn't already have a function.  */
+      if (param->get_scope ())
+	{
+	  /* We've already rejected attempts to reuse a param between
+	     different functions (within gcc_jit_context_new_function), so
+	     if the param *does* already have a function, it must be being
+	     reused within the params array for this function.  We must
+	     produce an error for this reuse (blocking the compile), since
+	     otherwise we'd have an ICE later on.  */
+	  gcc_assert (this == param->get_scope ());
+	  ctxt->add_error
+	    (loc,
+	     "gcc_jit_context_new_function:"
+	     " parameter %s (type: %s)"
+	     " is used more than once when creating function %s",
+	     param->get_debug_string (),
+	     param->get_type ()->get_debug_string (),
+	     name->c_str ());
+	}
+      else
+	{
+	  /* The normal, non-error case: associate this function with the
+	     param.  */
+	  param->set_scope (this);
+	}
+
+      m_params.safe_push (param);
+    }
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::function.  */
+
+void
+recording::function::replay_into (replayer *r)
+{
+  /* Convert m_params to a vec of playback param.  */
+  auto_vec <playback::param *> params;
+  int i;
+  recording::param *param;
+  params.create (m_params.length ());
+  FOR_EACH_VEC_ELT (m_params, i, param)
+    params.safe_push (param->playback_param ());
+
+  set_playback_obj (r->new_function (playback_location (r, m_loc),
+				     m_kind,
+				     m_return_type->playback_type (),
+				     m_name->c_str (),
+				     &params,
+				     m_is_variadic,
+				     m_builtin_id));
+}
+
+/* Create a recording::local instance and add it to
+   the functions's context's list of mementos, and to the function's
+   list of locals.
+
+   Implements the post-error-checking part of
+   gcc_jit_function_new_local.  */
+
+recording::lvalue *
+recording::function::new_local (recording::location *loc,
+				type *type,
+				const char *name)
+{
+  local *result = new local (this, loc, type, new_string (name));
+  m_ctxt->record (result);
+  m_locals.safe_push (result);
+  return result;
+}
+
+/* Create a recording::block instance and add it to
+   the functions's context's list of mementos, and to the function's
+   list of blocks.
+
+   Implements the post-error-checking part of
+   gcc_jit_function_new_block.  */
+
+recording::block*
+recording::function::new_block (const char *name)
+{
+  gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
+
+  recording::block *result =
+    new recording::block (this, m_blocks.length (), new_string (name));
+  m_ctxt->record (result);
+  m_blocks.safe_push (result);
+  return result;
+}
+
+/* Override the default implementation of
+   recording::memento::write_to_dump by dumping a C-like
+   representation of the function; either like a prototype
+   for GCC_JIT_FUNCTION_IMPORTED, or like a full definition for
+   all other kinds of function.  */
+
+void
+recording::function::write_to_dump (dump &d)
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+    case GCC_JIT_FUNCTION_EXPORTED:
+    case GCC_JIT_FUNCTION_IMPORTED:
+      d.write ("extern ");
+      break;
+    case GCC_JIT_FUNCTION_INTERNAL:
+      d.write ("static ");
+      break;
+    case GCC_JIT_FUNCTION_ALWAYS_INLINE:
+      d.write ("static inline ");
+      break;
+     }
+  d.write ("%s\n", m_return_type->get_debug_string ());
+
+  if (d.update_locations ())
+    m_loc = d.make_location ();
+
+  d.write ("%s (", get_debug_string ());
+
+  int i;
+  recording::param *param;
+  FOR_EACH_VEC_ELT (m_params, i, param)
+    {
+      if (i > 0)
+	d.write (", ");
+      d.write ("%s %s",
+	       param->get_type ()->get_debug_string (),
+	       param->get_debug_string ());
+    }
+  d.write (")");
+  if (m_kind == GCC_JIT_FUNCTION_IMPORTED)
+    {
+      d.write ("; /* (imported) */\n\n");
+    }
+  else
+    {
+      int i;
+      local *var = NULL;
+      block *b;
+      d.write ("\n{\n");
+
+      /* Write locals: */
+      FOR_EACH_VEC_ELT (m_locals, i, var)
+	var->write_to_dump (d);
+      if (m_locals.length ())
+	d.write ("\n");
+
+      /* Write each block: */
+      FOR_EACH_VEC_ELT (m_blocks, i, b)
+	{
+	  if (i > 0)
+	    d.write ("\n");
+	  b->write_to_dump (d);
+	}
+
+      d.write ("}\n\n");
+    }
+}
+
+/* Pre-compilation validation of a function, for those things we can't
+   check until the context is (supposedly) fully-populated.  */
+
+void
+recording::function::validate ()
+{
+  /* Complain about empty functions with non-void return type.  */
+  if (m_kind != GCC_JIT_FUNCTION_IMPORTED
+      && m_return_type != m_ctxt->get_type (GCC_JIT_TYPE_VOID))
+    if (0 == m_blocks.length ())
+      m_ctxt->add_error (m_loc,
+			 "function %s returns non-void (type: %s)"
+			 " but has no blocks",
+			 get_debug_string (),
+			 m_return_type->get_debug_string ());
+
+  /* Check that all blocks are terminated.  */
+  int num_invalid_blocks = 0;
+  {
+    int i;
+    block *b;
+
+    FOR_EACH_VEC_ELT (m_blocks, i, b)
+      if (!b->validate ())
+	num_invalid_blocks++;
+  }
+
+  /* Check that all blocks are reachable.  */
+  if (!m_ctxt->get_inner_bool_option
+        (INNER_BOOL_OPTION_ALLOW_UNREACHABLE_BLOCKS)
+      && m_blocks.length () > 0 && 0 == num_invalid_blocks)
+    {
+      /* Iteratively walk the graph of blocks, marking their "m_is_reachable"
+	 flag, starting at the initial block.  */
+      auto_vec<block *> worklist (m_blocks.length ());
+      worklist.safe_push (m_blocks[0]);
+      while (worklist.length () > 0)
+	{
+	  block *b = worklist.pop ();
+	  b->m_is_reachable = true;
+
+	  /* Add successor blocks that aren't yet marked to the worklist.  */
+	  /* We checked that each block has a terminating statement above .  */
+	  vec <block *> successors = b->get_successor_blocks ();
+	  int i;
+	  block *succ;
+	  FOR_EACH_VEC_ELT (successors, i, succ)
+	    if (!succ->m_is_reachable)
+	      worklist.safe_push (succ);
+	  successors.release ();
+	}
+
+      /* Now complain about any blocks that haven't been marked.  */
+      {
+	int i;
+	block *b;
+	FOR_EACH_VEC_ELT (m_blocks, i, b)
+	  if (!b->m_is_reachable)
+	    m_ctxt->add_error (b->get_loc (),
+			       "unreachable block: %s",
+			       b->get_debug_string ());
+      }
+    }
+}
+
+/* Implements the post-error-checking part of
+   gcc_jit_function_dump_to_dot.  */
+
+void
+recording::function::dump_to_dot (const char *path)
+{
+  FILE *fp  = fopen (path, "w");
+  if (!fp)
+    return;
+
+  pretty_printer the_pp;
+  the_pp.buffer->stream = fp;
+
+  pretty_printer *pp = &the_pp;
+
+  pp_printf (pp,
+	     "digraph %s {\n", get_debug_string ());
+
+  /* Blocks: */
+  {
+    int i;
+    block *b;
+    FOR_EACH_VEC_ELT (m_blocks, i, b)
+      b->dump_to_dot (pp);
+  }
+
+  /* Edges: */
+  {
+    int i;
+    block *b;
+    FOR_EACH_VEC_ELT (m_blocks, i, b)
+      b->dump_edges_to_dot (pp);
+  }
+
+  pp_printf (pp, "}\n");
+  pp_flush (pp);
+  fclose (fp);
+}
+
+/* Implements the post-error-checking part of
+   gcc_jit_function_get_address.  */
+
+recording::rvalue *
+recording::function::get_address (recording::location *loc)
+{
+  /* Lazily create and cache the function pointer type.  */
+  if (!m_fn_ptr_type)
+    {
+      /* Make a recording::function_type for this function.  */
+      auto_vec <recording::type *> param_types (m_params.length ());
+      unsigned i;
+      recording::param *param;
+      FOR_EACH_VEC_ELT (m_params, i, param)
+	param_types.safe_push (param->get_type ());
+      recording::function_type *fn_type
+	= m_ctxt->new_function_type (m_return_type,
+				     m_params.length (),
+				     param_types.address (),
+				     m_is_variadic);
+      m_fn_ptr_type = fn_type->get_pointer ();
+    }
+  gcc_assert (m_fn_ptr_type);
+
+  rvalue *result = new function_pointer (get_context (), loc, this, m_fn_ptr_type);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   functions.  */
+
+recording::string *
+recording::function::make_debug_string ()
+{
+  return m_name;
+}
+
+/* A table of enum gcc_jit_function_kind values expressed in string
+   form.  */
+
+static const char * const names_of_function_kinds[] = {
+  "GCC_JIT_FUNCTION_EXPORTED",
+  "GCC_JIT_FUNCTION_INTERNAL",
+  "GCC_JIT_FUNCTION_IMPORTED",
+  "GCC_JIT_FUNCTION_ALWAYS_INLINE"
+};
+
+/* Implementation of recording::memento::write_reproducer for functions. */
+
+void
+recording::function::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "func");
+
+  if (m_builtin_id)
+    {
+      r.write ("  gcc_jit_function *%s =\n"
+	       "    gcc_jit_context_get_builtin_function (%s,\n"
+	       "                                          %s);\n",
+	       id,
+	       r.get_identifier (get_context ()),
+	       m_name->get_debug_string ());
+      return;
+    }
+  const char *params_id = r.make_tmp_identifier ("params_for", this);
+  r.write ("  gcc_jit_param *%s[%i] = {\n",
+	   params_id,
+	   m_params.length ());
+  int i;
+  param *param;
+  FOR_EACH_VEC_ELT (m_params, i, param)
+    r.write ("    %s,\n", r.get_identifier (param));
+  r.write ("  };\n");
+  r.write ("  gcc_jit_function *%s =\n"
+	   "    gcc_jit_context_new_function (%s, /* gcc_jit_context *ctxt */\n"
+	   "                                  %s, /* gcc_jit_location *loc */\n"
+	   "                                  %s, /* enum gcc_jit_function_kind kind */\n"
+	   "                                  %s, /* gcc_jit_type *return_type */\n"
+	   "                                  %s, /* const char *name */\n"
+	   "                                  %i, /* int num_params */\n"
+	   "                                  %s, /* gcc_jit_param **params */\n"
+	   "                                  %i); /* int is_variadic */\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   r.get_identifier (m_loc),
+	   names_of_function_kinds[m_kind],
+	   r.get_identifier_as_type (m_return_type),
+	   m_name->get_debug_string (),
+	   m_params.length (),
+	   params_id,
+	   m_is_variadic);
+}
+
+
+/* The implementation of class gcc::jit::recording::block.  */
+
+/* Create a recording::eval instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the heart of gcc_jit_block_add_eval.  */
+
+recording::statement *
+recording::block::add_eval (recording::location *loc,
+			    recording::rvalue *rvalue)
+{
+  statement *result = new eval (this, loc, rvalue);
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+  return result;
+}
+
+/* Create a recording::assignment instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the heart of gcc_jit_block_add_assignment.  */
+
+recording::statement *
+recording::block::add_assignment (recording::location *loc,
+				  recording::lvalue *lvalue,
+				  recording::rvalue *rvalue)
+{
+  statement *result = new assignment (this, loc, lvalue, rvalue);
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+  return result;
+}
+
+/* Create a recording::assignment_op instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the heart of gcc_jit_block_add_assignment_op.  */
+
+recording::statement *
+recording::block::add_assignment_op (recording::location *loc,
+				     recording::lvalue *lvalue,
+				     enum gcc_jit_binary_op op,
+				     recording::rvalue *rvalue)
+{
+  statement *result = new assignment_op (this, loc, lvalue, op, rvalue);
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+  return result;
+}
+
+/* Create a recording::comment instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the heart of gcc_jit_block_add_comment.  */
+
+recording::statement *
+recording::block::add_comment (recording::location *loc,
+			       const char *text)
+{
+  statement *result = new comment (this, loc, new_string (text));
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+  return result;
+}
+
+/* Create a recording::end_with_conditional instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the heart of gcc_jit_block_end_with_conditional.  */
+
+recording::statement *
+recording::block::end_with_conditional (recording::location *loc,
+					recording::rvalue *boolval,
+					recording::block *on_true,
+					recording::block *on_false)
+{
+  statement *result = new conditional (this, loc, boolval, on_true, on_false);
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+  m_has_been_terminated = true;
+  return result;
+}
+
+/* Create a recording::end_with_jump instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the heart of gcc_jit_block_end_with_jump.  */
+
+recording::statement *
+recording::block::end_with_jump (recording::location *loc,
+				 recording::block *target)
+{
+  statement *result = new jump (this, loc, target);
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+  m_has_been_terminated = true;
+  return result;
+}
+
+/* Create a recording::end_with_return instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the post-error-checking parts of
+   gcc_jit_block_end_with_return and
+   gcc_jit_block_end_with_void_return.  */
+
+recording::statement *
+recording::block::end_with_return (recording::location *loc,
+				   recording::rvalue *rvalue)
+{
+  /* This is used by both gcc_jit_function_add_return and
+     gcc_jit_function_add_void_return; rvalue will be non-NULL for
+     the former and NULL for the latter.  */
+  statement *result = new return_ (this, loc, rvalue);
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+  m_has_been_terminated = true;
+  return result;
+}
+
+/* Create a recording::switch_ instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the heart of gcc_jit_block_end_with_switch.  */
+
+recording::statement *
+recording::block::end_with_switch (recording::location *loc,
+				   recording::rvalue *expr,
+				   recording::block *default_block,
+				   int num_cases,
+				   recording::case_ **cases)
+{
+  statement *result = new switch_ (this, loc,
+				   expr,
+				   default_block,
+				   num_cases,
+				   cases);
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+  m_has_been_terminated = true;
+  return result;
+}
+
+/* Override the default implementation of
+   recording::memento::write_to_dump for blocks by writing
+   an unindented block name as a label, followed by the indented
+   statements:
+
+    BLOCK_NAME:
+      STATEMENT_1;
+      STATEMENT_2;
+      ...
+      STATEMENT_N;  */
+
+void
+recording::block::write_to_dump (dump &d)
+{
+  d.write ("%s:\n", get_debug_string ());
+
+  int i;
+  statement *s;
+  FOR_EACH_VEC_ELT (m_statements, i, s)
+    s->write_to_dump (d);
+}
+
+/* Validate a block by ensuring that it has been terminated.  */
+
+bool
+recording::block::validate ()
+{
+  /* Check for termination.  */
+  if (!has_been_terminated ())
+    {
+      statement *stmt = get_last_statement ();
+      location *loc = stmt ? stmt->get_loc () : NULL;
+      m_func->get_context ()->add_error (loc,
+					 "unterminated block in %s: %s",
+					 m_func->get_debug_string (),
+					 get_debug_string ());
+      return false;
+    }
+
+  return true;
+}
+
+/* Get the source-location of a block by using that of the first
+   statement within it, if any.  */
+
+recording::location *
+recording::block::get_loc () const
+{
+  recording::statement *stmt = get_first_statement ();
+  if (stmt)
+    return stmt->get_loc ();
+  else
+    return NULL;
+}
+
+/* Get the first statement within a block, if any.  */
+
+recording::statement *
+recording::block::get_first_statement () const
+{
+  if (m_statements.length ())
+    return m_statements[0];
+  else
+    return NULL;
+}
+
+/* Get the last statement within a block, if any.  */
+
+recording::statement *
+recording::block::get_last_statement () const
+{
+  if (m_statements.length ())
+    return m_statements[m_statements.length () - 1];
+  else
+    return NULL;
+}
+
+/* Assuming that this block has been terminated, get the successor blocks
+   as a vector.  Ownership of the vector transfers to the caller, which
+   must call its release () method.
+
+   Used when validating functions, and when dumping dot representations
+   of them.  */
+
+vec <recording::block *>
+recording::block::get_successor_blocks () const
+{
+  gcc_assert (m_has_been_terminated);
+  statement *last_statement = get_last_statement ();
+  gcc_assert (last_statement);
+  return last_statement->get_successor_blocks ();
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::block.  */
+
+void
+recording::block::replay_into (replayer *)
+{
+  set_playback_obj (m_func->playback_function ()
+		      ->new_block (playback_string (m_name)));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   blocks.  */
+
+recording::string *
+recording::block::make_debug_string ()
+{
+  if (m_name)
+    return m_name;
+  else
+    return string::from_printf (m_ctxt,
+				"<UNNAMED BLOCK %p>",
+				(void *)this);
+}
+
+/* Implementation of recording::memento::write_reproducer for blocks. */
+
+void
+recording::block::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "block");
+  r.write ("  gcc_jit_block *%s =\n"
+	   "    gcc_jit_function_new_block (%s, %s);\n",
+	   id,
+	   r.get_identifier (m_func),
+	   m_name ? m_name->get_debug_string () : "NULL");
+}
+
+/* Dump a block in graphviz form into PP, capturing the block name (if
+   any) and the statements.  */
+
+void
+recording::block::dump_to_dot (pretty_printer *pp)
+{
+  pp_printf (pp,
+	     ("\tblock_%d "
+	      "[shape=record,style=filled,fillcolor=white,label=\"{"),
+	     m_index);
+  pp_write_text_to_stream (pp);
+  if (m_name)
+    {
+      pp_string (pp, m_name->c_str ());
+      pp_string (pp, ":");
+      pp_newline (pp);
+      pp_write_text_as_dot_label_to_stream (pp, true /*for_record*/);
+    }
+
+  int i;
+  statement *s;
+  FOR_EACH_VEC_ELT (m_statements, i, s)
+    {
+      pp_string (pp, s->get_debug_string ());
+      pp_newline (pp);
+      pp_write_text_as_dot_label_to_stream (pp, true /*for_record*/);
+    }
+
+  pp_printf (pp,
+	     "}\"];\n\n");
+  pp_flush (pp);
+}
+
+/* Dump the out-edges of the block in graphviz form into PP.  */
+
+void
+recording::block::dump_edges_to_dot (pretty_printer *pp)
+{
+  vec <block *> successors = get_successor_blocks ();
+  int i;
+  block *succ;
+  FOR_EACH_VEC_ELT (successors, i, succ)
+    pp_printf (pp,
+	       "\tblock_%d:s -> block_%d:n;\n",
+	       m_index, succ->m_index);
+  successors.release ();
+}
+
+/* The implementation of class gcc::jit::recording::global.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::global.  */
+
+void
+recording::global::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_global (playback_location (r, m_loc),
+				   m_kind,
+				   m_type->playback_type (),
+				   playback_string (m_name)));
+}
+
+/* Override the default implementation of
+   recording::memento::write_to_dump for globals.
+   This will be of the form:
+
+   GCC_JIT_GLOBAL_EXPORTED:
+      "TYPE NAME;"
+      e.g. "int foo;"
+
+   GCC_JIT_GLOBAL_INTERNAL:
+      "static TYPE NAME;"
+      e.g. "static int foo;"
+
+   GCC_JIT_GLOBAL_IMPORTED:
+      "extern TYPE NAME;"
+      e.g. "extern int foo;"
+
+   These are written to the top of the dump by
+   recording::context::dump_to_file.  */
+
+void
+recording::global::write_to_dump (dump &d)
+{
+  if (d.update_locations ())
+    m_loc = d.make_location ();
+
+  switch (m_kind)
+    {
+    default:
+      gcc_unreachable ();
+
+    case GCC_JIT_GLOBAL_EXPORTED:
+      break;
+
+    case GCC_JIT_GLOBAL_INTERNAL:
+      d.write ("static ");
+      break;
+
+    case GCC_JIT_GLOBAL_IMPORTED:
+      d.write ("extern ");
+      break;
+    }
+  d.write ("%s %s;\n",
+	   m_type->get_debug_string (),
+	   get_debug_string ());
+}
+
+/* A table of enum gcc_jit_global_kind values expressed in string
+   form.  */
+
+static const char * const global_kind_reproducer_strings[] = {
+  "GCC_JIT_GLOBAL_EXPORTED",
+  "GCC_JIT_GLOBAL_INTERNAL",
+  "GCC_JIT_GLOBAL_IMPORTED"
+};
+
+/* Implementation of recording::memento::write_reproducer for globals. */
+
+void
+recording::global::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "block");
+  r.write ("  gcc_jit_lvalue *%s =\n"
+    "    gcc_jit_context_new_global (%s, /* gcc_jit_context *ctxt */\n"
+    "                                %s, /* gcc_jit_location *loc */\n"
+    "                                %s, /* enum gcc_jit_global_kind kind */\n"
+    "                                %s, /* gcc_jit_type *type */\n"
+    "                                %s); /* const char *name */\n",
+    id,
+    r.get_identifier (get_context ()),
+    r.get_identifier (m_loc),
+    global_kind_reproducer_strings[m_kind],
+    r.get_identifier_as_type (get_type ()),
+    m_name->get_debug_string ());
+}
+
+/* The implementation of the various const-handling classes:
+   gcc::jit::recording::memento_of_new_rvalue_from_const <HOST_TYPE>.  */
+
+/* Explicit specialization of the various mementos we're interested in.  */
+template class recording::memento_of_new_rvalue_from_const <int>;
+template class recording::memento_of_new_rvalue_from_const <long>;
+template class recording::memento_of_new_rvalue_from_const <double>;
+template class recording::memento_of_new_rvalue_from_const <void *>;
+
+/* Implementation of the pure virtual hook recording::memento::replay_into
+   for recording::memento_of_new_rvalue_from_const <HOST_TYPE>.  */
+
+template <typename HOST_TYPE>
+void
+recording::
+memento_of_new_rvalue_from_const <HOST_TYPE>::replay_into (replayer *r)
+{
+    set_playback_obj
+      (r->new_rvalue_from_const <HOST_TYPE> (m_type->playback_type (),
+					     m_value));
+}
+
+/* The make_debug_string and write_reproducer methods vary between the
+   various
+     memento_of_new_rvalue_from_const <HOST_TYPE>
+   classes, so we explicitly write specializations of them.
+
+   I (dmalcolm) find the code to be clearer if the "recording" vs "playback"
+   namespaces are written out explicitly, which is why most of this file
+   doesn't abbreviate things by entering the "recording" namespace.
+
+   However, these specializations are required to be in the same namespace
+   as the template, hence we now have to enter the gcc::jit::recording
+   namespace.  */
+
+namespace recording
+{
+
+/* The make_debug_string specialization for <int>, which renders it as
+     (TARGET_TYPE)LITERAL
+   e.g.
+     "(int)42".  */
+
+template <>
+string *
+memento_of_new_rvalue_from_const <int>::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "(%s)%i",
+			      m_type->get_debug_string (),
+			      m_value);
+}
+
+/* The get_wide_int specialization for <int>.  */
+
+template <>
+bool
+memento_of_new_rvalue_from_const <int>::get_wide_int (wide_int *out) const
+{
+  *out = wi::shwi (m_value, sizeof (m_value) * 8);
+  return true;
+}
+
+/* The write_reproducer specialization for <int>.  */
+
+template <>
+void
+memento_of_new_rvalue_from_const <int>::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "rvalue");
+  r.write ("  gcc_jit_rvalue *%s =\n"
+    "    gcc_jit_context_new_rvalue_from_int (%s, /* gcc_jit_context *ctxt */\n"
+    "                                         %s, /* gcc_jit_type *numeric_type */\n"
+    "                                         %i); /* int value */\n",
+    id,
+    r.get_identifier (get_context ()),
+    r.get_identifier_as_type (m_type),
+    m_value);
+}
+
+/* The make_debug_string specialization for <long>, rendering it as
+     (TARGET_TYPE)LITERAL
+   e.g.
+     "(long)42".  */
+
+template <>
+string *
+memento_of_new_rvalue_from_const <long>::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "(%s)%li",
+			      m_type->get_debug_string (),
+			      m_value);
+}
+
+/* The get_wide_int specialization for <long>.  */
+
+template <>
+bool
+memento_of_new_rvalue_from_const <long>::get_wide_int (wide_int *out) const
+{
+  *out = wi::shwi (m_value, sizeof (m_value) * 8);
+  return true;
+}
+
+/* The write_reproducer specialization for <long>.  */
+
+template <>
+void
+recording::memento_of_new_rvalue_from_const <long>::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "rvalue");
+
+  /* We have to special-case LONG_MIN, since e.g.
+       -9223372036854775808L
+     is parsed as
+       -(9223372036854775808L)
+     and hence we'd get:
+	error: integer constant is so large that it is unsigned [-Werror]
+	Workaround this by writing (LONG_MIN + 1) - 1.  */
+  if (m_value == LONG_MIN)
+    {
+      r.write ("  gcc_jit_rvalue *%s =\n"
+	       "    gcc_jit_context_new_rvalue_from_long (%s, /* gcc_jit_context *ctxt */\n"
+	       "                                          %s, /* gcc_jit_type *numeric_type */\n"
+	       "                                          %ldL - 1); /* long value */\n",
+	       id,
+	       r.get_identifier (get_context ()),
+	       r.get_identifier_as_type (m_type),
+	       m_value + 1);;
+      return;
+    }
+
+  r.write ("  gcc_jit_rvalue *%s =\n"
+	   "    gcc_jit_context_new_rvalue_from_long (%s, /* gcc_jit_context *ctxt */\n"
+	   "                                          %s, /* gcc_jit_type *numeric_type */\n"
+	   "                                          %ldL); /* long value */\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   r.get_identifier_as_type (m_type),
+	   m_value);
+	   }
+
+/* The make_debug_string specialization for <double>, rendering it as
+     (TARGET_TYPE)LITERAL
+   e.g.
+     "(float)42.0".  */
+
+template <>
+string *
+memento_of_new_rvalue_from_const <double>::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "(%s)%f",
+			      m_type->get_debug_string (),
+			      m_value);
+}
+
+/* The get_wide_int specialization for <double>.  */
+
+template <>
+bool
+memento_of_new_rvalue_from_const <double>::get_wide_int (wide_int *) const
+{
+  return false;
+}
+
+/* The write_reproducer specialization for <double>.  */
+
+template <>
+void
+recording::memento_of_new_rvalue_from_const <double>::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "rvalue");
+  r.write ("  gcc_jit_rvalue *%s =\n"
+    "    gcc_jit_context_new_rvalue_from_double (%s, /* gcc_jit_context *ctxt */\n"
+    "                                            %s, /* gcc_jit_type *numeric_type */\n"
+    "                                            %f); /* double value */\n",
+    id,
+    r.get_identifier (get_context ()),
+    r.get_identifier_as_type (m_type),
+    m_value);
+}
+
+/* The make_debug_string specialization for <void *>, rendering it as
+     (TARGET_TYPE)HEX
+   e.g.
+     "(int *)0xdeadbeef"
+
+   Zero is rendered as NULL e.g.
+     "(int *)NULL".  */
+
+template <>
+string *
+memento_of_new_rvalue_from_const <void *>::make_debug_string ()
+{
+  if (m_value != NULL)
+    return string::from_printf (m_ctxt,
+				"(%s)%p",
+				m_type->get_debug_string (), m_value);
+  else
+    return string::from_printf (m_ctxt,
+				"(%s)NULL",
+				m_type->get_debug_string ());
+}
+
+/* The get_wide_int specialization for <void *>.  */
+
+template <>
+bool
+memento_of_new_rvalue_from_const <void *>::get_wide_int (wide_int *) const
+{
+  return false;
+}
+
+/* Implementation of recording::memento::write_reproducer for <void *>
+   values. */
+
+template <>
+void
+memento_of_new_rvalue_from_const <void *>::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "rvalue");
+  if (m_value)
+    r.write ("  gcc_jit_rvalue *%s =\n"
+	     "    gcc_jit_context_new_rvalue_from_ptr (%s, /* gcc_jit_context *ctxt */\n"
+	     "                                         %s, /* gcc_jit_type *pointer_type */\n"
+	     "                                         (void *)%p); /* void *value */\n",
+	     id,
+	     r.get_identifier (get_context ()),
+	     r.get_identifier_as_type (m_type),
+	     m_value);
+  else
+    r.write ("  gcc_jit_rvalue *%s =\n"
+	     "    gcc_jit_context_null (%s, /* gcc_jit_context *ctxt */\n"
+	     "                          %s); /* gcc_jit_type *pointer_type */\n",
+	     id,
+	     r.get_identifier (get_context ()),
+	     r.get_identifier_as_type (m_type));
+}
+
+/* We're done specializing make_debug_string and write_reproducer, so we
+   can exit the gcc::jit::recording namespace.  */
+
+} // namespace recording
+
+/* The implementation of class gcc::jit::recording::memento_of_new_string_literal.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_new_string_literal.  */
+
+void
+recording::memento_of_new_string_literal::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_string_literal (m_value->c_str ()));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   string literals.  */
+
+recording::string *
+recording::memento_of_new_string_literal::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s",
+			      m_value->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for string literal
+   values. */
+
+void
+recording::memento_of_new_string_literal::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "rvalue");
+  r.write ("  gcc_jit_rvalue *%s =\n"
+    "    gcc_jit_context_new_string_literal (%s, /* gcc_jit_context *ctxt */\n"
+    "                                        %s); /* const char *value */\n",
+    id,
+    r.get_identifier (get_context ()),
+    m_value->get_debug_string ());
+}
+
+/* The implementation of class
+   gcc::jit::recording::memento_of_new_rvalue_from_vector.  */
+
+/* The constructor for
+   gcc::jit::recording::memento_of_new_rvalue_from_vector.  */
+
+recording::memento_of_new_rvalue_from_vector::
+memento_of_new_rvalue_from_vector (context *ctxt,
+				   location *loc,
+				   vector_type *type,
+				   rvalue **elements)
+: rvalue (ctxt, loc, type),
+  m_vector_type (type),
+  m_elements ()
+{
+  for (unsigned i = 0; i < type->get_num_units (); i++)
+    m_elements.safe_push (elements[i]);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_new_rvalue_from_vector.  */
+
+void
+recording::memento_of_new_rvalue_from_vector::replay_into (replayer *r)
+{
+  auto_vec<playback::rvalue *> playback_elements;
+  playback_elements.create (m_elements.length ());
+  for (unsigned i = 0; i< m_elements.length (); i++)
+    playback_elements.safe_push (m_elements[i]->playback_rvalue ());
+
+  set_playback_obj (r->new_rvalue_from_vector (playback_location (r, m_loc),
+					       m_type->playback_type (),
+					       playback_elements));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+   for recording::memento_of_new_rvalue_from_vector.  */
+
+void
+recording::memento_of_new_rvalue_from_vector::visit_children (rvalue_visitor *v)
+{
+  for (unsigned i = 0; i< m_elements.length (); i++)
+    v->visit (m_elements[i]);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   vectors.  */
+
+recording::string *
+recording::memento_of_new_rvalue_from_vector::make_debug_string ()
+{
+  comma_separated_string elements (m_elements, get_precedence ());
+
+  /* Now build a string.  */
+  string *result = string::from_printf (m_ctxt,
+					"{%s}",
+					elements.as_char_ptr ());
+
+ return result;
+
+}
+
+/* Implementation of recording::memento::write_reproducer for
+   vectors.  */
+
+void
+recording::memento_of_new_rvalue_from_vector::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "vector");
+  const char *elements_id = r.make_tmp_identifier ("elements_for_", this);
+  r.write ("  gcc_jit_rvalue *%s[%i] = {\n",
+	   elements_id,
+	   m_elements.length ());
+  for (unsigned i = 0; i< m_elements.length (); i++)
+    r.write ("    %s,\n", r.get_identifier_as_rvalue (m_elements[i]));
+  r.write ("  };\n");
+  r.write ("  gcc_jit_rvalue *%s =\n"
+	   "    gcc_jit_context_new_rvalue_from_vector (%s, /* gcc_jit_context *ctxt */\n"
+	   "                                            %s, /* gcc_jit_location *loc */\n"
+	   "                                            %s, /* gcc_jit_type *vec_type */\n"
+	   "                                            %i, /* size_t num_elements  */ \n"
+	   "                                            %s); /* gcc_jit_rvalue **elements*/\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   r.get_identifier (m_loc),
+	   r.get_identifier (m_vector_type),
+	   m_elements.length (),
+	   elements_id);
+}
+
+/* The implementation of class gcc::jit::recording::unary_op.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::unary_op.  */
+
+void
+recording::unary_op::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_unary_op (playback_location (r, m_loc),
+				     m_op,
+				     get_type ()->playback_type (),
+				     m_a->playback_rvalue ()));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+   for recording::unary_op.  */
+void
+recording::unary_op::visit_children (rvalue_visitor *v)
+{
+  v->visit (m_a);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   unary ops.  */
+
+static const char * const unary_op_strings[] = {
+  "-", /* GCC_JIT_UNARY_OP_MINUS */
+  "~", /* GCC_JIT_UNARY_OP_BITWISE_NEGATE */
+  "!", /* GCC_JIT_UNARY_OP_LOGICAL_NEGATE */
+  "abs ", /* GCC_JIT_UNARY_OP_ABS */
+};
+
+recording::string *
+recording::unary_op::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s(%s)",
+			      unary_op_strings[m_op],
+			      m_a->get_debug_string ());
+}
+
+static const char * const unary_op_reproducer_strings[] = {
+  "GCC_JIT_UNARY_OP_MINUS",
+  "GCC_JIT_UNARY_OP_BITWISE_NEGATE",
+  "GCC_JIT_UNARY_OP_LOGICAL_NEGATE",
+  "GCC_JIT_UNARY_OP_ABS"
+};
+
+/* Implementation of recording::memento::write_reproducer for unary ops.  */
+
+void
+recording::unary_op::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "rvalue");
+  r.write ("  gcc_jit_rvalue *%s =\n"
+	   "    gcc_jit_context_new_unary_op (%s,\n"
+	   "                                  %s, /* gcc_jit_location *loc */\n"
+	   "                                  %s, /* enum gcc_jit_unary_op op */\n"
+	   "                                  %s, /* gcc_jit_type *result_type */\n"
+	   "                                  %s); /* gcc_jit_rvalue *a */\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   r.get_identifier (m_loc),
+	   unary_op_reproducer_strings[m_op],
+	   r.get_identifier_as_type (get_type ()),
+	   r.get_identifier_as_rvalue (m_a));
+}
+
+/* The implementation of class gcc::jit::recording::binary_op.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::binary_op.  */
+
+void
+recording::binary_op::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_binary_op (playback_location (r, m_loc),
+				      m_op,
+				      get_type ()->playback_type (),
+				      m_a->playback_rvalue (),
+				      m_b->playback_rvalue ()));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+   for recording::binary_op.  */
+void
+recording::binary_op::visit_children (rvalue_visitor *v)
+{
+  v->visit (m_a);
+  v->visit (m_b);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   binary ops.  */
+
+static const char * const binary_op_strings[] = {
+  "+", /* GCC_JIT_BINARY_OP_PLUS */
+  "-", /* GCC_JIT_BINARY_OP_MINUS */
+  "*", /* GCC_JIT_BINARY_OP_MULT */
+  "/", /* GCC_JIT_BINARY_OP_DIVIDE */
+  "%", /* GCC_JIT_BINARY_OP_MODULO */
+  "&", /* GCC_JIT_BINARY_OP_BITWISE_AND */
+  "^", /* GCC_JIT_BINARY_OP_BITWISE_XOR */
+  "|", /* GCC_JIT_BINARY_OP_BITWISE_OR */
+  "&&", /* GCC_JIT_BINARY_OP_LOGICAL_AND */
+  "||", /* GCC_JIT_BINARY_OP_LOGICAL_OR */
+  "<<", /* GCC_JIT_BINARY_OP_LSHIFT */
+  ">>", /* GCC_JIT_BINARY_OP_RSHIFT */
+};
+
+recording::string *
+recording::binary_op::make_debug_string ()
+{
+  enum precedence prec = get_precedence ();
+  return string::from_printf (m_ctxt,
+			      "%s %s %s",
+			      m_a->get_debug_string_parens (prec),
+			      binary_op_strings[m_op],
+			      m_b->get_debug_string_parens (prec));
+}
+
+static const char * const binary_op_reproducer_strings[] = {
+  "GCC_JIT_BINARY_OP_PLUS",
+  "GCC_JIT_BINARY_OP_MINUS",
+  "GCC_JIT_BINARY_OP_MULT",
+  "GCC_JIT_BINARY_OP_DIVIDE",
+  "GCC_JIT_BINARY_OP_MODULO",
+  "GCC_JIT_BINARY_OP_BITWISE_AND",
+  "GCC_JIT_BINARY_OP_BITWISE_XOR",
+  "GCC_JIT_BINARY_OP_BITWISE_OR",
+  "GCC_JIT_BINARY_OP_LOGICAL_AND",
+  "GCC_JIT_BINARY_OP_LOGICAL_OR",
+  "GCC_JIT_BINARY_OP_LSHIFT",
+  "GCC_JIT_BINARY_OP_RSHIFT"
+};
+
+/* Implementation of recording::memento::write_reproducer for binary ops.  */
+
+void
+recording::binary_op::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "rvalue");
+  r.write ("  gcc_jit_rvalue *%s =\n"
+	   "    gcc_jit_context_new_binary_op (%s,\n"
+	   "                                   %s, /* gcc_jit_location *loc */\n"
+	   "                                   %s, /* enum gcc_jit_binary_op op */\n"
+	   "                                   %s, /* gcc_jit_type *result_type */\n"
+	   "                                   %s, /* gcc_jit_rvalue *a */\n"
+	   "                                   %s); /* gcc_jit_rvalue *b */\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   r.get_identifier (m_loc),
+	   binary_op_reproducer_strings[m_op],
+	   r.get_identifier_as_type (get_type ()),
+	   r.get_identifier_as_rvalue (m_a),
+	   r.get_identifier_as_rvalue (m_b));
+}
+
+namespace recording {
+static const enum precedence binary_op_precedence[] = {
+  PRECEDENCE_ADDITIVE, /* GCC_JIT_BINARY_OP_PLUS */
+  PRECEDENCE_ADDITIVE, /* GCC_JIT_BINARY_OP_MINUS */
+
+  PRECEDENCE_MULTIPLICATIVE, /* GCC_JIT_BINARY_OP_MULT */
+  PRECEDENCE_MULTIPLICATIVE, /* GCC_JIT_BINARY_OP_DIVIDE */
+  PRECEDENCE_MULTIPLICATIVE, /* GCC_JIT_BINARY_OP_MODULO */
+
+  PRECEDENCE_BITWISE_AND, /* GCC_JIT_BINARY_OP_BITWISE_AND */
+  PRECEDENCE_BITWISE_XOR, /* GCC_JIT_BINARY_OP_BITWISE_XOR */
+  PRECEDENCE_BITWISE_IOR, /* GCC_JIT_BINARY_OP_BITWISE_OR */
+  PRECEDENCE_LOGICAL_AND, /* GCC_JIT_BINARY_OP_LOGICAL_AND */
+  PRECEDENCE_LOGICAL_OR, /* GCC_JIT_BINARY_OP_LOGICAL_OR */
+  PRECEDENCE_SHIFT, /* GCC_JIT_BINARY_OP_LSHIFT */
+  PRECEDENCE_SHIFT, /* GCC_JIT_BINARY_OP_RSHIFT */
+};
+} /* namespace recording */
+
+enum recording::precedence
+recording::binary_op::get_precedence () const
+{
+  return binary_op_precedence[m_op];
+}
+
+/* The implementation of class gcc::jit::recording::comparison.  */
+
+/* Implementation of recording::memento::make_debug_string for
+   comparisons.  */
+
+static const char * const comparison_strings[] =
+{
+  "==", /* GCC_JIT_COMPARISON_EQ */
+  "!=", /* GCC_JIT_COMPARISON_NE */
+  "<",  /* GCC_JIT_COMPARISON_LT */
+  "<=", /* GCC_JIT_COMPARISON_LE */
+  ">",  /* GCC_JIT_COMPARISON_GT */
+  ">=", /* GCC_JIT_COMPARISON_GE */
+};
+
+recording::string *
+recording::comparison::make_debug_string ()
+{
+  enum precedence prec = get_precedence ();
+  return string::from_printf (m_ctxt,
+			      "%s %s %s",
+			      m_a->get_debug_string_parens (prec),
+			      comparison_strings[m_op],
+			      m_b->get_debug_string_parens (prec));
+}
+
+/* A table of enum gcc_jit_comparison values expressed in string
+   form.  */
+
+static const char * const comparison_reproducer_strings[] =
+{
+  "GCC_JIT_COMPARISON_EQ",
+  "GCC_JIT_COMPARISON_NE",
+  "GCC_JIT_COMPARISON_LT",
+  "GCC_JIT_COMPARISON_LE",
+  "GCC_JIT_COMPARISON_GT",
+  "GCC_JIT_COMPARISON_GE"
+};
+
+/* Implementation of recording::memento::write_reproducer for comparisons.  */
+
+void
+recording::comparison::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "rvalue");
+  r.write ("  gcc_jit_rvalue *%s =\n"
+	   "    gcc_jit_context_new_comparison (%s,\n"
+	   "                                    %s, /* gcc_jit_location *loc */\n"
+	   "                                    %s, /* enum gcc_jit_comparison op */\n"
+	   "                                    %s, /* gcc_jit_rvalue *a */\n"
+	   "                                    %s); /* gcc_jit_rvalue *b */\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   r.get_identifier (m_loc),
+	   comparison_reproducer_strings[m_op],
+	   r.get_identifier_as_rvalue (m_a),
+	   r.get_identifier_as_rvalue (m_b));
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::comparison.  */
+
+void
+recording::comparison::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_comparison (playback_location (r, m_loc),
+				       m_op,
+				       m_a->playback_rvalue (),
+				       m_b->playback_rvalue ()));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+   for recording::comparison.  */
+
+void
+recording::comparison::visit_children (rvalue_visitor *v)
+{
+  v->visit (m_a);
+  v->visit (m_b);
+}
+
+namespace recording {
+static const enum precedence comparison_precedence[] =
+{
+  PRECEDENCE_EQUALITY, /* GCC_JIT_COMPARISON_EQ */
+  PRECEDENCE_EQUALITY, /* GCC_JIT_COMPARISON_NE */
+
+  PRECEDENCE_RELATIONAL,  /* GCC_JIT_COMPARISON_LT */
+  PRECEDENCE_RELATIONAL, /* GCC_JIT_COMPARISON_LE */
+  PRECEDENCE_RELATIONAL,  /* GCC_JIT_COMPARISON_GT */
+  PRECEDENCE_RELATIONAL, /* GCC_JIT_COMPARISON_GE */
+};
+} /* namespace recording */
+
+enum recording::precedence
+recording::comparison::get_precedence () const
+{
+  return comparison_precedence[m_op];
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::cast.  */
+
+void
+recording::cast::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_cast (playback_location (r, m_loc),
+				 m_rvalue->playback_rvalue (),
+				 get_type ()->playback_type ()));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+   for recording::cast.  */
+void
+recording::cast::visit_children (rvalue_visitor *v)
+{
+  v->visit (m_rvalue);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   casts.  */
+
+recording::string *
+recording::cast::make_debug_string ()
+{
+  enum precedence prec = get_precedence ();
+  return string::from_printf (m_ctxt,
+			      "(%s)%s",
+			      get_type ()->get_debug_string (),
+			      m_rvalue->get_debug_string_parens (prec));
+}
+
+/* Implementation of recording::memento::write_reproducer for casts.  */
+
+void
+recording::cast::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "rvalue");
+  r.write ("  gcc_jit_rvalue *%s =\n"
+	   "    gcc_jit_context_new_cast (%s,\n"
+	   "                              %s, /* gcc_jit_location *loc */\n"
+	   "                              %s, /* gcc_jit_rvalue *rvalue */\n"
+	   "                              %s); /* gcc_jit_type *type */\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   r.get_identifier (m_loc),
+	   r.get_identifier_as_rvalue (m_rvalue),
+	   r.get_identifier_as_type (get_type ()));
+}
+
+/* The implementation of class gcc::jit::recording::base_call.  */
+
+/* The constructor for gcc::jit::recording::base_call.  */
+
+recording::base_call::base_call (context *ctxt,
+				 location *loc,
+				 type *type_,
+				 int numargs,
+				 rvalue **args)
+: rvalue (ctxt, loc, type_),
+  m_args (),
+  m_require_tail_call (0)
+{
+  for (int i = 0; i< numargs; i++)
+    m_args.safe_push (args[i]);
+}
+
+/* Subroutine for use by call and call_though_ptr's write_reproducer
+   methods.  */
+
+void
+recording::base_call::write_reproducer_tail_call (reproducer &r,
+						  const char *id)
+{
+  if (m_require_tail_call)
+    {
+      r.write ("  gcc_jit_rvalue_set_bool_require_tail_call (%s,  /* gcc_jit_rvalue *call*/\n"
+	       "                                             %i); /* int require_tail_call*/\n",
+	       id,
+	       1);
+    }
+}
+
+/* The implementation of class gcc::jit::recording::call.  */
+
+/* The constructor for gcc::jit::recording::call.  */
+
+recording::call::call (recording::context *ctxt,
+		       recording::location *loc,
+		       recording::function *func,
+		       int numargs,
+		       rvalue **args)
+: base_call (ctxt, loc, func->get_return_type (), numargs, args),
+  m_func (func)
+{
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::call.  */
+
+void
+recording::call::replay_into (replayer *r)
+{
+  auto_vec<playback::rvalue *> playback_args;
+  playback_args.create (m_args.length ());
+  for (unsigned i = 0; i< m_args.length (); i++)
+    playback_args.safe_push (m_args[i]->playback_rvalue ());
+
+  set_playback_obj (r->new_call (playback_location (r, m_loc),
+				 m_func->playback_function (),
+				 &playback_args,
+				 m_require_tail_call));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+   for recording::call.  */
+
+void
+recording::call::visit_children (rvalue_visitor *v)
+{
+  for (unsigned i = 0; i< m_args.length (); i++)
+    v->visit (m_args[i]);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   function calls.  */
+
+recording::string *
+recording::call::make_debug_string ()
+{
+  /* First, build a buffer for the arguments.  */
+  comma_separated_string args (m_args, get_precedence ());
+
+  /* ...and use it to get the string for the call as a whole.  */
+  string *result = string::from_printf (m_ctxt,
+					"%s (%s)",
+					m_func->get_debug_string (),
+					args.as_char_ptr ());
+
+  return result;
+}
+
+void
+recording::call::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "call");
+  const char *args_id = r.make_tmp_identifier ("args_for_", this);
+  r.write ("  gcc_jit_rvalue *%s[%i] = {\n",
+	   args_id,
+	   m_args.length ());
+  for (unsigned i = 0; i< m_args.length (); i++)
+    r.write ("    %s,\n", r.get_identifier_as_rvalue (m_args[i]));
+  r.write ("  };\n");
+  r.write ("  gcc_jit_rvalue *%s =\n"
+	   "    gcc_jit_context_new_call (%s, /* gcc_jit_context *ctxt */\n"
+	   "                              %s, /* gcc_jit_location *loc */\n"
+	   "                              %s, /* gcc_jit_function *func */\n"
+	   "                              %i, /* int numargs  */ \n"
+	   "                              %s); /* gcc_jit_rvalue **args*/\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   r.get_identifier (m_loc),
+	   r.get_identifier (m_func),
+	   m_args.length (),
+	   args_id);
+  write_reproducer_tail_call (r, id);
+}
+
+/* The implementation of class gcc::jit::recording::call_through_ptr.  */
+
+/* The constructor for recording::call_through_ptr. */
+
+recording::call_through_ptr::call_through_ptr (recording::context *ctxt,
+					       recording::location *loc,
+					       recording::rvalue *fn_ptr,
+					       int numargs,
+					       rvalue **args)
+: base_call (ctxt, loc,
+	     fn_ptr->get_type ()->dereference ()
+	       ->as_a_function_type ()->get_return_type (),
+	     numargs, args),
+  m_fn_ptr (fn_ptr)
+{
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::call_through_ptr.  */
+
+void
+recording::call_through_ptr::replay_into (replayer *r)
+{
+  auto_vec<playback::rvalue *> playback_args;
+  playback_args.create (m_args.length ());
+  for (unsigned i = 0; i< m_args.length (); i++)
+    playback_args.safe_push (m_args[i]->playback_rvalue ());
+
+  set_playback_obj (r->new_call_through_ptr (playback_location (r, m_loc),
+					     m_fn_ptr->playback_rvalue (),
+					     &playback_args,
+					     m_require_tail_call));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+   for recording::call_through_ptr.  */
+
+void
+recording::call_through_ptr::visit_children (rvalue_visitor *v)
+{
+  v->visit (m_fn_ptr);
+  for (unsigned i = 0; i< m_args.length (); i++)
+    v->visit (m_args[i]);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   calls through function ptrs.  */
+
+recording::string *
+recording::call_through_ptr::make_debug_string ()
+{
+  enum precedence prec = get_precedence ();
+  /* First, build a buffer for the arguments.  */
+  /* Calculate length of said buffer.  */
+  size_t sz = 1; /* nil terminator */
+  for (unsigned i = 0; i< m_args.length (); i++)
+    {
+      sz += strlen (m_args[i]->get_debug_string_parens (prec));
+      sz += 2; /* ", " separator */
+    }
+
+  /* Now allocate and populate the buffer.  */
+  char *argbuf = new char[sz];
+  size_t len = 0;
+
+  for (unsigned i = 0; i< m_args.length (); i++)
+    {
+      strcpy (argbuf + len, m_args[i]->get_debug_string_parens (prec));
+      len += strlen (m_args[i]->get_debug_string_parens (prec));
+      if (i + 1 < m_args.length ())
+	{
+	  strcpy (argbuf + len, ", ");
+	  len += 2;
+	}
+    }
+  argbuf[len] = '\0';
+
+  /* ...and use it to get the string for the call as a whole.  */
+  string *result = string::from_printf (m_ctxt,
+					"%s (%s)",
+					m_fn_ptr->get_debug_string_parens (prec),
+					argbuf);
+
+  delete[] argbuf;
+
+  return result;
+}
+
+/* Implementation of recording::memento::write_reproducer for
+   call_through_ptr.  */
+
+void
+recording::call_through_ptr::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "call");
+  const char *args_id = r.make_tmp_identifier ("args_for_", this);
+  r.write ("  gcc_jit_rvalue *%s[%i] = {\n",
+	     args_id,
+	     m_args.length ());
+  for (unsigned i = 0; i< m_args.length (); i++)
+    r.write ("    %s,\n", r.get_identifier_as_rvalue (m_args[i]));
+  r.write ("  };\n");
+  r.write ("  gcc_jit_rvalue *%s =\n"
+	   "    gcc_jit_context_new_call_through_ptr (%s, /* gcc_jit_context *ctxt */\n"
+	   "                              %s, /* gcc_jit_location *loc */\n"
+	   "                              %s, /* gcc_jit_rvalue *fn_ptr */\n"
+	   "                              %i, /* int numargs  */ \n"
+	   "                              %s); /* gcc_jit_rvalue **args*/\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   r.get_identifier (m_loc),
+	   r.get_identifier_as_rvalue (m_fn_ptr),
+	   m_args.length (),
+	   args_id);
+  write_reproducer_tail_call (r, id);
+}
+
+/* The implementation of class gcc::jit::recording::array_access.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::array_access.  */
+
+void
+recording::array_access::replay_into (replayer *r)
+{
+  set_playback_obj (
+    r->new_array_access (playback_location (r, m_loc),
+			 m_ptr->playback_rvalue (),
+			 m_index->playback_rvalue ()));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+   for recording::array_access.  */
+
+void
+recording::array_access::visit_children (rvalue_visitor *v)
+{
+  v->visit (m_ptr);
+  v->visit (m_index);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   array accesses.  */
+
+recording::string *
+recording::array_access::make_debug_string ()
+{
+  enum precedence prec = get_precedence ();
+  return string::from_printf (m_ctxt,
+			      "%s[%s]",
+			      m_ptr->get_debug_string_parens (prec),
+			      m_index->get_debug_string_parens (prec));
+}
+
+/* Implementation of recording::memento::write_reproducer for
+   array_access.  */
+
+void
+recording::array_access::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "lvalue");
+  r.write ("  gcc_jit_lvalue *%s = \n"
+	   "    gcc_jit_context_new_array_access (%s, /* gcc_jit_context *ctxt */\n"
+	   "                                      %s, /*gcc_jit_location *loc */\n"
+	   "                                      %s, /* gcc_jit_rvalue *ptr */\n"
+	   "                                      %s); /* gcc_jit_rvalue *index */\n",
+	   id,
+	   r.get_identifier (get_context ()),
+	   r.get_identifier (m_loc),
+	   r.get_identifier_as_rvalue (m_ptr),
+	   r.get_identifier_as_rvalue (m_index));
+}
+
+/* The implementation of class gcc::jit::recording::access_field_of_lvalue.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::access_field_of_lvalue.  */
+
+void
+recording::access_field_of_lvalue::replay_into (replayer *r)
+{
+  set_playback_obj (
+    m_lvalue->playback_lvalue ()
+      ->access_field (playback_location (r, m_loc),
+		      m_field->playback_field ()));
+
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+   for recording::access_field_of_lvalue.  */
+
+void
+recording::access_field_of_lvalue::visit_children (rvalue_visitor *v)
+{
+  v->visit (m_lvalue);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   accessing a field of an lvalue.  */
+
+recording::string *
+recording::access_field_of_lvalue::make_debug_string ()
+{
+  enum precedence prec = get_precedence ();
+  return string::from_printf (m_ctxt,
+			      "%s.%s",
+			      m_lvalue->get_debug_string_parens (prec),
+			      m_field->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+   access_field_of_lvalue.  */
+
+void
+recording::access_field_of_lvalue::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "lvalue");
+  r.write ("  gcc_jit_lvalue *%s = \n"
+	   "    gcc_jit_lvalue_access_field (%s, /*gcc_jit_lvalue *struct_or_union */\n"
+	   "                                 %s, /*gcc_jit_location *loc */\n"
+	   "                                 %s);\n",
+	   id,
+	   r.get_identifier_as_lvalue (m_lvalue),
+	   r.get_identifier (m_loc),
+	   r.get_identifier (m_field));
+}
+
+/* The implementation of class gcc::jit::recording::access_field_rvalue.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::access_field_rvalue.  */
+
+void
+recording::access_field_rvalue::replay_into (replayer *r)
+{
+  set_playback_obj (
+    m_rvalue->playback_rvalue ()
+      ->access_field (playback_location (r, m_loc),
+		      m_field->playback_field ()));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+   for recording::access_field_rvalue.  */
+
+void
+recording::access_field_rvalue::visit_children (rvalue_visitor *v)
+{
+  v->visit (m_rvalue);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   accessing a field of an rvalue.  */
+
+recording::string *
+recording::access_field_rvalue::make_debug_string ()
+{
+  enum precedence prec = get_precedence ();
+  return string::from_printf (m_ctxt,
+			      "%s.%s",
+			      m_rvalue->get_debug_string_parens (prec),
+			      m_field->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+   access_field_rvalue.  */
+
+void
+recording::access_field_rvalue::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "rvalue");
+  r.write ("  gcc_jit_rvalue *%s = \n"
+	   "    gcc_jit_rvalue_access_field (%s, /*gcc_jit_rvalue *struct_or_union */\n"
+	   "                                 %s, /*gcc_jit_location *loc */\n"
+	   "                                 %s);\n",
+	   id,
+	   r.get_identifier_as_rvalue (m_rvalue),
+	   r.get_identifier (m_loc),
+	   r.get_identifier (m_field));
+}
+
+/* The implementation of class
+   gcc::jit::recording::dereference_field_rvalue.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::dereference_field_rvalue.  */
+
+void
+recording::dereference_field_rvalue::replay_into (replayer *r)
+{
+  set_playback_obj (
+    m_rvalue->playback_rvalue ()->
+      dereference_field (playback_location (r, m_loc),
+			 m_field->playback_field ()));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+   for recording::dereference_field_rvalue.  */
+
+void
+recording::dereference_field_rvalue::visit_children (rvalue_visitor *v)
+{
+  v->visit (m_rvalue);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   dereferencing a field of an rvalue.  */
+
+recording::string *
+recording::dereference_field_rvalue::make_debug_string ()
+{
+  enum precedence prec = get_precedence ();
+  return string::from_printf (m_ctxt,
+			      "%s->%s",
+			      m_rvalue->get_debug_string_parens (prec),
+			      m_field->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+   dereference_field_rvalue.  */
+
+void
+recording::dereference_field_rvalue::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "lvalue");
+  r.write ("  gcc_jit_lvalue *%s=\n"
+	   "    gcc_jit_rvalue_dereference_field (%s, /* gcc_jit_rvalue *ptr */\n"
+	   "                                      %s, /* gcc_jit_location *loc */\n"
+	   "                                      %s); /* gcc_jit_field *field */\n",
+	   id,
+	   r.get_identifier_as_rvalue (m_rvalue),
+	   r.get_identifier (m_loc),
+	   r.get_identifier (m_field));
+}
+
+/* The implementation of class gcc::jit::recording::dereference_rvalue.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::dereference_rvalue.  */
+
+void
+recording::dereference_rvalue::replay_into (replayer *r)
+{
+  set_playback_obj (
+    m_rvalue->playback_rvalue ()->
+      dereference (playback_location (r, m_loc)));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+   for recording::dereference_rvalue.  */
+
+void
+recording::dereference_rvalue::visit_children (rvalue_visitor *v)
+{
+  v->visit (m_rvalue);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   dereferencing an rvalue.  */
+
+recording::string *
+recording::dereference_rvalue::make_debug_string ()
+{
+  enum precedence prec = get_precedence ();
+  return string::from_printf (m_ctxt,
+			      "*%s",
+			      m_rvalue->get_debug_string_parens (prec));
+}
+
+/* Implementation of recording::memento::write_reproducer for
+   dereference_rvalue.  */
+
+void
+recording::dereference_rvalue::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "dereference");
+  r.write ("  gcc_jit_lvalue *%s =\n"
+	   "    gcc_jit_rvalue_dereference (%s, /* gcc_jit_rvalue *rvalue */\n"
+	   "                                %s); /* gcc_jit_location *loc */\n",
+	   id,
+	   r.get_identifier_as_rvalue (m_rvalue),
+	   r.get_identifier (m_loc));
+}
+
+/* The implementation of class gcc::jit::recording::get_address_of_lvalue.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::get_address_of_lvalue.  */
+
+void
+recording::get_address_of_lvalue::replay_into (replayer *r)
+{
+  set_playback_obj (
+    m_lvalue->playback_lvalue ()->
+      get_address (playback_location (r, m_loc)));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+   for recording::get_address_of_lvalue.  */
+
+void
+recording::get_address_of_lvalue::visit_children (rvalue_visitor *v)
+{
+  v->visit (m_lvalue);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   getting the address of an lvalue.  */
+
+recording::string *
+recording::get_address_of_lvalue::make_debug_string ()
+{
+  enum precedence prec = get_precedence ();
+  return string::from_printf (m_ctxt,
+			      "&%s",
+			      m_lvalue->get_debug_string_parens (prec));
+}
+
+/* Implementation of recording::memento::write_reproducer for
+   get_address_of_lvalue.  */
+
+void
+recording::get_address_of_lvalue::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "address_of");
+  r.write ("  gcc_jit_rvalue *%s =\n"
+	   "    gcc_jit_lvalue_get_address (%s, /* gcc_jit_lvalue *lvalue */\n"
+	   "                                %s); /* gcc_jit_location *loc */\n",
+	   id,
+	   r.get_identifier_as_lvalue (m_lvalue),
+	   r.get_identifier (m_loc));
+}
+
+/* The implementation of class gcc::jit::recording::function_pointer.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::function_pointer.  */
+
+void
+recording::function_pointer::replay_into (replayer *r)
+{
+  set_playback_obj (
+    m_fn->playback_function ()->
+      get_address (playback_location (r, m_loc)));
+}
+
+void
+recording::function_pointer::visit_children (rvalue_visitor *)
+{
+  /* Empty.  */
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   getting the address of an lvalue.  */
+
+recording::string *
+recording::function_pointer::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s",
+			      m_fn->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+   function_pointer.  */
+
+void
+recording::function_pointer::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "address_of");
+  r.write ("  gcc_jit_rvalue *%s =\n"
+	   "    gcc_jit_function_get_address (%s, /* gcc_jit_function *fn */\n"
+	   "                                  %s); /* gcc_jit_location *loc */\n",
+	   id,
+	   r.get_identifier (m_fn),
+	   r.get_identifier (m_loc));
+}
+
+/* The implementation of class gcc::jit::recording::local.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::local.  */
+
+void
+recording::local::replay_into (replayer *r)
+{
+  set_playback_obj (
+    m_func->playback_function ()
+      ->new_local (playback_location (r, m_loc),
+		   m_type->playback_type (),
+		   playback_string (m_name)));
+}
+
+/* Override the default implementation of
+   recording::memento::write_to_dump for locals by writing
+      TYPE NAME;
+   for use at the top of the function body as if it were a
+   declaration.  */
+
+void
+recording::local::write_to_dump (dump &d)
+{
+  if (d.update_locations ())
+    m_loc = d.make_location ();
+  d.write("  %s %s;\n",
+	  m_type->get_debug_string (),
+	  get_debug_string ());
+}
+
+void
+recording::local::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "local");
+  r.write ("  gcc_jit_lvalue *%s =\n"
+	   "    gcc_jit_function_new_local (%s, /* gcc_jit_function *func */\n"
+	   "                                %s, /* gcc_jit_location *loc */\n"
+	   "                                %s, /* gcc_jit_type *type */\n"
+	   "                                %s); /* const char *name */\n",
+	   id,
+	   r.get_identifier (m_func),
+	   r.get_identifier (m_loc),
+	   r.get_identifier_as_type (m_type),
+	   m_name->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::statement.  */
+
+/* We poison the default implementation of
+   gcc::jit::recording::statement::get_successor_blocks
+   since this vfunc must only ever be called on terminator
+   statements.  */
+
+vec <recording::block *>
+recording::statement::get_successor_blocks () const
+{
+  /* The base class implementation is for non-terminating statements,
+     and thus should never be called.  */
+  gcc_unreachable ();
+  vec <block *> result;
+  result.create (0);
+  return result;
+}
+
+/* Extend the default implementation of
+   recording::memento::write_to_dump for statements by (if requested)
+   updating the location of the statement to the current location in
+   the dumpfile.  */
+
+void
+recording::statement::write_to_dump (dump &d)
+{
+  memento::write_to_dump (d);
+  if (d.update_locations ())
+    m_loc = d.make_location ();
+}
+
+/* The implementation of class gcc::jit::recording::eval.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::eval.  */
+
+void
+recording::eval::replay_into (replayer *r)
+{
+  playback_block (get_block ())
+    ->add_eval (playback_location (r),
+		m_rvalue->playback_rvalue ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   an eval statement.  */
+
+recording::string *
+recording::eval::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "(void)%s;",
+			      m_rvalue->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+   eval statements.  */
+
+void
+recording::eval::write_reproducer (reproducer &r)
+{
+  r.write ("  gcc_jit_block_add_eval (%s, /*gcc_jit_block *block */\n"
+	   "                          %s, /* gcc_jit_location *loc */\n"
+	   "                          %s); /* gcc_jit_rvalue *rvalue */\n",
+	   r.get_identifier (get_block ()),
+	   r.get_identifier (get_loc ()),
+	   r.get_identifier_as_rvalue (m_rvalue));
+}
+
+/* The implementation of class gcc::jit::recording::assignment.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::assignment.  */
+
+void
+recording::assignment::replay_into (replayer *r)
+{
+  playback_block (get_block ())
+    ->add_assignment (playback_location (r),
+		      m_lvalue->playback_lvalue (),
+		      m_rvalue->playback_rvalue ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   an assignment statement.  */
+
+recording::string *
+recording::assignment::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s = %s;",
+			      m_lvalue->get_debug_string (),
+			      m_rvalue->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+   assignment statements.  */
+
+void
+recording::assignment::write_reproducer (reproducer &r)
+{
+  r.write ("  gcc_jit_block_add_assignment (%s, /*gcc_jit_block *block */\n"
+	   "                                %s, /* gcc_jit_location *loc */\n"
+	   "                                %s, /* gcc_jit_lvalue *lvalue */\n"
+	   "                                %s); /* gcc_jit_rvalue *rvalue */\n",
+	   r.get_identifier (get_block ()),
+	   r.get_identifier (get_loc ()),
+	   r.get_identifier_as_lvalue (m_lvalue),
+	   r.get_identifier_as_rvalue (m_rvalue));
+}
+
+/* The implementation of class gcc::jit::recording::assignment_op.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::assignment_op.  */
+
+void
+recording::assignment_op::replay_into (replayer *r)
+{
+  playback::type *result_type =
+    m_lvalue->playback_lvalue ()->get_type ();
+
+  playback::rvalue *binary_op =
+    r->new_binary_op (playback_location (r),
+		      m_op,
+		      result_type,
+		      m_lvalue->playback_rvalue (),
+		      m_rvalue->playback_rvalue ());
+
+  playback_block (get_block ())
+    ->add_assignment (playback_location (r),
+		      m_lvalue->playback_lvalue (),
+		      binary_op);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   an assignment_op statement.  */
+
+recording::string *
+recording::assignment_op::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s %s= %s;",
+			      m_lvalue->get_debug_string (),
+			      binary_op_strings[m_op],
+			      m_rvalue->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+   assignment_op statements.  */
+
+void
+recording::assignment_op::write_reproducer (reproducer &r)
+{
+  r.write ("  gcc_jit_block_add_assignment_op (%s, /*gcc_jit_block *block */\n"
+	   "                                   %s, /* gcc_jit_location *loc */\n"
+	   "                                   %s, /* gcc_jit_lvalue *lvalue */\n"
+	   "                                   %s, /* enum gcc_jit_binary_op op */\n"
+	   "                                   %s); /* gcc_jit_rvalue *rvalue */\n",
+	   r.get_identifier (get_block ()),
+	   r.get_identifier (get_loc ()),
+	   r.get_identifier_as_lvalue (m_lvalue),
+	   binary_op_reproducer_strings[m_op],
+	   r.get_identifier_as_rvalue (m_rvalue));
+}
+
+/* The implementation of class gcc::jit::recording::comment.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::comment.  */
+
+void
+recording::comment::replay_into (replayer *r)
+{
+  playback_block (get_block ())
+    ->add_comment (playback_location (r),
+		   m_text->c_str ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   a comment "statement".  */
+
+recording::string *
+recording::comment::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "/* %s */",
+			      m_text->c_str ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+   comments.  */
+
+void
+recording::comment::write_reproducer (reproducer &r)
+{
+  r.write ("  gcc_jit_block_add_comment (%s, /*gcc_jit_block *block */\n"
+	   "                             %s, /* gcc_jit_location *loc */\n"
+	   "                             %s); /* const char *text */\n",
+	   r.get_identifier (get_block ()),
+	   r.get_identifier (get_loc ()),
+	   m_text->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::conditional.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::conditional.  */
+
+void
+recording::conditional::replay_into (replayer *r)
+{
+  playback_block (get_block ())
+    ->add_conditional (playback_location (r),
+		       m_boolval->playback_rvalue (),
+		       playback_block (m_on_true),
+		       playback_block (m_on_false));
+}
+
+/* Override the poisoned default implementation of
+   gcc::jit::recording::statement::get_successor_blocks
+
+   A conditional jump has 2 successor blocks.  */
+
+vec <recording::block *>
+recording::conditional::get_successor_blocks () const
+{
+  vec <block *> result;
+  result.create (2);
+  result.quick_push (m_on_true);
+  result.quick_push (m_on_false);
+  return result;
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   a conditional jump statement.  */
+
+recording::string *
+recording::conditional::make_debug_string ()
+{
+  if (m_on_false)
+    return string::from_printf (m_ctxt,
+				"if (%s) goto %s; else goto %s;",
+				m_boolval->get_debug_string (),
+				m_on_true->get_debug_string (),
+				m_on_false->get_debug_string ());
+  else
+    return string::from_printf (m_ctxt,
+				"if (%s) goto %s;",
+				m_boolval->get_debug_string (),
+				m_on_true->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+   conditional statements.  */
+
+void
+recording::conditional::write_reproducer (reproducer &r)
+{
+  r.write ("  gcc_jit_block_end_with_conditional (%s, /*gcc_jit_block *block */\n"
+	   "                                      %s, /* gcc_jit_location *loc */\n"
+	   "                                      %s, /* gcc_jit_rvalue *boolval */\n"
+	   "                                      %s, /* gcc_jit_block *on_true */\n"
+	   "                                      %s); /* gcc_jit_block *on_false */\n",
+	   r.get_identifier (get_block ()),
+	   r.get_identifier (get_loc ()),
+	   r.get_identifier_as_rvalue (m_boolval),
+	   r.get_identifier (m_on_true),
+	   r.get_identifier (m_on_false));
+}
+
+/* The implementation of class gcc::jit::recording::jump.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::jump.  */
+
+void
+recording::jump::replay_into (replayer *r)
+{
+  playback_block (get_block ())
+    ->add_jump (playback_location (r),
+		m_target->playback_block ());
+}
+
+/* Override the poisoned default implementation of
+   gcc::jit::recording::statement::get_successor_blocks
+
+   An unconditional jump has 1 successor block.  */
+
+vec <recording::block *>
+recording::jump::get_successor_blocks () const
+{
+  vec <block *> result;
+  result.create (1);
+  result.quick_push (m_target);
+  return result;
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   a unconditional jump statement.  */
+
+recording::string *
+recording::jump::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "goto %s;",
+			      m_target->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+   jump statements.  */
+
+void
+recording::jump::write_reproducer (reproducer &r)
+{
+  r.write ("  gcc_jit_block_end_with_jump (%s, /*gcc_jit_block *block */\n"
+	   "                               %s, /* gcc_jit_location *loc */\n"
+	   "                               %s); /* gcc_jit_block *target */\n",
+	   r.get_identifier (get_block ()),
+	   r.get_identifier (get_loc ()),
+	   r.get_identifier (m_target));
+}
+
+/* The implementation of class gcc::jit::recording::return_.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::return_.  */
+
+void
+recording::return_::replay_into (replayer *r)
+{
+  playback_block (get_block ())
+    ->add_return (playback_location (r),
+		  m_rvalue ? m_rvalue->playback_rvalue () : NULL);
+}
+
+/* Override the poisoned default implementation of
+   gcc::jit::recording::statement::get_successor_blocks
+
+   A return statement has no successor block.  */
+
+vec <recording::block *>
+recording::return_::get_successor_blocks () const
+{
+  vec <block *> result;
+  result.create (0);
+  return result;
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   a return statement (covers both those with and without rvalues).  */
+
+recording::string *
+recording::return_::make_debug_string ()
+{
+  if (m_rvalue)
+    return string::from_printf (m_ctxt,
+				"return %s;",
+				m_rvalue->get_debug_string ());
+  else
+    return string::from_printf (m_ctxt,
+				"return;");
+}
+
+/* Implementation of recording::memento::write_reproducer for
+   return statements.  */
+
+void
+recording::return_::write_reproducer (reproducer &r)
+{
+  if (m_rvalue)
+    r.write ("  gcc_jit_block_end_with_return (%s, /*gcc_jit_block *block */\n"
+	     "                                 %s, /* gcc_jit_location *loc */\n"
+	     "                                 %s); /* gcc_jit_rvalue *rvalue */\n",
+	     r.get_identifier (get_block ()),
+	     r.get_identifier (get_loc ()),
+	     r.get_identifier_as_rvalue (m_rvalue));
+  else
+    r.write ("  gcc_jit_block_end_with_void_return (%s, /*gcc_jit_block *block */\n"
+	     "                                      %s); /* gcc_jit_location *loc */\n",
+	     r.get_identifier (get_block ()),
+	     r.get_identifier (get_loc ()));
+}
+
+/* The implementation of class gcc::jit::recording::case_.  */
+
+void
+recording::case_::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "case");
+  const char *fmt =
+    "  gcc_jit_case *%s = \n"
+    "    gcc_jit_context_new_case (%s, /*gcc_jit_context *ctxt */\n"
+    "                              %s, /* gcc_jit_rvalue *min_value */\n"
+    "                              %s, /* gcc_jit_rvalue *max_value */\n"
+    "                              %s); /* gcc_jit_block *dest_block */\n";
+  r.write (fmt,
+	   id,
+	   r.get_identifier (get_context ()),
+	   r.get_identifier_as_rvalue (m_min_value),
+	   r.get_identifier_as_rvalue (m_max_value),
+	   r.get_identifier (m_dest_block));
+}
+
+recording::string *
+recording::case_::make_debug_string ()
+{
+  return string::from_printf (get_context (),
+			      "case %s ... %s: goto %s;",
+			      m_min_value->get_debug_string (),
+			      m_max_value->get_debug_string (),
+			      m_dest_block->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::switch_.  */
+
+/* gcc::jit::recording::switch_'s constructor.  */
+
+recording::switch_::switch_ (block *b,
+			     location *loc,
+			     rvalue *expr,
+			     block *default_block,
+			     int num_cases,
+			     case_ **cases)
+: statement (b, loc),
+  m_expr (expr),
+  m_default_block (default_block)
+{
+  m_cases.reserve_exact (num_cases);
+  for (int i = 0; i< num_cases; i++)
+    m_cases.quick_push (cases[i]);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::switch_.  */
+
+void
+recording::switch_::replay_into (replayer *r)
+{
+  auto_vec <playback::case_> pcases;
+  int i;
+  recording::case_ *rcase;
+  pcases.reserve_exact (m_cases.length ());
+  FOR_EACH_VEC_ELT (m_cases, i, rcase)
+    {
+      playback::case_ pcase (rcase->get_min_value ()->playback_rvalue (),
+			     rcase->get_max_value ()->playback_rvalue (),
+			     rcase->get_dest_block ()->playback_block ());
+      pcases.safe_push (pcase);
+    }
+  playback_block (get_block ())
+    ->add_switch (playback_location (r),
+		  m_expr->playback_rvalue (),
+		  m_default_block->playback_block (),
+		  &pcases);
+}
+
+/* Override the poisoned default implementation of
+   gcc::jit::recording::statement::get_successor_blocks
+
+   A switch statement has (NUM_CASES + 1) successor blocks.  */
+
+vec <recording::block *>
+recording::switch_::get_successor_blocks () const
+{
+  vec <block *> result;
+  result.create (m_cases.length () + 1);
+  result.quick_push (m_default_block);
+  int i;
+  case_ *c;
+  FOR_EACH_VEC_ELT (m_cases, i, c)
+    result.quick_push (c->get_dest_block ());
+  return result;
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   a switch statement.  */
+
+recording::string *
+recording::switch_::make_debug_string ()
+{
+  auto_vec <char> cases_str;
+  int i;
+  case_ *c;
+  FOR_EACH_VEC_ELT (m_cases, i, c)
+    {
+      size_t len = strlen (c->get_debug_string ());
+      unsigned idx = cases_str.length ();
+      cases_str.safe_grow (idx + 1 + len);
+      cases_str[idx] = ' ';
+      memcpy (&(cases_str[idx + 1]),
+	      c->get_debug_string (),
+	      len);
+    }
+  cases_str.safe_push ('\0');
+
+  return string::from_printf (m_ctxt,
+			      "switch (%s) {default: goto %s;%s}",
+			      m_expr->get_debug_string (),
+			      m_default_block->get_debug_string (),
+			      &cases_str[0]);
+}
+
+/* Implementation of recording::memento::write_reproducer for
+   switch statements.  */
+
+void
+recording::switch_::write_reproducer (reproducer &r)
+{
+  r.make_identifier (this, "switch");
+  int i;
+  case_ *c;
+  const char *cases_id =
+    r.make_tmp_identifier ("cases_for", this);
+  r.write ("  gcc_jit_case *%s[%i] = {\n",
+	   cases_id,
+	   m_cases.length ());
+  FOR_EACH_VEC_ELT (m_cases, i, c)
+    r.write ("    %s,\n", r.get_identifier (c));
+  r.write ("  };\n");
+  const char *fmt =
+    "  gcc_jit_block_end_with_switch (%s, /*gcc_jit_block *block */\n"
+    "                                 %s, /* gcc_jit_location *loc */\n"
+    "                                 %s, /* gcc_jit_rvalue *expr */\n"
+    "                                 %s, /* gcc_jit_block *default_block */\n"
+    "                                 %i, /* int num_cases */\n"
+    "                                 %s); /* gcc_jit_case **cases */\n";
+    r.write (fmt,
+	     r.get_identifier (get_block ()),
+	     r.get_identifier (get_loc ()),
+	     r.get_identifier_as_rvalue (m_expr),
+	     r.get_identifier (m_default_block),
+	     m_cases.length (),
+	     cases_id);
+}
+
+} // namespace gcc::jit
+
+} // namespace gcc