From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 26303 invoked by alias); 26 Nov 2014 01:32:05 -0000 Mailing-List: contact jit-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Post: List-Help: List-Subscribe: Sender: jit-owner@gcc.gnu.org Received: (qmail 26192 invoked by uid 89); 26 Nov 2014 01:32:04 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Checked: by ClamAV 0.98.4 on sourceware.org X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.0 required=5.0 tests=AWL,BAYES_00,SPF_HELO_PASS,SPF_PASS,T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-Spam-Status: No, score=-2.0 required=5.0 tests=AWL,BAYES_00,SPF_HELO_PASS,SPF_PASS,T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on sourceware.org X-Spam-Level: X-Spam-User: qpsmtpd, 2 recipients X-HELO: mx1.redhat.com From: David Malcolm To: gcc-patches@gcc.gnu.org, jit@gcc.gnu.org Cc: David Malcolm Subject: [PATCH 07/08] PR jit/63854: Fix leaks in toyvm.c Date: Wed, 01 Jan 2014 00:00:00 -0000 Message-Id: <1416965978-15582-8-git-send-email-dmalcolm@redhat.com> In-Reply-To: <1416965978-15582-1-git-send-email-dmalcolm@redhat.com> References: <1416965978-15582-1-git-send-email-dmalcolm@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-SW-Source: 2014-q4/txt/msg00208.txt.bz2 Introduce a struct toyvm_compiled_function so that we can clean things up fully, avoiding warnings from valgrind. gcc/jit/ChangeLog: PR jit/63854 (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. --- gcc/jit/docs/examples/tut04-toyvm/toyvm.c | 54 +++++++++++++++++++++++++------ gcc/jit/docs/intro/tutorial04.rst | 11 ++++++- 2 files changed, 55 insertions(+), 10 deletions(-) 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 -- 1.8.5.3