From 52b9468f1575b87e490cc3fdcff4c51f25fb49c1 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Mon, 1 Dec 2014 17:40:03 +0000 Subject: [PATCH] PR jit/63854: Fix leaks in toyvm.c gcc/jit/ChangeLog: PR jit/63854 * docs/examples/tut04-toyvm/toyvm.c (toyvm_compiled_function): New typedef. (toyvm_compiled_func) Rename to... (toyvm_compiled_code) ...this. (struct toyvm_compiled_function): New struct. (toyvm_function_compile): Return a toyvm_compiled_function * rather than a toyvm_compiled_func, so that the caller can fully clean things up. Free "funcname". (test_script): Update for change to toyvm_function_compile. Clean up the toyvm_compiled_function. (main): Likewise. (docs/intro/tutorial04.rst): Update to reflect the above changes, and to better spell out the lifetime of the compiled code. From-SVN: r218234 --- gcc/jit/ChangeLog | 17 ++++++++++ gcc/jit/docs/examples/tut04-toyvm/toyvm.c | 54 +++++++++++++++++++++++++------ gcc/jit/docs/intro/tutorial04.rst | 11 ++++++- 3 files changed, 72 insertions(+), 10 deletions(-) diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog index c103eb2..210dcb0 100644 --- a/gcc/jit/ChangeLog +++ b/gcc/jit/ChangeLog @@ -1,6 +1,23 @@ 2014-12-01 David Malcolm PR jit/63854 + * docs/examples/tut04-toyvm/toyvm.c + (toyvm_compiled_function): New typedef. + (toyvm_compiled_func) Rename to... + (toyvm_compiled_code) ...this. + (struct toyvm_compiled_function): New struct. + (toyvm_function_compile): Return a toyvm_compiled_function * + rather than a toyvm_compiled_func, so that the caller can fully + clean things up. Free "funcname". + (test_script): Update for change to toyvm_function_compile. + Clean up the toyvm_compiled_function. + (main): Likewise. + (docs/intro/tutorial04.rst): Update to reflect the above changes, + and to better spell out the lifetime of the compiled code. + +2014-12-01 David Malcolm + + PR jit/63854 * jit-builtins.c (gcc::jit::recording::builtins_manager::make_fn_type): Call the context's new_function_type method, rather than directly creating diff --git a/gcc/jit/docs/examples/tut04-toyvm/toyvm.c b/gcc/jit/docs/examples/tut04-toyvm/toyvm.c index 666bf2e..07de507 100644 --- a/gcc/jit/docs/examples/tut04-toyvm/toyvm.c +++ b/gcc/jit/docs/examples/tut04-toyvm/toyvm.c @@ -33,9 +33,10 @@ typedef struct toyvm_op toyvm_op; typedef struct toyvm_function toyvm_function; typedef struct toyvm_frame toyvm_frame; typedef struct compilation_state compilation_state; +typedef struct toyvm_compiled_function toyvm_compiled_function; /* Functions are compiled to this function ptr type. */ -typedef int (*toyvm_compiled_func) (int); +typedef int (*toyvm_compiled_code) (int); enum opcode { /* Ops taking no operand. */ @@ -440,9 +441,17 @@ add_pop (compilation_state *state, gcc_jit_lvalue_as_rvalue (state->stack_depth)))); } +/* A struct to hold the compilation results. */ + +struct toyvm_compiled_function +{ + gcc_jit_result *cf_jit_result; + toyvm_compiled_code cf_code; +}; + /* The main compilation hook. */ -static toyvm_compiled_func +static toyvm_compiled_function * toyvm_function_compile (toyvm_function *fn) { compilation_state state; @@ -724,12 +733,26 @@ toyvm_function_compile (toyvm_function *fn) } /* end of loop on PC locations. */ /* We've now finished populating the context. Compile it. */ - gcc_jit_result *result = gcc_jit_context_compile (state.ctxt); + gcc_jit_result *jit_result = gcc_jit_context_compile (state.ctxt); gcc_jit_context_release (state.ctxt); - return (toyvm_compiled_func)gcc_jit_result_get_code (result, - funcname); - /* (this leaks "result" and "funcname") */ + toyvm_compiled_function *toyvm_result = + (toyvm_compiled_function *)calloc (1, sizeof (toyvm_compiled_function)); + if (!toyvm_result) + { + fprintf (stderr, "out of memory allocating toyvm_compiled_function\n"); + gcc_jit_result_release (jit_result); + return NULL; + } + + toyvm_result->cf_jit_result = jit_result; + toyvm_result->cf_code = + (toyvm_compiled_code)gcc_jit_result_get_code (jit_result, + funcname); + + free (funcname); + + return toyvm_result; } char test[1024]; @@ -768,7 +791,8 @@ test_script (const char *scripts_dir, const char *script_name, int input, char *script_path; toyvm_function *fn; int interpreted_result; - toyvm_compiled_func code; + toyvm_compiled_function *compiled_fn; + toyvm_compiled_code code; int compiled_result; snprintf (test, sizeof (test), "toyvm.c: %s", script_name); @@ -784,12 +808,18 @@ test_script (const char *scripts_dir, const char *script_name, int input, interpreted_result = toyvm_function_interpret (fn, input, NULL); CHECK_VALUE (interpreted_result, expected_result); - code = toyvm_function_compile (fn); + compiled_fn = toyvm_function_compile (fn); + CHECK_NON_NULL (compiled_fn); + + code = (toyvm_compiled_code)compiled_fn->cf_code; CHECK_NON_NULL (code); compiled_result = code (input); CHECK_VALUE (compiled_result, expected_result); + gcc_jit_result_release (compiled_fn->cf_jit_result); + free (compiled_fn); + free (fn); free (script_path); } @@ -853,9 +883,15 @@ main (int argc, char **argv) toyvm_function_interpret (fn, atoi (argv[2]), NULL)); /* JIT-compilation. */ - toyvm_compiled_func code = toyvm_function_compile (fn); + toyvm_compiled_function *compiled_fn + = toyvm_function_compile (fn); + + toyvm_compiled_code code = compiled_fn->cf_code; printf ("compiler result: %d\n", code (atoi (argv[2]))); + gcc_jit_result_release (compiled_fn->cf_jit_result); + free (compiled_fn); + return 0; } diff --git a/gcc/jit/docs/intro/tutorial04.rst b/gcc/jit/docs/intro/tutorial04.rst index cafdddb..3aac670 100644 --- a/gcc/jit/docs/intro/tutorial04.rst +++ b/gcc/jit/docs/intro/tutorial04.rst @@ -101,6 +101,15 @@ then directly executed in-process: :end-before: enum opcode :language: c +The lifetime of the code is tied to that of a :c:type:`gcc_jit_result *`. +We'll handle this by bundling them up in a structure, so that we can +clean them up together by calling :c:func:`gcc_jit_result_release`: + + .. literalinclude:: ../examples/tut04-toyvm/toyvm.c + :start-after: /* A struct to hold the compilation results. */ + :end-before: /* The main compilation hook. */ + :language: c + Our compiler isn't very sophisticated; it takes the implementation of each opcode above, and maps it directly to the operations supported by the libgccjit API. @@ -155,7 +164,7 @@ a block, implementing pushing and popping values: .. literalinclude:: ../examples/tut04-toyvm/toyvm.c :start-after: /* Stack manipulation. */ - :end-before: /* The main compilation hook. */ + :end-before: /* A struct to hold the compilation results. */ :language: c We will support single-stepping through the generated code in the -- 2.7.4