diff mbox

[jit] Eliminate the code-creation callback

Message ID 1390619454-32181-1-git-send-email-dmalcolm@redhat.com
State New
Headers show

Commit Message

David Malcolm Jan. 25, 2014, 3:10 a.m. UTC
Committed to branch dmalcolm/jit:

Eliminate the code-creation callback, so that clients can simply call the
API directly.

All "contextual" objects change from merely being "alive" during the
callback (and eventually garbage-collected) to having a lifetime equal to
that of the context they are created within, with automatic cleanup
when the context is released.

Internally this is implemented by having two parallel class-hierarchies:
the existing gcc::jit classes become gcc::jit::playback classes, plus a
new parallel hierarchy within a gcc::jit::recording namespace.  Calls to
the client API are recorded as jit::recording objects, and during
compilation are played back as jit::playback objects, which create GCC
trees.

This should let us play better with C++ exception-handling, and support
more interesting objects lifetimes of the kind discussed in
http://gcc.gnu.org/ml/jit/2014-q1/msg00001.html
(aka "Caching one-time startup (and GNU Octave JIT)")

gcc/
	* timevar.def: Replace TV_CLIENT_CALLBACK with TV_JIT_REPLAY.

gcc/jit/
	* libgccjit.h: Update comments to eliminate the code-creation
	callback.  All "contextual" objects change from merely being
	"alive" during the callback to having a lifetime equal to that
	of the context they are created within, with automatic cleanup
	when the context is released.
	(gcc_jit_code_callback): Delete.
	(gcc_jit_context_set_code_factory): Delete.

	* libgccjit.map (gcc_jit_context_set_code_factory): Delete.

	* dummy-frontend.c (my_walker): Update for rename of the singleton
	reference-owning context.
	(jit_langhook_parse_file): Rather than run a client-provided
	callback, we now replay a recording of the client activity.

	* internal-api.h (gcc::jit): Split the existing API into two
	copies...
	(gcc::jit::recording): ...a class hierarchy used to implement
	the client-facing API, which records the API calls made to it
	and...
	(gcc::jit::playback): ...a class hierarchy used within the
	dummy GCC frontend, which plays back the recorded API calls once
	GCC is initialized.

	* internal-api.c (gcc::jit::recording::playback_location): New
	API, in which client API calls are recorded as a list of "memento"
	objects, to be played back into GCC when the dummy frontend runs.
	(gcc::jit::recording::playback_string): Likewise.
	(gcc::jit::recording::playback_label): Likewise.
	(gcc::jit::recording::context::~context): Likewise.
	(gcc::jit::recording::context::replay_into): Likewise.
	(gcc::jit::recording::context::disassociate_from_playback): Likewise.
	(gcc::jit::recording::context::new_string): Likewise.
	(gcc::jit::recording::context::new_location): Likewise.
	(gcc::jit::recording::context::get_type): Likewise.
	(gcc::jit::recording::context::new_field): Likewise.
	(gcc::jit::recording::context::new_struct_type): Likewise.
	(gcc::jit::recording::context::new_param): Likewise.
	(gcc::jit::recording::context::new_function): Likewise.
	(gcc::jit::recording::context::new_global): Likewise.
	(gcc::jit::recording::context::new_rvalue_from_int): Likewise.
	(gcc::jit::recording::context::new_rvalue_from_double): Likewise.
	(gcc::jit::recording::context::new_rvalue_from_ptr): Likewise.
	(gcc::jit::recording::context::new_string_literal): Likewise.
	(gcc::jit::recording::context::new_unary_op): Likewise.
	(gcc::jit::recording::context::new_binary_op): Likewise.
	(gcc::jit::recording::context::new_comparison): Likewise.
	(gcc::jit::recording::context::new_call): Likewise.
	(gcc::jit::recording::context::new_array_lookup): Likewise.
	(gcc::jit::recording::string::string): Likewise.
	(gcc::jit::recording::string::~string): Likewise.
	(gcc::jit::recording::location::replay_into): Likewise.
	(gcc::jit::recording::type::get_pointer): Likewise.
	(gcc::jit::recording::type::get_const): Likewise.
	(gcc::jit::recording::memento_of_get_type::replay_into): Likewise.
	(gcc::jit::recording::memento_of_get_pointer::replay_into): Likewise.
	(gcc::jit::recording::memento_of_get_const::replay_into): Likewise.
	(gcc::jit::recording::field::replay_into): Likewise.
	(gcc::jit::recording::struct_::replay_into): Likewise.
	(gcc::jit::recording::rvalue::access_field): Likewise.
	(gcc::jit::recording::rvalue::dereference_field): Likewise.
	(gcc::jit::recording::rvalue::dereference): Likewise.
	(gcc::jit::recording::lvalue::access_field): Likewise.
	(gcc::jit::recording::lvalue::get_address): Likewise.
	(gcc::jit::recording::param::replay_into): Likewise.
	(gcc::jit::recording::function::function): Likewise.
	(gcc::jit::recording::function::replay_into): Likewise.
	(gcc::jit::recording::function::new_local): Likewise.
	(gcc::jit::recording::function::new_forward_label): Likewise.
	(gcc::jit::recording::function::add_eval): Likewise.
	(gcc::jit::recording::function::add_assignment): Likewise.
	(gcc::jit::recording::function::add_assignment_op): Likewise.
	(gcc::jit::recording::function::add_comment): Likewise.
	(gcc::jit::recording::function::add_conditional): Likewise.
	(gcc::jit::recording::function::add_label): Likewise.
	(gcc::jit::recording::function::place_forward_label): Likewise.
	(gcc::jit::recording::function::add_jump): Likewise.
	(gcc::jit::recording::function::add_return): Likewise.
	(gcc::jit::recording::function::new_loop): Likewise.
	(gcc::jit::recording::label::replay_into): Likewise.
	(gcc::jit::recording::global::replay_into): Likewise.
	(gcc::jit::recording::memento_of_new_rvalue_from_int::replay_into):
	Likewise.
	(gcc::jit::recording::memento_of_new_rvalue_from_double::replay_into):
	Likewise.
	(gcc::jit::recording::memento_of_new_rvalue_from_ptr::replay_into):
	Likewise.
	(gcc::jit::recording::memento_of_new_string_literal::replay_into):
	Likewise.
	(gcc::jit::recording::unary_op::replay_into): Likewise.
	(gcc::jit::recording::binary_op::replay_into): Likewise.
	(gcc::jit::recording::comparison::replay_into): Likewise.
	(gcc::jit::recording::call::call): Likewise.
	(gcc::jit::recording::call::replay_into): Likewise.
	(gcc::jit::recording::array_lookup::replay_into): Likewise.
	(gcc::jit::recording::access_field_of_lvalue::replay_into): Likewise.
	(gcc::jit::recording::access_field_rvalue::replay_into): Likewise.
	(gcc::jit::recording::dereference_field_rvalue::replay_into): Likewise.
	(gcc::jit::recording::dereference_rvalue::replay_into): Likewise.
	(gcc::jit::recording::get_address_of_lvalue::replay_into): Likewise.
	(gcc::jit::recording::local::replay_into): Likewise.
	(gcc::jit::recording::eval::replay_into): Likewise.
	(gcc::jit::recording::assignment::replay_into): Likewise.
	(gcc::jit::recording::assignment_op::replay_into): Likewise.
	(gcc::jit::recording::comment::replay_into): Likewise.
	(gcc::jit::recording::conditional::replay_into): Likewise.
	(gcc::jit::recording::place_label::replay_into): Likewise.
	(gcc::jit::recording::jump::replay_into): Likewise.
	(gcc::jit::recording::return_::replay_into): Likewise.
	(gcc::jit::recording::loop::replay_into): Likewise.
	(gcc::jit::recording::loop::end): Likewise.
	(gcc::jit::recording::loop_end::replay_into): Likewise.

	(gcc::jit::recording::context::set_str_option): Likewise.
	Option setting and error-handling is now "owned" by the recording
	context; the playback context delegates to the recording context
	for these aspects.
	(gcc::jit::recording::context::set_int_option): Likewise.
	(gcc::jit::recording::context::set_bool_option): Likewise.
	(gcc::jit::recording::context::compile): Likewise.
	(gcc::jit::recording::context::add_error): Likewise.
	(gcc::jit::recording::context::add_error_va): Likewise.
	(gcc::jit::recording::context::get_first_error): Likewise.

	(gcc::jit::context::context): Rename to...
	(gcc::jit::playback::context::context): ...this.
	(gcc::jit::context::~context): Rename to...
	(gcc::jit::playback::context::~context): ...this.
	(gcc::jit::context::gt_ggc_mx): Rename to...
	(gcc::jit::playback::context::gt_ggc_mx): ...this.

	(gcc::jit::context::set_code_factory): Eliminate.

	(gcc::jit::context::get_type): Rename to...
	(gcc::jit::playback::context::get_type): ...this.
	(gcc::jit::context::new_field): Rename to...
	(gcc::jit::playback::context::new_field): ...this.
	(gcc::jit::context::new_struct_type): Rename to...
	(gcc::jit::playback::context::new_struct_type): ...this, and
	update to require a vec<field *>.
	(gcc::jit::context::new_param): Rename to...
	(gcc::jit::playback::context::new_param): ...this.
	(gcc::jit::context::new_function): Rename to...
	(gcc::jit::playback::context::new_function): ...this, and update
	to require a vec<param *>.
	(gcc::jit::context::new_global): Rename to...
	(gcc::jit::playback::context::new_global): ...this.
	(gcc::jit::context::new_rvalue_from_int): Rename to...
	(gcc::jit::playback::context::new_rvalue_from_int): ...this.
	(gcc::jit::context::new_rvalue_from_double): Rename to...
	(gcc::jit::playback::context::new_rvalue_from_double): ...this.
	(gcc::jit::context::new_rvalue_from_ptr): Rename to...
	(gcc::jit::playback::context::new_rvalue_from_ptr): ...this.
	(gcc::jit::context::new_string_literal): Rename to...
	(gcc::jit::playback::context::new_string_literal): ...this.
	(gcc::jit::context::as_truth_value): Rename to...
	(gcc::jit::playback::context::as_truth_value): ...this.
	(gcc::jit::context::new_unary_op): Rename to...
	(gcc::jit::playback::context::new_unary_op): ...this.
	(gcc::jit::context::new_binary_op): Rename to...
	(gcc::jit::playback::context::new_binary_op): ...this.
	(gcc::jit::context::new_comparison): Rename to...
	(gcc::jit::playback::context::new_comparison): ...this.
	(gcc::jit::context::new_call): Rename to...
	(gcc::jit::playback::context::new_call): ...this, and update
	to require a vec<rvalue *>.
	(gcc::jit::context::new_array_lookup): Rename to...
	(gcc::jit::playback::context::new_array_lookup): ...this.
	(gcc::jit::context::new_field_access): Rename to...
	(gcc::jit::playback::context::new_field_access): ...this.
	(gcc::jit::context::new_dereference): Rename to...
	(gcc::jit::playback::context::new_dereference): ...this.

	(gcc::jit::lvalue::access_field): Rename to...
	(gcc::jit::playback::lvalue::access_field): ...this.
	(gcc::jit::lvalue::get_address): Rename to...
	(gcc::jit::playback::lvalue::get_address): ...this.

	(gcc::jit::rvalue::dereference_field): Rename to...
	(gcc::jit::playback::rvalue::dereference_field): ...this.

	(gcc::jit::rvalue::dereference): Rename to...
	(gcc::jit::playback::rvalue::dereference): ...this.

	(gcc::jit::wrapper::operator new): Rename to...
	(gcc::jit::playback::wrapper::operator new): ...this.

	(gcc::jit::function::function): Rename to...
	(gcc::jit::playback::function::function): ...this.
	(gcc::jit::function::gt_ggc_mx): Rename to...
	(gcc::jit::playback::function::gt_ggc_mx): ...this.
	(gcc::jit::function::get_return_type_as_tree): Rename to...
	(gcc::jit::playback::function::get_return_type_as_tree): ...this.
	(gcc::jit::function::new_local): Rename to...
	(gcc::jit::playback::function::new_local): ...this.
	(gcc::jit::function::new_forward_label): Rename to...
	(gcc::jit::playback::function::new_forward_label): ...this.
	(gcc::jit::function::postprocess): Rename to...
	(gcc::jit::playback::function::postprocess): ...this.
	(gcc::jit::function::add_eval): Rename to...
	(gcc::jit::playback::function::add_eval): ...this.
	(gcc::jit::function::add_assignment): Rename to...
	(gcc::jit::playback::function::add_assignment): ...this.
	(gcc::jit::function::add_comment): Rename to...
	(gcc::jit::playback::function::add_comment): ...this.
	(gcc::jit::function::add_conditional): Rename to...
	(gcc::jit::playback::function::add_conditional): ...this.
	(gcc::jit::function::add_label): Rename to...
	(gcc::jit::playback::function::add_label): ...this.
	(gcc::jit::function::place_forward_label): Rename to...
	(gcc::jit::playback::function::place_forward_label): ...this.
	(gcc::jit::function::add_jump): Rename to...
	(gcc::jit::playback::function::add_jump): ...this.
	(gcc::jit::function::add_return): Rename to...
	(gcc::jit::playback::function::add_return): ...this.
	(gcc::jit::function::new_loop): Rename to...
	(gcc::jit::playback::function::new_loop): ...this.

	(gcc::jit::label::label): Rename to...
	(gcc::jit::playback::label::label): ...this.

	(gcc::jit::loop::loop): Rename to...
	(gc::jit::playback::loop::loop): ...this.
	(gcc::jit::loop::end): Rename to...
	(gcc::jit::playback::loop): ...this.

	(gcc::jit::active_jit_ctxt): Eliminate in favor of...
	(gcc::jit::active_playback_ctxt): ...this.

	(gcc::jit::context::compile): Rename to...
	(gcc::jit::playback::context::compile): ...this, and eliminate the
	mutex handling; this is done for us by the caller.

	(gcc::jit::context::invoke_code_factory): Rename to...
	(gcc::jit::playback::context::replay): this.  Rather than call
	a client-provided callback, instead replay the recorded API
	calls.

	(gcc::jit::context::dump_generated_code): Rename to...
	(gcc::jit::playback::context::dump_generated_code): ...this.

	(location_comparator): Update for renamed types.

	(gcc::jit::context::handle_locations): Rename to...
	(gcc::jit::playback::context::handle_locations): ...this.

	(gcc::jit::context::add_error): Rename to...
	(gcc::jit::playback::context::add_error): this, and delegate to
	the recording context's add_error_va.

	(gcc::jit::context::add_error_va): Rename to...
	(gcc::jit::playback::context::add_error_va): this, and delegate
	to the recording context.

	(gcc::jit::context::new_location): Rename to...
	(gcc::jit::playback::context::new_location): ...this.
	(gcc::jit::context::set_tree_location): Rename to...
	(gcc::jit::playback::context::set_tree_location): ...this.
	(gcc::jit::context::get_source_file): Rename to...
	(gcc::jit::playback::context::get_source_file): ...this.
	(gcc::jit::source_file::source_file): Rename to...
	(gcc::jit::playback::source_file::source_file): ...this.
	(gcc::jit::source_file::get_source_line): Rename to...
	(gcc::jit::playback::source_file::get_source_line): ...this.
	(gcc::jit::source_line::source_line): Rename to...
	(gcc::jit::playback::source_line::source_line): ...this.
	(gcc::jit::source_line::get_location): Rename to...
	(gcc::jit::playback::source_line::get_location): ...this.

	(gcc::jit::location::location): Rename to...
	(gcc::jit::playback::location::location): ...this.

	* libgccjit.c: Update classes to derive from the "jit::recording"
	class hierarchy.
	(RETURN_IF_NOT_INITIAL_CTXT): Eliminate, as it relates to
	code-creation callbacks.
	(RETURN_NULL_IF_NOT_INITIAL_CTXT): Likewise.
	(RETURN_NULL_IF_NOT_CALLBACK_CTXT): Likewise.
	(jit_error): There isn't an "active jit context" anymore, except
	during actual compilation, so simplify the logic here.
	(gcc_jit_context_set_code_factory): Delete.

	(gcc_jit_context_new_location): Update preconditions now that we
	don't have code-creation callbacks.
	(gcc_jit_context_get_type): Likewise.
	(gcc_jit_type_get_pointer): Likewise.
	(gcc_jit_type_get_const): Likewise.
	(gcc_jit_context_new_field): Likewise.
	(gcc_jit_context_new_struct_type): Likewise.
	(gcc_jit_context_new_param): Likewise.
	(gcc_jit_param_as_lvalue): Likewise.
	(gcc_jit_param_as_rvalue): Likewise.
	(gcc_jit_context_new_function): Likewise.
	(gcc_jit_context_new_function): Likewise.
	(gcc_jit_function_new_forward_label): Likewise.
	(gcc_jit_context_new_global): Likewise.
	(gcc_jit_lvalue_as_rvalue): Likewise.
	(gcc_jit_context_new_rvalue_from_int): Likewise.
	(gcc_jit_context_zero): Likewise.
	(gcc_jit_context_one): Likewise.
	(gcc_jit_context_new_rvalue_from_double): Likewise.
	(gcc_jit_context_new_rvalue_from_ptr): Likewise.
	(gcc_jit_context_new_string_literal): Likewise.
	(gcc_jit_context_new_unary_op): Likewise.
	(gcc_jit_context_new_binary_op): Likewise.
	(gcc_jit_context_new_comparison): Likewise.
	(gcc_jit_context_new_call): Likewise.
	(gcc_jit_context_new_call): Likewise.
	(gcc_jit_context_new_array_lookup): Likewise.
	(gcc_jit_context_set_str_option): Likewise.
	(gcc_jit_context_set_int_option): Likewise.
	(gcc_jit_context_set_bool_option): Likewise.
	(gcc_jit_context_compile): Likewise.
	(gcc_jit_function_add_assignment_op): Likewise.  Also,
	reimplement as a separate kind of recording, since we can't know
	the type of the lvalue at recording-time.

	* notes.txt: Update diagram to reflect the new implementation.

gcc/testsuite/
	* jit.dg/harness.h (code_making_callback): Rename to...
	(create_code): ...this, and eliminate the returned
	error-handling value: test cases will simply call into the
	gcc_jit_ API, without needing to be run from a callback.
	(test_jit): Don't register a callback, simply call the
	"create_code" function for the testcase before compiling the
	context.

	* jit.dg/test-accessing-struct.c: Rename "code_making_callback"
	to "create_code" and eliminate the return code.
	* jit.dg/test-calling-external-function.c: Likewise.
	* jit.dg/test-combination.c: Likewise.
	* jit.dg/test-dot-product.c: Likewise.
	* jit.dg/test-expressions.c: Likewise.
	* jit.dg/test-factorial.c: Likewise.
	* jit.dg/test-fibonacci.c: Likewise.
	* jit.dg/test-fuzzer.c: Likewise.
	* jit.dg/test-hello-world.c: Likewise.
	* jit.dg/test-null-passed-to-api.c: Likewise.
	* jit.dg/test-quadratic.c: Likewise.
	* jit.dg/test-reading-struct.c: Likewise.
	* jit.dg/test-string-literal.c: Likewise.
	* jit.dg/test-sum-of-squares.c: Likewise.
	* jit.dg/test-types.c: Likewise.
	* jit.dg/test-using-global.c: Likewise.

	* jit.dg/test-failure.c: Remove this test case, since it was
	specifically for testing the now-defunct callback-based API.
