This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH, committed] New jit API entrypoint: gcc_jit_context_set_logfile


When attempting to debug libgccjit embedded inside PyPy I found
I needed a detailed log that tracked the various activity within
the library.

This commit adds a new API entrypoint:
  gcc_jit_context_set_logfile
allowing detailed information to be logged to a FILE *, with logging
being mostly a no-op for the default case where no logfile has been
enabled.

An example logfile can be seen as part of the commit, appearing in
the "Internals" documentation.

As well as for debugging, this may be of use for newcomers to
libgccjit's internals, to see how it fits together.

Committed to trunk as r219357.

gcc/jit/ChangeLog:
	* Make-lang.in (jit_OBJS): Add jit/jit-logging.o.
	* docs/internals/index.rst (Overview of code structure): Mention
	gcc_jit_context_set_logfile, and embed the example logfile.
	* docs/internals/test-hello-world.exe.log.txt: New file: example
	of a logfile.
	* docs/topics/contexts.rst (Debugging): Add documentation
	for gcc_jit_context_set_logfile.
	* docs/_build/texinfo/libgccjit.texi: Regenerate.
	* dummy-frontend.c: Include "jit-logging.h".
	(jit_langhook_init): Assert that there is an active playback
	context.  If it has a logger, log entry/exit to this function.
	(jit_langhook_write_globals): Likewise.
	* jit-common.h (gcc::jit::logger): New forward declaration.
	* jit-logging.c: New file.
	* jit-logging.h: New file.
	* jit-playback.c: Include "jit-logging.h".
	(gcc::jit::playback::context::context): Initialize the log_user
	base class from the recording context's logger (if any).  Use
	JIT_LOG_SCOPE to log entry/exit from the function body.
	(gcc::jit::playback::context::~context): Use JIT_LOG_SCOPE to
	log entry/exit from the function body.
	(gcc::jit::playback::build_stmt_list): Likewise.
	(gcc::jit::playback::function::postprocess): Likewise.
	(gcc::jit::playback::context::compile): Likewise.  Log the
	entry/exit to toplev::main and toplev::finalize.  Log the
	fake argv passed to toplev::main.
	(gcc::jit::playback::context::acquire_mutex): Use JIT_LOG_SCOPE to
	log entry/exit from the function body.
	(gcc::jit::playback::context::release_mutex): Likewise.
	(gcc::jit::playback::context::make_fake_args): Likewise.
	(gcc::jit::playback::context::extract_any_requested_dumps):
	Likewise.
	(gcc::jit::playback::context::convert_to_dso): Likewise. Also,
	log the arguments that the driver is invoked with.
	(gcc::jit::playback::context::dlopen_built_dso): Likewise.  Pass
	the logger to the result object.
	(gcc::jit::playback::context::replay): Use JIT_LOG_SCOPE to
	log entry/exit from the function body.
	(gcc::jit::playback::context::dump_generated_code): Likewise.
	(gcc::jit::playback::context::handle_locations): Likewise.
	* jit-playback.h (gcc::jit::playback::context): Make this be
	a subclass of gcc::jit::log_user.
	* jit-recording.c: Include "jit-logging.h".
	(gcc::jit::recording::context::context: Initialize the logger to
	NULL for root contexts, or to the parent's logger for child
	contexts.
	(gcc::jit::recording::context::~context): Use JIT_LOG_SCOPE to
	log entry/exit from the function body.
	(gcc::jit::recording::context::replay_into): Likewise.
	(gcc::jit::recording::context::disassociate_from_playback):
	Likewise.
	(gcc::jit::recording::context::compile): Likewise.
	(recording::context::add_error_va): Likewise.  Also, log the
	error.
	(gcc::jit::recording::context::validate): Use JIT_LOG_SCOPE to
	log entry/exit from the function body.
	* jit-recording.h: Include "jit-logging.h".
	(gcc::jit::recording::context): Make this be a subclass of
	gcc::jit::log_user.
	* jit-result.c: Include "jit-common.h" and "jit-logging.h".
	(gcc::jit::result::result): Add logger param, recording it.
	Use JIT_LOG_SCOPE to log entry/exit from the function body.
	(gcc::jit::result::~result(): Use JIT_LOG_SCOPE to
	log entry/exit from the function body.
	(gcc::jit::result::get_code): Likewise.
	* jit-result.h (gcc::jit::result): Make this be a subclass of
	gcc::jit::log_user.
	(gcc::jit::result::result): Add logger parameter.
	* libgccjit++.h (gccjit::context::set_logfile): New function.
	* libgccjit.c: Include "jit-logging.h".
	(gcc_jit_context_acquire): Log the context.
	(gcc_jit_context_release): Use JIT_LOG_FUNC to
	log entry/exit from the function body, and log the context.
	(gcc_jit_context_new_child_context): Likewise, logging both
	contexts.
	(gcc_jit_context_new_location): Use JIT_LOG_FUNC to
	log entry/exit from the function body.
	(gcc_jit_context_get_type): Likewise.
	(gcc_jit_context_get_int_type): Likewise.
	(gcc_jit_context_new_array_type): Likewise.
	(gcc_jit_context_new_field): Likewise.
	(gcc_jit_context_new_struct_type): Likewise.
	(gcc_jit_context_new_opaque_struct): Likewise.
	(gcc_jit_struct_set_fields): Likewise.
	(gcc_jit_context_new_union_type): Likewise.
	(gcc_jit_context_new_function_ptr_type): Likewise.
	(gcc_jit_context_new_param): Likewise.
	(gcc_jit_context_new_function): Likewise.
	(gcc_jit_context_get_builtin_function): Likewise.
	(gcc_jit_function_get_param): Likewise.
	(gcc_jit_function_dump_to_dot): Likewise.
	(gcc_jit_function_new_block): Likewise.
	(gcc_jit_context_new_global): 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_null): 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_through_ptr): Likewise.
	(gcc_jit_context_new_cast): Likewise.
	(gcc_jit_context_new_array_access): Likewise.
	(gcc_jit_lvalue_access_field): Likewise.
	(gcc_jit_rvalue_access_field): Likewise.
	(gcc_jit_rvalue_dereference_field): Likewise.
	(gcc_jit_rvalue_dereference): Likewise.
	(gcc_jit_lvalue_get_address): Likewise.
	(gcc_jit_function_new_local): Likewise.
	(gcc_jit_block_add_eval): Likewise.
	(gcc_jit_block_add_assignment): Likewise.
	(gcc_jit_block_add_assignment_op): Likewise.
	(gcc_jit_block_end_with_conditional): Likewise.
	(gcc_jit_block_add_comment): Likewise.
	(gcc_jit_block_end_with_jump): Likewise.
	(gcc_jit_block_end_with_return): Likewise.
	(gcc_jit_block_end_with_void_return): 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_enable_dump): Likewise.
	(gcc_jit_context_compile): Likewise.  Also log the context,
	and the result.
	(gcc_jit_context_dump_to_file): Likewise.
	(gcc_jit_context_set_logfile): New function.
	(gcc_jit_context_get_first_error): Use JIT_LOG_FUNC to
	log entry/exit from the function body.
	(gcc_jit_result_get_code): Likewise.  Also log the fnname)
	and the ptr to be returned.
	(gcc_jit_result_release): Likewise.  Also log the result.
	* libgccjit.h: Include <stdio.h>, since we need FILE *.
	(gcc_jit_context_set_logfile): New declaration.
	* libgccjit.map (gcc_jit_context_set_logfile): New.

gcc/testsuite/ChangeLog:
	* jit.dg/harness.h (set_up_logging): New function.
	(test_jit): Fail if gcc_jit_context_acquire fails.  Call
	set_up_logging on the context, so that every testcase is
	logged to a particular file.
	* jit.dg/test-nested-contexts.c (main): Open a logfile,
	and call gcc_jit_context_set_logfile on the top-level context.
---
 gcc/jit/Make-lang.in                               |   1 +
 gcc/jit/docs/internals/index.rst                   |   9 +
 .../docs/internals/test-hello-world.exe.log.txt    | 126 ++++++++++++++
 gcc/jit/docs/topics/contexts.rst                   |  50 ++++++
 gcc/jit/dummy-frontend.c                           |   7 +
 gcc/jit/jit-common.h                               |   1 +
 gcc/jit/jit-logging.c                              | 168 ++++++++++++++++++
 gcc/jit/jit-logging.h                              | 191 +++++++++++++++++++++
 gcc/jit/jit-playback.c                             |  36 +++-
 gcc/jit/jit-playback.h                             |   2 +-
 gcc/jit/jit-recording.c                            |  16 +-
 gcc/jit/jit-recording.h                            |   3 +-
 gcc/jit/jit-result.c                               |  13 +-
 gcc/jit/jit-result.h                               |   4 +-
 gcc/jit/libgccjit++.h                              |  15 ++
 gcc/jit/libgccjit.c                                | 133 ++++++++++++--
 gcc/jit/libgccjit.h                                |  15 ++
 gcc/jit/libgccjit.map                              |   1 +
 gcc/testsuite/jit.dg/harness.h                     |  54 +++++-
 gcc/testsuite/jit.dg/test-nested-contexts.c        |  10 ++
 20 files changed, 827 insertions(+), 28 deletions(-)
 create mode 100644 gcc/jit/docs/internals/test-hello-world.exe.log.txt
 create mode 100644 gcc/jit/jit-logging.c
 create mode 100644 gcc/jit/jit-logging.h

