@@ -37,10 +37,28 @@ gcc::context::context ()
before the pass manager. */
m_dumps = new gcc::dump_manager ();
m_passes = new gcc::pass_manager (this);
+ obstack_init (&m_longterm_obstack);
}
gcc::context::~context ()
{
delete m_passes;
delete m_dumps;
+ obstack_free (&m_longterm_obstack, NULL);
+}
+
+void *
+gcc::context::longterm_xalloc (size_t sz)
+{
+ return obstack_alloc (&m_longterm_obstack, sz);
+}
+
+char *
+gcc::context::longterm_xstrdup (const char *str)
+{
+ gcc_assert (str);
+ size_t sz = strlen (str) + 1;
+ char *buf = reinterpret_cast <char *> (longterm_xalloc (sz));
+ memcpy (buf, str, sz);
+ return buf;
}
@@ -20,6 +20,8 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_CONTEXT_H
#define GCC_CONTEXT_H
+#include <obstack.h>
+
namespace gcc {
class pass_manager;
@@ -45,6 +47,40 @@ public:
dump_manager *get_dumps () {gcc_assert (m_dumps); return m_dumps; }
+ /* Long-term allocation.
+
+ GCC's startup code sometimes uses a mix of static and dynamic memory
+ allocation, with no cleanup of the latter. Such allocations were
+ written under the assumption that the buffers can persist for the
+ rest of the compile and be effectively freed when the process
+ terminates.
+
+ This works for cc1 etc since these allocations are only called once,
+ but for libgccjit they are small per-invocation leaks.
+
+ The following functions provide a simple way to retrofit cleanup
+ into such places that weren't expecting the compiler to be called
+ more than once in-process.
+
+ They allocate buffers that will persist until the context is
+ deleted, when they are all cleaned up at once. */
+
+ /* Allocate a buffer, to persist until the context is deleted, without
+ needing explicit cleanup. */
+ void *longterm_xalloc (size_t) ATTRIBUTE_RETURNS_NONNULL;
+
+ /* Allocate an array of T, to persist until the context is deleted,
+ without needing explicit cleanup. */
+ template <typename T>
+ T *longterm_xallocvec (size_t len) ATTRIBUTE_RETURNS_NONNULL;
+
+ /* Copy a string into a memory buffer without fail.
+
+ As per libiberty's xstrdup, but the buffer is longterm-allocated so
+ that it persists until the context is deleted, without needing
+ explicit cleanup. */
+ char *longterm_xstrdup (const char *) ATTRIBUTE_RETURNS_NONNULL;
+
private:
/* Pass-management. */
pass_manager *m_passes;
@@ -52,10 +88,20 @@ private:
/* Dump files. */
dump_manager *m_dumps;
+ /* Long-term allocation is implemented using an obstack. */
+ struct obstack m_longterm_obstack;
+
}; // class context
} // namespace gcc
+template <typename T>
+inline T *
+gcc::context::longterm_xallocvec (size_t len)
+{
+ return reinterpret_cast <T *> (longterm_xalloc (sizeof (T) * len));
+}
+
/* The global singleton context aka "g".
(the name is chosen to be easy to type in a debugger). */
extern gcc::context *g;
@@ -936,7 +936,7 @@ init_asm_output (const char *name)
if (asm_file_name == 0)
{
int len = strlen (dump_base_name);
- char *dumpname = XNEWVEC (char, len + 6);
+ char *dumpname = g->longterm_xallocvec <char> (len + 6);
memcpy (dumpname, dump_base_name, len + 1);
strip_off_ending (dumpname, len);
@@ -1332,7 +1332,7 @@ process_options (void)
;
else if (main_input_filename)
{
- char *name = xstrdup (lbasename (main_input_filename));
+ char *name = g->longterm_xstrdup (lbasename (main_input_filename));
strip_off_ending (name, strlen (name));
aux_base_name = name;
@@ -88,6 +88,7 @@ along with GCC; see the file COPYING3. If not see
#include "intl.h"
#include "wide-int.h"
#include "builtins.h"
+#include "context.h"
/* Tree code classes. */
@@ -10126,6 +10127,7 @@ build_common_builtin_nodes (void)
enum built_in_function mcode, dcode;
tree type, inner_type;
const char *prefix = "__";
+ char *name;
if (targetm.libfunc_gnu_prefix)
prefix = "__gnu_";
@@ -10147,15 +10149,18 @@ build_common_builtin_nodes (void)
*q = TOLOWER (*p);
*q = '\0';
- built_in_names[mcode] = concat (prefix, "mul", mode_name_buf, "3",
- NULL);
- local_define_builtin (built_in_names[mcode], ftype, mcode,
+ name = concat (prefix, "mul", mode_name_buf, "3", NULL);
+ built_in_names[mcode] = g->longterm_xstrdup (name);
+ free (name);
+ local_define_builtin (built_in_names[mcode], ftype, mcode,
built_in_names[mcode],
ECF_CONST | ECF_NOTHROW | ECF_LEAF);
- built_in_names[dcode] = concat (prefix, "div", mode_name_buf, "3",
- NULL);
- local_define_builtin (built_in_names[dcode], ftype, dcode,
+ name = concat (prefix, "div", mode_name_buf, "3", NULL);
+ built_in_names[dcode] = g->longterm_xstrdup (name);
+ free (name);
+
+ local_define_builtin (built_in_names[dcode], ftype, dcode,
built_in_names[dcode],
ECF_CONST | ECF_NOTHROW | ECF_LEAF);
}