---
 gcc/ChangeLog.jit                                  |    4 +
 gcc/jit/ChangeLog.jit                              |  321 +++++
 gcc/jit/dummy-frontend.c                           |   10 +-
 gcc/jit/internal-api.c                             | 1352 ++++++++++++++++----
 gcc/jit/internal-api.h                             | 1224 +++++++++++++++++-
 gcc/jit/libgccjit.c                                |  134 +-
 gcc/jit/libgccjit.h                                |   49 +-
 gcc/jit/libgccjit.map                              |    1 -
 gcc/jit/notes.txt                                  |   30 +-
 gcc/testsuite/ChangeLog.jit                        |   31 +
 gcc/testsuite/jit.dg/harness.h                     |   12 +-
 gcc/testsuite/jit.dg/test-accessing-struct.c       |    6 +-
 .../jit.dg/test-calling-external-function.c        |    6 +-
 gcc/testsuite/jit.dg/test-combination.c            |   81 +-
 gcc/testsuite/jit.dg/test-dot-product.c            |    6 +-
 gcc/testsuite/jit.dg/test-expressions.c            |    6 +-
 gcc/testsuite/jit.dg/test-factorial.c              |    5 +-
 gcc/testsuite/jit.dg/test-failure.c                |   19 -
 gcc/testsuite/jit.dg/test-fibonacci.c              |    5 +-
 gcc/testsuite/jit.dg/test-fuzzer.c                 |    6 +-
 gcc/testsuite/jit.dg/test-hello-world.c            |    5 +-
 gcc/testsuite/jit.dg/test-null-passed-to-api.c     |    7 +-
 gcc/testsuite/jit.dg/test-quadratic.c              |    5 +-
 gcc/testsuite/jit.dg/test-reading-struct.c         |    8 +-
 gcc/testsuite/jit.dg/test-string-literal.c         |    6 +-
 gcc/testsuite/jit.dg/test-sum-of-squares.c         |    6 +-
 gcc/testsuite/jit.dg/test-types.c                  |    6 +-
 gcc/testsuite/jit.dg/test-using-global.c           |    6 +-
 gcc/timevar.def                                    |    2 +-
 29 files changed, 2769 insertions(+), 590 deletions(-)
 delete mode 100644 gcc/testsuite/jit.dg/test-failure.c
diff mbox

Patch

diff --git a/gcc/ChangeLog.jit b/gcc/ChangeLog.jit
index 07406bb..555fc76 100644
--- a/gcc/ChangeLog.jit
+++ b/gcc/ChangeLog.jit
@@ -1,3 +1,7 @@ 
+2014-01-24  David Malcolm  <dmalcolm@redhat.com>
+
+	* timevar.def: Replace TV_CLIENT_CALLBACK with TV_JIT_REPLAY.
+
 2013-10-11  David Malcolm  <dmalcolm@redhat.com>
 
 	* doc/install.texi (--enable-shared): Add note contrasting it
diff --git a/gcc/jit/ChangeLog.jit b/gcc/jit/ChangeLog.jit
index f13d0c5..0868fc3 100644
--- a/gcc/jit/ChangeLog.jit
+++ b/gcc/jit/ChangeLog.jit
@@ -1,5 +1,326 @@ 
 2014-01-24  David Malcolm  <dmalcolm@redhat.com>
 
+	* libgccjit.h: Update comments to eliminate the code-creation
+	callback.  All "contextual" objects change from merely being
+	"alive" during the callback to having a lifetime equal to that
+	of the context they are created within, with automatic cleanup
+	when the context is released.
+	(gcc_jit_code_callback): Delete.
+	(gcc_jit_context_set_code_factory): Delete.
+
+	* libgccjit.map (gcc_jit_context_set_code_factory): Delete.
+
+	* dummy-frontend.c (my_walker): Update for rename of the singleton
+	reference-owning context.
+	(jit_langhook_parse_file): Rather than run a client-provided
+	callback, we now replay a recording of the client activity.
+
+	* internal-api.h (gcc::jit): Split the existing API into two
+	copies...
+	(gcc::jit::recording): ...a class hierarchy used to implement
+	the client-facing API, which records the API calls made to it
+	and...
+	(gcc::jit::playback): ...a class hierarchy used within the
+	dummy GCC frontend, which plays back the recorded API calls once
+	GCC is initialized.
+
+	* internal-api.c (gcc::jit::recording::playback_location): New
+	API, in which client API calls are recorded as a list of "memento"
+	objects, to be played back into GCC when the dummy frontend runs.
+	(gcc::jit::recording::playback_string): Likewise.
+	(gcc::jit::recording::playback_label): Likewise.
+	(gcc::jit::recording::context::~context): Likewise.
+	(gcc::jit::recording::context::replay_into): Likewise.
+	(gcc::jit::recording::context::disassociate_from_playback): Likewise.
+	(gcc::jit::recording::context::new_string): Likewise.
+	(gcc::jit::recording::context::new_location): Likewise.
+	(gcc::jit::recording::context::get_type): Likewise.
+	(gcc::jit::recording::context::new_field): Likewise.
+	(gcc::jit::recording::context::new_struct_type): Likewise.
+	(gcc::jit::recording::context::new_param): Likewise.
+	(gcc::jit::recording::context::new_function): Likewise.
+	(gcc::jit::recording::context::new_global): Likewise.
+	(gcc::jit::recording::context::new_rvalue_from_int): Likewise.
+	(gcc::jit::recording::context::new_rvalue_from_double): Likewise.
+	(gcc::jit::recording::context::new_rvalue_from_ptr): Likewise.
+	(gcc::jit::recording::context::new_string_literal): Likewise.
+	(gcc::jit::recording::context::new_unary_op): Likewise.
+	(gcc::jit::recording::context::new_binary_op): Likewise.
+	(gcc::jit::recording::context::new_comparison): Likewise.
+	(gcc::jit::recording::context::new_call): Likewise.
+	(gcc::jit::recording::context::new_array_lookup): Likewise.
+	(gcc::jit::recording::string::string): Likewise.
+	(gcc::jit::recording::string::~string): Likewise.
+	(gcc::jit::recording::location::replay_into): Likewise.
+	(gcc::jit::recording::type::get_pointer): Likewise.
+	(gcc::jit::recording::type::get_const): Likewise.
+	(gcc::jit::recording::memento_of_get_type::replay_into): Likewise.
+	(gcc::jit::recording::memento_of_get_pointer::replay_into): Likewise.
+	(gcc::jit::recording::memento_of_get_const::replay_into): Likewise.
+	(gcc::jit::recording::field::replay_into): Likewise.
+	(gcc::jit::recording::struct_::replay_into): Likewise.
+	(gcc::jit::recording::rvalue::access_field): Likewise.
+	(gcc::jit::recording::rvalue::dereference_field): Likewise.
+	(gcc::jit::recording::rvalue::dereference): Likewise.
+	(gcc::jit::recording::lvalue::access_field): Likewise.
+	(gcc::jit::recording::lvalue::get_address): Likewise.
+	(gcc::jit::recording::param::replay_into): Likewise.
+	(gcc::jit::recording::function::function): Likewise.
+	(gcc::jit::recording::function::replay_into): Likewise.
+	(gcc::jit::recording::function::new_local): Likewise.
+	(gcc::jit::recording::function::new_forward_label): Likewise.
+	(gcc::jit::recording::function::add_eval): Likewise.
+	(gcc::jit::recording::function::add_assignment): Likewise.
+	(gcc::jit::recording::function::add_assignment_op): Likewise.
+	(gcc::jit::recording::function::add_comment): Likewise.
+	(gcc::jit::recording::function::add_conditional): Likewise.
+	(gcc::jit::recording::function::add_label): Likewise.
+	(gcc::jit::recording::function::place_forward_label): Likewise.
+	(gcc::jit::recording::function::add_jump): Likewise.
+	(gcc::jit::recording::function::add_return): Likewise.
+	(gcc::jit::recording::function::new_loop): Likewise.
+	(gcc::jit::recording::label::replay_into): Likewise.
+	(gcc::jit::recording::global::replay_into): Likewise.
+	(gcc::jit::recording::memento_of_new_rvalue_from_int::replay_into):
+	Likewise.
+	(gcc::jit::recording::memento_of_new_rvalue_from_double::replay_into):
+	Likewise.
+	(gcc::jit::recording::memento_of_new_rvalue_from_ptr::replay_into):
+	Likewise.
+	(gcc::jit::recording::memento_of_new_string_literal::replay_into):
+	Likewise.
+	(gcc::jit::recording::unary_op::replay_into): Likewise.
+	(gcc::jit::recording::binary_op::replay_into): Likewise.
+	(gcc::jit::recording::comparison::replay_into): Likewise.
+	(gcc::jit::recording::call::call): Likewise.
+	(gcc::jit::recording::call::replay_into): Likewise.
+	(gcc::jit::recording::array_lookup::replay_into): Likewise.
+	(gcc::jit::recording::access_field_of_lvalue::replay_into): Likewise.
+	(gcc::jit::recording::access_field_rvalue::replay_into): Likewise.
+	(gcc::jit::recording::dereference_field_rvalue::replay_into): Likewise.
+	(gcc::jit::recording::dereference_rvalue::replay_into): Likewise.
+	(gcc::jit::recording::get_address_of_lvalue::replay_into): Likewise.
+	(gcc::jit::recording::local::replay_into): Likewise.
+	(gcc::jit::recording::eval::replay_into): Likewise.
+	(gcc::jit::recording::assignment::replay_into): Likewise.
+	(gcc::jit::recording::assignment_op::replay_into): Likewise.
+	(gcc::jit::recording::comment::replay_into): Likewise.
+	(gcc::jit::recording::conditional::replay_into): Likewise.
+	(gcc::jit::recording::place_label::replay_into): Likewise.
+	(gcc::jit::recording::jump::replay_into): Likewise.
+	(gcc::jit::recording::return_::replay_into): Likewise.
+	(gcc::jit::recording::loop::replay_into): Likewise.
+	(gcc::jit::recording::loop::end): Likewise.
+	(gcc::jit::recording::loop_end::replay_into): Likewise.
+
+	(gcc::jit::recording::context::set_str_option): Likewise.
+	Option setting and error-handling is now "owned" by the recording
+	context; the playback context delegates to the recording context
+	for these aspects.
+	(gcc::jit::recording::context::set_int_option): Likewise.
+	(gcc::jit::recording::context::set_bool_option): Likewise.
+	(gcc::jit::recording::context::compile): Likewise.
+	(gcc::jit::recording::context::add_error): Likewise.
+	(gcc::jit::recording::context::add_error_va): Likewise.
+	(gcc::jit::recording::context::get_first_error): Likewise.
+
+	(gcc::jit::context::context): Rename to...
+	(gcc::jit::playback::context::context): ...this.
+	(gcc::jit::context::~context): Rename to...
+	(gcc::jit::playback::context::~context): ...this.
+	(gcc::jit::context::gt_ggc_mx): Rename to...
+	(gcc::jit::playback::context::gt_ggc_mx): ...this.
+
+	(gcc::jit::context::set_code_factory): Eliminate.
+
+	(gcc::jit::context::get_type): Rename to...
+	(gcc::jit::playback::context::get_type): ...this.
+	(gcc::jit::context::new_field): Rename to...
+	(gcc::jit::playback::context::new_field): ...this.
+	(gcc::jit::context::new_struct_type): Rename to...
+	(gcc::jit::playback::context::new_struct_type): ...this, and
+	update to require a vec<field *>.
+	(gcc::jit::context::new_param): Rename to...
+	(gcc::jit::playback::context::new_param): ...this.
+	(gcc::jit::context::new_function): Rename to...
+	(gcc::jit::playback::context::new_function): ...this, and update
+	to require a vec<param *>.
+	(gcc::jit::context::new_global): Rename to...
+	(gcc::jit::playback::context::new_global): ...this.
+	(gcc::jit::context::new_rvalue_from_int): Rename to...
+	(gcc::jit::playback::context::new_rvalue_from_int): ...this.
+	(gcc::jit::context::new_rvalue_from_double): Rename to...
+	(gcc::jit::playback::context::new_rvalue_from_double): ...this.
+	(gcc::jit::context::new_rvalue_from_ptr): Rename to...
+	(gcc::jit::playback::context::new_rvalue_from_ptr): ...this.
+	(gcc::jit::context::new_string_literal): Rename to...
+	(gcc::jit::playback::context::new_string_literal): ...this.
+	(gcc::jit::context::as_truth_value): Rename to...
+	(gcc::jit::playback::context::as_truth_value): ...this.
+	(gcc::jit::context::new_unary_op): Rename to...
+	(gcc::jit::playback::context::new_unary_op): ...this.
+	(gcc::jit::context::new_binary_op): Rename to...
+	(gcc::jit::playback::context::new_binary_op): ...this.
+	(gcc::jit::context::new_comparison): Rename to...
+	(gcc::jit::playback::context::new_comparison): ...this.
+	(gcc::jit::context::new_call): Rename to...
+	(gcc::jit::playback::context::new_call): ...this, and update
+	to require a vec<rvalue *>.
+	(gcc::jit::context::new_array_lookup): Rename to...
+	(gcc::jit::playback::context::new_array_lookup): ...this.
+	(gcc::jit::context::new_field_access): Rename to...
+	(gcc::jit::playback::context::new_field_access): ...this.
+	(gcc::jit::context::new_dereference): Rename to...
+	(gcc::jit::playback::context::new_dereference): ...this.
+
+	(gcc::jit::lvalue::access_field): Rename to...
+	(gcc::jit::playback::lvalue::access_field): ...this.
+	(gcc::jit::lvalue::get_address): Rename to...
+	(gcc::jit::playback::lvalue::get_address): ...this.
+
+	(gcc::jit::rvalue::dereference_field): Rename to...
+	(gcc::jit::playback::rvalue::dereference_field): ...this.
+
+	(gcc::jit::rvalue::dereference): Rename to...
+	(gcc::jit::playback::rvalue::dereference): ...this.
+
+	(gcc::jit::wrapper::operator new): Rename to...
+	(gcc::jit::playback::wrapper::operator new): ...this.
+
+	(gcc::jit::function::function): Rename to...
+	(gcc::jit::playback::function::function): ...this.
+	(gcc::jit::function::gt_ggc_mx): Rename to...
+	(gcc::jit::playback::function::gt_ggc_mx): ...this.
+	(gcc::jit::function::get_return_type_as_tree): Rename to...
+	(gcc::jit::playback::function::get_return_type_as_tree): ...this.
+	(gcc::jit::function::new_local): Rename to...
+	(gcc::jit::playback::function::new_local): ...this.
+	(gcc::jit::function::new_forward_label): Rename to...
+	(gcc::jit::playback::function::new_forward_label): ...this.
+	(gcc::jit::function::postprocess): Rename to...
+	(gcc::jit::playback::function::postprocess): ...this.
+	(gcc::jit::function::add_eval): Rename to...
+	(gcc::jit::playback::function::add_eval): ...this.
+	(gcc::jit::function::add_assignment): Rename to...
+	(gcc::jit::playback::function::add_assignment): ...this.
+	(gcc::jit::function::add_comment): Rename to...
+	(gcc::jit::playback::function::add_comment): ...this.
+	(gcc::jit::function::add_conditional): Rename to...
+	(gcc::jit::playback::function::add_conditional): ...this.
+	(gcc::jit::function::add_label): Rename to...
+	(gcc::jit::playback::function::add_label): ...this.
+	(gcc::jit::function::place_forward_label): Rename to...
+	(gcc::jit::playback::function::place_forward_label): ...this.
+	(gcc::jit::function::add_jump): Rename to...
+	(gcc::jit::playback::function::add_jump): ...this.
+	(gcc::jit::function::add_return): Rename to...
+	(gcc::jit::playback::function::add_return): ...this.
+	(gcc::jit::function::new_loop): Rename to...
+	(gcc::jit::playback::function::new_loop): ...this.
+
+	(gcc::jit::label::label): Rename to...
+	(gcc::jit::playback::label::label): ...this.
+
+	(gcc::jit::loop::loop): Rename to...
+	(gc::jit::playback::loop::loop): ...this.
+	(gcc::jit::loop::end): Rename to...
+	(gcc::jit::playback::loop): ...this.
+
+	(gcc::jit::active_jit_ctxt): Eliminate in favor of...
+	(gcc::jit::active_playback_ctxt): ...this.
+
+	(gcc::jit::context::compile): Rename to...
+	(gcc::jit::playback::context::compile): ...this, and eliminate the
+	mutex handling; this is done for us by the caller.
+
+	(gcc::jit::context::invoke_code_factory): Rename to...
+	(gcc::jit::playback::context::replay): this.  Rather than call
+	a client-provided callback, instead replay the recorded API
+	calls.
+
+	(gcc::jit::context::dump_generated_code): Rename to...
+	(gcc::jit::playback::context::dump_generated_code): ...this.
+
+	(location_comparator): Update for renamed types.
+
+	(gcc::jit::context::handle_locations): Rename to...
+	(gcc::jit::playback::context::handle_locations): ...this.
+
+	(gcc::jit::context::add_error): Rename to...
+	(gcc::jit::playback::context::add_error): this, and delegate to
+	the recording context's add_error_va.
+
+	(gcc::jit::context::add_error_va): Rename to...
+	(gcc::jit::playback::context::add_error_va): this, and delegate
+	to the recording context.
+
+	(gcc::jit::context::new_location): Rename to...
+	(gcc::jit::playback::context::new_location): ...this.
+	(gcc::jit::context::set_tree_location): Rename to...
+	(gcc::jit::playback::context::set_tree_location): ...this.
+	(gcc::jit::context::get_source_file): Rename to...
+	(gcc::jit::playback::context::get_source_file): ...this.
+	(gcc::jit::source_file::source_file): Rename to...
+	(gcc::jit::playback::source_file::source_file): ...this.
+	(gcc::jit::source_file::get_source_line): Rename to...
+	(gcc::jit::playback::source_file::get_source_line): ...this.
+	(gcc::jit::source_line::source_line): Rename to...
+	(gcc::jit::playback::source_line::source_line): ...this.
+	(gcc::jit::source_line::get_location): Rename to...
+	(gcc::jit::playback::source_line::get_location): ...this.
+
+	(gcc::jit::location::location): Rename to...
+	(gcc::jit::playback::location::location): ...this.
+
+	* libgccjit.c: Update classes to derive from the "jit::recording"
+	class hierarchy.
+	(RETURN_IF_NOT_INITIAL_CTXT): Eliminate, as it relates to
+	code-creation callbacks.
+	(RETURN_NULL_IF_NOT_INITIAL_CTXT): Likewise.
+	(RETURN_NULL_IF_NOT_CALLBACK_CTXT): Likewise.
+	(jit_error): There isn't an "active jit context" anymore, except
+	during actual compilation, so simplify the logic here.
+	(gcc_jit_context_set_code_factory): Delete.
+
+	(gcc_jit_context_new_location): Update preconditions now that we
+	don't have code-creation callbacks.
+	(gcc_jit_context_get_type): Likewise.
+	(gcc_jit_type_get_pointer): Likewise.
+	(gcc_jit_type_get_const): Likewise.
+	(gcc_jit_context_new_field): Likewise.
+	(gcc_jit_context_new_struct_type): Likewise.
+	(gcc_jit_context_new_param): Likewise.
+	(gcc_jit_param_as_lvalue): Likewise.
+	(gcc_jit_param_as_rvalue): Likewise.
+	(gcc_jit_context_new_function): Likewise.
+	(gcc_jit_context_new_function): Likewise.
+	(gcc_jit_function_new_forward_label): Likewise.
+	(gcc_jit_context_new_global): Likewise.
+	(gcc_jit_lvalue_as_rvalue): Likewise.
+	(gcc_jit_context_new_rvalue_from_int): Likewise.
+	(gcc_jit_context_zero): Likewise.
+	(gcc_jit_context_one): Likewise.
+	(gcc_jit_context_new_rvalue_from_double): Likewise.
+	(gcc_jit_context_new_rvalue_from_ptr): Likewise.
+	(gcc_jit_context_new_string_literal): Likewise.
+	(gcc_jit_context_new_unary_op): Likewise.
+	(gcc_jit_context_new_binary_op): Likewise.
+	(gcc_jit_context_new_comparison): Likewise.
+	(gcc_jit_context_new_call): Likewise.
+	(gcc_jit_context_new_call): Likewise.
+	(gcc_jit_context_new_array_lookup): Likewise.
+	(gcc_jit_context_set_str_option): Likewise.
+	(gcc_jit_context_set_int_option): Likewise.
+	(gcc_jit_context_set_bool_option): Likewise.
+	(gcc_jit_context_compile): Likewise.
+	(gcc_jit_function_add_assignment_op): Likewise.  Also,
+	reimplement as a separate kind of recording, since we can't know
+	the type of the lvalue at recording-time.
+
+	* notes.txt: Update diagram to reflect the new implementation.
+
+2014-01-24  David Malcolm  <dmalcolm@redhat.com>
+
 	* libgccjit.h (enum gcc_jit_binary_op): We will use the result
 	type to determine if GCC_JIT_BINARY_OP_DIVIDE should
 	truncate towards zero, or be floating-point division.