diff --git a/gcc/jit/Make-lang.in b/gcc/jit/Make-lang.in
index a0c2bac..551b115 100644
--- a/gcc/jit/Make-lang.in
+++ b/gcc/jit/Make-lang.in
@@ -62,6 +62,7 @@ jit: $(LIBGCCJIT_FILENAME) \
 jit_OBJS = attribs.o \
 	jit/dummy-frontend.o \
 	jit/libgccjit.o \
+	jit/jit-logging.o \
 	jit/jit-recording.o \
 	jit/jit-playback.o \
 	jit/jit-result.o \
diff --git a/gcc/jit/docs/internals/index.rst b/gcc/jit/docs/internals/index.rst
index 694f058..20ac337 100644
--- a/gcc/jit/docs/internals/index.rst
+++ b/gcc/jit/docs/internals/index.rst
@@ -268,3 +268,12 @@ Here is a high-level summary from ``jit-common.h``:
 .. include:: ../../jit-common.h
   :start-after: This comment is included by the docs.
   :end-before: End of comment for inclusion in the docs.  */
+
+.. _example-of-log-file:
+
+Another way to understand the structure of the code is to enable logging,
+via :c:func:`gcc_jit_context_set_logfile`.  Here is an example of a log
+generated via this call:
+
+.. literalinclude:: test-hello-world.exe.log.txt
+    :lines: 1-
diff --git a/gcc/jit/docs/internals/test-hello-world.exe.log.txt b/gcc/jit/docs/internals/test-hello-world.exe.log.txt
new file mode 100644
index 0000000..a96d80f
--- /dev/null
+++ b/gcc/jit/docs/internals/test-hello-world.exe.log.txt
@@ -0,0 +1,126 @@
+JIT: entering: gcc_jit_context_set_str_option
+JIT: exiting: gcc_jit_context_set_str_option
+JIT: entering: gcc_jit_context_set_int_option
+JIT: exiting: gcc_jit_context_set_int_option
+JIT: entering: gcc_jit_context_set_bool_option
+JIT: exiting: gcc_jit_context_set_bool_option
+JIT: entering: gcc_jit_context_set_bool_option
+JIT: exiting: gcc_jit_context_set_bool_option
+JIT: entering: gcc_jit_context_set_bool_option
+JIT: exiting: gcc_jit_context_set_bool_option
+JIT: entering: gcc_jit_context_set_bool_option
+JIT: exiting: gcc_jit_context_set_bool_option
+JIT: entering: gcc_jit_context_set_bool_option
+JIT: exiting: gcc_jit_context_set_bool_option
+JIT: entering: gcc_jit_context_get_type
+JIT: exiting: gcc_jit_context_get_type
+JIT: entering: gcc_jit_context_get_type
+JIT: exiting: gcc_jit_context_get_type
+JIT: entering: gcc_jit_context_new_param
+JIT: exiting: gcc_jit_context_new_param
+JIT: entering: gcc_jit_context_new_function
+JIT: exiting: gcc_jit_context_new_function
+JIT: entering: gcc_jit_context_new_param
+JIT: exiting: gcc_jit_context_new_param
+JIT: entering: gcc_jit_context_get_type
+JIT: exiting: gcc_jit_context_get_type
+JIT: entering: gcc_jit_context_new_function
+JIT: exiting: gcc_jit_context_new_function
+JIT: entering: gcc_jit_context_new_string_literal
+JIT: exiting: gcc_jit_context_new_string_literal
+JIT: entering: gcc_jit_function_new_block
+JIT: exiting: gcc_jit_function_new_block
+JIT: entering: gcc_jit_block_add_comment
+JIT: exiting: gcc_jit_block_add_comment
+JIT: entering: gcc_jit_context_new_call
+JIT: exiting: gcc_jit_context_new_call
+JIT: entering: gcc_jit_block_add_eval
+JIT: exiting: gcc_jit_block_add_eval
+JIT: entering: gcc_jit_block_end_with_void_return
+JIT: exiting: gcc_jit_block_end_with_void_return
+JIT: entering: gcc_jit_context_compile
+JIT:  compiling ctxt: 0x1283e20
+JIT:  entering: gcc::jit::result* gcc::jit::recording::context::compile()
+JIT:   entering: void gcc::jit::recording::context::validate()
+JIT:   exiting: void gcc::jit::recording::context::validate()
+JIT:   entering: gcc::jit::playback::context::context(gcc::jit::recording::context*)
+JIT:   exiting: gcc::jit::playback::context::context(gcc::jit::recording::context*)
+JIT:   entering: gcc::jit::result* gcc::jit::playback::context::compile()
+JIT:    entering: void gcc::jit::playback::context::make_fake_args(vec<char*>*, const char*, vec<gcc::jit::recording::requested_dump>*)
+JIT:    exiting: void gcc::jit::playback::context::make_fake_args(vec<char*>*, const char*, vec<gcc::jit::recording::requested_dump>*)
+JIT:    entering: void gcc::jit::playback::context::acquire_mutex()
+JIT:    exiting: void gcc::jit::playback::context::acquire_mutex()
+JIT:    entering: toplev::main
+JIT:     argv[0]: ./test-hello-world.c.exe
+JIT:     argv[1]: /tmp/libgccjit-CKq1M9/fake.c
+JIT:     argv[2]: -fPIC
+JIT:     argv[3]: -O3
+JIT:     argv[4]: -g
+JIT:     argv[5]: -quiet
+JIT:     argv[6]: --param
+JIT:     argv[7]: ggc-min-expand=0
+JIT:     argv[8]: --param
+JIT:     argv[9]: ggc-min-heapsize=0
+JIT:     entering: bool jit_langhook_init()
+JIT:     exiting: bool jit_langhook_init()
+JIT:     entering: void gcc::jit::playback::context::replay()
+JIT:      entering: void gcc::jit::recording::context::replay_into(gcc::jit::replayer*)
+JIT:      exiting: void gcc::jit::recording::context::replay_into(gcc::jit::replayer*)
+JIT:      entering: void gcc::jit::recording::context::disassociate_from_playback()
+JIT:      exiting: void gcc::jit::recording::context::disassociate_from_playback()
+JIT:      entering: void gcc::jit::playback::context::handle_locations()
+JIT:      exiting: void gcc::jit::playback::context::handle_locations()
+JIT:      entering: void gcc::jit::playback::function::build_stmt_list()
+JIT:      exiting: void gcc::jit::playback::function::build_stmt_list()
+JIT:      entering: void gcc::jit::playback::function::build_stmt_list()
+JIT:      exiting: void gcc::jit::playback::function::build_stmt_list()
+JIT:      entering: void gcc::jit::playback::function::postprocess()
+JIT:      exiting: void gcc::jit::playback::function::postprocess()
+JIT:      entering: void gcc::jit::playback::function::postprocess()
+JIT:      exiting: void gcc::jit::playback::function::postprocess()
+JIT:     exiting: void gcc::jit::playback::context::replay()
+JIT:     entering: void jit_langhook_write_globals()
+JIT:     exiting: void jit_langhook_write_globals()
+JIT:    exiting: toplev::main
+JIT:    entering: void gcc::jit::playback::context::extract_any_requested_dumps(vec<gcc::jit::recording::requested_dump>*)
+JIT:    exiting: void gcc::jit::playback::context::extract_any_requested_dumps(vec<gcc::jit::recording::requested_dump>*)
+JIT:    entering: toplev::finalize
+JIT:    exiting: toplev::finalize
+JIT:    entering: void gcc::jit::playback::context::convert_to_dso(const char*)
+JIT:     argv[0]: x86_64-unknown-linux-gnu-gcc-5.0.0
+JIT:     argv[1]: -shared
+JIT:     argv[2]: /tmp/libgccjit-CKq1M9/fake.s
+JIT:     argv[3]: -o
+JIT:     argv[4]: /tmp/libgccjit-CKq1M9/fake.so
+JIT:     argv[5]: -fno-use-linker-plugin
+JIT:     argv[6]: (null)
+JIT:    exiting: void gcc::jit::playback::context::convert_to_dso(const char*)
+JIT:    entering: gcc::jit::result* gcc::jit::playback::context::dlopen_built_dso()
+JIT:     entering: gcc::jit::result::result(gcc::jit::logger*, void*)
+JIT:     exiting: gcc::jit::result::result(gcc::jit::logger*, void*)
+JIT:    exiting: gcc::jit::result* gcc::jit::playback::context::dlopen_built_dso()
+JIT:    entering: void gcc::jit::playback::context::release_mutex()
+JIT:    exiting: void gcc::jit::playback::context::release_mutex()
+JIT:   exiting: gcc::jit::result* gcc::jit::playback::context::compile()
+JIT:   entering: gcc::jit::playback::context::~context()
+JIT:   exiting: gcc::jit::playback::context::~context()
+JIT:  exiting: gcc::jit::result* gcc::jit::recording::context::compile()
+JIT:  gcc_jit_context_compile: returning (gcc_jit_result *)0x12f75d0
+JIT: exiting: gcc_jit_context_compile
+JIT: entering: gcc_jit_result_get_code
+JIT:  locating fnname: hello_world
+JIT:  entering: void* gcc::jit::result::get_code(const char*)
+JIT:  exiting: void* gcc::jit::result::get_code(const char*)
+JIT:  gcc_jit_result_get_code: returning (void *)0x7ff6b8cd87f0
+JIT: exiting: gcc_jit_result_get_code
+JIT: entering: gcc_jit_context_release
+JIT:  deleting ctxt: 0x1283e20
+JIT:  entering: gcc::jit::recording::context::~context()
+JIT:  exiting: gcc::jit::recording::context::~context()
+JIT: exiting: gcc_jit_context_release
+JIT: entering: gcc_jit_result_release
+JIT:  deleting result: 0x12f75d0
+JIT:  entering: virtual gcc::jit::result::~result()
+JIT:  exiting: virtual gcc::jit::result::~result()
+JIT: exiting: gcc_jit_result_release
+JIT: gcc::jit::logger::~logger()
diff --git a/gcc/jit/docs/topics/contexts.rst b/gcc/jit/docs/topics/contexts.rst
index 626e7c8..6099c69 100644
--- a/gcc/jit/docs/topics/contexts.rst
+++ b/gcc/jit/docs/topics/contexts.rst
@@ -153,6 +153,56 @@ Debugging
    code in a debugger.
 
 .. function:: void\
