Implementation of the gcc::jit::recording internal API, so that
libgccjit.c can record the calls that are made to the public API, for
later playback by the dummy frontend.

gcc/jit/
        * jit-recording.c: New.
---
 gcc/jit/jit-recording.c | 3434 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 3434 insertions(+)
 create mode 100644 gcc/jit/jit-recording.c

diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
new file mode 100644
index 0000000..8daa8f2
--- /dev/null
+++ b/gcc/jit/jit-recording.c
@@ -0,0 +1,3434 @@
+/* Internals of libgccjit: classes for recording calls made to the JIT API.
+   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalc...@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 "opts.h"
+#include "tree.h"
+#include "pretty-print.h"
+
+#include <pthread.h>
+
+#include "jit-common.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, ...)
+{
+  va_list ap;
+  char *buf = NULL;
+
+  /* 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);
+  vasprintf (&buf, fmt, ap);
+  va_end (ap);
+
+  if (!buf)
+    {
+      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);
+
+  /* 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);
+}
+
+/**********************************************************************
+ 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)
+  : m_parent_ctxt (parent_ctxt),
+    m_error_count (0),
+    m_first_error_str (NULL),
+    m_owns_first_error_str (false),
+    m_mementos (),
+    m_compound_types (),
+    m_functions (),
+    m_FILE_type (NULL),
+    m_builtins_manager(NULL)
+{
+  if (parent_ctxt)
+    {
+      /* Inherit options from parent.
+         Note that the first memcpy means copying pointers to strings.  */
+      memcpy (m_str_options,
+              parent_ctxt->m_str_options,
+              sizeof (m_str_options));
+      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));
+    }
+  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_basic_types, 0, sizeof (m_basic_types));
+}
+
+/* The destructor for gcc::jit::recording::context, implicitly used by
+   gcc_jit_context_release.  */
+
+recording::context::~context ()
+{
+  int i;
+  memento *m;
+  FOR_EACH_VEC_ELT (m_mementos, i, m)
+    {
+      delete m;
+    }
+
+  if (m_builtins_manager)
+    delete m_builtins_manager;
+
+  if (m_owns_first_error_str)
+    free (m_first_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)
+{
+  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 ()
+{
+  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)
+{
+  recording::location *result =
+    new recording::location (this,
+                           new_string (filename),
+                           line, column);
+  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::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 (this,
+                      return_type,
+                      num_params,
+                      param_types,
+                      is_variadic);
+  record (fn_type);
+
+  /* Return a pointer-type to the 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;
+}
+
+/* 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)
+{
+  if (!m_builtins_manager)
+    m_builtins_manager = new builtins_manager (this);
+  return m_builtins_manager->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,
+                               recording::type *type,
+                               const char *name)
+{
+  recording::lvalue *result =
+    new recording::global (this, loc, type, new_string (name));
+  record (result);
+  return result;
+}
+
+/* Create a recording::memento_of_new_rvalue_from_int instance and add
+   it to this context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_rvalue_from_int.  */
+
+recording::rvalue *
+recording::context::new_rvalue_from_int (recording::type *type,
+                                        int value)
+{
+  recording::rvalue *result =
+    new memento_of_new_rvalue_from_int (this, NULL, type, value);
+  record (result);
+  return result;
+}
+
+/* Create a recording::memento_of_new_rvalue_from_double instance and
+   add it to this context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_rvalue_from_double.  */
+
+recording::rvalue *
+recording::context::new_rvalue_from_double (recording::type *type,
+                                           double value)
+{
+  recording::rvalue *result =
+    new memento_of_new_rvalue_from_double (this, NULL, type, value);
+  record (result);
+  return result;
+}
+
+/* Create a recording::memento_of_new_rvalue_from_ptr instance and add
+   it to this context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_rvalue_from_ptr.  */
+
+recording::rvalue *
+recording::context::new_rvalue_from_ptr (recording::type *type,
+                                        void *value)
+{
+  recording::rvalue *result =
+    new memento_of_new_rvalue_from_ptr (this, NULL, type, value);
+  record (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::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;
+}
+
+/* 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;
+    }
+  m_str_options[opt] = value;
+}
+
+/* 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;
+}
+
+/* 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;
+}
+
+/* This mutex guards gcc::jit::recording::context::compile, so that only
+   one thread can be accessing the bulk of GCC's state at once.  */
+
+static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Validate this context, and if it passes, compile it within a
+   mutex.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_compile.  */
+
+result *
+recording::context::compile ()
+{
+  validate ();
+
+  if (errors_occurred ())
+    return NULL;
+
+  /* Acquire the big GCC mutex. */
+  pthread_mutex_lock (&jit_mutex);
+  gcc_assert (NULL == ::gcc::jit::active_playback_ctxt);
+
+  /* Set up a playback context.  */
+  ::gcc::jit::playback::context replayer (this);
+  ::gcc::jit::active_playback_ctxt = &replayer;
+
+  result *result_obj = replayer.compile ();
+
+  /* Release the big GCC mutex. */
+  ::gcc::jit::active_playback_ctxt = NULL;
+  pthread_mutex_unlock (&jit_mutex);
+
+  return result_obj;
+}
+
+/* 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)
+{
+  char *malloced_msg;
+  const char *errmsg;
+  bool has_ownership;
+
+  vasprintf (&malloced_msg, fmt, ap);
+  if (malloced_msg)
+    {
+      errmsg = malloced_msg;
+      has_ownership = true;
+    }
+  else
+    {
+      errmsg = "out of memory generating error message";
+      has_ownership = false;
+    }
+
+  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;
+    }
+  else
+    if (has_ownership)
+      free (malloced_msg);
+
+  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;
+}
+
+/* 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");
+      }
+
+  function *fn;
+  FOR_EACH_VEC_ELT (m_functions, i, fn)
+    {
+      fn->write_to_dump (d);
+    }
+}
+
+/* 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 ()
+{
+  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, ...)
+{
+  va_list ap;
+  char *buf = NULL;
+  recording::string *result;
+
+  va_start (ap, fmt);
+  vasprintf (&buf, fmt, ap);
+  va_end (ap);
+
+  if (!buf)
+    {
+      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;
+}
+
+/* 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);
+}
+
+/* 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;
+}
+
+/* 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:
+      /* 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;
+    }
+}
+
+/* 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;
+    }
+}
+
+/* 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;
+    }
+}
+
+/* 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 */
+
+};
+
+/* 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]);
+}
+
+/* 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 ());
+}
+
+/* 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 ());
+}
+
+/* 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 ());
+}
+
+/* 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);
+}
+
+/* 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 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.  */
+  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;
+}
+
+/* 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;
+}
+
+/* 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 */));
+}
+
+/* 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 ());
+}
+
+/* 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 ());
+}
+
+/* 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 *)
+{
+  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::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;
+}
+
+/* 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;
+}
+
+/* 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 ()));
+}
+
+
+/* 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 ()
+{
+  for (int i = 0; i< num_params; i++)
+    m_params.safe_push (params[i]);
+}
+
+/* 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.  */
+  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_blocks.length () > 0 && 0 == num_invalid_blocks)
+    {
+      /* Iteratively walk the graph of blocks, marking their "m_is_reachable"
+        flag, starting at the initial block.  */
+      vec<block *> worklist;
+      worklist.create (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 .  */
+         block *next1, *next2;
+         int n = b->get_successor_blocks (&next1, &next2);
+         switch (n)
+           {
+           default:
+             gcc_unreachable ();
+           case 2:
+             if (!next2->m_is_reachable)
+               worklist.safe_push (next2);
+             /* fallthrough */
+           case 1:
+             if (!next1->m_is_reachable)
+               worklist.safe_push (next1);
+             break;
+           case 0:
+             break;
+           }
+       }
+
+      /* 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);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   functions.  */
+
+recording::string *
+recording::function::make_debug_string ()
+{
+  return m_name;
+}
+
+/* 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 post-error-checking part of
+   gcc_jit_block_add_eval.  */
+
+void
+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);
+}
+
+/* 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 post-error-checking part of
+   gcc_jit_block_add_assignment.  */
+
+void
+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);
+}
+
+/* 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 post-error-checking part of
+   gcc_jit_block_add_assignment_op.  */
+
+void
+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);
+}
+
+/* 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 post-error-checking part of
+   gcc_jit_block_add_comment.  */
+
+void
+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);
+}
+
+/* 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 post-error-checking part of
+   gcc_jit_block_end_with_conditional.  */
+
+void
+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;
+}
+
+/* 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 post-error-checking part of
+   gcc_jit_block_end_with_jump.  */
+
+void
+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;
+}
+
+/* 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.  */
+
+void
+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;
+}
+
+/* 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 ()
+{
+  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 number of
+   successor blocks, which will be 0, 1 or 2, for return, unconditional
+   jump, and conditional jump respectively.
+   NEXT1 and NEXT2 must be non-NULL.  The first successor block (if any)
+   is written to NEXT1, and the second (if any) to NEXT2.
+
+   Used when validating functions, and when dumping dot representations
+   of them.  */
+
+int
+recording::block::get_successor_blocks (block **next1, block **next2) const
+{
+  gcc_assert (m_has_been_terminated);
+  gcc_assert (next1);
+  gcc_assert (next2);
+  statement *last_statement = get_last_statement ();
+  gcc_assert (last_statement);
+  return last_statement->get_successor_blocks (next1, next2);
+}
+
+/* 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);
+}
+
+/* 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)
+{
+  block *next[2];
+  int num_succs = get_successor_blocks (&next[0], &next[1]);
+  for (int i = 0; i < num_succs; i++)
+    pp_printf (pp,
+              "\tblock_%d:s -> block_%d:n;\n",
+              m_index, next[i]->m_index);
+}
+
+/* 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_type->playback_type (),
+                                  playback_string (m_name)));
+}
+
+/* The implementation of class 
gcc::jit::recording::memento_of_new_rvalue_from_int.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_new_rvalue_from_int.  */
+
+void
+recording::memento_of_new_rvalue_from_int::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_rvalue_from_int (m_type->playback_type (),
+                                           m_value));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   rvalue_from_int, rendering it as
+     (TYPE)LITERAL
+   e.g.
+     "(int)42".  */
+
+recording::string *
+recording::memento_of_new_rvalue_from_int::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "(%s)%i",
+                             m_type->get_debug_string (),
+                             m_value);
+}
+
+/* The implementation of class 
gcc::jit::recording::memento_of_new_rvalue_from_double.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_new_rvalue_from_double.  */
+
+void
+recording::memento_of_new_rvalue_from_double::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_rvalue_from_double (m_type->playback_type (),
+                                              m_value));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   rvalue_from_double, rendering it as
+     (TYPE)LITERAL
+   e.g.
+     "(float)42.0".  */
+
+recording::string *
+recording::memento_of_new_rvalue_from_double::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "(%s)%f",
+                             m_type->get_debug_string (),
+                             m_value);
+}
+
+/* The implementation of class 
gcc::jit::recording::memento_of_new_rvalue_from_ptr.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_new_rvalue_from_ptr.  */
+
+void
+recording::memento_of_new_rvalue_from_ptr::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_rvalue_from_ptr (m_type->playback_type (),
+                                           m_value));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   rvalue_from_ptr, rendering it as
+     (TYPE)HEX
+   e.g.
+     "(int *)0xdeadbeef"
+
+   Zero is rendered as NULL e.g.
+     "(int *)NULL".  */
+
+recording::string *
+recording::memento_of_new_rvalue_from_ptr::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 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,
+                             m_value->get_debug_string ());
+}
+
+/* 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 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 */
+};
+
+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 ());
+}
+
+/* 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 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 ()
+{
+  return string::from_printf (m_ctxt,
+                             "%s %s %s",
+                             m_a->get_debug_string (),
+                             binary_op_strings[m_op],
+                             m_b->get_debug_string ());
+}
+
+/* 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 ()
+{
+  return string::from_printf (m_ctxt,
+                             "%s %s %s",
+                             m_a->get_debug_string (),
+                             comparison_strings[m_op],
+                             m_b->get_debug_string ());
+}
+
+/* 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::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 recording::memento::make_debug_string for
+   casts.  */
+
+recording::string *
+recording::cast::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "(%s)%s",
+                             get_type ()->get_debug_string (),
+                             m_rvalue->get_debug_string ());
+}
+
+/* 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)
+: rvalue (ctxt, loc, func->get_return_type ()),
+  m_func (func),
+  m_args ()
+{
+  for (int i = 0; i< numargs; i++)
+    m_args.safe_push (args[i]);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::call.  */
+
+void
+recording::call::replay_into (replayer *r)
+{
+  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));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   function calls.  */
+
+recording::string *
+recording::call::make_debug_string ()
+{
+  /* 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 ());
+      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 ());
+      len += strlen (m_args[i]->get_debug_string ());
+      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_func->get_debug_string (),
+                                       argbuf);
+
+  delete[] argbuf;
+
+  return result;
+}
+
+/* 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)
+: rvalue (ctxt, loc,
+         fn_ptr->get_type ()->dereference ()
+           ->as_a_function_type ()->get_return_type ()),
+  m_fn_ptr (fn_ptr),
+  m_args ()
+{
+  for (int i = 0; i< numargs; i++)
+    m_args.safe_push (args[i]);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::call_through_ptr.  */
+
+void
+recording::call_through_ptr::replay_into (replayer *r)
+{
+  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));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   calls through function ptrs.  */
+
+recording::string *
+recording::call_through_ptr::make_debug_string ()
+{
+  /* 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 ());
+      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 ());
+      len += strlen (m_args[i]->get_debug_string ());
+      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 (),
+                                       argbuf);
+
+  delete[] argbuf;
+
+  return result;
+}
+
+/* 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 recording::memento::make_debug_string for
+   array accesses.  */
+
+recording::string *
+recording::array_access::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "%s[%s]",
+                             m_ptr->get_debug_string (),
+                             m_index->get_debug_string ());
+}
+
+/* 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 recording::memento::make_debug_string for
+   accessing a field of an lvalue.  */
+
+recording::string *
+recording::access_field_of_lvalue::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "%s.%s",
+                             m_lvalue->get_debug_string (),
+                             m_field->get_debug_string ());
+}
+
+/* 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 recording::memento::make_debug_string for
+   accessing a field of an rvalue.  */
+
+recording::string *
+recording::access_field_rvalue::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "%s.%s",
+                             m_rvalue->get_debug_string (),
+                             m_field->get_debug_string ());
+}
+
+/* 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 recording::memento::make_debug_string for
+   dereferencing a field of an rvalue.  */
+
+recording::string *
+recording::dereference_field_rvalue::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "%s->%s",
+                             m_rvalue->get_debug_string (),
+                             m_field->get_debug_string ());
+}
+
+/* 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 recording::memento::make_debug_string for
+   dereferencing an rvalue.  */
+
+recording::string *
+recording::dereference_rvalue::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "*%s",
+                             m_rvalue->get_debug_string ());
+}
+
+/* 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 recording::memento::make_debug_string for
+   getting the address of an lvalue.  */
+
+recording::string *
+recording::get_address_of_lvalue::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "&%s",
+                             m_lvalue->get_debug_string ());
+}
+
+/* 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 ());
+}
+
+/* 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.  */
+
+int
+recording::statement::get_successor_blocks (block **/*out_next1*/,
+                                           block **/*out_next2*/) const
+{
+  /* The base class implementation is for non-terminating statements,
+     and thus should never be called.  */
+  gcc_unreachable ();
+  return 0;
+}
+
+/* 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 ());
+}
+
+/* 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 ());
+}
+
+/* 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 ());
+}
+
+/* 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 ());
+}
+
+/* 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.  */
+
+int
+recording::conditional::get_successor_blocks (block **out_next1,
+                                             block **out_next2) const
+{
+  *out_next1 = m_on_true;
+  *out_next2 = m_on_false;
+  return 2;
+}
+
+/* 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 ());
+}
+
+/* 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.  */
+
+int
+recording::jump::get_successor_blocks (block **out_next1,
+                                      block **/*out_next2*/) const
+{
+  *out_next1 = m_target;
+  return 1;
+}
+
+/* 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 ());
+}
+
+/* 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.  */
+
+int
+recording::return_::get_successor_blocks (block **/*out_next1*/,
+                                         block **/*out_next2*/) const
+{
+  return 0;
+}
+
+/* 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;");
+}
+
+} // namespace gcc::jit
+
+} // namespace gcc
-- 
1.8.5.3

Reply via email to