diff --git a/gcc/jit/dummy-frontend.c b/gcc/jit/dummy-frontend.c
index b5a561d..0144ebc 100644
--- a/gcc/jit/dummy-frontend.c
+++ b/gcc/jit/dummy-frontend.c
@@ -77,8 +77,8 @@  struct GTY(()) language_function
 
 void my_walker (void *)
 {
-  if (gcc::jit::active_jit_ctxt)
-    gcc::jit::active_jit_ctxt->gt_ggc_mx ();
+  if (gcc::jit::active_playback_ctxt)
+    gcc::jit::active_playback_ctxt->gt_ggc_mx ();
 }
 
 const char *dummy;
@@ -124,9 +124,9 @@  jit_langhook_init (void)
 static void
 jit_langhook_parse_file (void)
 {
-  /* Run the IR-creation code provided by the client.  */
-  gcc_assert (gcc::jit::active_jit_ctxt);
-  gcc::jit::active_jit_ctxt->invoke_code_factory ();
+  /* Replay the activity by the client, recorded on the context.  */
+  gcc_assert (gcc::jit::active_playback_ctxt);
+  gcc::jit::active_playback_ctxt->replay ();
 }
 
 static tree
diff --git a/gcc/jit/internal-api.c b/gcc/jit/internal-api.c
index f95c09f..64a0912 100644
--- a/gcc/jit/internal-api.c
+++ b/gcc/jit/internal-api.c
@@ -21,8 +21,959 @@ 
 
 #include "internal-api.h"
 
-gcc::jit::context::
-~context ()
+namespace gcc {
+namespace jit {
+
+/**********************************************************************
+ Recording.
+ **********************************************************************/
+
+playback::location *
+recording::playback_location (recording::location *loc)
+{
+  if (loc)
+    return loc->playback_location ();
+  else
+    return NULL;
+}
+
+const char *
+recording::playback_string (recording::string *str)
+{
+  if (str)
+    return str->c_str ();
+  else
+    return NULL;
+}
+
+playback::label *
+recording::playback_label (recording::label *lab)
+{
+  if (lab)
+    return lab->playback_label ();
+  else
+    return NULL;
+}
+
+/* gcc::jit::recording::context:: */
+
+recording::context::~context ()
+{
+  int i;
+  memento *m;
+  FOR_EACH_VEC_ELT (m_mementos, i, m)
+    {
+      delete m;
+    }
+}
+
+void
+recording::context::replay_into (replayer *r)
+{
+  int i;
+  memento *m;
+  FOR_EACH_VEC_ELT (m_mementos, i, m)
+    {
+      m->replay_into (r);
+    }
+}
+
+/* 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;
+  FOR_EACH_VEC_ELT (m_mementos, i, m)
+    {
+      m->set_playback_obj (NULL);
+    }
+}
+
+recording::string *
+recording::context::new_string (const char *text)
+{
+  if (!text)
+    return NULL;
+
+  recording::string *result = new string (this, text);
+  record (result);
+  return result;
+}
+
+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;
+}
+
+recording::type *
+recording::context::get_type (enum gcc_jit_types kind)
+{
+  recording::type *result = new memento_of_get_type (this, kind);
+  record (result);
+  return result;
+}
+
+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;
+}
+
+recording::type *
+recording::context::new_struct_type (recording::location *loc,
+				     const char *name,
+				     int num_fields,
+				     field **fields)
+{
+  vec<field *> vec_fields;
+  vec_fields.create (num_fields);
+  for (int i = 0; i < num_fields; i++)
+    vec_fields.safe_push (fields[i]);
+  recording::type *result = new struct_ (this, loc, new_string (name),
+			      vec_fields);
+  record (result);
+  return result;
+}
+
+
+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;
+}
+
+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)
+{
+  recording::function *result =
+    new recording::function (this,
+			     loc, kind, return_type,
+			     new_string (name),
+			     num_params, params, is_variadic);
+  record (result);
+  return result;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+recording::rvalue *
+recording::context::new_array_lookup (recording::location *loc,
+				      recording::rvalue *ptr,
+				      recording::rvalue *index)
+{
+  recording::rvalue *result = new array_lookup (this, loc, ptr, index);
+  record (result);
+  return result;
+}
+
+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 ("unrecognized (enum gcc_jit_str_option) value: %i", opt);
+      return;
+    }
+  m_str_options[opt] = value;
+}
+
+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 ("unrecognized (enum gcc_jit_int_option) value: %i", opt);
+      return;
+    }
+  m_int_options[opt] = value;
+}
+
+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 ("unrecognized (enum gcc_jit_bool_option) value: %i", opt);
+      return;
+    }
+  m_bool_options[opt] = value ? true : false;
+}
+
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+result *
+recording::context::compile ()
+{
+  if (errors_occurred ())
+    return NULL;
+
+  /* Acquire the big GCC mutex. */
+  pthread_mutex_lock (&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 (&mutex);
+
+  return result_obj;
+}
+
+void
+recording::context::add_error (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  add_error_va (fmt, ap);
+  va_end (ap);
+}
+
+void
+recording::context::add_error_va (const char *fmt, va_list ap)
+{
+  char buf[1024];
+  vsnprintf (buf, sizeof (buf) - 1, fmt, ap);
+
+  fprintf (stderr, "%s: %s\n",
+	   get_str_option (GCC_JIT_STR_OPTION_PROGNAME),
+	   buf);
+
+  if (!m_error_count)
+    {
+      strncpy (m_first_error_str, buf, sizeof(m_first_error_str));
+      m_first_error_str[sizeof(m_first_error_str) - 1] = '\0';
+    }
+
+  m_error_count++;
+}
+
+const char *
+recording::context::get_first_error () const
+{
+  if (m_error_count)
+    return m_first_error_str;
+  else
+    return NULL;
+}
+
+/* gcc::jit::recording::string:: */
+recording::string::string (context *ctxt, const char *text)
+  : memento (ctxt)
+{
+  m_len = strlen (text) ;
+  m_copy = new char[m_len + 1];
+  strcpy (m_copy, text);
+}
+
+recording::string::~string ()
+{
+  delete[] m_copy;
+}
+
+
+
+/* gcc::jit::recording::location:: */
+void
+recording::location::replay_into (replayer *r)
+{
+  m_playback_obj = r->new_location (m_filename->c_str (), m_line, m_column);
+}
+
+/* gcc::jit::recording::type:: */
+
+recording::type *
+recording::type::get_pointer ()
+{
+  recording::type *result = new memento_of_get_pointer (this);
+  m_ctxt->record (result);
+  return result;
+}
+
+recording::type *
+recording::type::get_const ()
+{
+  recording::type *result = new memento_of_get_const (this);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* gcc::jit::recording::memento_of_get_type:: */
+void
+recording::memento_of_get_type::replay_into (replayer *r)
+{
+  set_playback_obj (r->get_type (m_kind));
+}
+
+/* gcc::jit::recording::memento_of_get_pointer:: */
+void
+recording::memento_of_get_pointer::replay_into (replayer *)
+{
+  set_playback_obj (m_other_type->playback_type ()->get_pointer ());
+}
+
+/* gcc::jit::recording::memento_of_get_const:: */
+
+void
+recording::memento_of_get_const::replay_into (replayer *)
+{
+  set_playback_obj (m_other_type->playback_type ()->get_const ());
+}
+
+/* gcc::jit::recording::field:: */
+void
+recording::field::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_field (playback_location (m_loc),
+				  m_type->playback_type (),
+				  playback_string (m_name)));
+}
+
+/* gcc::jit::recording::struct_:: */
+void
+recording::struct_::replay_into (replayer *r)
+{
+  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 ());
+
+  set_playback_obj (
+    r->new_struct_type (playback_location (m_loc),
+			m_name->c_str (),
+			&playback_fields));
+}
+
+
+/* gcc::jit::recording::rvalue:: */
+
+recording::rvalue *
+recording::rvalue::access_field (recording::location *loc,
+		      const char *fieldname)
+{
+  recording::rvalue *result =
+    new access_field_rvalue (m_ctxt, loc, this,
+			     new_string (fieldname));
+  m_ctxt->record (result);
+  return result;
+}
+
+recording::lvalue *
+recording::rvalue::dereference_field (recording::location *loc,
+			   const char *fieldname)
+{
+  recording::lvalue *result =
+    new dereference_field_rvalue (m_ctxt, loc, this,
+				  new_string (fieldname));
+  m_ctxt->record (result);
+  return result;
+}
+
+recording::lvalue *
+recording::rvalue::dereference (recording::location *loc)
+{
+  recording::lvalue *result =
+    new dereference_rvalue (m_ctxt, loc, this);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* gcc::jit::recording::lvalue:: */
+
+recording::lvalue *
+recording::lvalue::access_field (recording::location *loc,
+		      const char *fieldname)
+{
+  recording::lvalue *result =
+    new access_field_of_lvalue (m_ctxt, loc, this,
+				new_string (fieldname));
+  m_ctxt->record (result);
+  return result;
+}
+
+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;
+}
+
+/* gcc::jit::recording::param:: */
+void
+recording::param::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_param (playback_location (m_loc),
+				  m_type->playback_type (),
+				  m_name->c_str ()));
+}
+
+
+/* gcc::jit::recording::function:: */
+
+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)
+: memento (ctxt),
+  m_loc (loc),
+  m_kind (kind),
+  m_return_type (return_type),
+  m_name (name),
+  m_params (),
+  m_is_variadic (is_variadic)
+{
+  for (int i = 0; i< num_params; i++)
+    m_params.safe_push (params[i]);
+}
+
+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 (m_loc),
+				     m_kind,
+				     m_return_type->playback_type (),
+				     m_name->c_str (),
+				     &params,
+				     m_is_variadic));
+}
+
+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);
+  return result;
+}
+
+recording::label*
+recording::function::new_forward_label (const char *name)
+{
+  recording::label *result =
+    new recording::label (this, new_string (name));
+  m_ctxt->record (result);
+  return result;
+}
+
+void
+recording::function::add_eval (recording::location *loc,
+			       recording::rvalue *rvalue)
+{
+  statement *result = new eval (this, loc, rvalue);
+  m_ctxt->record (result);
+}
+
+void
+recording::function::add_assignment (recording::location *loc,
+				     recording::lvalue *lvalue,
+				     recording::rvalue *rvalue)
+{
+  statement *result = new assignment (this, loc, lvalue, rvalue);
+  m_ctxt->record (result);
+}
+
+void
+recording::function::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);
+}
+
+void
+recording::function::add_comment (recording::location *loc,
+				  const char *text)
+{
+  statement *result = new comment (this, loc, new_string (text));
+  m_ctxt->record (result);
+}
+
+void
+recording::function::add_conditional (recording::location *loc,
+				      recording::rvalue *boolval,
+				      recording::label *on_true,
+				      recording::label *on_false)
+{
+  statement *result = new conditional (this, loc, boolval, on_true, on_false);
+  m_ctxt->record (result);
+}
+
+recording::label *
+recording::function::add_label (recording::location *loc,
+				const char *name)
+{
+  recording::label *lab = new_forward_label (name);
+  place_forward_label (loc, lab);
+  return lab;
+}
+
+void
+recording::function::place_forward_label (recording::location *loc,
+					  recording::label *lab)
+{
+  statement *result = new place_label (this, loc, lab);
+  m_ctxt->record (result);
+}
+
+void
+recording::function::add_jump (recording::location *loc,
+			       recording::label *target)
+{
+  statement *result = new jump (this, loc, target);
+  m_ctxt->record (result);
+}
+
+void
+recording::function::add_return (recording::location *loc,
+				 recording::rvalue *rvalue)
+{
+  statement *result = new return_ (this, loc, rvalue);
+  m_ctxt->record (result);
+}
+
+recording::loop *
+recording::function::new_loop (recording::location *loc,
+			       recording::rvalue *boolval)
+{
+  recording::loop *result = new recording::loop (this, loc, boolval);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* gcc::jit::recording::label:: */
+
+void
+recording::label::replay_into (replayer *)
+{
+  set_playback_obj (m_func->playback_function ()
+		      ->new_forward_label (playback_string (m_name)));
+}
+
+/* gcc::jit::recording::global:: */
+void
+recording::global::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_global (playback_location (m_loc),
+				   m_type->playback_type (),
+				   playback_string (m_name)));
+}
+
+/* gcc::jit::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));
+}
+
+/* gcc::jit::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));
+}
+
+/* gcc::jit::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));
+}
+
+/* gcc::jit::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 ()));
+}
+
+/* gcc::jit::recording::unary_op:: */
+void
+recording::unary_op::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_unary_op (playback_location (m_loc),
+				     m_op,
+				     m_result_type->playback_type (),
+				     m_a->playback_rvalue ()));
+}
+
+
+/* gcc::jit::recording::binary_op:: */
+void
+recording::binary_op::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_binary_op (playback_location (m_loc),
+				      m_op,
+				      m_result_type->playback_type (),
+				      m_a->playback_rvalue (),
+				      m_b->playback_rvalue ()));
+}
+
+void
+recording::comparison::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_comparison (playback_location (m_loc),
+				       m_op,
+				       m_a->playback_rvalue (),
+				       m_b->playback_rvalue ()));
+}
+
+recording::call::call (recording::context *ctxt,
+		       recording::location *loc,
+		       recording::function *func,
+		       int numargs,
+		       rvalue **args)
+: rvalue (ctxt, loc),
+  m_func (func),
+  m_args ()
+{
+  for (int i = 0; i< numargs; i++)
+    m_args.safe_push (args[i]);
+}
+
+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 (m_loc),
+				 m_func->playback_function (),
+				 playback_args));
+}
+
+void
+recording::array_lookup::replay_into (replayer *r)
+{
+  set_playback_obj (
+    r->new_array_lookup (playback_location (m_loc),
+			 m_ptr->playback_rvalue (),
+			 m_index->playback_rvalue ()));
+}
+
+void
+recording::access_field_of_lvalue::replay_into (replayer *)
+{
+  set_playback_obj (
+    m_lvalue->playback_lvalue ()
+      ->access_field (playback_location (m_loc),
+		      m_fieldname->c_str ()));
+}
+
+void
+recording::access_field_rvalue::replay_into (replayer *)
+{
+  set_playback_obj (
+    m_rvalue->playback_rvalue ()
+      ->access_field (playback_location (m_loc),
+		      m_fieldname->c_str ()));
+}
+
+void
+recording::dereference_field_rvalue::replay_into (replayer *)
+{
+  set_playback_obj (
+    m_rvalue->playback_rvalue ()->
+      dereference_field (playback_location (m_loc),
+			 m_fieldname->c_str ()));
+}
+
+void
+recording::dereference_rvalue::replay_into (replayer *)
+{
+  set_playback_obj (
+    m_rvalue->playback_rvalue ()->
+      dereference (playback_location (m_loc)));
+}
+
+void
+recording::get_address_of_lvalue::replay_into (replayer *)
+{
+  set_playback_obj (
+    m_lvalue->playback_lvalue ()->
+      get_address (playback_location (m_loc)));
+}
+
+void
+recording::local::replay_into (replayer *)
+{
+  set_playback_obj (
+    m_func->playback_function ()
+      ->new_local (playback_location (m_loc),
+		   m_type->playback_type (),
+		   playback_string (m_name)));
+}
+
+void
+recording::eval::replay_into (replayer *)
+{
+  playback_function ()
+    ->add_eval (playback_location (),
+		m_rvalue->playback_rvalue ());
+}
+
+void
+recording::assignment::replay_into (replayer *)
+{
+  playback_function ()
+    ->add_assignment (playback_location (),
+		      m_lvalue->playback_lvalue (),
+		      m_rvalue->playback_rvalue ());
+}
+
+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 (),
+		      m_op,
+		      result_type,
+		      m_lvalue->playback_rvalue (),
+		      m_rvalue->playback_rvalue ());
+
+  playback_function ()
+    ->add_assignment (playback_location (),
+		      m_lvalue->playback_lvalue (),
+		      binary_op);
+}
+
+void
+recording::comment::replay_into (replayer *)
+{
+  playback_function ()
+    ->add_comment (playback_location (),
+		   m_text->c_str ());
+}
+
+void
+recording::conditional::replay_into (replayer *)
+{
+  playback_function ()
+    ->add_conditional (playback_location (),
+		       m_boolval->playback_rvalue (),
+		       playback_label (m_on_true),
+		       playback_label (m_on_false));
+}
+
+void
+recording::place_label::replay_into (replayer *)
+{
+  playback_function ()
+    ->place_forward_label (playback_location (),
+			   m_label->playback_label ());
+}
+
+void
+recording::jump::replay_into (replayer *)
+{
+  playback_function ()
+    ->add_jump (playback_location (),
+		m_target->playback_label ());
+}
+
+void
+recording::return_::replay_into (replayer *)
+{
+  playback_function ()
+    ->add_return (playback_location (),
+		  m_rvalue ? m_rvalue->playback_rvalue () : NULL);
+}
+
+void
+recording::loop::replay_into (replayer *)
+{
+  set_playback_obj (
+    m_func->playback_function ()
+      ->new_loop (playback_location (m_loc),
+		  m_boolval->playback_rvalue ()));
+}
+
+void
+recording::loop::end (location *loc)
+{
+  recording::loop_end *m = new loop_end (this, loc);
+  m_ctxt->record (m);
+}
+
+void
+recording::loop_end::replay_into (replayer *)
+{
+  m_loop->playback_loop ()->end (playback_location (m_loc));
+}
+
+/**********************************************************************
+ Playback.
+ **********************************************************************/
+
+playback::context::context (recording::context *ctxt)
+  : m_recording_ctxt (ctxt),
+    m_char_array_type_node (NULL),
+    m_const_char_ptr (NULL)
+{
+  m_functions.create (0);
+  m_source_files.create (0);
+  m_cached_locations.create (0);
+}
+
+playback::context::~context ()
 {
   if (get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES))
     fprintf (stderr, "intermediate files written to %s\n", m_path_tempdir);
@@ -47,7 +998,7 @@  gcc::jit::context::
 }
 
 void
-gcc::jit::context::
+playback::context::
 gt_ggc_mx ()
 {
   int i;
@@ -59,15 +1010,6 @@  gt_ggc_mx ()
     }
 }
 
-void
-gcc::jit::context::
-set_code_factory (gcc_jit_code_callback cb,
-		  void *user_data)
-{
-  m_code_factory = cb;
-  m_user_data = user_data;
-}
-
 static tree
 get_tree_node_for_type (enum gcc_jit_types type_)
 {
@@ -130,8 +1072,8 @@  get_tree_node_for_type (enum gcc_jit_types type_)
   return NULL;
 }
 
-gcc::jit::type *
-gcc::jit::context::
+playback::type *
+playback::context::
 get_type (enum gcc_jit_types type_)
 {
   tree type_node = get_tree_node_for_type (type_);
@@ -144,10 +1086,10 @@  get_type (enum gcc_jit_types type_)
   return new type (type_node);
 }
 