+              gcc_jit_context_set_logfile (gcc_jit_context *ctxt,\
+                                           FILE *logfile,\
+                                           int flags,\
+                                           int verbosity)
+
+   To help with debugging; enable ongoing logging of the context's
+   activity to the given file.
+
+   For example, the following will enable logging to stderr.
+
+   .. code-block:: c
+
+      gcc_jit_context_set_logfile (ctxt, stderr, 0, 0);
+
+   Examples of information logged include:
+
+   * API calls
+
+   * the various steps involved within compilation
+
+   * activity on any :c:type:`gcc_jit_result` instances created by
+     the context
+
+   * activity within any child contexts
+
+   An example of a log can be seen :ref:`here <example-of-log-file>`,
+   though the precise format and kinds of information logged is subject
+   to change.
+
+   The caller remains responsible for closing `logfile`, and it must not
+   be closed until all users are released.  In particular, note that
+   child contexts and :c:type:`gcc_jit_result` instances created by
+   the context will use the logfile.
+
+   There may a performance cost for logging.
+
+   You can turn off logging on `ctxt` by passing `NULL` for `logfile`.
+   Doing so only affects the context; it does not affect child contexts
+   or :c:type:`gcc_jit_result` instances already created by
+   the context.
+
+   The parameters "flags" and "verbosity" are reserved for future
+   expansion, and must be zero for now.
+
+To contrast the above: :c:func:`gcc_jit_context_dump_to_file` dumps the
+current state of a context to the given path, whereas
+:c:func:`gcc_jit_context_set_logfile` enables on-going logging of
+future activies on a context to the given `FILE *`.
+
+.. function:: void\
               gcc_jit_context_enable_dump (gcc_jit_context *ctxt,\
                                            const char *dumpname, \
                                            char **out_ptr)
diff --git a/gcc/jit/dummy-frontend.c b/gcc/jit/dummy-frontend.c
index 9bea2c1..23883ad 100644
--- a/gcc/jit/dummy-frontend.c
+++ b/gcc/jit/dummy-frontend.c
@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cgraph.h"
 
 #include "jit-common.h"
+#include "jit-logging.h"
 #include "jit-playback.h"
 
 #include <mpfr.h>
@@ -113,6 +114,9 @@ struct ggc_root_tab jit_root_tab[] =
 static bool
 jit_langhook_init (void)
 {
+  gcc_assert (gcc::jit::active_playback_ctxt);
+  JIT_LOG_SCOPE (gcc::jit::active_playback_ctxt->get_logger ());
+
   static bool registered_root_tab = false;
   if (!registered_root_tab)
     {
@@ -212,6 +216,9 @@ jit_langhook_getdecls (void)
 static void
 jit_langhook_write_globals (void)
 {
+  gcc_assert (gcc::jit::active_playback_ctxt);
+  JIT_LOG_SCOPE (gcc::jit::active_playback_ctxt->get_logger ());
+
   /* This is the hook that runs the middle and backends: */
   symtab->finalize_compilation_unit ();
 }
diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h
index 4dd976e..80e1cbe 100644
--- a/gcc/jit/jit-common.h
+++ b/gcc/jit/jit-common.h
@@ -97,6 +97,7 @@ namespace jit {
 
 class result;
 class dump;
+class logger;
 class builtins_manager; // declared within jit-builtins.h
 class tempdir;
 
diff --git a/gcc/jit/jit-logging.c b/gcc/jit/jit-logging.c
new file mode 100644
index 0000000..61b898b
--- /dev/null
+++ b/gcc/jit/jit-logging.c
@@ -0,0 +1,168 @@
+/* Internals of libgccjit: logging
+   Copyright (C) 2014-2015 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "jit-logging.h"
+
+namespace gcc {
+
+namespace jit {
+
+/* Implementation of class gcc::jit::logger.  */
+
+/* The constructor for gcc::jit::logger, used by
+   gcc_jit_context_set_logfile.  */
+
+logger::logger (FILE *f_out,
+		int, /* flags */
+		int /* verbosity */) :
+  m_refcount (0),
+  m_f_out (f_out),
+  m_indent_level (0),
+  m_log_refcount_changes (false)
+{
+}
+
+/* The destructor for gcc::jit::logger, invoked via
+   the decref method when the refcount hits zero.
+   Note that we do not close the underlying FILE * (m_f_out).  */
+
+logger::~logger ()
+{
+  /* This should be the last message emitted.  */
+  log ("%s", __PRETTY_FUNCTION__);
+  gcc_assert (m_refcount == 0);
+}
+
+/* Increment the reference count of the gcc::jit::logger.  */
+
+void
+logger::incref (const char *reason)
+{
+  m_refcount++;
+  if (m_log_refcount_changes)
+    log ("%s: reason: %s refcount now %i ",
+	 __PRETTY_FUNCTION__, reason, m_refcount);
+}
+
+/* Decrement the reference count of the gcc::jit::logger,
+   deleting it if nothing is referring to it.  */
+
+void
+logger::decref (const char *reason)
+{
+  gcc_assert (m_refcount > 0);
+  --m_refcount;
+  if (m_log_refcount_changes)
+    log ("%s: reason: %s refcount now %i",
+	 __PRETTY_FUNCTION__, reason, m_refcount);
+  if (0 == m_refcount)
+    delete this;
+}
+
+/* Write a formatted message to the log, by calling the log_va method.  */
+
+void
+logger::log (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  log_va (fmt, ap);
+  va_end (ap);
+}
+
+/* Write an indented line to the log file.
+
+   We explicitly flush after each line: if something crashes the process,
+   we want the logfile/stream to contain the most up-to-date hint about the
+   last thing that was happening, without it being hidden in an in-process
+   buffer.  */
+
+void
+logger::log_va (const char *fmt, va_list ap)
+{
+  fprintf (m_f_out, "JIT: ");
+  for (int i = 0; i < m_indent_level; i++)
+    fputc (' ', m_f_out);
+  vfprintf (m_f_out, fmt, ap);
+  fprintf (m_f_out, "\n");
+  fflush (m_f_out);
+}
+
+/* Record the entry within a particular scope, indenting subsequent
+   log lines accordingly.  */
+
+void
+logger::enter_scope (const char *scope_name)
+{
+  log ("entering: %s", scope_name);
+  m_indent_level += 1;
+}
+
+/* Record the exit from a particular scope, restoring the indent level to
+   before the scope was entered.  */
+
+void
+logger::exit_scope (const char *scope_name)
+{
+  if (m_indent_level)
+    m_indent_level -= 1;
+  else
+    log ("(mismatching indentation)");
+  log ("exiting: %s", scope_name);
+}
+
+/* Implementation of class gcc::jit::log_user.  */
+
+/* The constructor for gcc::jit::log_user.  */
+
+log_user::log_user (logger *logger) : m_logger (logger)
+{
+  if (m_logger)
+    m_logger->incref("log_user ctor");
+}
+
+/* The destructor for gcc::jit::log_user.  */
+
+log_user::~log_user ()
+{
+  if (m_logger)
+    m_logger->decref("log_user dtor");
+}
+
+/* Set the logger for a gcc::jit::log_user, managing the reference counts
+   of the old and new logger (either of which might be NULL).  */
+
+void
+log_user::set_logger (logger *logger)
+{
+  if (logger)
+    logger->incref ("log_user::set_logger");
+  if (m_logger)
+    m_logger->decref ("log_user::set_logger");
+  m_logger = logger;
+}
+
+} // namespace gcc::jit
+
+} // namespace gcc
diff --git a/gcc/jit/jit-logging.h b/gcc/jit/jit-logging.h
new file mode 100644
index 0000000..581090c
--- /dev/null
+++ b/gcc/jit/jit-logging.h
@@ -0,0 +1,191 @@
+/* Internals of libgccjit: logging
+   Copyright (C) 2014-2015 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef JIT_LOGGING_H
+#define JIT_LOGGING_H
+
+#include "jit-common.h"
+
+namespace gcc {
+
+namespace jit {
+
+/* A gcc::jit::logger encapsulates a logging stream: a way to send
+   lines of pertinent information to a FILE *.  */
+
+class logger
+{
+ public:
+  logger (FILE *f_out, int flags, int verbosity);
+  ~logger ();
+
+  void incref (const char *reason);
+  void decref (const char *reason);
+
+  void log (const char *fmt, ...)
+    GNU_PRINTF(2, 3);
+  void log_va (const char *fmt, va_list ap)
+    GNU_PRINTF(2, 0);
+
+  void enter_scope (const char *scope_name);
+  void exit_scope (const char *scope_name);
+
+private:
+  int m_refcount;
+  FILE *m_f_out;
+  int m_indent_level;
+  bool m_log_refcount_changes;
+};
+
+/* The class gcc::jit::log_scope is an RAII-style class intended to make
+   it easy to notify a logger about entering and exiting the body of a
+   given function.  */
+
+class log_scope
+{
+public:
+  log_scope (logger *logger, const char *name);
+  ~log_scope ();
+
+ private:
+  logger *m_logger;
+  const char *m_name;
+};
+
+/* The constructor for gcc::jit::log_scope.
+
+   The normal case is that the logger is NULL, in which case this should
+   be largely a no-op.
+
+   If we do have a logger, notify it that we're entering the given scope.
+   We also need to hold a reference on it, to avoid a use-after-free
+   when logging the cleanup of the owner of the logger.  */
+
+inline
+log_scope::log_scope (logger *logger, const char *name) :
+ m_logger (logger),
+ m_name (name)
+{
+  if (m_logger)
+    {
+      m_logger->incref ("log_scope ctor");
+      m_logger->enter_scope (m_name);
+    }
+}
+
+/* The destructor for gcc::jit::log_scope; essentially the opposite of
+   the constructor.  */
+
+inline
+log_scope::~log_scope ()
+{
+  if (m_logger)
+    {
+      m_logger->exit_scope (m_name);
+      m_logger->decref ("log_scope dtor");
+    }
+}
+
+/* A gcc::jit::log_user is something that potentially uses a
+   gcc::jit::logger (which could be NULL).
+
+   It is the base class for each of:
+
+      - class gcc::jit::recording::context
+
+      - class gcc::jit::playback::context
+
+      - class gcc::jit::result
+
+   The log_user class keeps the reference-count of a logger up-to-date.  */
+
+class log_user
+{
+ public:
+  log_user (logger *logger);
+  ~log_user ();
+
+  logger * get_logger () const { return m_logger; }
+  void set_logger (logger * logger);
+
+  void log (const char *fmt, ...)
+    GNU_PRINTF(2, 3);
+
+  void enter_scope (const char *scope_name);
+  void exit_scope (const char *scope_name);
+
+ private:
+  logger *m_logger;
+};
+
+/* A shortcut for calling log from a context/result, handling the common
+   case where the underlying logger is NULL via a no-op.  */
+
+inline void
+log_user::log (const char *fmt, ...)
+{
+  if (m_logger)
+    {
+      va_list ap;
+      va_start (ap, fmt);
+      m_logger->log_va (fmt, ap);
+      va_end (ap);
+    }
+}
+
+/* A shortcut for recording entry into a scope from a context/result,
+   handling the common case where the underlying logger is NULL via
+   a no-op.  */
+
+inline void
+log_user::enter_scope (const char *scope_name)
+{
+  if (m_logger)
+    m_logger->enter_scope (scope_name);
+}
+
+/* A shortcut for recording exit from a scope from a context/result,
+   handling the common case where the underlying logger is NULL via
+   a no-op.  */
+
+inline void
+log_user::exit_scope (const char *scope_name)
+{
+  if (m_logger)
+    m_logger->exit_scope (scope_name);
+}
+
+} // namespace gcc::jit
+
+} // namespace gcc
+
+/* If the given logger is non-NULL, log entry/exit of this scope to
+   it, identifying it using __PRETTY_FUNCTION__.  */
+
+#define JIT_LOG_SCOPE(LOGGER) \
+  gcc::jit::log_scope s (LOGGER, __PRETTY_FUNCTION__)
+
+/* If the given logger is non-NULL, log entry/exit of this scope to
+   it, identifying it using __func__.  */
+
+#define JIT_LOG_FUNC(LOGGER) \
+  gcc::jit::log_scope s (LOGGER, __func__)
+
+#endif /* JIT_LOGGING_H */
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index 013ee0f..a8a281a 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -50,6 +50,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "context.h"
 
 #include "jit-common.h"
