PR jit/63854: Fix leaks in toyvm.c
authorDavid Malcolm <dmalcolm@redhat.com>
Mon, 1 Dec 2014 17:40:03 +0000 (17:40 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Mon, 1 Dec 2014 17:40:03 +0000 (17:40 +0000)
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
gcc/jit/docs/examples/tut04-toyvm/toyvm.c
gcc/jit/docs/intro/tutorial04.rst

index c103eb2045c9b4fb9ed69b4bdee1c5f067884129..210dcb0c8eaf11feabcc4e8f6745df7eb2db9714 100644 (file)
@@ -1,3 +1,20 @@
+2014-12-01  David Malcolm  <dmalcolm@redhat.com>
+
+       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  <dmalcolm@redhat.com>
 
        PR jit/63854
index 666bf2ed2d3e0913d5e77f985a793c8b7ce1797c..07de507a132b826b276a8f48b3a9ed703d31f4ab 100644 (file)
@@ -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;
 }
index cafdddb2aefc21f1a2176f2aec9eaf12aa8bd31a..3aac6703b4c634abb615e2fc148833a93293e86e 100644 (file)
@@ -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