-gcc::jit::field *
-gcc::jit::context::
-new_field (gcc::jit::location *loc,
-	   gcc::jit::type *type,
+playback::field *
+playback::context::
+new_field (location *loc,
+	   type *type,
 	   const char *name)
 {
   gcc_assert (type);
@@ -163,15 +1105,14 @@  new_field (gcc::jit::location *loc,
   return new field (decl);
 }
 
-gcc::jit::type *
-gcc::jit::context::
-new_struct_type (gcc::jit::location *loc,
+playback::type *
+playback::context::
+new_struct_type (location *loc,
 		 const char *name,
-		 int num_fields,
-		 gcc::jit::field **fields)
+		 vec<field *> *fields)
 {
   gcc_assert (name);
-  gcc_assert ((num_fields == 0) || fields);
+  gcc_assert (fields);
 
   /* Compare with c/c-decl.c: start_struct and finish_struct. */
 
@@ -179,10 +1120,10 @@  new_struct_type (gcc::jit::location *loc,
   TYPE_NAME (t) = get_identifier (name);
   TYPE_SIZE (t) = 0;
 
- tree fieldlist = NULL;
-  for (int i = 0; i < num_fields; i++)
+  tree fieldlist = NULL;
+  for (unsigned i = 0; i < fields->length (); i++)
     {
-      field *f = fields[i];
+      field *f = (*fields)[i];
       DECL_CONTEXT (f->as_tree ()) = t;
       fieldlist = chainon (f->as_tree (), fieldlist);
     }
@@ -198,8 +1139,8 @@  new_struct_type (gcc::jit::location *loc,
 }
 
 
-gcc::jit::param *
-gcc::jit::context::
+playback::param *
+playback::context::
 new_param (location *loc,
 	   type *type,
 	   const char *name)
@@ -214,32 +1155,32 @@  new_param (location *loc,
   return new param (this, inner);
 }
 
-gcc::jit::function *
-gcc::jit::context::
+playback::function *
+playback::context::
 new_function (location *loc,
 	      enum gcc_jit_function_kind kind,
 	      type *return_type,
 	      const char *name,
-	      int num_params,
-	      param **params,
+	      vec<param *> *params,
 	      int is_variadic)
- {
+{
+  int i;
+  param *param;
+
   //can return_type be NULL?
   gcc_assert (name);
-  gcc_assert ((num_params == 0) || params);
 
-  tree *arg_types = (tree *)xcalloc(num_params, sizeof(tree*));
-  for (int i = 0; i < num_params; i++)
-    {
-      arg_types[i] = TREE_TYPE (params[i]->as_tree ());
-    }
+  tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
+  FOR_EACH_VEC_ELT (*params, i, param)
+    arg_types[i] = TREE_TYPE (param->as_tree ());
+
   tree fn_type;
   if (is_variadic)
     fn_type = build_varargs_function_type_array (return_type->as_tree (),
-						 num_params, arg_types);
+						 params->length (), arg_types);
   else
     fn_type = build_function_type_array (return_type->as_tree (),
-					 num_params, arg_types);
+					 params->length (), arg_types);
   free (arg_types);
 
   /* FIXME: this uses input_location: */
@@ -257,9 +1198,9 @@  new_function (location *loc,
   if (kind != GCC_JIT_FUNCTION_IMPORTED)
     {
       tree param_decl_list = NULL;
-      for (int i = 0; i < num_params; i++)
+      FOR_EACH_VEC_ELT (*params, i, param)
 	{
-	  param_decl_list = chainon (params[i]->as_tree (), param_decl_list);
+	  param_decl_list = chainon (param->as_tree (), param_decl_list);
 	}
 
       /* The param list was created in reverse order; fix it: */
@@ -281,8 +1222,8 @@  new_function (location *loc,
   return func;
 }
 
-gcc::jit::lvalue *
-gcc::jit::context::
+playback::lvalue *
+playback::context::
 new_global (location *loc,
             type *type,
             const char *name)
@@ -302,8 +1243,8 @@  new_global (location *loc,
   return new lvalue (this, inner);
 }
 
-gcc::jit::rvalue *
-gcc::jit::context::
+playback::rvalue *
+playback::context::
 new_rvalue_from_int (type *type,
 		     int value)
 {
@@ -323,8 +1264,8 @@  new_rvalue_from_int (type *type,
     }
 }
 
-gcc::jit::rvalue *
-gcc::jit::context::
+playback::rvalue *
+playback::context::
 new_rvalue_from_double (type *type,
 			double value)
 {
@@ -351,8 +1292,8 @@  new_rvalue_from_double (type *type,
   return new rvalue (this, inner);
 }
 
-gcc::jit::rvalue *
-gcc::jit::context::
+playback::rvalue *
+playback::context::
 new_rvalue_from_ptr (type *type,
 		     void *value)
 {
@@ -362,8 +1303,8 @@  new_rvalue_from_ptr (type *type,
   return new rvalue (this, inner);
 }
 
-gcc::jit::rvalue *
-gcc::jit::context::
+playback::rvalue *
+playback::context::
 new_string_literal (const char *value)
 {
   tree t_str = build_string (strlen (value), value);
@@ -379,7 +1320,7 @@  new_string_literal (const char *value)
 }
 
 tree
-gcc::jit::context::
+playback::context::
 as_truth_value (tree expr, location *loc)
 {
   /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
@@ -396,8 +1337,8 @@  as_truth_value (tree expr, location *loc)
   return expr;
 }
 
-gcc::jit::rvalue *
-gcc::jit::context::
+playback::rvalue *
+playback::context::
 new_unary_op (location *loc,
 	      enum gcc_jit_unary_op op,
 	      type *result_type,
@@ -443,8 +1384,8 @@  new_unary_op (location *loc,
   return new rvalue (this, inner_result);
 }
 
-gcc::jit::rvalue *
-gcc::jit::context::
+playback::rvalue *
+playback::context::
 new_binary_op (location *loc,
 	       enum gcc_jit_binary_op op,
 	       type *result_type,
@@ -526,8 +1467,8 @@  new_binary_op (location *loc,
   return new rvalue (this, inner_expr);
 }
 
-gcc::jit::rvalue *
-gcc::jit::context::
+playback::rvalue *
+playback::context::
 new_comparison (location *loc,
 		enum gcc_jit_comparison op,
 		rvalue *a, rvalue *b)
@@ -573,26 +1514,24 @@  new_comparison (location *loc,
   return new rvalue (this, inner_expr);
 }
 
-gcc::jit::rvalue *
-gcc::jit::context::
+playback::rvalue *
+playback::context::
 new_call (location *loc,
 	  function *func,
-	  int numargs , rvalue **args)
+	  vec<rvalue *> args)
 {
   tree fndecl;
   vec<tree, va_gc> *tree_args;
 
   gcc_assert (func);
-  gcc_assert (numargs >= 0);
-  gcc_assert ((args == 0) || (args != NULL));
 
   // FIXME: type checking
   // FIXME: check num args and types
 
   fndecl = func->as_fndecl ();
 
-  vec_alloc (tree_args, numargs);
-  for (int i = 0; i < numargs; i++)
+  vec_alloc (tree_args, args.length ());
+  for (unsigned i = 0; i < args.length (); i++)
     tree_args->quick_push (args[i]->as_tree ());
 
   tree fntype = TREE_TYPE (fndecl);
@@ -616,8 +1555,8 @@  new_call (location *loc,
    */
 }
 
-gcc::jit::rvalue *
-gcc::jit::context::
+playback::rvalue *
+playback::context::
 new_array_lookup (location *loc,
 		  rvalue *ptr,
 		  rvalue *index)
@@ -675,7 +1614,7 @@  get_field (tree type, tree component)
 }
 
 tree
-gcc::jit::context::
+playback::context::
 new_field_access (location *loc,
 		  tree datum,
 		  const char *fieldname)
@@ -683,9 +1622,10 @@  new_field_access (location *loc,
   gcc_assert (datum);
   gcc_assert (fieldname);
 
-  /* Compare with c/ctypeck.c:lookup_field, build_indirect_ref, and
+  /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
      build_component_ref. */
   tree type = TREE_TYPE (datum);
+  gcc_assert (type);
   gcc_assert (TREE_CODE (type) != POINTER_TYPE);
 
   tree component = get_identifier (fieldname);
@@ -703,7 +1643,7 @@  new_field_access (location *loc,
 }
 
 tree
-gcc::jit::context::
+playback::context::
 new_dereference (tree ptr,
 		 location *loc)
 {
@@ -716,8 +1656,8 @@  new_dereference (tree ptr,
   return datum;
 }
 
-gcc::jit::lvalue *
-gcc::jit::lvalue::
+playback::lvalue *
+playback::lvalue::
 access_field (location *loc,
 	      const char *fieldname)
 {
@@ -728,9 +1668,9 @@  access_field (location *loc,
   return new lvalue (get_context (), ref);
 }
 
-gcc::jit::rvalue *
-gcc::jit::rvalue::
-access_field (gcc::jit::location *loc,
+playback::rvalue *
+playback::rvalue::
+access_field (location *loc,
 	      const char *fieldname)
 {
   tree datum = as_tree ();
@@ -740,30 +1680,32 @@  access_field (gcc::jit::location *loc,
   return new rvalue (get_context (), ref);
 }
 
-gcc::jit::lvalue *
-gcc::jit::rvalue::
-dereference_field (gcc::jit::location *loc,
+playback::lvalue *
+playback::rvalue::
+dereference_field (location *loc,
 		   const char *fieldname)
 {
   tree ptr = as_tree ();
   tree datum = get_context ()->new_dereference (ptr, loc);
+  if (!datum)
+    return NULL;
   tree ref = get_context ()->new_field_access (loc, datum, fieldname);
   if (!ref)
     return NULL;
   return new lvalue (get_context (), ref);
 }
 
-gcc::jit::lvalue *
-gcc::jit::rvalue::
-dereference (gcc::jit::location *loc)
+playback::lvalue *
+playback::rvalue::
+dereference (location *loc)
 {
   tree ptr = as_tree ();
   tree datum = get_context ()->new_dereference (ptr, loc);
   return new lvalue (get_context (), datum);
 }
 
-gcc::jit::rvalue *
-gcc::jit::lvalue::
+playback::rvalue *
+playback::lvalue::
 get_address (location *loc)
 {
   tree t_lvalue = as_tree ();
@@ -776,14 +1718,16 @@  get_address (location *loc)
 }
 
 void *
-gcc::jit::wrapper::
+playback::wrapper::
 operator new (size_t sz)
 {
   return ggc_internal_cleared_alloc_stat (sz MEM_STAT_INFO);
 }
 
-gcc::jit::function::
-function(gcc::jit::context *ctxt, tree fndecl, enum gcc_jit_function_kind kind)
+playback::function::
+function (context *ctxt,
+	  tree fndecl,
+	  enum gcc_jit_function_kind kind)
 : m_ctxt(ctxt),
   m_inner_fndecl (fndecl),
   m_inner_bind_expr (NULL),
@@ -804,7 +1748,7 @@  function(gcc::jit::context *ctxt, tree fndecl, enum gcc_jit_function_kind kind)
 }
 
 void
-gcc::jit::function::
+playback::function::
 gt_ggc_mx ()
 {
   gt_ggc_m_9tree_node (m_inner_fndecl);
@@ -813,14 +1757,14 @@  gt_ggc_mx ()
 }
 
 tree
-gcc::jit::function::
+playback::function::
 get_return_type_as_tree () const
 {
   return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
 }
 
-gcc::jit::lvalue *
-gcc::jit::function::
+playback::lvalue *
+playback::function::
 new_local (location *loc,
 	   type *type,
 	   const char *name)
@@ -841,16 +1785,16 @@  new_local (location *loc,
   return new lvalue (m_ctxt, inner);
 }
 
-gcc::jit::label *
-gcc::jit::function::
+playback::label *
+playback::function::
 new_forward_label (const char *name)
 {
   gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
-  return new label (this, name);
+  return new playback::label (this, name);
 }
 
 void
-gcc::jit::function::
+playback::function::
 postprocess ()
 {
   if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
@@ -894,7 +1838,7 @@  postprocess ()
 }
 
 void
-gcc::jit::function::
+playback::function::
 add_eval (location *loc,
 	  rvalue *rvalue)
 {
@@ -908,7 +1852,7 @@  add_eval (location *loc,
 }
 
 void
-gcc::jit::function::
+playback::function::
 add_assignment (location *loc,
 		lvalue *lvalue,
 		rvalue *rvalue)
@@ -937,7 +1881,7 @@  add_assignment (location *loc,
 }
 
 void
-gcc::jit::function::
+playback::function::
 add_comment (location *loc,
 	     const char *text)
 {
@@ -958,7 +1902,7 @@  add_comment (location *loc,
 }
 
 void
-gcc::jit::function::
+playback::function::
 add_conditional (location *loc,
 		 rvalue *boolval,
 		 label *on_true,
@@ -995,8 +1939,8 @@  add_conditional (location *loc,
   add_stmt (stmt);
 }
 
-gcc::jit::label *
-gcc::jit::function::
+playback::label *
+playback::function::
 add_label (location *loc,
 	   const char *name)
 {
@@ -1008,7 +1952,7 @@  add_label (location *loc,
 }
 
 void
-gcc::jit::function::
+playback::function::
 place_forward_label (location *loc, label *lab)
 {
   gcc_assert (lab);
@@ -1024,7 +1968,7 @@  place_forward_label (location *loc, label *lab)
 }
 
 void
-gcc::jit::function::
+playback::function::
 add_jump (location *loc,
 	  label *target)
 {
@@ -1062,7 +2006,7 @@  c_finish_goto_label (location_t loc, tree label)
 }
 
 void
-gcc::jit::function::
+playback::function::
 add_return (location *loc,
 	    rvalue *rvalue)
 {
@@ -1087,15 +2031,15 @@  add_return (location *loc,
   add_stmt (return_stmt);
 }
 
-gcc::jit::loop *
-gcc::jit::function::
+playback::loop *
+playback::function::
 new_loop (location *loc,
 	  rvalue *boolval)
 {
   return new loop (this, loc, boolval);
 }
 
-gcc::jit::label::
+playback::label::
 label (function *func,
        const char *name)
 {
@@ -1114,7 +2058,7 @@  label (function *func,
 }
 
 
-gcc::jit::loop::
+playback::loop::
 loop (function *func, location *loc, rvalue *boolval) :
   m_func(func)
 {
@@ -1126,63 +2070,15 @@  loop (function *func, location *loc, rvalue *boolval) :
 }
 
 void
-gcc::jit::loop::
+playback::loop::
 end (location *loc)
 {
   m_func->add_jump (loc, m_label_cond);
   m_func->place_forward_label (loc, m_label_end);
 }
 
-void
-gcc::jit::context::
-set_str_option (enum gcc_jit_str_option opt,
-		const char *value)
-{
-  if (opt < 0 || opt >= GCC_JIT_NUM_STR_OPTIONS)
-    {
-      add_error ("unrecognized (enum gcc_jit_str_option) value: %i", opt);
-      return;
-    }
-  m_str_options[opt] = value;
-}
-
-void
-gcc::jit::context::
-set_int_option (enum gcc_jit_int_option opt,
-		int value)
-{
-  if (opt < 0 || opt >= GCC_JIT_NUM_INT_OPTIONS)
-    {
-      add_error ("unrecognized (enum gcc_jit_int_option) value: %i", opt);
-      return;
-    }
-  m_int_options[opt] = value;
-}
-
-void
-gcc::jit::context::
-set_bool_option (enum gcc_jit_bool_option opt,
-		 int value)
-{
-  if (opt < 0 || opt >= GCC_JIT_NUM_BOOL_OPTIONS)
-    {
-      add_error ("unrecognized (enum gcc_jit_bool_option) value: %i", opt);
-      return;
-    }
-  m_bool_options[opt] = value ? true : false;
-}
-
-namespace gcc
-{
-  namespace jit
-  {
-    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-    context *active_jit_ctxt;
-  }
-}
-
-gcc::jit::result *
-gcc::jit::context::
+result *
+playback::context::
 compile ()
 {
   void *handle = NULL;
@@ -1191,22 +2087,16 @@  compile ()
   const char *fake_args[20];
   unsigned int num_args;
 
-  /* Acquire the big GCC mutex. */
-  pthread_mutex_lock (&mutex);
-
-  gcc_assert (NULL == active_jit_ctxt);
-  active_jit_ctxt = this;
-
   m_path_template = xstrdup ("/tmp/libgccjit-XXXXXX");
   if (!m_path_template)
-    goto error;
+    return NULL;
 
   /* Create tempdir using mkdtemp.  This is created with 0700 perms and
      is unique.  Hence no other (non-root) users should have access to
      the paths within it.  */
   m_path_tempdir = mkdtemp (m_path_template);
   if (!m_path_tempdir)
-    goto error;
+    return NULL;
   m_path_c_file = concat (m_path_tempdir, "/fake.c", NULL);
   m_path_s_file = concat (m_path_tempdir, "/fake.s", NULL);
   m_path_so_file = concat (m_path_tempdir, "/fake.so", NULL);
@@ -1239,7 +2129,7 @@  compile ()
     default:
       add_error ("unrecognized optimization level: %i",
 		 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
-      goto error;
+      return NULL;
 
     case 0:
       ADD_ARG ("-O0");
@@ -1297,18 +2187,15 @@  compile ()
   toplev_main (num_args, const_cast <char **> (fake_args), &toplev_opts);
   toplev_finalize ();
 
-  active_jit_ctxt = NULL;
+  active_playback_ctxt = NULL;
 
   if (errors_occurred ())
     {
       timevar_stop (TV_TOTAL);
       timevar_print (stderr);
-      goto error;
+      return NULL;
     }
 
-  if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
-    dump_generated_code ();
-
   timevar_push (TV_ASSEMBLE);
 
   /* Gross hacks follow:
@@ -1329,7 +2216,7 @@  compile ()
 	timevar_pop (TV_ASSEMBLE);
 	timevar_stop (TV_TOTAL);
 	timevar_print (stderr);
-	goto error;
+	return NULL;
       }
   }
   timevar_pop (TV_ASSEMBLE);
@@ -1360,17 +2247,12 @@  compile ()
   timevar_stop (TV_TOTAL);
   timevar_print (stderr);
 
- error:
-  /* Release the big GCC mutex. */
-  active_jit_ctxt = NULL;
-  pthread_mutex_unlock (&mutex);
-
   return result_obj;
 }
 
 void
-gcc::jit::context::
-invoke_code_factory ()
+playback::context::
+replay ()
 {
   /* Adapted from c-common.c:c_common_nodes_and_builtins.  */
   tree array_domain_type = build_index_type (size_int (200));
@@ -1381,12 +2263,18 @@  invoke_code_factory ()
     = build_pointer_type (build_qualified_type (char_type_node,
 						TYPE_QUAL_CONST));
 
-  /* Call the client-provided code factory:  */
-  timevar_push (TV_CLIENT_CALLBACK);
-  m_within_code_factory = true;
-  m_cb_result = m_code_factory ((gcc_jit_context *)this, m_user_data);
-  m_within_code_factory = false;
-  timevar_pop (TV_CLIENT_CALLBACK);
+  /* Replay the recorded events:  */
+  timevar_push (TV_JIT_REPLAY);
+
+  m_recording_ctxt->replay_into (this);
+
+  /* Clean away the temporary references from recording objects
+     to playback objects.  We have to do this now since the
+     latter are GC-allocated, but the former don't mark these
+     refs.  Hence we must stop using them before the GC can run.  */
+  m_recording_ctxt->disassociate_from_playback ();
+
+  timevar_pop (TV_JIT_REPLAY);
 
   if (!errors_occurred ())
     {
@@ -1406,7 +2294,7 @@  invoke_code_factory ()
 }
 
 void
-gcc::jit::context::
+playback::context::
 dump_generated_code ()
 {
   char buf[4096];
@@ -1424,25 +2312,25 @@  dump_generated_code ()
 static int
 line_comparator (const void *lhs, const void *rhs)
 {
-  const gcc::jit::source_line *line_lhs = \
-    *static_cast<const gcc::jit::source_line * const*> (lhs);
-  const gcc::jit::source_line *line_rhs = \
-    *static_cast<const gcc::jit::source_line * const*> (rhs);
+  const playback::source_line *line_lhs = \
+    *static_cast<const playback::source_line * const*> (lhs);
+  const playback::source_line *line_rhs = \
+    *static_cast<const playback::source_line * const*> (rhs);
   return line_lhs->get_line_num () - line_rhs->get_line_num ();
 }
 
 static int
 location_comparator (const void *lhs, const void *rhs)
 {
-  const gcc::jit::location *loc_lhs = \
-    *static_cast<const gcc::jit::location * const *> (lhs);
-  const gcc::jit::location *loc_rhs = \
-    *static_cast<const gcc::jit::location * const *> (rhs);
+  const playback::location *loc_lhs = \
+    *static_cast<const playback::location * const *> (lhs);
+  const playback::location *loc_rhs = \
+    *static_cast<const playback::location * const *> (rhs);
   return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
 }
 
 void
-gcc::jit::context::
+playback::context::
 handle_locations ()
 {
   /* Create the source code locations, following the ordering rules
@@ -1518,57 +2406,35 @@  handle_locations ()
 
 
 void
-gcc::jit::context::
+playback::context::
 add_error (const char *fmt, ...)
 {
   va_list ap;
   va_start (ap, fmt);
-  add_error_va (fmt, ap);
+  m_recording_ctxt->add_error_va (fmt, ap);
   va_end (ap);
 }
 
 void
-gcc::jit::context::
+playback::context::
 add_error_va (const char *fmt, va_list ap)
 {
-  char buf[1024];
-  vsnprintf (buf, sizeof (buf) - 1, fmt, ap);
-
-  error ("%s\n", buf);
-
-  if (!m_error_count)
-    {
-      strncpy (m_first_error_str, buf, sizeof(m_first_error_str));
-      m_first_error_str[sizeof(m_first_error_str) - 1] = '\0';
-    }
-
-  m_error_count++;
+  m_recording_ctxt->add_error_va (fmt, ap);
 }
 
-const char *
-gcc::jit::context::
-get_first_error () const
-{
-  if (m_error_count)
-    return m_first_error_str;
-  else
-    return NULL;
-}
-
-gcc::jit::result::
+result::
 result(void *dso_handle)
   : m_dso_handle(dso_handle)
 {
 }
 
-gcc::jit::result::
-~result()
+result::~result()
 {
   dlclose (m_dso_handle);
 }
 
 void *
-gcc::jit::result::
+result::
 get_code (const char *funcname)
 {
   void *code;
@@ -1588,8 +2454,8 @@  get_code (const char *funcname)
 
 /* Dealing with the linemap API.  */
 
-gcc::jit::location *
-gcc::jit::context::
+playback::location *
+playback::context::
 new_location (const char *filename,
 	      int line,
 	      int column)
@@ -1604,15 +2470,15 @@  new_location (const char *filename,
 }
 
 void
-gcc::jit::context::
+playback::context::
 set_tree_location (tree t, location *loc)
 {
   m_cached_locations.safe_push (std::make_pair (t, loc));
 }
 
 
-gcc::jit::source_file *
-gcc::jit::context::
+playback::source_file *
+playback::context::
 get_source_file (const char *filename)
 {
   /* Locate the file.
@@ -1632,14 +2498,14 @@  get_source_file (const char *filename)
   return file;
 }
 
-gcc::jit::source_file::source_file (tree filename) :
+playback::source_file::source_file (tree filename) :
   m_source_lines (),
   m_filename (filename)
 {
 }
 
-gcc::jit::source_line *
-gcc::jit::source_file::
+playback::source_line *
+playback::source_file::
 get_source_line (int line_num)
 {
   /* Locate the line.
@@ -1658,15 +2524,15 @@  get_source_line (int line_num)
   return line;
 }
 
-gcc::jit::source_line::source_line (source_file *file, int line_num) :
+playback::source_line::source_line (source_file *file, int line_num) :
   m_locations (),
   m_source_file (file),
   m_line_num (line_num)
 {
 }
 
-gcc::jit::location *
-gcc::jit::source_line::
+playback::location *
+playback::source_line::
 get_location (int column_num)
 {
   int i;
@@ -1683,8 +2549,14 @@  get_location (int column_num)
   return loc;
 }
 
-gcc::jit::location::location (source_line *line, int column_num) :
+playback::location::location (source_line *line, int column_num) :
   m_line (line),
   m_column_num(column_num)
 {
 }
+
+playback::context *active_playback_ctxt;
+
+} // namespace gcc::jit
+
+} // namespace gcc
diff --git a/gcc/jit/internal-api.h b/gcc/jit/internal-api.h
index 3f0e9eb..15f5918 100644
--- a/gcc/jit/internal-api.h
+++ b/gcc/jit/internal-api.h
@@ -13,34 +13,1163 @@ 
 #endif
 #endif
 
+/* In order to allow jit objects to be usable outside of a compile
+   whilst working with the existing structure of GCC's code the
+   C API is implemented in terms of a gcc::jit::recording::context,
+   which records the calls made to it.
+
+   When a gcc_jit_context is compiled, the recording context creates a
+   playback context.  The playback context invokes the bulk of the GCC
+   code, and within the "frontend" parsing hook, plays back the recorded
+   API calls, creating GCC tree objects.
+
+   So there are two parallel families of classes: those relating to
+   recording, and those relating to playback:
+
+   * Visibility: recording objects are exposed back to client code,
+     whereas playback objects are internal to the library.
+
+   * Lifetime: recording objects have a lifetime equal to that of the
+     recording context that created them, whereas playback objects only
+     exist within the frontend hook.
+
+   * Memory allocation: recording objects are allocated by the recording
+     context, and automatically freed by it when the context is released,
+     whereas playback objects are allocated within the GC heap, and
+     garbage-collected; they can own GC-references.
+
+   * Integration with rest of GCC: recording objects are unrelated to the
+     rest of GCC, whereas playback objects are wrappers around "tree"
+     instances.  Hence you can't ask a recording rvalue or lvalue what its
+     type is, whereas you can for a playback rvalue of lvalue (since it
+     can work with the underlying GCC tree nodes).
+
+   * Instancing: There can be multiple recording contexts "alive" at once
+     (albeit it only one compiling at once), whereas there can only be one
+     playback context alive at one time (since it interacts with the GC).
+
+   Ultimately if GCC could support multiple GC heaps and contexts, and
+   finer-grained initialization, then this recording vs playback
+   distinction could be eliminated.
+
+   During a playback, we associate objects from the recording with
+   their counterparts during this playback.  For simplicity, we store this
+   within the recording objects, as "void *m_playback_obj", casting it to
+   the appropriate playback object subclass.  For these casts to make
+   sense, the two class hierarchies need to have the same structure.
+
+   Note that the playback objects that "m_playback_obj" points to are
+   GC-allocated, but the recording objects don't own references:
+   these associations only exist within a part of the code where
+   the GC doesn't collect, and are set back to NULL before the GC can
+   run.  */
+
 namespace gcc {
 
-namespace jit {
+namespace jit {
+
+class result;
+
+namespace recording {
+  class context;
+  class memento;
+  class string;
+  class location;
+  class type;
+  class field;
+  class function;
+  class label;
+  class rvalue;
+  class lvalue;
+  class param;
+  class loop;
+}
+
+namespace playback {
+  class context;
+  class location;
+  class type;
+  class field;
+  class function;
+  class label;
+  class rvalue;
+  class lvalue;
+  class param;
+  class loop;
+  class source_file;
+  class source_line;
+}
+
+typedef playback::context replayer;
+
+/**********************************************************************
+ Recording.
+ **********************************************************************/
+
+namespace recording {
+
+playback::location *
+playback_location (location *loc);
+
+const char *
+playback_string (string *str);
+
+playback::label *
+playback_label (label *lab);
+
+/* A JIT-compilation context.  */
+class context
+{
+public:
+  ~context ();
+
+  void record (memento *m) { m_mementos.safe_push (m); }
+  void replay_into (replayer *r);
+  void disassociate_from_playback ();
+
+  string *
+  new_string (const char *text);
+
+  location *
+  new_location (const char *filename,
+		int line,
+		int column);
+
+  type *
+  get_type (enum gcc_jit_types type);
+
+  field *
+  new_field (location *loc,
+	     type *type,
+	     const char *name);
+
+  type *
+  new_struct_type (location *loc,
+		   const char *name,
+		   int num_fields,
+		   field **fields);
+
+
+  param *
+  new_param (location *loc,
+	     type *type,
+	     const char *name);
+
+  function *
+  new_function (location *loc,
+		enum gcc_jit_function_kind kind,
+		type *return_type,
+		const char *name,
+		int num_params,
+		param **params,
+		int is_variadic);
+
+  lvalue *
+  new_global (location *loc,
+	      type *type,
+	      const char *name);
+
+  rvalue *
+  new_rvalue_from_int (type *type,
+		       int value);
+
+  rvalue *
+  new_rvalue_from_double (type *type,
+			  double value);
+
+  rvalue *
+  new_rvalue_from_ptr (type *type,
+		       void *value);
+
+  rvalue *
+  new_string_literal (const char *value);
+
+  rvalue *
+  new_unary_op (location *loc,
+		enum gcc_jit_unary_op op,
+		type *result_type,
+		rvalue *a);
+
+  rvalue *
+  new_binary_op (location *loc,
+		 enum gcc_jit_binary_op op,
+		 type *result_type,
+		 rvalue *a, rvalue *b);
+
+  rvalue *
+  new_comparison (location *loc,
+		  enum gcc_jit_comparison op,
+		  rvalue *a, rvalue *b);
+
+  rvalue *
+  new_call (location *loc,
+	    function *func,
+	    int numargs, rvalue **args);
+
+  rvalue *
+  new_array_lookup (location *loc,
+		    rvalue *ptr,
+		    rvalue *index);
+
+  void
+  set_str_option (enum gcc_jit_str_option opt,
+		  const char *value);
+
+  void
+  set_int_option (enum gcc_jit_int_option opt,
+		  int value);
+
+  void
+  set_bool_option (enum gcc_jit_bool_option opt,
+		   int value);
+
+  const char *
+  get_str_option (enum gcc_jit_str_option opt) const
+  {
+    return m_str_options[opt];
+  }
+
+  int
+  get_int_option (enum gcc_jit_int_option opt) const
+  {
+    return m_int_options[opt];
+  }
+
+  int
+  get_bool_option (enum gcc_jit_bool_option opt) const
+  {
+    return m_bool_options[opt];
+  }
+
+  result *
+  compile ();
+
+  void
+  add_error (const char *fmt, ...)
+      GNU_PRINTF(2, 3);
+
+  void
+  add_error_va (const char *fmt, va_list ap)
+      GNU_PRINTF(2, 0);
+
+  const char *
+  get_first_error () const;
+
+  bool errors_occurred () const
+  {
+    return m_error_count;
+  }
+
+private:
+  int m_error_count;
+  char m_first_error_str[1024];
+
+  const char *m_str_options[GCC_JIT_NUM_STR_OPTIONS];
+  int m_int_options[GCC_JIT_NUM_INT_OPTIONS];
+  bool m_bool_options[GCC_JIT_NUM_BOOL_OPTIONS];
+
+  /* Recorded API usage.  */
+  vec<memento *> m_mementos;
+
+};
+
+
+/* An object with lifetime managed by the context i.e.
+   it lives until the context is released, at which
+   point it itself is cleaned up.  */
+
+class memento
+{
+public:
+  virtual ~memento () {}
+
+  /* Hook for replaying this.  */
+  virtual void replay_into (replayer *r) = 0;
+
+  void set_playback_obj (void *obj) { m_playback_obj = obj; }
+
+protected:
+  memento (context *ctxt)
+  : m_ctxt (ctxt),
+    m_playback_obj (NULL)
+  {}
+
+  string *new_string (const char *text) { return m_ctxt->new_string (text); }
+
+public:
+  context *m_ctxt;
+
+protected:
+  void *m_playback_obj;
+};
+
+/* or just use std::string? */
+class string : public memento
+{
+public:
+  string (context *ctxt, const char *text);
+  ~string ();
+
+  const char *c_str () { return m_copy; }
+
+  void replay_into (replayer *) {}
+
+private:
+  size_t m_len;
+  char *m_copy;
+};
+
+class location : public memento
+{
+public:
+  location (context *ctxt, string *filename, int line, int column)
+  : memento (ctxt),
+    m_filename (filename),
+    m_line (line),
+    m_column (column)
+ {}
+
+  void replay_into (replayer *r);
+
+  playback::location *
+  playback_location () const
+  {
+    return static_cast <playback::location *> (m_playback_obj);
+  }
+
+private:
+  string *m_filename;
+  int m_line;
+  int m_column;
+};
+
+class type : public memento
+{
+public:
+  type *get_pointer ();
+  type *get_const ();
+
+  playback::type *
+  playback_type ()
+  {
+    return static_cast <playback::type *> (m_playback_obj);
+  }
+
+protected:
+  type (context *ctxt)
+    : memento (ctxt) {}
+
+};
+
+/* Result of "gcc_jit_type_get_type".  */
+class memento_of_get_type : public type
+{
+public:
+  memento_of_get_type (context *ctxt,
+		       enum gcc_jit_types kind)
+  : type (ctxt),
+    m_kind (kind) {}
+
+public:
+  void replay_into (replayer *r);
+
+private:
+  enum gcc_jit_types m_kind;
+};
+
+/* Result of "gcc_jit_type_get_pointer".  */
+class memento_of_get_pointer : public type
+{
+public:
+  memento_of_get_pointer (type *other_type)
+  : type (other_type->m_ctxt),
+    m_other_type (other_type) {}
+
+  void replay_into (replayer *r);
+
+private:
+  type *m_other_type;
+};
+
+/* Result of "gcc_jit_type_get_const".  */
+class memento_of_get_const : public type
+{
+public:
+  memento_of_get_const (type *other_type)
+  : type (other_type->m_ctxt),
+    m_other_type (other_type) {}
+
+  void replay_into (replayer *);
+
+private:
+  type *m_other_type;
+};
+
+class field : public memento
+{
+public:
+  field (context *ctxt,
+	 location *loc,
+	 type *type,
+	 string *name)
+  : memento (ctxt),
+    m_loc (loc),
+    m_type (type),
+    m_name (name)
+  {}
+
+  void replay_into (replayer *);
+
+  playback::field *
+  playback_field () const
+  {
+    return static_cast <playback::field *> (m_playback_obj);
+  }
+
+private:
+  location *m_loc;
+  type *m_type;
+  string *m_name;
+};
+
+class struct_ : public type
+{
+public:
+  struct_ (context *ctxt,
+	   location *loc,
+	   string *name,
+	   vec<field *> fields)
+  : type (ctxt),
+    m_loc (loc),
+    m_name (name),
+    m_fields (fields)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  location *m_loc;
+  string *m_name;
+  vec<field *> m_fields;
+};
+
+class rvalue : public memento
+{
+public:
+  rvalue (context *ctxt,
+	  location *loc)
+  : memento (ctxt),
+    m_loc (loc)
+  {}
+
+  playback::rvalue *
+  playback_rvalue () const
+  {
+    return static_cast <playback::rvalue *> (m_playback_obj);
+  }
+  rvalue *
+  access_field (location *loc,
+		const char *fieldname);
+
+  lvalue *
+  dereference_field (location *loc,
+		     const char *fieldname);
+
+  lvalue *
+  dereference (location *loc);
+
+protected:
+  location *m_loc;
+};
+
+class lvalue : public rvalue
+{
+public:
+  lvalue (context *ctxt,
+	  location *loc)
+    : rvalue (ctxt, loc)
+    {}
+
+  playback::lvalue *
+  playback_lvalue () const
+  {
+    return static_cast <playback::lvalue *> (m_playback_obj);
+  }
+
+  lvalue *
+  access_field (location *loc,
+		const char *fieldname);
+
+  rvalue *
+  get_address (location *loc);
+
+  rvalue *
+  as_rvalue () { return this; }
+};
+
+class param : public lvalue
+{
+public:
+  param (context *ctxt,
+	 location *loc,
+	 type *type,
+	 string *name)
+  : lvalue (ctxt, loc),
+    m_type (type),
+    m_name (name) {}
+
+  lvalue *
+  as_lvalue () { return this; }
+
+  void replay_into (replayer *r);
+
+  playback::param *
+  playback_param () const
+  {
+    return static_cast <playback::param *> (m_playback_obj);
+  }
+
+private:
+  type *m_type;
+  string *m_name;
+};
+
+class function : public memento
+{
+public:
+  function (context *ctxt,
+	    location *loc,
+	    enum gcc_jit_function_kind kind,
+	    type *return_type,
+	    string *name,
+	    int num_params,
+	    param **params,
+	    int is_variadic);
+
+  void replay_into (replayer *r);
+
+  playback::function *
+  playback_function () const
+  {
+    return static_cast <playback::function *> (m_playback_obj);
+  }
+
+  enum gcc_jit_function_kind get_kind () const { return m_kind; }
+
+  lvalue *
+  new_local (location *loc,
+	     type *type,
+	     const char *name);
+
+  label*
+  new_forward_label (const char *name);
+
+  void
+  add_eval (location *loc,
+	    rvalue *rvalue);
+
+  void
+  add_assignment (location *loc,
+		  lvalue *lvalue,
+		  rvalue *rvalue);
+
+  void
+  add_assignment_op (location *loc,
+		     lvalue *lvalue,
+		     enum gcc_jit_binary_op op,
+		     rvalue *rvalue);
+
+  void
+  add_comment (location *loc,
+	       const char *text);
+
+  void
+  add_conditional (location *loc,
+		   rvalue *boolval,
+		   label *on_true,
+		   label *on_false);
+
+  label *
+  add_label (location *loc,
+	     const char *name);
+
+  void
+  place_forward_label (location *loc, label *lab);
+
+  void
+  add_jump (location *loc,
+	    label *target);
+
+  void
+  add_return (location *loc,
+	      rvalue *rvalue);
+
+  loop *
+  new_loop (location *loc,
+	    rvalue *boolval);
+
+private:
+  location *m_loc;
+  enum gcc_jit_function_kind m_kind;
+  type *m_return_type;
+  string *m_name;
+  vec<param *> m_params;
+  int m_is_variadic;
+};
+
+class label : public memento
+{
+public:
+  label (function *func, string *name)
+  : memento (func->m_ctxt),
+    m_func (func),
+    m_name (name)
+  {
+  }
+
+  void replay_into (replayer *r);
+
+  playback::label *
+  playback_label () const
+  {
+    return static_cast <playback::label *> (m_playback_obj);
+  }
+
+private:
+  function *m_func;
+  string *m_name;
+};
+
+class global : public lvalue
+{
+public:
+  global (context *ctxt,
+	  location *loc,
+	  type *type,
+	  string *name)
+  : lvalue (ctxt, loc),
+    m_type (type),
+    m_name (name)
+  {}
+
+  void replay_into (replayer *);
+
+private:
+  type *m_type;
+  string *m_name;
+};
+
+class memento_of_new_rvalue_from_int : public rvalue
+{
+public:
+  memento_of_new_rvalue_from_int (context *ctxt,
+				  location *loc,
+				  type *type,
+				  int value)
+  : rvalue (ctxt, loc),
+    m_type (type),
+    m_value (value) {}
+
+  void replay_into (replayer *r);
 
-class result;
-class source_file;
-class source_line;
-class location;
-class type;
-class field;
-class function;
-class label;
-class rvalue;
-class lvalue;
-class param;
-class loop;
+private:
+  type *m_type;
+  int m_value;
+};
+
+class memento_of_new_rvalue_from_double : public rvalue
+{
+public:
+  memento_of_new_rvalue_from_double (context *ctxt,
+				     location *loc,
+				     type *type,
+				     double value)
+  : rvalue (ctxt, loc),
+    m_type (type),
+    m_value (value)
+  {}
+
+  void replay_into (replayer *);
+
+private:
+  type *m_type;
+  double m_value;
+};
+
+class memento_of_new_rvalue_from_ptr : public rvalue
+{
+public:
+  memento_of_new_rvalue_from_ptr (context *ctxt,
+				  location *loc,
+				  type *type,
+				  void *value)
+  : rvalue (ctxt, loc),
+    m_type (type),
+    m_value (value)
+  {}
+
+  void replay_into (replayer *);
+
+private:
+  type *m_type;
+  void *m_value;
+};
+
+class memento_of_new_string_literal : public rvalue
+{
+public:
+  memento_of_new_string_literal (context *ctxt,
+				 location *loc,
+				 string *value)
+  : rvalue (ctxt, loc),
+    m_value (value) {}
+
+  void replay_into (replayer *r);
+
+private:
+  string *m_value;
+};
+
+class unary_op : public rvalue
+{
+public:
+  unary_op (context *ctxt,
+	    location *loc,
+	    enum gcc_jit_unary_op op,
+	    type *result_type,
+	    rvalue *a)
+  : rvalue (ctxt, loc),
+    m_op (op),
+    m_result_type (result_type),
+    m_a (a)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  enum gcc_jit_unary_op m_op;
+  type *m_result_type;
+  rvalue *m_a;
+};
+
+class binary_op : public rvalue
+{
+public:
+  binary_op (context *ctxt,
+	     location *loc,
+	     enum gcc_jit_binary_op op,
+	     type *result_type,
+	     rvalue *a, rvalue *b)
+  : rvalue (ctxt, loc),
+    m_op (op),
+    m_result_type (result_type),
+    m_a (a),
+    m_b (b) {}
+
+  void replay_into (replayer *r);
+
+private:
+  enum gcc_jit_binary_op m_op;
+  type *m_result_type;
+  rvalue *m_a;
+  rvalue *m_b;
+};
+
+class comparison : public rvalue
+{
+public:
+  comparison (context *ctxt,
+	      location *loc,
+	      enum gcc_jit_comparison op,
+	      rvalue *a, rvalue *b)
+  : rvalue (ctxt, loc),
+    m_op (op),
+    m_a (a),
+    m_b (b)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  enum gcc_jit_comparison m_op;
+  rvalue *m_a;
+  rvalue *m_b;
+};
+
+class call : public rvalue
+{
+public:
+  call (context *ctxt,
+	location *loc,
+	function *func,
+	int numargs,
+	rvalue **args);
+
+  void replay_into (replayer *r);
+
+private:
+  function *m_func;
+  vec<rvalue *> m_args;
+};
+
+class array_lookup : public rvalue
+{
+public:
+  array_lookup (context *ctxt,
+		location *loc,
+		rvalue *ptr,
+		rvalue *index)
+  : rvalue (ctxt, loc),
+    m_ptr (ptr),
+    m_index (index)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  rvalue *m_ptr;
+  rvalue *m_index;
+};
+
+class access_field_of_lvalue : public lvalue
+{
+public:
+  access_field_of_lvalue (context *ctxt,
+			  location *loc,
+			  lvalue *val,
+			  string *fieldname)
+  : lvalue (ctxt, loc),
+    m_lvalue (val),
+    m_fieldname (fieldname)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  lvalue *m_lvalue;
+  string *m_fieldname;
+};
+
+class access_field_rvalue : public rvalue
+{
+public:
+  access_field_rvalue (context *ctxt,
+		       location *loc,
+		       rvalue *val,
+		       string *fieldname)
+  : rvalue (ctxt, loc),
+    m_rvalue (val),
+    m_fieldname (fieldname) {}
+
+  void replay_into (replayer *r);
+
+private:
+  rvalue *m_rvalue;
+  string *m_fieldname;
+};
+
+class dereference_field_rvalue : public lvalue
+{
+public:
+  dereference_field_rvalue (context *ctxt,
+			    location *loc,
+			    rvalue *val,
+			    string *fieldname)
+  : lvalue (ctxt, loc),
+    m_rvalue (val),
+    m_fieldname (fieldname) {}
+
+  void replay_into (replayer *r);
+
+private:
+  rvalue *m_rvalue;
+  string *m_fieldname;
+};
+
+class dereference_rvalue : public lvalue
+{
+public:
+  dereference_rvalue (context *ctxt,
+		      location *loc,
+		      rvalue *val)
+  : lvalue (ctxt, loc),
+    m_rvalue (val) {}
+
+  void replay_into (replayer *r);
+
+private:
+  rvalue *m_rvalue;
+};
+
+class get_address_of_lvalue : public rvalue
+{
+public:
+  get_address_of_lvalue (context *ctxt,
+			 location *loc,
+			 lvalue *val)
+  : rvalue (ctxt, loc),
+    m_lvalue (val)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  lvalue *m_lvalue;
+};
+
+class local : public lvalue
+{
+public:
+  local (function *func, location *loc, type *type_, string *name)
+  : lvalue (func->m_ctxt, loc),
+    m_func (func),
+    m_type (type_),
+    m_name (name) {}
+
+  void replay_into (replayer *r);
+
+private:
+  function *m_func;
+  type *m_type;
+  string *m_name;
+};
+
+class statement : public memento
+{
+protected:
+  statement (function *func, location *loc)
+  : memento (func->m_ctxt),
+    m_func (func),
+    m_loc (loc) {}
+
+  playback::function *
+  playback_function () const
+  {
+    return m_func->playback_function ();
+  }
+
+  playback::location *
+  playback_location () const
+  {
+    return ::gcc::jit::recording::playback_location (m_loc);
+  }
+
+private:
+  function *m_func;
+  location *m_loc;
+};
+
+class eval : public statement
+{
+public:
+  eval (function *func,
+	location *loc,
+	rvalue *rvalue)
+  : statement (func, loc),
+    m_rvalue (rvalue) {}
+
+  void replay_into (replayer *r);
+
+private:
+  rvalue *m_rvalue;
+};
+
+class assignment : public statement
+{
+public:
+  assignment (function *func,
+	      location *loc,
+	      lvalue *lvalue,
+	      rvalue *rvalue)
+  : statement (func, loc),
+    m_lvalue (lvalue),
+    m_rvalue (rvalue) {}
+
+  void replay_into (replayer *r);
+
+private:
+  lvalue *m_lvalue;
+  rvalue *m_rvalue;
+};
+
+class assignment_op : public statement
+{
+public:
+  assignment_op (function *func,
+		 location *loc,
+		 lvalue *lvalue,
+		 enum gcc_jit_binary_op op,
+		 rvalue *rvalue)
+  : statement (func, loc),
+    m_lvalue (lvalue),
+    m_op (op),
+    m_rvalue (rvalue) {}
+
+  void replay_into (replayer *r);
+
+private:
+  lvalue *m_lvalue;
+  enum gcc_jit_binary_op m_op;
+  rvalue *m_rvalue;
+};
+
+class comment : public statement
+{
+public:
+  comment (function *func,
+	   location *loc,
+	   string *text)
+  : statement (func, loc),
+    m_text (text) {}
+
+  void replay_into (replayer *r);
+
+private:
+  string *m_text;
+};
+
+class conditional : public statement
+{
+public:
+  conditional (function *func,
+	       location *loc,
+	       rvalue *boolval,
+	       label *on_true,
+	       label *on_false)
+  : statement (func, loc),
+    m_boolval (boolval),
+    m_on_true (on_true),
+    m_on_false (on_false) {}
+
+  void replay_into (replayer *r);
+
+private:
+  rvalue *m_boolval;
+  label *m_on_true;
+  label *m_on_false;
+};
+
+class place_label : public statement
+{
+public:
+  place_label (function *func,
+	       location *loc,
+	       label *lab)
+  : statement (func, loc),
+    m_label (lab) {}
+
+  void replay_into (replayer *r);
+
+private:
+  label *m_label;
+};
+
+class jump : public statement
+{
+public:
+  jump (function *func,
+	location *loc,
+	label *target)
+  : statement (func, loc),
+    m_target (target) {}
+
+  void replay_into (replayer *r);
+
+private:
+  label *m_target;
+};
+
+class return_ : public statement
+{
+public:
+  return_ (function *func,
+	   location *loc,
+	   rvalue *rvalue)
+  : statement (func, loc),
+    m_rvalue (rvalue) {}
+
+  void replay_into (replayer *r);
+
+private:
+  rvalue *m_rvalue;
+};
+
+class loop : public memento
+{
+public:
+  loop (function *func,
+	location *loc,
+	rvalue *boolval)
+  : memento (func->m_ctxt),
+    m_func (func),
+    m_loc (loc),
+    m_boolval (boolval) {}
+
+  void replay_into (replayer *r);
+
+  void end (location *loc);
+
+  playback::loop *
+  playback_loop ()
+  {
+    return static_cast <playback::loop *> (m_playback_obj);
+  }
+
+private:
+  function *m_func;
+  location *m_loc;
+  rvalue *m_boolval;
+};
+
+class loop_end : public memento
+{
+public:
+  loop_end (loop *loop,
+	    location *loc)
+  : memento (loop->m_ctxt),
+    m_loop (loop),
+    m_loc (loc)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  loop *m_loop;
+  location *m_loc;
+};
+
+} // namespace gcc::jit::recording
+
+/* The result of JIT-compilation.  */
+class result
+{
+public:
+  result(void *dso_handle);
+
+  virtual ~result();
+
+  void *
+  get_code (const char *funcname);
+
+private:
+  void *m_dso_handle;
+};
+
+/**********************************************************************
+ Playback.
+ **********************************************************************/
+
+namespace playback {
 
-/* A JIT-compilation context.  */
 class context
 {
 public:
+  context (::gcc::jit::recording::context *ctxt);
   ~context ();
 
   void gt_ggc_mx ();
 
-  void
-  set_code_factory (gcc_jit_code_callback cb,
-		    void *user_data);
+  void replay ();
 
   location *
   new_location (const char *filename,
@@ -58,9 +1187,7 @@  public:
   type *
   new_struct_type (location *loc,
 		   const char *name,
-		   int num_fields,
-		   field **fields);
-
+		   vec<field *> *fields);
 
   param *
   new_param (location *loc,
@@ -72,8 +1199,7 @@  public:
 		enum gcc_jit_function_kind kind,
 		type *return_type,
 		const char *name,
-		int num_params,
-		param **params,
+		vec<param *> *params,
 		int is_variadic);
 
   lvalue *
@@ -116,7 +1242,7 @@  public:
   rvalue *
   new_call (location *loc,
 	    function *func,
-	    int numargs , rvalue **args);
+	    vec<rvalue *> args);
 
   rvalue *
   new_array_lookup (location *loc,
@@ -138,31 +1264,25 @@  public:
   const char *
   get_str_option (enum gcc_jit_str_option opt) const
   {
-    return m_str_options[opt];
+    return m_recording_ctxt->get_str_option (opt);
   }
 
   int
   get_int_option (enum gcc_jit_int_option opt) const
   {
-    return m_int_options[opt];
+    return m_recording_ctxt->get_int_option (opt);
   }
 
   int
   get_bool_option (enum gcc_jit_bool_option opt) const
   {
-    return m_bool_options[opt];
+    return m_recording_ctxt->get_bool_option (opt);
   }
 
   result *
   compile ();
 
   void
-  invoke_code_factory ();
-
-  bool
-  within_code_factory () const { return m_within_code_factory; }
-
-  void
   add_error (const char *fmt, ...)
       GNU_PRINTF(2, 3);
 
@@ -195,23 +1315,13 @@  private:
 
   void handle_locations ();
 
-
-  /* Did errors occur in the client callback (either recorded
-     by our internal checking, or reported by the client).  */
   bool errors_occurred () const
   {
-    return m_error_count || m_cb_result;
+    return m_recording_ctxt->errors_occurred ();
   }
 
-
 private:
-  gcc_jit_code_callback m_code_factory;
-  bool m_within_code_factory;
-  void *m_user_data;
-
-  int m_error_count;
-  char m_first_error_str[1024];
-  int m_cb_result; /* Result from client-provided code factory.  */
+  ::gcc::jit::recording::context *m_recording_ctxt;
 
   /* Allocated using xmalloc (by xstrdup).  */
   char *m_path_template;
@@ -225,9 +1335,6 @@  private:
   char *m_path_so_file;
 
   vec<function *> m_functions;
-  const char *m_str_options[GCC_JIT_NUM_STR_OPTIONS];
-  int m_int_options[GCC_JIT_NUM_INT_OPTIONS];
-  bool m_bool_options[GCC_JIT_NUM_BOOL_OPTIONS];
   tree m_char_array_type_node;
   tree m_const_char_ptr;
 
@@ -237,25 +1344,8 @@  private:
   vec<std::pair<tree, location *> > m_cached_locations;
 };
 
-/* The result of JIT-compilation.  */
-class result
-{
-public:
-  result(void *dso_handle);
-
-  virtual ~result();
-
-  void *
-  get_code (const char *funcname);
-
-private:
-  void *m_dso_handle;
-};
-
-extern context *active_jit_ctxt;
-
 /* A temporary wrapper object.
-   These objects are (mostly) only valid within the code factory callback.
+   These objects are (mostly) only valid during replay.
    We allocate them on the GC heap, so that they will be cleaned
    the next time the GC collects.
    The exception is the "function" class, which is tracked and marked by
@@ -542,6 +1632,10 @@  private:
   int m_column_num;
 };
 
+} // namespace gcc::jit::playback
+
+extern playback::context *active_playback_ctxt;
+
 } // namespace gcc::jit
 
 } // namespace gcc
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index d094def..b0b6020 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -8,7 +8,7 @@ 
 #include "libgccjit.h"
 #include "internal-api.h"
 
-struct gcc_jit_context : public gcc::jit::context
+struct gcc_jit_context : public gcc::jit::recording::context
 {
 };
 
@@ -16,39 +16,39 @@  struct gcc_jit_result : public gcc::jit::result
 {
 };
 
-struct gcc_jit_location : public gcc::jit::location
+struct gcc_jit_location : public gcc::jit::recording::location
 {
 };
 
-struct gcc_jit_type : public gcc::jit::type
+struct gcc_jit_type : public gcc::jit::recording::type
 {
 };
 
-struct gcc_jit_field : public gcc::jit::field
+struct gcc_jit_field : public gcc::jit::recording::field
 {
 };
 
-struct gcc_jit_function : public gcc::jit::function
+struct gcc_jit_function : public gcc::jit::recording::function
 {
 };
 
-struct gcc_jit_label : public gcc::jit::label
+struct gcc_jit_label : public gcc::jit::recording::label
 {
 };
 
-struct gcc_jit_rvalue : public gcc::jit::rvalue
+struct gcc_jit_rvalue : public gcc::jit::recording::rvalue
 {
 };
 
-struct gcc_jit_lvalue : public gcc::jit::lvalue
+struct gcc_jit_lvalue : public gcc::jit::recording::lvalue
 {
 };
 
-struct gcc_jit_param : public gcc::jit::param
+struct gcc_jit_param : public gcc::jit::recording::param
 {
 };
 
-struct gcc_jit_loop : public gcc::jit::loop
+struct gcc_jit_loop : public gcc::jit::recording::loop
 {
 };
 
@@ -85,35 +85,6 @@  struct gcc_jit_loop : public gcc::jit::loop
       }								\
   JIT_END_STMT
 
-/* Check that CTXT is non-NULL, and that is is before the callback.  */
-#define RETURN_IF_NOT_INITIAL_CTXT(CTXT)			\
-  JIT_BEGIN_STMT						\
-    RETURN_IF_FAIL ((CTXT), (CTXT), "NULL context");		\
-    RETURN_IF_FAIL (!(CTXT)->within_code_factory (),		\
-		    (CTXT),					\
-		    ("erroneously used within code factory"	\
-		     " callback"));				\
-  JIT_END_STMT
-
-#define RETURN_NULL_IF_NOT_INITIAL_CTXT(CTXT)				\
-  JIT_BEGIN_STMT							\
-    RETURN_NULL_IF_FAIL ((CTXT), (CTXT), "NULL context");		\
-    RETURN_NULL_IF_FAIL (!(CTXT)->within_code_factory (),		\
-			 (CTXT),					\
-			 ("erroneously used within code factory"	\
-			  " callback"));				\
-  JIT_END_STMT
-
-/* Check that CTXT is non-NULL, and that is is within the callback.  */
-#define RETURN_NULL_IF_NOT_CALLBACK_CTXT(CTXT)				\
-  JIT_BEGIN_STMT							\
-    RETURN_NULL_IF_FAIL ((CTXT), (CTXT), "NULL context");		\
-    RETURN_NULL_IF_FAIL ((CTXT)->within_code_factory (),		\
-			 (CTXT),					\
-			 ("erroneously used outside of code factory"	\
-			  " callback"));				\
-  JIT_END_STMT
-
 /* Check that FUNC is non-NULL, and that it's OK to add statements to
    it.  */
 #define RETURN_IF_NOT_FUNC_DEFINITION(FUNC) \
@@ -142,11 +113,6 @@  jit_error (gcc_jit_context *ctxt, const char *fmt, ...)
   va_list ap;
   va_start (ap, fmt);
 
-  /* If no context was given/known, try to report it on the active
-     context, if any.  */
-  if (!ctxt)
-    ctxt = (gcc_jit_context *)gcc::jit::active_jit_ctxt;
-
   if (ctxt)
     ctxt->add_error_va (fmt, ap);
   else
@@ -170,18 +136,6 @@  gcc_jit_context_release (gcc_jit_context *ctxt)
   delete ctxt;
 }
 
-void
-gcc_jit_context_set_code_factory (gcc_jit_context *ctxt,
-				  gcc_jit_code_callback cb,
-				  void *user_data)
-{
-  RETURN_IF_NOT_INITIAL_CTXT (ctxt);
-  RETURN_IF_FAIL (cb, ctxt, "NULL callback");
-  /* user_data can be anything.  */
-
-  ctxt->set_code_factory (cb, user_data);
-}
-
 /**********************************************************************
  Functions for use within the code factory.
  **********************************************************************/
@@ -191,7 +145,7 @@  gcc_jit_context_new_location (gcc_jit_context *ctxt,
 			      int line,
 			      int column)
 {
-  RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
 
   return (gcc_jit_location *)ctxt->new_location (filename, line, column);
 }
@@ -200,7 +154,7 @@  gcc_jit_type *
 gcc_jit_context_get_type (gcc_jit_context *ctxt,
 			  enum gcc_jit_types type)
 {
-  RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
   /* The inner function checks "type" for us.  */
 
   return (gcc_jit_type *)ctxt->get_type (type);
@@ -210,7 +164,6 @@  gcc_jit_type *
 gcc_jit_type_get_pointer (gcc_jit_type *type)
 {
   RETURN_NULL_IF_FAIL (type, NULL, "NULL type");
-  /* can't check for WITHIN_CALLBACK */
 
   return (gcc_jit_type *)type->get_pointer ();
 }
@@ -219,7 +172,6 @@  gcc_jit_type *
 gcc_jit_type_get_const (gcc_jit_type *type)
 {
   RETURN_NULL_IF_FAIL (type, NULL, "NULL type");
-  /* can't check for WITHIN_CALLBACK */
 
   return (gcc_jit_type *)type->get_const ();
 }
@@ -230,7 +182,7 @@  gcc_jit_context_new_field (gcc_jit_context *ctxt,
 			   gcc_jit_type *type,
 			   const char *name)
 {
-  RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
   RETURN_NULL_IF_FAIL (type, ctxt, "NULL type");
   RETURN_NULL_IF_FAIL (name, ctxt, "NULL name");
 
@@ -244,7 +196,7 @@  gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,
 				 int num_fields,
 				 gcc_jit_field **fields)
 {
-  RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
   RETURN_NULL_IF_FAIL (name, ctxt, "NULL name");
   if (num_fields)
     RETURN_NULL_IF_FAIL (fields, ctxt, "NULL fields ptr");
@@ -252,7 +204,7 @@  gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,
     RETURN_NULL_IF_FAIL (fields[i], ctxt, "NULL field ptr");
 
   return (gcc_jit_type *)ctxt->new_struct_type (loc, name, num_fields,
-						(gcc::jit::field **)fields);
+						(gcc::jit::recording::field **)fields);
 }
 
 
@@ -263,7 +215,7 @@  gcc_jit_context_new_param (gcc_jit_context *ctxt,
 			   gcc_jit_type *type,
 			   const char *name)
 {
-  RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
   RETURN_NULL_IF_FAIL (type, ctxt, "NULL type");
   RETURN_NULL_IF_FAIL (name, ctxt, "NULL name");
 
@@ -274,7 +226,6 @@  gcc_jit_lvalue *
 gcc_jit_param_as_lvalue (gcc_jit_param *param)
 {
   RETURN_NULL_IF_FAIL (param, NULL, "NULL param");
-  /* can't check for WITHIN_CALLBACK */
 
   return (gcc_jit_lvalue *)param->as_lvalue ();
 }
@@ -283,7 +234,6 @@  gcc_jit_rvalue *
 gcc_jit_param_as_rvalue (gcc_jit_param *param)
 {
   RETURN_NULL_IF_FAIL (param, NULL, "NULL param");
-  /* can't check for WITHIN_CALLBACK */
 
   return (gcc_jit_rvalue *)param->as_rvalue ();
 }
@@ -298,7 +248,7 @@  gcc_jit_context_new_function (gcc_jit_context *ctxt,
 			      gcc_jit_param **params,
 			      int is_variadic)
 {
-  RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
   RETURN_NULL_IF_FAIL (return_type, ctxt, "NULL return_type");
   RETURN_NULL_IF_FAIL (name, ctxt, "NULL name");
   RETURN_NULL_IF_FAIL ((num_params == 0) || params, ctxt, "NULL params");
@@ -312,7 +262,7 @@  gcc_jit_context_new_function (gcc_jit_context *ctxt,
   return (gcc_jit_function*)
     ctxt->new_function (loc, kind, return_type, name,
 			num_params,
-			(gcc::jit::param **)params,
+			(gcc::jit::recording::param **)params,
 			is_variadic);
 }
 
@@ -320,7 +270,6 @@  gcc_jit_label*
 gcc_jit_function_new_forward_label (gcc_jit_function *func,
 				    const char *name)
 {
-  /* can't check for WITHIN_CALLBACK */
   RETURN_NULL_IF_FAIL (func, NULL, "NULL function");
   /* name can be NULL.  */
 
@@ -333,7 +282,7 @@  gcc_jit_context_new_global (gcc_jit_context *ctxt,
 			    gcc_jit_type *type,
 			    const char *name)
 {
-  RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
   RETURN_NULL_IF_FAIL (type, ctxt, "NULL type");
   RETURN_NULL_IF_FAIL (name, ctxt, "NULL name");
 
@@ -344,7 +293,6 @@  gcc_jit_rvalue *
 gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue *lvalue)
 {
   RETURN_NULL_IF_FAIL (lvalue, NULL, "NULL lvalue");
-  /* can't check for WITHIN_CALLBACK */
 
   return (gcc_jit_rvalue *)lvalue->as_rvalue ();
 }
@@ -354,7 +302,7 @@  gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt,
 				     gcc_jit_type *type,
 				     int value)
 {
-  RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
   RETURN_NULL_IF_FAIL (type, ctxt, "NULL type");
 
   return (gcc_jit_rvalue *)ctxt->new_rvalue_from_int (type, value);
@@ -364,7 +312,7 @@  gcc_jit_rvalue *
 gcc_jit_context_zero (gcc_jit_context *ctxt,
 		      gcc_jit_type *type)
 {
-  RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
   RETURN_NULL_IF_FAIL (type, ctxt, "NULL type");
 
   return gcc_jit_context_new_rvalue_from_int (ctxt, type, 0);
@@ -374,7 +322,7 @@  gcc_jit_rvalue *
 gcc_jit_context_one (gcc_jit_context *ctxt,
 		     gcc_jit_type *type)
 {
-  RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
   RETURN_NULL_IF_FAIL (type, ctxt, "NULL type");
 
   return gcc_jit_context_new_rvalue_from_int (ctxt, type, 1);
@@ -385,7 +333,7 @@  gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt,
 					gcc_jit_type *type,
 					double value)
 {
-  RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
   RETURN_NULL_IF_FAIL (type, ctxt, "NULL type");
 
   return (gcc_jit_rvalue *)ctxt->new_rvalue_from_double (type, value);
@@ -396,7 +344,7 @@  gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt,
 				     gcc_jit_type *type,
 				     void *value)
 {
-  RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
   RETURN_NULL_IF_FAIL (type, ctxt, "NULL type");
 
   return (gcc_jit_rvalue *)ctxt->new_rvalue_from_ptr (type, value);
@@ -406,7 +354,7 @@  gcc_jit_rvalue *
 gcc_jit_context_new_string_literal (gcc_jit_context *ctxt,
 				    const char *value)
 {
-  RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
   RETURN_NULL_IF_FAIL (value, ctxt, "NULL value");
 
   return (gcc_jit_rvalue *)ctxt->new_string_literal (value);
@@ -419,7 +367,7 @@  gcc_jit_context_new_unary_op (gcc_jit_context *ctxt,
 			      gcc_jit_type *result_type,
 			      gcc_jit_rvalue *rvalue)
 {
-  RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
   /* op is checked by the inner function.  */
   RETURN_NULL_IF_FAIL (result_type, ctxt, "NULL result_type");
   RETURN_NULL_IF_FAIL (rvalue, ctxt, "NULL rvalue");
@@ -434,7 +382,7 @@  gcc_jit_context_new_binary_op (gcc_jit_context *ctxt,
 			       gcc_jit_type *result_type,
 			       gcc_jit_rvalue *a, gcc_jit_rvalue *b)
 {
-  RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
   /* op is checked by the inner function.  */
   RETURN_NULL_IF_FAIL (result_type, ctxt, "NULL result_type");
   RETURN_NULL_IF_FAIL (a, ctxt, "NULL a");
@@ -449,7 +397,7 @@  gcc_jit_context_new_comparison (gcc_jit_context *ctxt,
 				enum gcc_jit_comparison op,
 				gcc_jit_rvalue *a, gcc_jit_rvalue *b)
 {
-  RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
   /* op is checked by the inner function.  */
   RETURN_NULL_IF_FAIL (a, ctxt, "NULL a");
   RETURN_NULL_IF_FAIL (b, ctxt, "NULL b");
@@ -463,7 +411,7 @@  gcc_jit_context_new_call (gcc_jit_context *ctxt,
 			  gcc_jit_function *func,
 			  int numargs , gcc_jit_rvalue **args)
 {
-  RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
   RETURN_NULL_IF_FAIL (func, ctxt, "NULL function");
   if (numargs)
     RETURN_NULL_IF_FAIL (args, ctxt, "NULL args");
@@ -471,7 +419,7 @@  gcc_jit_context_new_call (gcc_jit_context *ctxt,
   return (gcc_jit_rvalue *)ctxt->new_call (loc,
 					   func,
 					   numargs,
-					   (gcc::jit::rvalue **)args);
+					   (gcc::jit::recording::rvalue **)args);
 }
 
 extern gcc_jit_rvalue *
@@ -480,7 +428,7 @@  gcc_jit_context_new_array_lookup (gcc_jit_context *ctxt,
 				  gcc_jit_rvalue *ptr,
 				  gcc_jit_rvalue *index)
 {
-  RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
   RETURN_NULL_IF_FAIL (ptr, ctxt, "NULL ptr");
   RETURN_NULL_IF_FAIL (index, ctxt, "NULL index");
 
@@ -609,18 +557,10 @@  gcc_jit_function_add_assignment_op (gcc_jit_function *func,
 {
   RETURN_IF_NOT_FUNC_DEFINITION (func);
   RETURN_IF_FAIL (lvalue, NULL, "NULL lvalue");
-  /* op is checked by new_binary_op */
+  /* FIXME: op is checked by new_binary_op */
   RETURN_IF_FAIL (rvalue, NULL, "NULL rvalue");
 
-  gcc_jit_type *type = (gcc_jit_type *)lvalue->get_type ();
-  gcc_jit_function_add_assignment (
-    func, loc,
-    lvalue,
-    gcc_jit_context_new_binary_op (
-      (gcc_jit_context *)func->m_ctxt,
-      loc, op, type,
-      gcc_jit_lvalue_as_rvalue (lvalue),
-      rvalue));
+  return func->add_assignment_op (loc, lvalue, op, rvalue);
 }
 
 void
@@ -700,7 +640,7 @@  gcc_jit_context_set_str_option (gcc_jit_context *ctxt,
 				enum gcc_jit_str_option opt,
 				const char *value)
 {
-  RETURN_IF_NOT_INITIAL_CTXT (ctxt);
+  RETURN_IF_FAIL (ctxt, NULL, "NULL context");
   /* opt is checked by the inner function.
      value can be NULL.  */
 
@@ -712,7 +652,7 @@  gcc_jit_context_set_int_option (gcc_jit_context *ctxt,
 				enum gcc_jit_int_option opt,
 				int value)
 {
-  RETURN_IF_NOT_INITIAL_CTXT (ctxt);
+  RETURN_IF_FAIL (ctxt, NULL, "NULL context");
   /* opt is checked by the inner function.  */
 
   ctxt->set_int_option (opt, value);
@@ -723,7 +663,7 @@  gcc_jit_context_set_bool_option (gcc_jit_context *ctxt,
 				 enum gcc_jit_bool_option opt,
 				 int value)
 {
-  RETURN_IF_NOT_INITIAL_CTXT (ctxt);
+  RETURN_IF_FAIL (ctxt, NULL, "NULL context");
   /* opt is checked by the inner function.  */
 
   ctxt->set_bool_option (opt, value);
@@ -732,7 +672,7 @@  gcc_jit_context_set_bool_option (gcc_jit_context *ctxt,
 gcc_jit_result *
 gcc_jit_context_compile (gcc_jit_context *ctxt)
 {
-  RETURN_NULL_IF_NOT_INITIAL_CTXT (ctxt);
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
 
   return (gcc_jit_result *)ctxt->compile ();
 }
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index dd287e8..7f4f2d0 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -14,16 +14,14 @@  extern "C" {
 /* All structs within the API are opaque. */
 
 /* A gcc_jit_context encapsulates the state of a compilation.  It goes
-   through three states:
+   through two states:
 
-   (1) "initial", during which you can set up options on it.
-       Invoking gcc_jit_context_compile on it transisions it to the
-       "within compilation" state.
+   (1) "initial", during which you can set up options on it, and add
+       types, functions and code, using the API below.
+       Invoking gcc_jit_context_compile on it transitions it to the
+       "after compilation" state.
 
-   (2) "within compilation", during which you can call functions to create
-       code.
-
-   (3) "after compilation", when you can call gcc_jit_context_release to
+   (2) "after compilation", when you can call gcc_jit_context_release to
        clean up.  */
 typedef struct gcc_jit_context gcc_jit_context;
 
@@ -75,9 +73,6 @@  typedef struct gcc_jit_param gcc_jit_param;
    to manually manage gcc_jit_label instances.  */
 typedef struct gcc_jit_loop gcc_jit_loop;
 
-/**********************************************************************
- Functions for use outside of the code-creation callback.
- **********************************************************************/
 /*
    Acquire a JIT-compilation context.
 
@@ -91,27 +86,6 @@  gcc_jit_context_acquire (void);
 extern void
 gcc_jit_context_release (gcc_jit_context *ctxt);
 
-/* A function-pointer type.
-   This is the client-provided hook for calling into the code-generation
-   API.
-   It should return 0 if there were no errors, or nonzero if errors
-   occurred (e.g. within client code that the library has no knowledge
-   of).  */
-typedef int (*gcc_jit_code_callback) (gcc_jit_context *ctxt,
-				      void *user_data);
-
-extern void
-gcc_jit_context_set_code_factory (gcc_jit_context *ctxt,
-				  gcc_jit_code_callback cb,
-				  void *user_data);
-     /* clearly I'm handwaving for now about the details of what that
-	callback looks like, but by doing it in a callback we also
-	avoid dealing with lifetimes of the results: entities can
-	only be referenced within the lifetime of the callback - once
-	control returns out of the callback, you can't use them.  This
-	avoids having to expose details of GCC's garbage-collector,
-	I hope. */
-
 /* Options taking string values. */
 enum gcc_jit_str_option
 {
@@ -245,11 +219,14 @@  gcc_jit_result_release (gcc_jit_result *result);
 
 
 /**********************************************************************
- Functions for use within the code factory.
+ Functions for creating "contextual" objects.
+
+ All objects created by these functions share the lifetime of the context
+ they are created within, and are automatically cleaned up for you when
+ you call gcc_jit_context_release on the context.
 
- All objects created by these functions are cleaned up for you, after
- your code-creation hook returns.  Note that this means you can't hold
- references to them for use after you return from your callback.
+ Note that this means you can't use references to them after you've
+ released their context.
 
  All (const char *) string arguments passed to these functions are
  copied, so you don't need to keep them around.  Note that this *isn't*
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index bcb4411..3a123f3 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -24,7 +24,6 @@ 
     gcc_jit_context_one;
     gcc_jit_context_release;
     gcc_jit_context_set_bool_option;
-    gcc_jit_context_set_code_factory;
     gcc_jit_context_set_int_option;
     gcc_jit_context_set_str_option;
     gcc_jit_context_zero;
diff --git a/gcc/jit/notes.txt b/gcc/jit/notes.txt
index 2c225ce..5f8a21e 100644
--- a/gcc/jit/notes.txt
+++ b/gcc/jit/notes.txt
@@ -3,6 +3,12 @@  Client Code   . Generated .            libgccjit.so
               .           . JIT API  . JIT "Frontend". (libbackend.a)
 ....................................................................................
    │          .           .          .               .
+    ──────────────────────────>      .               .
+              .           .    │     .               .
+
+              .       (record API calls)             .
+              .           .    │     .               .
+   <───────────────────────────      .               .
    │          .           .          .               .
    │          .           .          .               .
    V          .           .  gcc_jit_context_compile .
@@ -20,26 +26,12 @@  Client Code   . Generated .            libgccjit.so
               .           .          .    │ (jit_langhook_parse_file)
               .           .          .    │          .
 ..........................................│..................VVVVVVVVVVVVV...
- code factory .           .          .    │          .       No GC in here
- callback     .           .          .    │          .
-       <───────────────────────────────────          .
-       │      .           .          .   (invoke_cb) .
-       │      .           .  C API   .               .
-       ──────────────────────>       .               .
-              .           .  │ Internal API          .
-              .           .  ───>    .               .
-              .           .      │   .               .
-              .           .      ────────────────────────> creation of functions,
-              .           .          .               .     types, expression trees
-              .           .      <──────────────────────── etc
-              .           .  <───    .               .
-              .           .  │       .               .
-       ──────────────────────        .               .
-       │etc   .           .          .               .
-       │      .           .          .               .
-       ──────────────────────────────────>           .
-Return from client callback          .    │          .
+              .           .          .    │          .       No GC in here
               .           .          .    │          .
+              .           .          .  (playback of API calls)
+              .           .          .    ───────────────> creation of functions,
+              .           .          .               .     types, expression trees
+              .           .          .    <──────────────── etc
               .           .          .    │(handle_locations: add locations to
               .           .          .    │ linemap and associate them with trees)
               .           .          .    │          .
diff --git a/gcc/testsuite/ChangeLog.jit b/gcc/testsuite/ChangeLog.jit
index 02e73c7..924030f 100644
--- a/gcc/testsuite/ChangeLog.jit
+++ b/gcc/testsuite/ChangeLog.jit
@@ -1,3 +1,34 @@ 
+2014-01-24  David Malcolm  <dmalcolm@redhat.com>
+
+	* jit.dg/harness.h (code_making_callback): Rename to...
+	(create_code): ...this, and eliminate the returned
+	error-handling value: test cases will simply call into the
+	gcc_jit_ API, without needing to be run from a callback.
+	(test_jit): Don't register a callback, simply call the
+	"create_code" function for the testcase before compiling the
+	context.
+
+	* jit.dg/test-accessing-struct.c: Rename "code_making_callback"
+	to "create_code" and eliminate the return code.
+	* jit.dg/test-calling-external-function.c: Likewise.
+	* jit.dg/test-combination.c: Likewise.
+	* jit.dg/test-dot-product.c: Likewise.
+	* jit.dg/test-expressions.c: Likewise.
+	* jit.dg/test-factorial.c: Likewise.
+	* jit.dg/test-fibonacci.c: Likewise.
+	* jit.dg/test-fuzzer.c: Likewise.
+	* jit.dg/test-hello-world.c: Likewise.
+	* jit.dg/test-null-passed-to-api.c: Likewise.
+	* jit.dg/test-quadratic.c: Likewise.
+	* jit.dg/test-reading-struct.c: Likewise.
+	* jit.dg/test-string-literal.c: Likewise.
+	* jit.dg/test-sum-of-squares.c: Likewise.
+	* jit.dg/test-types.c: Likewise.
+	* jit.dg/test-using-global.c: Likewise.
+
+	* jit.dg/test-failure.c: Remove this test case, since it was
+	specifically for testing the now-defunct callback-based API.
+
 2014-01-23  David Malcolm  <dmalcolm@redhat.com>
 
 	* jit.dg/test-quadratic.c: New test case, written to achieve test
diff --git a/gcc/testsuite/jit.dg/harness.h b/gcc/testsuite/jit.dg/harness.h
index 353c7c1..c9b8a3d 100644
--- a/gcc/testsuite/jit.dg/harness.h
+++ b/gcc/testsuite/jit.dg/harness.h
@@ -4,8 +4,8 @@ 
   This file contains "main" and support code.
   Each testcase should implement the following hooks:
 
-    extern int
-    code_making_callback (gcc_jit_context *ctxt, void * user_data);
+    extern void
+    create_code (gcc_jit_context *ctxt, void * user_data);
 
     extern void
     verify_code (gcc_jit_context *ctxt, gcc_jit_result *result);
@@ -51,8 +51,8 @@  static char test[1024];
   check_string_value ((ACTUAL), (EXPECTED));
 
 /* Hooks that testcases should provide.  */
-extern int
-code_making_callback (gcc_jit_context *ctxt, void * user_data);
+extern void
+create_code (gcc_jit_context *ctxt, void * user_data);
 
 extern void
 verify_code (gcc_jit_context *ctxt, gcc_jit_result *result);
@@ -101,8 +101,6 @@  test_jit (const char *argv0, void *user_data)
   ctxt = gcc_jit_context_acquire ();
      /* FIXME: error-handling */
 
-  gcc_jit_context_set_code_factory (ctxt, code_making_callback, user_data);
-
   /* Set up options.  */
   gcc_jit_context_set_str_option (
     ctxt,
@@ -133,6 +131,8 @@  test_jit (const char *argv0, void *user_data)
     GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
     1);
 
+  create_code (ctxt, user_data);
+
   /* This actually calls into GCC and runs the build, all
      in a mutex for now.  */
   result = gcc_jit_context_compile (ctxt);
diff --git a/gcc/testsuite/jit.dg/test-accessing-struct.c b/gcc/testsuite/jit.dg/test-accessing-struct.c
index 46c6f5b..031916a 100644
--- a/gcc/testsuite/jit.dg/test-accessing-struct.c
+++ b/gcc/testsuite/jit.dg/test-accessing-struct.c
@@ -12,8 +12,8 @@  struct foo
   int z;
 };
 
-int
-code_making_callback (gcc_jit_context *ctxt, void *user_data)
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
 {
   /* Let's try to inject the equivalent of:
      void
@@ -83,8 +83,6 @@  code_making_callback (gcc_jit_context *ctxt, void *user_data)
       NULL,
       "z"),
     sum);
-
-  return 0;
 }
 
 void
diff --git a/gcc/testsuite/jit.dg/test-calling-external-function.c b/gcc/testsuite/jit.dg/test-calling-external-function.c
index bfc0641..9bf2e7e 100644
--- a/gcc/testsuite/jit.dg/test-calling-external-function.c
+++ b/gcc/testsuite/jit.dg/test-calling-external-function.c
@@ -16,8 +16,8 @@  extern "C" {
 }
 #endif
 
-int
-code_making_callback (gcc_jit_context *ctxt, void *user_data)
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
 {
   /* Let's try to inject the equivalent of:
      extern void called_function (int i, int j, int k);
@@ -80,8 +80,6 @@  code_making_callback (gcc_jit_context *ctxt, void *user_data)
                               NULL,
                               called_fn,
                               3, args));
-
-    return 0;
 }
 
 static int called_with[3];
diff --git a/gcc/testsuite/jit.dg/test-combination.c b/gcc/testsuite/jit.dg/test-combination.c
index 562f031..ffdf4bb 100644
--- a/gcc/testsuite/jit.dg/test-combination.c
+++ b/gcc/testsuite/jit.dg/test-combination.c
@@ -8,97 +8,97 @@ 
 #define TEST_COMBINATION
 
 /* test-accessing-struct.c */
-#define code_making_callback code_making_callback_accessing_struct
+#define create_code create_code_accessing_struct
 #define verify_code verify_code_accessing_struct
 #include "test-accessing-struct.c"
-#undef code_making_callback
+#undef create_code
 #undef verify_code
 
 /* test-calling-external-function.c */
-#define code_making_callback code_making_callback_calling_external_function
+#define create_code create_code_calling_external_function
 #define verify_code verify_code_calling_external_function
 #include "test-calling-external-function.c"
-#undef code_making_callback
+#undef create_code
 #undef verify_code
 
 /* test-dot-product.c */
-#define code_making_callback code_making_callback_dot_product
+#define create_code create_code_dot_product
 #define verify_code verify_code_dot_product
 #include "test-dot-product.c"
-#undef code_making_callback
+#undef create_code
 #undef verify_code
 
 /* test-expressions.c */
-#define code_making_callback code_making_callback_expressions
+#define create_code create_code_expressions
 #define verify_code verify_code_expressions
 #include "test-expressions.c"
-#undef code_making_callback
+#undef create_code
 #undef verify_code
 
 /* test-factorial.c */
-#define code_making_callback code_making_callback_factorial
+#define create_code create_code_factorial
 #define verify_code verify_code_factorial
 #include "test-factorial.c"
-#undef code_making_callback
+#undef create_code
 #undef verify_code
 
 /* We don't use test-failure.c; we don't want its failure to affect our
    combined case.  */
 
 /* test-fibonacci.c */
-#define code_making_callback code_making_callback_fibonacci
+#define create_code create_code_fibonacci
 #define verify_code verify_code_fibonacci
 #include "test-fibonacci.c"
-#undef code_making_callback
+#undef create_code
 #undef verify_code
 
 /* test-hello-world.c */
-#define code_making_callback code_making_callback_hello_world
+#define create_code create_code_hello_world
 #define verify_code verify_code_hello_world
 #include "test-hello-world.c"
-#undef code_making_callback
+#undef create_code
 #undef verify_code
 
 /* test-quadratic.c */
-#define code_making_callback code_making_callback_quadratic
+#define create_code create_code_quadratic
 #define verify_code verify_code_quadratic
 #include "test-quadratic.c"
-#undef code_making_callback
+#undef create_code
 #undef verify_code
 
 /* test-reading-struct.c */
-#define code_making_callback code_making_callback_reading_struct
+#define create_code create_code_reading_struct
 #define verify_code verify_code_reading_struct
 #include "test-reading-struct.c"
-#undef code_making_callback
+#undef create_code
 #undef verify_code
 
 /* test-string-literal.c */
-#define code_making_callback code_making_callback_string_literal
+#define create_code create_code_string_literal
 #define verify_code verify_code_string_literal
 #include "test-string-literal.c"
-#undef code_making_callback
+#undef create_code
 #undef verify_code
 
 /* test-sum-of-squares.c */
-#define code_making_callback code_making_callback_sum_of_squares
+#define create_code create_code_sum_of_squares
 #define verify_code verify_code_sum_of_squares
 #include "test-sum-of-squares.c"
-#undef code_making_callback
+#undef create_code
 #undef verify_code
 
 /* test-types.c */
-#define code_making_callback code_making_callback_types
+#define create_code create_code_types
 #define verify_code verify_code_types
 #include "test-types.c"
-#undef code_making_callback
+#undef create_code
 #undef verify_code
 
 /* test-using-global.c */
-#define code_making_callback code_making_callback_using_global
+#define create_code create_code_using_global
 #define verify_code verify_code_using_global
 #include "test-using-global.c"
-#undef code_making_callback
+#undef create_code
 #undef verify_code
 
 /* Now construct a test case from all the other test cases.
@@ -109,23 +109,20 @@ 
 #include "harness.h"
 
 /* Our testing hooks are the combination of the other test cases.  */
-int
-code_making_callback (gcc_jit_context *ctxt, void * user_data)
+void
+create_code (gcc_jit_context *ctxt, void * user_data)
 {
-  int errors = 0;
-  errors += code_making_callback_accessing_struct (ctxt, user_data);
-  errors += code_making_callback_calling_external_function (ctxt, user_data);
-  errors += code_making_callback_dot_product (ctxt, user_data);
-  errors += code_making_callback_expressions (ctxt, user_data);
-  errors += code_making_callback_factorial (ctxt, user_data);
-  errors += code_making_callback_fibonacci (ctxt, user_data);
-  errors += code_making_callback_hello_world (ctxt, user_data);
-  errors += code_making_callback_string_literal (ctxt, user_data);
-  errors += code_making_callback_sum_of_squares (ctxt, user_data);
-  errors += code_making_callback_types (ctxt, user_data);
-  errors += code_making_callback_using_global (ctxt, user_data);
-
-  return errors;
+  create_code_accessing_struct (ctxt, user_data);
+  create_code_calling_external_function (ctxt, user_data);
+  create_code_dot_product (ctxt, user_data);
+  create_code_expressions (ctxt, user_data);
+  create_code_factorial (ctxt, user_data);
+  create_code_fibonacci (ctxt, user_data);
+  create_code_hello_world (ctxt, user_data);
+  create_code_string_literal (ctxt, user_data);
+  create_code_sum_of_squares (ctxt, user_data);
+  create_code_types (ctxt, user_data);
+  create_code_using_global (ctxt, user_data);
 }
 
 void
diff --git a/gcc/testsuite/jit.dg/test-dot-product.c b/gcc/testsuite/jit.dg/test-dot-product.c
index dffccae..0cc6282 100644
--- a/gcc/testsuite/jit.dg/test-dot-product.c
+++ b/gcc/testsuite/jit.dg/test-dot-product.c
@@ -6,8 +6,8 @@ 
 
 #include "harness.h"
 
-int
-code_making_callback (gcc_jit_context *ctxt, void *user_data)
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
 {
   /* Let's try to inject the equivalent of:
 
@@ -94,8 +94,6 @@  code_making_callback (gcc_jit_context *ctxt, void *user_data)
     func,
     NULL,
     gcc_jit_lvalue_as_rvalue (result));
-
-  return 0;
 }
 
 void
diff --git a/gcc/testsuite/jit.dg/test-expressions.c b/gcc/testsuite/jit.dg/test-expressions.c
index b224347..43d548f 100644
--- a/gcc/testsuite/jit.dg/test-expressions.c
+++ b/gcc/testsuite/jit.dg/test-expressions.c
@@ -550,16 +550,14 @@  verify_get_address (gcc_jit_result *result)
  Code for harness
  **********************************************************************/
 
-int
-code_making_callback (gcc_jit_context *ctxt, void *user_data)
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
 {
   make_tests_of_unary_ops (ctxt);
   make_tests_of_binary_ops (ctxt);
   make_tests_of_comparisons (ctxt);
   make_tests_of_dereferences (ctxt);
   make_test_of_get_address (ctxt);
-
-  return 0;
 }
 
 void
diff --git a/gcc/testsuite/jit.dg/test-factorial.c b/gcc/testsuite/jit.dg/test-factorial.c
index 758cd2d..d71db9f 100644
--- a/gcc/testsuite/jit.dg/test-factorial.c
+++ b/gcc/testsuite/jit.dg/test-factorial.c
@@ -6,8 +6,8 @@ 
 
 #include "harness.h"
 
-int
-code_making_callback (gcc_jit_context *ctxt, void *user_data)
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
 {
   /* Let's try to inject the equivalent of:
 
@@ -88,7 +88,6 @@  code_making_callback (gcc_jit_context *ctxt, void *user_data)
         ctxt, NULL,
         func,
         1, &x_minus_1)));
-  return 0;
 }
 
 void
diff --git a/gcc/testsuite/jit.dg/test-failure.c b/gcc/testsuite/jit.dg/test-failure.c
deleted file mode 100644
index 4a7b788..0000000
--- a/gcc/testsuite/jit.dg/test-failure.c
+++ /dev/null
@@ -1,19 +0,0 @@ 
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "libgccjit.h"
-
-#include "harness.h"
-
-int
-code_making_callback (gcc_jit_context *ctxt, void *user_data)
-{
-  return 1;
-}
-
-void
-verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
-{
-  CHECK_VALUE (result, NULL);
-}
-
diff --git a/gcc/testsuite/jit.dg/test-fibonacci.c b/gcc/testsuite/jit.dg/test-fibonacci.c
index 23903fa..63e9bbb 100644
--- a/gcc/testsuite/jit.dg/test-fibonacci.c
+++ b/gcc/testsuite/jit.dg/test-fibonacci.c
@@ -6,8 +6,8 @@ 
 
 #include "harness.h"
 
-int
-code_making_callback (gcc_jit_context *ctxt, void *user_data)
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
 {
   const int FIRST_LINE = __LINE__ + 4;
   /* Let's try to inject the equivalent of:
@@ -128,7 +128,6 @@  FIRST_LINE + 7: }
 	gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 51),
 	func,
 	1, &x_minus_2)));
-  return 0;
 }
 
 void
diff --git a/gcc/testsuite/jit.dg/test-fuzzer.c b/gcc/testsuite/jit.dg/test-fuzzer.c
index d35286b..7fbb5a2 100644
--- a/gcc/testsuite/jit.dg/test-fuzzer.c
+++ b/gcc/testsuite/jit.dg/test-fuzzer.c
@@ -400,15 +400,13 @@  static gcc_jit_rvalue *get_random_rvalue (function_fuzzer *ff, int max_depth)
 
 
 /* Top-level defns for use by harness.	*/
-int
-code_making_callback (gcc_jit_context *ctxt, void *user_data)
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
 {
   fuzzer f;
   int seed = *(int*)user_data;
 
   fuzzer_init (&f, ctxt, seed);
-
-  return 0;
 }
 
 static int num_completed_compilations = 0;
diff --git a/gcc/testsuite/jit.dg/test-hello-world.c b/gcc/testsuite/jit.dg/test-hello-world.c
index 22e4e9e..5778f78 100644
--- a/gcc/testsuite/jit.dg/test-hello-world.c
+++ b/gcc/testsuite/jit.dg/test-hello-world.c
@@ -5,8 +5,8 @@ 
 
 #include "harness.h"
 
-extern int
-code_making_callback (gcc_jit_context *ctxt, void *user_data)
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
 {
   /* Let's try to inject the equivalent of:
      void
@@ -54,7 +54,6 @@  code_making_callback (gcc_jit_context *ctxt, void *user_data)
                               NULL,
                               printf_func,
                               2, args));
-  return 0;
 }
 
 extern void
diff --git a/gcc/testsuite/jit.dg/test-null-passed-to-api.c b/gcc/testsuite/jit.dg/test-null-passed-to-api.c
index 1e9d89c..ea4390b 100644
--- a/gcc/testsuite/jit.dg/test-null-passed-to-api.c
+++ b/gcc/testsuite/jit.dg/test-null-passed-to-api.c
@@ -5,8 +5,8 @@ 
 
 #include "harness.h"
 
-int
-code_making_callback (gcc_jit_context *ctxt, void *user_data)
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
 {
   /* Trigger an API error by passing bad data.  */
   gcc_jit_context_new_function (ctxt, NULL,
@@ -15,9 +15,6 @@  code_making_callback (gcc_jit_context *ctxt, void *user_data)
                                 "hello_world",
                                 0, NULL,
                                 0);
-
-  /* Client code erroneously considers that it succeeded, so returns 0.  */
-  return 0;
 }
 
 void
diff --git a/gcc/testsuite/jit.dg/test-quadratic.c b/gcc/testsuite/jit.dg/test-quadratic.c
index 7b154fe..fad4b72 100644
--- a/gcc/testsuite/jit.dg/test-quadratic.c
+++ b/gcc/testsuite/jit.dg/test-quadratic.c
@@ -446,8 +446,8 @@  make_test_quadratic (struct quadratic_test *testcase)
     gcc_jit_context_zero (testcase->ctxt, testcase->int_type));
 }
 
-int
-code_making_callback (gcc_jit_context *ctxt, void *user_data)
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
 {
   struct quadratic_test testcase;
   memset (&testcase, 0, sizeof (testcase));
@@ -456,7 +456,6 @@  code_making_callback (gcc_jit_context *ctxt, void *user_data)
   make_sqrt (&testcase);
   make_calc_discriminant (&testcase);
   make_test_quadratic (&testcase);
-  return 0;
 }
 
 void
diff --git a/gcc/testsuite/jit.dg/test-reading-struct.c b/gcc/testsuite/jit.dg/test-reading-struct.c
index 94c36fe..eeb6321 100644
--- a/gcc/testsuite/jit.dg/test-reading-struct.c
+++ b/gcc/testsuite/jit.dg/test-reading-struct.c
@@ -11,8 +11,8 @@  struct bar
   int y;
 };
 
-int
-code_making_callback (gcc_jit_context *ctxt, void *user_data)
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
 {
   /* Let's try to inject the equivalent of:
 
@@ -93,7 +93,6 @@  code_making_callback (gcc_jit_context *ctxt, void *user_data)
     gcc_jit_function_new_local (fn_test_writing, NULL,
 				struct_type,
 				"tmp");
-#if 1
   /* tmp.x = 5; */
   gcc_jit_function_add_assignment (
     fn_test_writing, NULL,
@@ -105,7 +104,6 @@  code_making_callback (gcc_jit_context *ctxt, void *user_data)
     fn_test_writing, NULL,
     gcc_jit_lvalue_access_field (local_tmp, NULL, "y"),
     gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 7));
-#endif
 
   /* return test_reading (&tmp); */
   gcc_jit_rvalue *arg = gcc_jit_lvalue_get_address (local_tmp, NULL);
@@ -116,8 +114,6 @@  code_making_callback (gcc_jit_context *ctxt, void *user_data)
       ctxt, NULL,
       fn_test_reading,
       1, &arg));
-
-  return 0;
 }
 
 void
diff --git a/gcc/testsuite/jit.dg/test-string-literal.c b/gcc/testsuite/jit.dg/test-string-literal.c
index b9ba895..5d1b15f 100644
--- a/gcc/testsuite/jit.dg/test-string-literal.c
+++ b/gcc/testsuite/jit.dg/test-string-literal.c
@@ -6,8 +6,8 @@ 
 
 #include "harness.h"
 
-int
-code_making_callback (gcc_jit_context *ctxt, void *user_data)
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
 {
   /* Let's try to inject the equivalent of:
 
@@ -32,8 +32,6 @@  code_making_callback (gcc_jit_context *ctxt, void *user_data)
   gcc_jit_function_add_return (
     test_fn, NULL,
     gcc_jit_context_new_string_literal (ctxt, "hello world"));
-
-  return 0;
 }
 
 void
diff --git a/gcc/testsuite/jit.dg/test-sum-of-squares.c b/gcc/testsuite/jit.dg/test-sum-of-squares.c
index 934d58d..10b1644 100644
--- a/gcc/testsuite/jit.dg/test-sum-of-squares.c
+++ b/gcc/testsuite/jit.dg/test-sum-of-squares.c
@@ -6,8 +6,8 @@ 
 
 #include "harness.h"
 
-int
-code_making_callback (gcc_jit_context *ctxt, void *user_data)
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
 {
   /*
     Simple sum-of-squares, to test conditionals and looping
@@ -114,8 +114,6 @@  code_making_callback (gcc_jit_context *ctxt, void *user_data)
     func,
     NULL,
     gcc_jit_lvalue_as_rvalue (sum));
-
-  return 0;
 }
 
 void
diff --git a/gcc/testsuite/jit.dg/test-types.c b/gcc/testsuite/jit.dg/test-types.c
index e4a042e..1d5758d 100644
--- a/gcc/testsuite/jit.dg/test-types.c
+++ b/gcc/testsuite/jit.dg/test-types.c
@@ -82,8 +82,8 @@  int *test_ptr = &test_int;
 
 const char *test_string = "test_string";
 
-int
-code_making_callback (gcc_jit_context *ctxt, void *user_data)
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
 {
   /* Let's try to inject the equivalent of:
 
@@ -236,8 +236,6 @@  code_making_callback (gcc_jit_context *ctxt, void *user_data)
       stderr))
 
 #undef ASSIGN
-
-  return 0;
 }
 
 void
diff --git a/gcc/testsuite/jit.dg/test-using-global.c b/gcc/testsuite/jit.dg/test-using-global.c
index f9390f8..801bcce 100644
--- a/gcc/testsuite/jit.dg/test-using-global.c
+++ b/gcc/testsuite/jit.dg/test-using-global.c
@@ -15,8 +15,8 @@  extern "C" {
 }
 #endif
 
-int
-code_making_callback (gcc_jit_context *ctxt, void *user_data)
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
 {
   /* Let's try to inject the equivalent of:
      extern int the_global;
@@ -46,8 +46,6 @@  code_making_callback (gcc_jit_context *ctxt, void *user_data)
     gcc_jit_context_new_global (ctxt, NULL, int_type, "the_global"),
     GCC_JIT_BINARY_OP_PLUS,
     gcc_jit_context_one (ctxt, int_type));
-
-    return 0;
 }
 
 int the_global;
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 9a3b345..957bf46 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -275,7 +275,7 @@  DEFTIMEVAR (TV_REBUILD_FREQUENCIES   , "rebuild frequencies")
 DEFTIMEVAR (TV_REPAIR_LOOPS	     , "repair loop structures")
 
 /* Stuff used by libgccjit.so.  */
-DEFTIMEVAR (TV_CLIENT_CALLBACK	     , "JIT client callback")
+DEFTIMEVAR (TV_JIT_REPLAY	     , "replay of JIT client activity")
 DEFTIMEVAR (TV_ASSEMBLE	     , "assemble JIT code")
 DEFTIMEVAR (TV_LINK		     , "link JIT code")
 DEFTIMEVAR (TV_LOAD		     , "load JIT result")