+#include "jit-logging.h"
 #include "jit-playback.h"
 #include "jit-result.h"
 #include "jit-builtins.h"
@@ -86,11 +87,13 @@ namespace jit {
 /* The constructor for gcc::jit::playback::context.  */
 
 playback::context::context (recording::context *ctxt)
-  : m_recording_ctxt (ctxt),
+  : log_user (ctxt->get_logger ()),
+    m_recording_ctxt (ctxt),
     m_tempdir (NULL),
     m_char_array_type_node (NULL),
     m_const_char_ptr (NULL)
 {
+  JIT_LOG_SCOPE (get_logger ());
   m_functions.create (0);
   m_source_files.create (0);
   m_cached_locations.create (0);
@@ -100,6 +103,7 @@ playback::context::context (recording::context *ctxt)
 
 playback::context::~context ()
 {
+  JIT_LOG_SCOPE (get_logger ());
   if (m_tempdir)
     delete m_tempdir;
   m_functions.release ();
@@ -1219,6 +1223,8 @@ build_stmt_list ()
   int i;
   block *b;
 
+  JIT_LOG_SCOPE (m_ctxt->get_logger ());
+
   FOR_EACH_VEC_ELT (m_blocks, i, b)
     {
       int j;
@@ -1244,6 +1250,8 @@ void
 playback::function::
 postprocess ()
 {
+  JIT_LOG_SCOPE (m_ctxt->get_logger ());
+
   if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
     debug_tree (m_stmt_list);
 
@@ -1538,6 +1546,8 @@ result *
 playback::context::
 compile ()
 {
+  JIT_LOG_SCOPE (get_logger ());
+
   const char *ctxt_progname;
   result *result_obj = NULL;
 
@@ -1572,8 +1582,13 @@ compile ()
 
   /* This runs the compiler.  */
   toplev toplev (false);
+  enter_scope ("toplev::main");
+  if (get_logger ())
+    for (unsigned i = 0; i < fake_args.length (); i++)
+      get_logger ()->log ("argv[%i]: %s", i, fake_args[i]);
   toplev.main (fake_args.length (),
 	       const_cast <char **> (fake_args.address ()));
+  exit_scope ("toplev::main");
 
   /* Extracting dumps makes use of the gcc::dump_manager, hence we
      need to do it between toplev::main (which creates the dump manager)
@@ -1581,7 +1596,9 @@ compile ()
   extract_any_requested_dumps (&requested_dumps);
 
   /* Clean up the compiler.  */
+  enter_scope ("toplev::finalize");
   toplev.finalize ();
+  exit_scope ("toplev::finalize");
 
   /* Ideally we would release the jit mutex here, but we can't yet since
      followup activities use timevars, which are global state.  */
@@ -1622,6 +1639,7 @@ void
 playback::context::acquire_mutex ()
 {
   /* Acquire the big GCC mutex. */
+  JIT_LOG_SCOPE (get_logger ());
   pthread_mutex_lock (&jit_mutex);
   gcc_assert (NULL == active_playback_ctxt);
   active_playback_ctxt = this;
@@ -1633,6 +1651,7 @@ void
 playback::context::release_mutex ()
 {
   /* Release the big GCC mutex. */
+  JIT_LOG_SCOPE (get_logger ());
   gcc_assert (active_playback_ctxt == this);
   active_playback_ctxt = NULL;
   pthread_mutex_unlock (&jit_mutex);
@@ -1647,6 +1666,8 @@ make_fake_args (vec <char *> *argvec,
 		const char *ctxt_progname,
 		vec <recording::requested_dump> *requested_dumps)
 {
+  JIT_LOG_SCOPE (get_logger ());
+
 #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
 #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
 
@@ -1734,6 +1755,8 @@ void
 playback::context::
 extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
 {
+  JIT_LOG_SCOPE (get_logger ());
+
   int i;
   recording::requested_dump *d;
   FOR_EACH_VEC_ELT (*requested_dumps, i, d)
@@ -1819,6 +1842,7 @@ void
 playback::context::
 convert_to_dso (const char *ctxt_progname)
 {
+  JIT_LOG_SCOPE (get_logger ());
   /* Currently this lumps together both assembling and linking into
      TV_ASSEMBLE.  */
   auto_timevar assemble_timevar (TV_ASSEMBLE);
@@ -1852,6 +1876,10 @@ convert_to_dso (const char *ctxt_progname)
   /* pex_one's error-handling requires pname to be non-NULL.  */
   gcc_assert (ctxt_progname);
 
+  if (get_logger ())
+    for (unsigned i = 0; i < argvec.length (); i++)
+      get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
+
   errmsg = pex_one (PEX_SEARCH, /* int flags, */
 		    gcc_driver_name,
 		    const_cast <char *const *> (argvec.address ()),
@@ -1892,6 +1920,7 @@ result *
 playback::context::
 dlopen_built_dso ()
 {
+  JIT_LOG_SCOPE (get_logger ());
   auto_timevar load_timevar (TV_LOAD);
   void *handle = NULL;
   const char *error = NULL;
@@ -1906,7 +1935,7 @@ dlopen_built_dso ()
     add_error (NULL, "%s", error);
   }
   if (handle)
-    result_obj = new result (handle);
+    result_obj = new result (get_logger (), handle);
   else
     result_obj = NULL;
 
@@ -1923,6 +1952,7 @@ void
 playback::context::
 replay ()
 {
+  JIT_LOG_SCOPE (get_logger ());
   /* Adapted from c-common.c:c_common_nodes_and_builtins.  */
   tree array_domain_type = build_index_type (size_int (200));
   m_char_array_type_node
@@ -1984,6 +2014,7 @@ void
 playback::context::
 dump_generated_code ()
 {
+  JIT_LOG_SCOPE (get_logger ());
   char buf[4096];
   size_t sz;
   FILE *f_in = fopen (get_path_s_file (), "r");
@@ -2069,6 +2100,7 @@ handle_locations ()
      imposed by the linemap API.
 
      line_table is a global.  */
+  JIT_LOG_SCOPE (get_logger ());
   int i;
   source_file *file;
 
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index 4d087de..3a03b3a 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -35,7 +35,7 @@ namespace jit {
 
 namespace playback {
 
-class context
+class context : public log_user
 {
 public:
   context (::gcc::jit::recording::context *ctxt);
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index dc7a7fb..a872063 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "jit-common.h"
 #include "jit-builtins.h"
+#include "jit-logging.h"
 #include "jit-recording.h"
 #include "jit-playback.h"
 
@@ -169,7 +170,8 @@ recording::playback_block (recording::block *b)
    gcc_jit_context_acquire and gcc_jit_context_new_child_context.  */
 
 recording::context::context (context *parent_ctxt)
-  : m_parent_ctxt (parent_ctxt),
+  : log_user (NULL),
+    m_parent_ctxt (parent_ctxt),
     m_error_count (0),
     m_first_error_str (NULL),
     m_owns_first_error_str (false),
@@ -195,6 +197,7 @@ recording::context::context (context *parent_ctxt)
       memcpy (m_bool_options,
 	      parent_ctxt->m_bool_options,
 	      sizeof (m_bool_options));
+      set_logger (parent_ctxt->get_logger ());
     }
   else
     {
@@ -211,6 +214,7 @@ recording::context::context (context *parent_ctxt)
 
 recording::context::~context ()
 {
+  JIT_LOG_SCOPE (get_logger ());
   int i;
   memento *m;
   FOR_EACH_VEC_ELT (m_mementos, i, m)
@@ -245,6 +249,7 @@ recording::context::record (memento *m)
 void
 recording::context::replay_into (replayer *r)
 {
+  JIT_LOG_SCOPE (get_logger ());
   int i;
   memento *m;
 
@@ -302,6 +307,7 @@ recording::context::replay_into (replayer *r)
 void
 recording::context::disassociate_from_playback ()
 {
+  JIT_LOG_SCOPE (get_logger ());
   int i;
   memento *m;
 
@@ -904,6 +910,8 @@ recording::context::enable_dump (const char *dumpname,
 result *
 recording::context::compile ()
 {
+  JIT_LOG_SCOPE (get_logger ());
+
   validate ();
 
   if (errors_occurred ())
@@ -940,6 +948,8 @@ recording::context::add_error_va (location *loc, const char *fmt, va_list ap)
   const char *errmsg;
   bool has_ownership;
 
+  JIT_LOG_SCOPE (get_logger ());
+
   vasprintf (&malloced_msg, fmt, ap);
   if (malloced_msg)
     {
@@ -951,6 +961,8 @@ recording::context::add_error_va (location *loc, const char *fmt, va_list ap)
       errmsg = "out of memory generating error message";
       has_ownership = false;
     }
+  if (get_logger ())
+    get_logger ()->log ("error %i: %s", m_error_count, errmsg);
 
   const char *ctxt_progname =
     get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
@@ -1060,6 +1072,8 @@ recording::context::get_all_requested_dumps (vec <recording::requested_dump> *ou
 void
 recording::context::validate ()
 {
+  JIT_LOG_SCOPE (get_logger ());
+
   if (m_parent_ctxt)
     m_parent_ctxt->validate ();
 
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 9034e11..dddf0db 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 #define JIT_RECORDING_H
 
 #include "jit-common.h"
+#include "jit-logging.h"
 
 namespace gcc {
 
@@ -53,7 +54,7 @@ struct requested_dump
 };
 
 /* A JIT-compilation context.  */
-class context
+class context : public log_user
 {
 public:
   context (context *parent_ctxt);
diff --git a/gcc/jit/jit-result.c b/gcc/jit/jit-result.c
index 532b302..67699e0 100644
--- a/gcc/jit/jit-result.c
+++ b/gcc/jit/jit-result.c
@@ -21,6 +21,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+
+#include "jit-common.h"
+#include "jit-logging.h"
 #include "jit-result.h"
 
 namespace gcc {
@@ -29,9 +32,11 @@ namespace jit {
 /* Constructor for gcc::jit::result.  */
 
 result::
-result(void *dso_handle)
-  : m_dso_handle(dso_handle)
+result(logger *logger, void *dso_handle) :
+  log_user (logger),
+  m_dso_handle (dso_handle)
 {
+  JIT_LOG_SCOPE (get_logger ());
 }
 
 /* gcc::jit::result's destructor.
@@ -40,6 +45,8 @@ result(void *dso_handle)
 
 result::~result()
 {
+  JIT_LOG_SCOPE (get_logger ());
+
   dlclose (m_dso_handle);
 }
 
@@ -53,6 +60,8 @@ void *
 result::
 get_code (const char *funcname)
 {
+  JIT_LOG_SCOPE (get_logger ());
+
   void *code;
   const char *error;
 
diff --git a/gcc/jit/jit-result.h b/gcc/jit/jit-result.h
index b1a9631..59d28a1 100644
--- a/gcc/jit/jit-result.h
+++ b/gcc/jit/jit-result.h
@@ -26,10 +26,10 @@ namespace gcc {
 namespace jit {
 
 /* The result of JIT-compilation.  */
-class result
+class result : public log_user
 {
 public:
-  result(void *dso_handle);
+  result(logger *logger, void *dso_handle);
 
   virtual ~result();
 
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index d6631e5..600219c 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -102,6 +102,10 @@ namespace gccjit
     void dump_to_file (const std::string &path,
 		       bool update_locations);
 
+    void set_logfile (FILE *logfile,
+		      int flags,
+		      int verbosity);
+
     void set_str_option (enum gcc_jit_str_option opt,
 			 const char *value);
 
@@ -541,6 +545,17 @@ context::dump_to_file (const std::string &path,
 }
 
 inline void
+context::set_logfile (FILE *logfile,
+		      int flags,
+		      int verbosity)
+{
+  gcc_jit_context_set_logfile (m_inner_ctxt,
+			       logfile,
+			       flags,
+			       verbosity);
+}
+
+inline void
 context::set_str_option (enum gcc_jit_str_option opt,
 			 const char *value)
 {
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 99b2d56..c043961 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -26,6 +26,7 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "libgccjit.h"
 #include "jit-common.h"
+#include "jit-logging.h"
 #include "jit-recording.h"
 #include "jit-result.h"
 
@@ -323,7 +324,9 @@ compatible_types (gcc::jit::recording::type *ltype,
 gcc_jit_context *
 gcc_jit_context_acquire (void)
 {
-  return new gcc_jit_context (NULL);
+  gcc_jit_context *ctxt = new gcc_jit_context (NULL);
+  ctxt->log ("new top-level ctxt: %p", (void *)ctxt);
+  return ctxt;
 }
 
 /* Public entrypoint for releasing a gcc_jit_context.
@@ -333,6 +336,9 @@ gcc_jit_context_acquire (void)
 void
 gcc_jit_context_release (gcc_jit_context *ctxt)
 {
+  RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL ctxt");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  ctxt->log ("deleting ctxt: %p", (void *)ctxt);
   delete ctxt;
 }
 
@@ -345,7 +351,12 @@ gcc_jit_context_release (gcc_jit_context *ctxt)
 gcc_jit_context *
 gcc_jit_context_new_child_context (gcc_jit_context *parent_ctxt)
 {
-  return new gcc_jit_context (parent_ctxt);
+  RETURN_NULL_IF_FAIL (parent_ctxt, NULL, NULL, "NULL parent ctxt");
+  JIT_LOG_FUNC (parent_ctxt->get_logger ());
+  parent_ctxt->log ("parent_ctxt: %p", (void *)parent_ctxt);
+  gcc_jit_context *child_ctxt = new gcc_jit_context (parent_ctxt);
+  child_ctxt->log ("new child_ctxt: %p", (void *)child_ctxt);
+  return child_ctxt;
 }
 
 /* Public entrypoint.  See description in libgccjit.h.
@@ -361,7 +372,7 @@ gcc_jit_context_new_location (gcc_jit_context *ctxt,
 			      int column)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
-
+  JIT_LOG_FUNC (ctxt->get_logger ());
   return (gcc_jit_location *)ctxt->new_location (filename, line, column);
 }
 
@@ -404,6 +415,7 @@ gcc_jit_context_get_type (gcc_jit_context *ctxt,
 			  enum gcc_jit_types type)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   RETURN_NULL_IF_FAIL_PRINTF1 (
     (type >= GCC_JIT_TYPE_VOID
      && type <= GCC_JIT_TYPE_FILE_PTR),
@@ -425,6 +437,7 @@ gcc_jit_context_get_int_type (gcc_jit_context *ctxt,
 			      int num_bytes, int is_signed)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   RETURN_NULL_IF_FAIL (num_bytes >= 0, ctxt, NULL, "negative size");
 
   return (gcc_jit_type *)ctxt->get_int_type (num_bytes, is_signed);
@@ -485,6 +498,7 @@ gcc_jit_context_new_array_type (gcc_jit_context *ctxt,
 				int num_elements)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   /* LOC can be NULL.  */
   RETURN_NULL_IF_FAIL (element_type, ctxt, loc, "NULL type");
   RETURN_NULL_IF_FAIL (num_elements >= 0, ctxt, NULL, "negative size");
@@ -507,6 +521,7 @@ gcc_jit_context_new_field (gcc_jit_context *ctxt,
 			   const char *name)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   /* LOC can be NULL.  */
   RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
   RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
@@ -543,6 +558,7 @@ gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,
 				 gcc_jit_field **fields)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   /* LOC can be NULL.  */
   RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
   if (num_fields)
@@ -578,6 +594,7 @@ gcc_jit_context_new_opaque_struct (gcc_jit_context *ctxt,
 				   const char *name)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   /* LOC can be NULL.  */
   RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
 
@@ -611,8 +628,9 @@ gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,
 			   gcc_jit_field **fields)
 {
   RETURN_IF_FAIL (struct_type, NULL, loc, "NULL struct_type");
-  /* LOC can be NULL.  */
   gcc::jit::recording::context *ctxt = struct_type->m_ctxt;
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  /* LOC can be NULL.  */
   RETURN_IF_FAIL_PRINTF1 (
     NULL == struct_type->get_fields (), ctxt, loc,
     "%s already has had fields set",
@@ -649,6 +667,7 @@ gcc_jit_context_new_union_type (gcc_jit_context *ctxt,
 				gcc_jit_field **fields)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   /* LOC can be NULL.  */
   RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
   if (num_fields)
@@ -687,6 +706,7 @@ gcc_jit_context_new_function_ptr_type (gcc_jit_context *ctxt,
 				       int is_variadic)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   /* LOC can be NULL.  */
   RETURN_NULL_IF_FAIL (return_type, ctxt, loc, "NULL return_type");
   RETURN_NULL_IF_FAIL (
@@ -720,6 +740,7 @@ gcc_jit_context_new_param (gcc_jit_context *ctxt,
 			   const char *name)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   /* LOC can be NULL.  */
   RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
   RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
@@ -785,6 +806,7 @@ gcc_jit_context_new_function (gcc_jit_context *ctxt,
 			      int is_variadic)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   /* LOC can be NULL.  */
   RETURN_NULL_IF_FAIL_PRINTF1 (
     ((kind >= GCC_JIT_FUNCTION_EXPORTED)
@@ -846,6 +868,7 @@ gcc_jit_context_get_builtin_function (gcc_jit_context *ctxt,
 				      const char *name)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   RETURN_NULL_IF_FAIL (name, ctxt, NULL, "NULL name");
 
   return static_cast <gcc_jit_function *> (ctxt->get_builtin_function (name));
@@ -876,6 +899,7 @@ gcc_jit_function_get_param (gcc_jit_function *func, int index)
 {
   RETURN_NULL_IF_FAIL (func, NULL, NULL, "NULL function");
   gcc::jit::recording::context *ctxt = func->m_ctxt;
+  JIT_LOG_FUNC (ctxt->get_logger ());
   RETURN_NULL_IF_FAIL (index >= 0, ctxt, NULL, "negative index");
   int num_params = func->get_params ().length ();
   RETURN_NULL_IF_FAIL_PRINTF3 (index < num_params,
@@ -900,6 +924,7 @@ gcc_jit_function_dump_to_dot (gcc_jit_function *func,
 {
   RETURN_IF_FAIL (func, NULL, NULL, "NULL function");
   gcc::jit::recording::context *ctxt = func->m_ctxt;
+  JIT_LOG_FUNC (ctxt->get_logger ());
   RETURN_IF_FAIL (path, ctxt, NULL, "NULL path");
 
   func->dump_to_dot (path);
@@ -916,6 +941,7 @@ gcc_jit_function_new_block (gcc_jit_function *func,
 			    const char *name)
 {
   RETURN_NULL_IF_FAIL (func, NULL, NULL, "NULL function");
+  JIT_LOG_FUNC (func->get_context ()->get_logger ());
   RETURN_NULL_IF_FAIL (func->get_kind () != GCC_JIT_FUNCTION_IMPORTED,
 		       func->get_context (), NULL,
 		       "cannot add block to an imported function");
@@ -965,6 +991,7 @@ gcc_jit_context_new_global (gcc_jit_context *ctxt,
 			    const char *name)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   /* LOC can be NULL.  */
   RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
   RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
@@ -1050,6 +1077,7 @@ gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt,
 				     int value)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);
 
   return (gcc_jit_rvalue *)ctxt->new_rvalue_from_int (numeric_type, value);
@@ -1066,6 +1094,7 @@ gcc_jit_context_zero (gcc_jit_context *ctxt,
 		      gcc_jit_type *numeric_type)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);
 
   return gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 0);
@@ -1082,6 +1111,7 @@ gcc_jit_context_one (gcc_jit_context *ctxt,
 		     gcc_jit_type *numeric_type)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);
 
   return gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 1);
@@ -1099,6 +1129,7 @@ gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt,
 					double value)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);
 
   return (gcc_jit_rvalue *)ctxt->new_rvalue_from_double (numeric_type, value);
@@ -1116,6 +1147,7 @@ gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt,
 				     void *value)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   RETURN_NULL_IF_FAIL (pointer_type, ctxt, NULL, "NULL type");
   RETURN_NULL_IF_FAIL_PRINTF1 (
     pointer_type->is_pointer (),
@@ -1137,6 +1169,7 @@ gcc_jit_context_null (gcc_jit_context *ctxt,
 		      gcc_jit_type *pointer_type)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   RETURN_NULL_IF_FAIL (pointer_type, ctxt, NULL, "NULL type");
   RETURN_NULL_IF_FAIL_PRINTF1 (
     pointer_type->is_pointer (),
@@ -1158,6 +1191,7 @@ gcc_jit_context_new_string_literal (gcc_jit_context *ctxt,
 				    const char *value)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   RETURN_NULL_IF_FAIL (value, ctxt, NULL, "NULL value");
 
   return (gcc_jit_rvalue *)ctxt->new_string_literal (value);
@@ -1177,6 +1211,7 @@ gcc_jit_context_new_unary_op (gcc_jit_context *ctxt,
 			      gcc_jit_rvalue *rvalue)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   /* LOC can be NULL.  */
   RETURN_NULL_IF_FAIL_PRINTF1 (
     (op >= GCC_JIT_UNARY_OP_MINUS
@@ -1215,6 +1250,7 @@ gcc_jit_context_new_binary_op (gcc_jit_context *ctxt,
 			       gcc_jit_rvalue *a, gcc_jit_rvalue *b)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   /* LOC can be NULL.  */
   RETURN_NULL_IF_FAIL_PRINTF1 (
     valid_binary_op_p (op),
@@ -1250,6 +1286,7 @@ gcc_jit_context_new_comparison (gcc_jit_context *ctxt,
 				gcc_jit_rvalue *a, gcc_jit_rvalue *b)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   /* LOC can be NULL.  */
   RETURN_NULL_IF_FAIL_PRINTF1 (
     (op >= GCC_JIT_COMPARISON_EQ
@@ -1285,6 +1322,7 @@ gcc_jit_context_new_call (gcc_jit_context *ctxt,
 			  int numargs , gcc_jit_rvalue **args)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   /* LOC can be NULL.  */
   RETURN_NULL_IF_FAIL (func, ctxt, loc, "NULL function");
   if (numargs)
@@ -1357,6 +1395,7 @@ gcc_jit_context_new_call_through_ptr (gcc_jit_context *ctxt,
 				      int numargs, gcc_jit_rvalue **args)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   /* LOC can be NULL.  */
   RETURN_NULL_IF_FAIL (fn_ptr, ctxt, loc, "NULL fn_ptr");
   if (numargs)
@@ -1486,6 +1525,7 @@ gcc_jit_context_new_cast (gcc_jit_context *ctxt,
 			  gcc_jit_type *type)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   /* LOC can be NULL.  */
   RETURN_NULL_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
   RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
@@ -1513,6 +1553,7 @@ gcc_jit_context_new_array_access (gcc_jit_context *ctxt,
 				  gcc_jit_rvalue *index)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   /* LOC can be NULL.  */
   RETURN_NULL_IF_FAIL (ptr, ctxt, loc, "NULL ptr");
   RETURN_NULL_IF_FAIL (index, ctxt, loc, "NULL index");
@@ -1572,8 +1613,9 @@ gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_,
 			     gcc_jit_field *field)
 {
   RETURN_NULL_IF_FAIL (struct_, NULL, loc, "NULL struct");
-  /* LOC can be NULL.  */
   gcc::jit::recording::context *ctxt = struct_->m_ctxt;
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  /* LOC can be NULL.  */
   RETURN_NULL_IF_FAIL (field, ctxt, loc, "NULL field");
   RETURN_NULL_IF_FAIL_PRINTF1 (field->get_container (), field->m_ctxt, loc,
 			       "field %s has not been placed in a struct",
@@ -1594,8 +1636,9 @@ gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_,
 			     gcc_jit_field *field)
 {
   RETURN_NULL_IF_FAIL (struct_, NULL, loc, "NULL struct");
-  /* LOC can be NULL.  */
   gcc::jit::recording::context *ctxt = struct_->m_ctxt;
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  /* LOC can be NULL.  */
   RETURN_NULL_IF_FAIL (field, ctxt, loc, "NULL field");
   RETURN_NULL_IF_FAIL_PRINTF1 (field->get_container (), field->m_ctxt, loc,
 			       "field %s has not been placed in a struct",
@@ -1616,6 +1659,7 @@ gcc_jit_rvalue_dereference_field (gcc_jit_rvalue *ptr,
 				  gcc_jit_field *field)
 {
   RETURN_NULL_IF_FAIL (ptr, NULL, loc, "NULL ptr");
+  JIT_LOG_FUNC (ptr->get_context ()->get_logger ());
   /* LOC can be NULL.  */
   RETURN_NULL_IF_FAIL (field, NULL, loc, "NULL field");
   gcc::jit::recording::type *underlying_type =
@@ -1652,6 +1696,7 @@ gcc_jit_rvalue_dereference (gcc_jit_rvalue *rvalue,
 			    gcc_jit_location *loc)
 {
   RETURN_NULL_IF_FAIL (rvalue, NULL, loc, "NULL rvalue");
+  JIT_LOG_FUNC (rvalue->get_context ()->get_logger ());
   /* LOC can be NULL.  */
 
   gcc::jit::recording::type *underlying_type =
@@ -1684,6 +1729,7 @@ gcc_jit_lvalue_get_address (gcc_jit_lvalue *lvalue,
 			    gcc_jit_location *loc)
 {
   RETURN_NULL_IF_FAIL (lvalue, NULL, loc, "NULL lvalue");
+  JIT_LOG_FUNC (lvalue->get_context ()->get_logger ());
   /* LOC can be NULL.  */
 
   return (gcc_jit_rvalue *)lvalue->get_address (loc);
@@ -1701,8 +1747,9 @@ gcc_jit_function_new_local (gcc_jit_function *func,
 			    const char *name)
 {
   RETURN_NULL_IF_FAIL (func, NULL, loc, "NULL function");
-  /* LOC can be NULL.  */
   gcc::jit::recording::context *ctxt = func->m_ctxt;
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  /* LOC can be NULL.  */
   RETURN_NULL_IF_FAIL (func->get_kind () != GCC_JIT_FUNCTION_IMPORTED,
 		       ctxt, loc,
 		       "Cannot add locals to an imported function");
@@ -1723,8 +1770,9 @@ gcc_jit_block_add_eval (gcc_jit_block *block,
 			gcc_jit_rvalue *rvalue)
 {
   RETURN_IF_NOT_VALID_BLOCK (block, loc);
-  /* LOC can be NULL.  */
   gcc::jit::recording::context *ctxt = block->get_context ();
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  /* LOC can be NULL.  */
   RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
 
   return block->add_eval (loc, rvalue);
@@ -1743,8 +1791,9 @@ gcc_jit_block_add_assignment (gcc_jit_block *block,
 			      gcc_jit_rvalue *rvalue)
 {
   RETURN_IF_NOT_VALID_BLOCK (block, loc);
-  /* LOC can be NULL.  */
   gcc::jit::recording::context *ctxt = block->get_context ();
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  /* LOC can be NULL.  */
   RETURN_IF_FAIL (lvalue, ctxt, loc, "NULL lvalue");
   RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
   RETURN_IF_FAIL_PRINTF4 (
@@ -1775,8 +1824,9 @@ gcc_jit_block_add_assignment_op (gcc_jit_block *block,
 				 gcc_jit_rvalue *rvalue)
 {
   RETURN_IF_NOT_VALID_BLOCK (block, loc);
-  /* LOC can be NULL.  */
   gcc::jit::recording::context *ctxt = block->get_context ();
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  /* LOC can be NULL.  */
   RETURN_IF_FAIL (lvalue, ctxt, loc, "NULL lvalue");
   RETURN_IF_FAIL_PRINTF1 (
     valid_binary_op_p (op),
@@ -1814,8 +1864,9 @@ gcc_jit_block_end_with_conditional (gcc_jit_block *block,
 				    gcc_jit_block *on_false)
 {
   RETURN_IF_NOT_VALID_BLOCK (block, loc);
-  /* LOC can be NULL.  */
   gcc::jit::recording::context *ctxt = block->get_context ();
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  /* LOC can be NULL.  */
   RETURN_IF_FAIL (boolval, ctxt, loc, "NULL boolval");
   RETURN_IF_FAIL_PRINTF2 (
    is_bool (boolval), ctxt, loc,
@@ -1860,8 +1911,9 @@ gcc_jit_block_add_comment (gcc_jit_block *block,
 			   const char *text)
 {
   RETURN_IF_NOT_VALID_BLOCK (block, loc);
-  /* LOC can be NULL.  */
   gcc::jit::recording::context *ctxt = block->get_context ();
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  /* LOC can be NULL.  */
   RETURN_IF_FAIL (text, ctxt, loc, "NULL text");
 
   block->add_comment (loc, text);
@@ -1879,8 +1931,9 @@ gcc_jit_block_end_with_jump (gcc_jit_block *block,
 			     gcc_jit_block *target)
 {
   RETURN_IF_NOT_VALID_BLOCK (block, loc);
-  /* LOC can be NULL.  */
   gcc::jit::recording::context *ctxt = block->get_context ();
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  /* LOC can be NULL.  */
   RETURN_IF_FAIL (target, ctxt, loc, "NULL target");
   RETURN_IF_FAIL_PRINTF4 (
     block->get_function () == target->get_function (),
@@ -1908,8 +1961,9 @@ gcc_jit_block_end_with_return (gcc_jit_block *block,
 			       gcc_jit_rvalue *rvalue)
 {
   RETURN_IF_NOT_VALID_BLOCK (block, loc);
-  /* LOC can be NULL.  */
   gcc::jit::recording::context *ctxt = block->get_context ();
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  /* LOC can be NULL.  */
   gcc::jit::recording::function *func = block->get_function ();
   RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
   RETURN_IF_FAIL_PRINTF4 (
@@ -1938,8 +1992,9 @@ gcc_jit_block_end_with_void_return (gcc_jit_block *block,
 				    gcc_jit_location *loc)
 {
   RETURN_IF_NOT_VALID_BLOCK (block, loc);
-  /* LOC can be NULL.  */
   gcc::jit::recording::context *ctxt = block->get_context ();
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  /* LOC can be NULL.  */
   gcc::jit::recording::function *func = block->get_function ();
   RETURN_IF_FAIL_PRINTF2 (
     func->get_return_type () == ctxt->get_type (GCC_JIT_TYPE_VOID),
@@ -1968,6 +2023,7 @@ gcc_jit_context_set_str_option (gcc_jit_context *ctxt,
 				const char *value)
 {
   RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   /* opt is checked by the inner function.
      value can be NULL.  */
 
@@ -1986,6 +2042,7 @@ gcc_jit_context_set_int_option (gcc_jit_context *ctxt,
 				int value)
 {
   RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   /* opt is checked by the inner function.  */
 
   ctxt->set_int_option (opt, value);
@@ -2003,6 +2060,7 @@ gcc_jit_context_set_bool_option (gcc_jit_context *ctxt,
 				 int value)
 {
   RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   /* opt is checked by the inner function.  */
 
   ctxt->set_bool_option (opt, value);
@@ -2020,6 +2078,7 @@ gcc_jit_context_enable_dump (gcc_jit_context *ctxt,
 			     char **out_ptr)
 {
   RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   RETURN_IF_FAIL (dumpname, ctxt, NULL, "NULL dumpname");
   RETURN_IF_FAIL (out_ptr, ctxt, NULL, "NULL out_ptr");
 
@@ -2037,7 +2096,16 @@ gcc_jit_context_compile (gcc_jit_context *ctxt)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
 
-  return (gcc_jit_result *)ctxt->compile ();
+  JIT_LOG_FUNC (ctxt->get_logger ());
+
+  ctxt->log ("compiling ctxt: %p", (void *)ctxt);
+
+  gcc_jit_result *result = (gcc_jit_result *)ctxt->compile ();
+
+  ctxt->log ("%s: returning (gcc_jit_result *)%p",
+	     __func__, (void *)result);
+
+  return result;
 }
 
 /* Public entrypoint.  See description in libgccjit.h.
@@ -2052,10 +2120,32 @@ gcc_jit_context_dump_to_file (gcc_jit_context *ctxt,
 			      int update_locations)
 {
   RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
   RETURN_IF_FAIL (path, ctxt, NULL, "NULL path");
   ctxt->dump_to_file (path, update_locations);
 }
 
+/* Public entrypoint.  See description in libgccjit.h.  */
+
+void
+gcc_jit_context_set_logfile (gcc_jit_context *ctxt,
+			     FILE *logfile,
+			     int flags,
+			     int verbosity)
+{
+  RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  RETURN_IF_FAIL ((flags == 0), ctxt, NULL, "flags must be 0 for now");
+  RETURN_IF_FAIL ((verbosity == 0), ctxt, NULL, "verbosity must be 0 for now");
+
+  gcc::jit::logger *logger;
+  if (logfile)
+    logger = new gcc::jit::logger (logfile, flags, verbosity);
+  else
+    logger = NULL;
+  ctxt->set_logger (logger);
+}
+
 /* Public entrypoint.  See description in libgccjit.h.
 
    After error-checking, the real work is done by the
@@ -2066,6 +2156,7 @@ const char *
 gcc_jit_context_get_first_error (gcc_jit_context *ctxt)
 {
   RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
 
   return ctxt->get_first_error ();
 }
@@ -2080,9 +2171,14 @@ gcc_jit_result_get_code (gcc_jit_result *result,
 			 const char *fnname)
 {
   RETURN_NULL_IF_FAIL (result, NULL, NULL, "NULL result");
+  JIT_LOG_FUNC (result->get_logger ());
   RETURN_NULL_IF_FAIL (fnname, NULL, NULL, "NULL fnname");
 
-  return result->get_code (fnname);
+  result->log ("locating fnname: %s", fnname);
+  void *code = result->get_code (fnname);
+  result->log ("%s: returning (void *)%p", __func__, code);
+
+  return code;
 }
 
 /* Public entrypoint.  See description in libgccjit.h.
@@ -2094,6 +2190,7 @@ void
 gcc_jit_result_release (gcc_jit_result *result)
 {
   RETURN_IF_FAIL (result, NULL, NULL, "NULL result");
-
+  JIT_LOG_FUNC (result->get_logger ());
+  result->log ("deleting result: %p", (void *)result);
   delete result;
 }
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 2049795..91ca409 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -20,6 +20,8 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef LIBGCCJIT_H
 #define LIBGCCJIT_H
 
+#include <stdio.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
@@ -254,6 +256,19 @@ gcc_jit_context_dump_to_file (gcc_jit_context *ctxt,
 			      const char *path,
 			      int update_locations);
 
+/* To help with debugging; enable ongoing logging of the context's
+   activity to the given FILE *.
+
+   The caller remains responsible for closing "logfile".
+
+   Params "flags" and "verbosity" are reserved for future use, and
+   must both be 0 for now.  */
+extern void
+gcc_jit_context_set_logfile (gcc_jit_context *ctxt,
+			     FILE *logfile,
+			     int flags,
+			     int verbosity);
+
 /* To be called after a compile, this gives the first error message
    that occurred on the context.
 
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 600d397..267898c 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -65,6 +65,7 @@
     gcc_jit_context_release;
     gcc_jit_context_set_bool_option;
     gcc_jit_context_set_int_option;
+    gcc_jit_context_set_logfile;
     gcc_jit_context_set_str_option;
     gcc_jit_context_zero;
     gcc_jit_field_as_object;
diff --git a/gcc/testsuite/jit.dg/harness.h b/gcc/testsuite/jit.dg/harness.h
index fda797c..1252af5 100644
--- a/gcc/testsuite/jit.dg/harness.h
+++ b/gcc/testsuite/jit.dg/harness.h
@@ -251,15 +251,64 @@ static void set_options (gcc_jit_context *ctxt, const char *argv0)
 }
 
 #ifndef TEST_ESCHEWS_TEST_JIT
+/* Set up logging to a logfile of the form "test-FOO.exe.log.txt".
+
+   For example,
+     SRCDIR/gcc/testsuite/jit.dg/test-hello-world.c
+   is built as:
+     BUILDDIR/gcc/testsuite/jit/test-hello-world.c.exe
+   and is logged to
+     BUILDDIR/gcc/testsuite/jit/test-hello-world.c.exe.log.txt
+
+   The logfile must be closed by the caller.
+
+   Note that not every testcase enables logging.  */
+static FILE *
+set_up_logging (gcc_jit_context *ctxt, const char *argv0)
+{
+  const char *logfile_name_suffix = ".log.txt";
+  char *logfile_name = NULL;
+  FILE *logfile = NULL;
+
+  /* Build a logfile name of the form "test-FOO.exe.log.txt".  */
+  logfile_name = (char *)malloc (strlen (argv0)
+				 + strlen (logfile_name_suffix)
+				 + 1);
+  if (!logfile_name)
+    {
+      fail ("malloc failure");
+      return NULL;
+    }
+  strcpy (logfile_name, argv0);
+  strcpy (logfile_name + strlen (argv0), logfile_name_suffix);
+  logfile_name[strlen (argv0) + strlen (logfile_name_suffix)] = '\0';
+
+  logfile = fopen (logfile_name, "w");
+  CHECK_NON_NULL (logfile);
+  free (logfile_name);
+
+  if (logfile)
+    gcc_jit_context_set_logfile (ctxt, logfile, 0, 0);
+
+  return logfile;
+}
+
 /* Run one iteration of the test.  */
 static void
 test_jit (const char *argv0, void *user_data)
 {
   gcc_jit_context *ctxt;
+  FILE *logfile;
   gcc_jit_result *result;
 
   ctxt = gcc_jit_context_acquire ();
-     /* FIXME: error-handling */
+  if (!ctxt)
+    {
+      fail ("gcc_jit_context_acquire failed");
+      return;
+    }
+
+  logfile = set_up_logging (ctxt, argv0);
 
   set_options (ctxt, argv0);
 
@@ -275,6 +324,9 @@ test_jit (const char *argv0, void *user_data)
 
   /* Once we're done with the code, this unloads the built .so file: */
   gcc_jit_result_release (result);
+
+  if (logfile)
+    fclose (logfile);
 }
 #endif /* #ifndef TEST_ESCHEWS_TEST_JIT */
 
diff --git a/gcc/testsuite/jit.dg/test-nested-contexts.c b/gcc/testsuite/jit.dg/test-nested-contexts.c
index 16bc63f..81b1bb2 100644
--- a/gcc/testsuite/jit.dg/test-nested-contexts.c
+++ b/gcc/testsuite/jit.dg/test-nested-contexts.c
@@ -532,6 +532,10 @@ main (int argc, char **argv)
   /* We do the whole thing multiple times to shake out state-management
      issues in the underlying code.  */
 
+  FILE *logfile = fopen ("test-nested-contexts.c.exe.log.txt", "w");
+  if (!logfile)
+    fail ("error opening logfile");
+
   for (i = 1; i <= NUM_TOP_ITERATIONS; i++)
     {
       /* Create the top-level context.  */
@@ -544,6 +548,9 @@ main (int argc, char **argv)
       memset (&top_level, 0, sizeof (top_level));
 
       top_level.ctxt = gcc_jit_context_acquire ();
+      gcc_jit_context_set_logfile (top_level.ctxt,
+				   logfile,
+				   0, 0);
       set_options (top_level.ctxt, argv[0]);
 
       make_types (&top_level);
@@ -635,6 +642,9 @@ main (int argc, char **argv)
       gcc_jit_context_release (top_level.ctxt);
    }
 
+  if (logfile)
+    fclose (logfile);
+
   totals ();
 
   return 0;
-- 
1.8.5.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]