summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2012-01-14 00:26:43 (GMT)
committerDavid Malcolm <dmalcolm@redhat.com>2012-01-14 01:14:12 (GMT)
commit58d65a1b353220efbcf8d908b0946ef5d1c4fafd (patch)
treeab6de25c1e22048d6715224939710313f69b69a6
parente75f80d759f42a24f564952dd393568c5a83b529 (diff)
downloadgcc-python-plugin-58d65a1b353220efbcf8d908b0946ef5d1c4fafd.zip
gcc-python-plugin-58d65a1b353220efbcf8d908b0946ef5d1c4fafd.tar.gz
gcc-python-plugin-58d65a1b353220efbcf8d908b0946ef5d1c4fafd.tar.xz
integrate with GCC's garbage collector (ticket #1)
Support creating instances of PyTypeObject subclasses in cpybuilder.py, and convert all of the various wrapper object classes from being PyObject subclasses to being subclassed from PyGccWrapper. All instances of PyGccWrapper are now tracked in a doubly-linked list (and thus the types require a tp_dealloc of gcc_python_wrapper_dealloc in order to remove them from this list. Introduce wrapperbuilder.py and use it to convert all of the type objects for the wrapper classes to being instances of a new PyGccWrapperTypeObject. The above class changes allow us to add a new per-wrapper hook ("wrtp_mark") for working with GCC's garbage collector. Change "struct_name" from "struct foo" to "foo" when creating PyTypeObject instances in the various generate-*-c.py files, so that we can easily match up the autogenerated "wrtp_mark_for" callback from that file with the declaration of said callback from the DECLARE_SIMPLE_WRAPPER() macro in gcc-python.h Wire up to GCC's garbage collector (in the new gcc-python-wrapper.c), so that when it runs, we can iterate through all of our wrapper objects, and mark the wrapped objects, so they don't get swept (and deleted) from under us. Add gcc._gc_selftest() to exercise this machinery (for trees only, so far, and without exercising recursive marking) Add gc._force_garbage_collection() and a selftest for this. Fixes https://fedorahosted.org/gcc-python-plugin/ticket/1
-rw-r--r--Makefile27
-rw-r--r--cpybuilder.py30
-rw-r--r--gcc-python-callgraph.c27
-rw-r--r--gcc-python-cfg.c31
-rw-r--r--gcc-python-compat.h6
-rw-r--r--gcc-python-diagnostics.c2
-rw-r--r--gcc-python-function.c14
-rw-r--r--gcc-python-gimple.c16
-rw-r--r--gcc-python-location.c17
-rw-r--r--gcc-python-option.c17
-rw-r--r--gcc-python-parameter.c12
-rw-r--r--gcc-python-pass.c26
-rw-r--r--gcc-python-rtl.c17
-rw-r--r--gcc-python-tree.c22
-rw-r--r--gcc-python-variable.c9
-rw-r--r--gcc-python-wrapper.c264
-rw-r--r--gcc-python-wrappers.h10
-rw-r--r--gcc-python.c10
-rw-r--r--gcc-python.h82
-rw-r--r--generate-callgraph-c.py15
-rw-r--r--generate-cfg-c.py20
-rw-r--r--generate-function-c.py13
-rw-r--r--generate-gimple-c.py25
-rw-r--r--generate-location-c.py12
-rw-r--r--generate-option-c.py10
-rw-r--r--generate-parameter-c.py10
-rw-r--r--generate-pass-c.py16
-rw-r--r--generate-rtl-c.py24
-rw-r--r--generate-tree-c.py30
-rw-r--r--generate-variable-c.py10
-rw-r--r--tests/plugin/gc/_force_garbage_collection/input.c28
-rw-r--r--tests/plugin/gc/_force_garbage_collection/script.py55
-rw-r--r--tests/plugin/gc/_force_garbage_collection/stdout.txt2
-rw-r--r--tests/plugin/gc/_gc_selftest/input.c55
-rw-r--r--tests/plugin/gc/_gc_selftest/script.py25
-rw-r--r--tests/plugin/gc/_gc_selftest/stdout.txt18
-rw-r--r--wrapperbuilder.py43
37 files changed, 887 insertions, 163 deletions
diff --git a/Makefile b/Makefile
index a2e7421..9cb244d 100644
--- a/Makefile
+++ b/Makefile
@@ -36,6 +36,7 @@ PLUGIN_SOURCE_FILES= \
gcc-python-tree.c \
gcc-python-variable.c \
gcc-python-version.c \
+ gcc-python-wrapper.c \
autogenerated-callgraph.c \
autogenerated-cfg.c \
autogenerated-option.c \
@@ -52,6 +53,8 @@ PLUGIN_SOURCE_FILES= \
PLUGIN_OBJECT_FILES= $(patsubst %.c,%.o,$(PLUGIN_SOURCE_FILES))
GCCPLUGINS_DIR:= $(shell $(GCC) --print-file-name=plugin)
+GENERATOR_DEPS=cpybuilder.py wrapperbuilder.py
+
# The plugin supports both Python 2 and Python 3
#
# In theory we could have arbitrary combinations of python versions for each
@@ -116,40 +119,40 @@ autogenerated-rtl-types.txt: rtl-types.txt.in
autogenerated-tree-types.txt: tree-types.txt.in
cpp $(CFLAGS) $^ -o $@
-autogenerated-callgraph.c: cpybuilder.py generate-callgraph-c.py
+autogenerated-callgraph.c: $(GENERATOR_DEPS) generate-callgraph-c.py
python generate-callgraph-c.py > $@
-autogenerated-cfg.c: cpybuilder.py generate-cfg-c.py
+autogenerated-cfg.c: $(GENERATOR_DEPS) generate-cfg-c.py
$(PYTHON) generate-cfg-c.py > $@
-autogenerated-function.c: cpybuilder.py generate-function-c.py
+autogenerated-function.c: $(GENERATOR_DEPS) generate-function-c.py
$(PYTHON) generate-function-c.py > $@
-autogenerated-gimple.c: cpybuilder.py generate-gimple-c.py autogenerated-gimple-types.txt maketreetypes.py
+autogenerated-gimple.c: $(GENERATOR_DEPS) generate-gimple-c.py autogenerated-gimple-types.txt maketreetypes.py
$(PYTHON) generate-gimple-c.py > $@
-autogenerated-location.c: cpybuilder.py generate-location-c.py
+autogenerated-location.c: $(GENERATOR_DEPS) generate-location-c.py
$(PYTHON) generate-location-c.py > $@
-autogenerated-option.c: cpybuilder.py generate-option-c.py
+autogenerated-option.c: $(GENERATOR_DEPS) generate-option-c.py
$(PYTHON) generate-option-c.py > $@
-autogenerated-parameter.c: cpybuilder.py generate-parameter-c.py
+autogenerated-parameter.c: $(GENERATOR_DEPS) generate-parameter-c.py
$(PYTHON) generate-parameter-c.py > $@
-autogenerated-pass.c: cpybuilder.py generate-pass-c.py
+autogenerated-pass.c: $(GENERATOR_DEPS) generate-pass-c.py
$(PYTHON) generate-pass-c.py > $@
-autogenerated-pretty-printer.c: cpybuilder.py generate-pretty-printer-c.py
+autogenerated-pretty-printer.c: $(GENERATOR_DEPS) generate-pretty-printer-c.py
$(PYTHON) generate-pretty-printer-c.py > $@
-autogenerated-tree.c: cpybuilder.py generate-tree-c.py autogenerated-tree-types.txt maketreetypes.py
+autogenerated-tree.c: $(GENERATOR_DEPS) generate-tree-c.py autogenerated-tree-types.txt maketreetypes.py
$(PYTHON) generate-tree-c.py > $@
-autogenerated-rtl.c: cpybuilder.py generate-rtl-c.py autogenerated-rtl-types.txt maketreetypes.py
+autogenerated-rtl.c: $(GENERATOR_DEPS) generate-rtl-c.py autogenerated-rtl-types.txt maketreetypes.py
python generate-rtl-c.py > $@
-autogenerated-variable.c: cpybuilder.py generate-variable-c.py autogenerated-gimple-types.txt maketreetypes.py
+autogenerated-variable.c: $(GENERATOR_DEPS) generate-variable-c.py autogenerated-gimple-types.txt maketreetypes.py
$(PYTHON) generate-variable-c.py > $@
# Hint for debugging: add -v to the gcc options
diff --git a/cpybuilder.py b/cpybuilder.py
index cf743ed..ec22706 100644
--- a/cpybuilder.py
+++ b/cpybuilder.py
@@ -1,5 +1,5 @@
-# Copyright 2011 David Malcolm <dmalcolm@redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+# Copyright 2011, 2012 Red Hat, Inc.
#
# This is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -75,6 +75,17 @@ class NamedEntity:
else:
return ' %s, /* %s */\n' % (val, name)
+ def c_src_field_value(self, name, val, cast=None):
+ if cast:
+ caststr = '(%s)' % cast
+ else:
+ caststr = ''
+ if with_gcc_extensions:
+ # Designate the initializer fields:
+ return ' .%s = %s%s,\n' % (name, caststr, val)
+ else:
+ return ' %s%s, /* %s */\n' % (caststr, val, name)
+
class PyGetSetDef:
def __init__(self, name, get, set, doc, closure=None):
self.name = name
@@ -229,7 +240,13 @@ class PyTypeObject(NamedEntity):
def c_defn(self):
result = '\n'
result += 'PyTypeObject %(identifier)s = {\n' % self.__dict__
- result += ' PyVarObject_HEAD_INIT(0, 0)\n'
+ result += self.c_initializer()
+ result += '};\n' % self.__dict__
+ result +='\n'
+ return result
+
+ def c_initializer(self):
+ result = ' PyVarObject_HEAD_INIT(0, 0)\n'
result += ' "%(tp_name)s", /*tp_name*/\n' % self.__dict__
result += ' sizeof(%(struct_name)s), /*tp_basicsize*/\n' % self.__dict__
result += ' 0, /*tp_itemsize*/\n'
@@ -263,7 +280,7 @@ class PyTypeObject(NamedEntity):
result += self.c_ptr_field('tp_methods')
result += self.c_ptr_field('tp_members')
result += self.c_ptr_field('tp_getset')
- result += self.c_ptr_field('tp_base')
+ result += self.c_ptr_field('tp_base', 'PyTypeObject*')
result += self.c_ptr_field('tp_dict')
result += self.c_ptr_field('tp_descr_get')
result += self.c_ptr_field('tp_descr_set')
@@ -282,12 +299,11 @@ class PyTypeObject(NamedEntity):
result += '#if PY_VERSION_HEX >= 0x02060000\n' % self.__dict__
result += ' 0, /*tp_version_tag*/\n' % self.__dict__
result += '#endif\n' % self.__dict__
- result += '};\n' % self.__dict__
- result +='\n'
+ result += '\n'
return result
def c_invoke_type_ready(self):
- return (' if (PyType_Ready(&%(identifier)s) < 0)\n'
+ return (' if (PyType_Ready((PyTypeObject*)&%(identifier)s) < 0)\n'
' goto error;\n'
'\n') % self.__dict__
diff --git a/gcc-python-callgraph.c b/gcc-python-callgraph.c
index 289380a..ec5c1e1 100644
--- a/gcc-python-callgraph.c
+++ b/gcc-python-callgraph.c
@@ -1,6 +1,6 @@
/*
- Copyright 2011 David Malcolm <dmalcolm@redhat.com>
- Copyright 2011 Red Hat, Inc.
+ Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+ Copyright 2011, 2012 Red Hat, Inc.
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
@@ -120,13 +120,12 @@ gcc_python_make_wrapper_cgraph_edge(struct cgraph_edge * edge)
{
struct PyGccCallgraphEdge *obj = NULL;
- obj = PyObject_New(struct PyGccCallgraphEdge, &gcc_CallgraphEdgeType);
+ obj = PyGccWrapper_New(struct PyGccCallgraphEdge, &gcc_CallgraphEdgeType);
if (!obj) {
goto error;
}
obj->edge = edge;
- /* FIXME: do we need to do something for the GCC GC? */
return (PyObject*)obj;
@@ -134,19 +133,27 @@ error:
return NULL;
}
+void
+wrtp_mark_for_PyGccCallgraphEdge(PyGccCallgraphEdge *wrapper)
+{
+ /* Mark the underlying object (recursing into its fields): */
+ gt_ggc_mx_cgraph_edge(wrapper->edge);
+}
+
+
PyObject *
real_make_cgraph_node_wrapper(void *ptr)
{
struct cgraph_node * node = (struct cgraph_node *)ptr;
struct PyGccCallgraphNode *obj = NULL;
- obj = PyObject_New(struct PyGccCallgraphNode, &gcc_CallgraphNodeType);
+ obj = PyGccWrapper_New(struct PyGccCallgraphNode,
+ &gcc_CallgraphNodeType);
if (!obj) {
goto error;
}
obj->node = node;
- /* FIXME: do we need to do something for the GCC GC? */
return (PyObject*)obj;
@@ -154,6 +161,14 @@ error:
return NULL;
}
+void
+wrtp_mark_for_PyGccCallgraphNode(PyGccCallgraphNode *wrapper)
+{
+ /* Mark the underlying object (recursing into its fields): */
+ gt_ggc_mx_cgraph_node(wrapper->node);
+}
+
+
static PyObject *cgraph_node_wrapper_cache = NULL;
PyObject *
gcc_python_make_wrapper_cgraph_node(struct cgraph_node * node)
diff --git a/gcc-python-cfg.c b/gcc-python-cfg.c
index dae6a46..b72d298 100644
--- a/gcc-python-cfg.c
+++ b/gcc-python-cfg.c
@@ -42,13 +42,12 @@ gcc_python_make_wrapper_edge(edge e)
Py_RETURN_NONE;
}
- obj = PyObject_New(struct PyGccEdge, &gcc_EdgeType);
+ obj = PyGccWrapper_New(struct PyGccEdge, &gcc_EdgeType);
if (!obj) {
goto error;
}
obj->e = e;
- /* FIXME: do we need to do something for the GCC GC? */
return (PyObject*)obj;
@@ -56,6 +55,14 @@ error:
return NULL;
}
+void
+wrtp_mark_for_PyGccEdge(PyGccEdge *wrapper)
+{
+ /* Mark the underlying object (recursing into its fields): */
+ gt_ggc_mx_edge_def(wrapper->e);
+}
+
+
/*
"struct basic_block_def" is declared in basic-block.h, c.f:
struct GTY((chain_next ("%h.next_bb"), chain_prev ("%h.prev_bb"))) basic_block_def {
@@ -348,7 +355,7 @@ real_make_basic_block_wrapper(void *ptr)
Py_RETURN_NONE;
}
- obj = PyObject_New(struct PyGccBasicBlock, &gcc_BasicBlockType);
+ obj = PyGccWrapper_New(struct PyGccBasicBlock, &gcc_BasicBlockType);
if (!obj) {
goto error;
}
@@ -415,7 +422,6 @@ real_make_basic_block_wrapper(void *ptr)
#endif
obj->bb = bb;
- /* FIXME: do we need to do something for the GCC GC? */
return (PyObject*)obj;
@@ -423,6 +429,14 @@ error:
return NULL;
}
+void
+wrtp_mark_for_PyGccBasicBlock(PyGccBasicBlock *wrapper)
+{
+ /* Mark the underlying object (recursing into its fields): */
+ gt_ggc_mx_basic_block_def(wrapper->bb);
+}
+
+
static PyObject *basic_block_wrapper_cache = NULL;
PyObject *
gcc_python_make_wrapper_basic_block(basic_block bb)
@@ -507,13 +521,12 @@ gcc_python_make_wrapper_cfg(struct control_flow_graph *cfg)
Py_RETURN_NONE;
}
- obj = PyObject_New(struct PyGccCfg, &gcc_CfgType);
+ obj = PyGccWrapper_New(struct PyGccCfg, &gcc_CfgType);
if (!obj) {
goto error;
}
obj->cfg = cfg;
- /* FIXME: do we need to do something for the GCC GC? */
return (PyObject*)obj;
@@ -521,6 +534,12 @@ error:
return NULL;
}
+void
+wrtp_mark_for_PyGccCfg(PyGccCfg *wrapper)
+{
+ /* Mark the underlying object (recursing into its fields): */
+ gt_ggc_mx_control_flow_graph(wrapper->cfg);
+}
/*
PEP-7
diff --git a/gcc-python-compat.h b/gcc-python-compat.h
index 3c3985e..b12a4b8 100644
--- a/gcc-python-compat.h
+++ b/gcc-python-compat.h
@@ -1,6 +1,6 @@
/*
- Copyright 2011 David Malcolm <dmalcolm@redhat.com>
- Copyright 2011 Red Hat, Inc.
+ Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+ Copyright 2011, 2012 Red Hat, Inc.
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
@@ -50,6 +50,8 @@ extern int
dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
bool is_stmt);
+/* Within gcc/gcc-internal.h, not exposed by plugin API */
+extern bool ggc_force_collect;
/* From c-family/c-common.h */
extern tree c_sizeof_or_alignof_type (location_t, tree, bool, int);
diff --git a/gcc-python-diagnostics.c b/gcc-python-diagnostics.c
index b3e509c..7b6f9db 100644
--- a/gcc-python-diagnostics.c
+++ b/gcc-python-diagnostics.c
@@ -115,7 +115,7 @@ gcc_python_warning(PyObject *self, PyObject *args, PyObject *kwargs)
assert(opt_obj);
/* If a gcc.Option was given, extract the code: */
- if (Py_TYPE(opt_obj) == &gcc_OptionType) {
+ if (Py_TYPE(opt_obj) == (PyTypeObject*)&gcc_OptionType) {
opt_code = ((PyGccOption*)opt_obj)->opt_code;
/* Ugly workaround; see this function: */
diff --git a/gcc-python-function.c b/gcc-python-function.c
index 379bd5e..a4997d6 100644
--- a/gcc-python-function.c
+++ b/gcc-python-function.c
@@ -1,6 +1,6 @@
/*
- Copyright 2011 David Malcolm <dmalcolm@redhat.com>
- Copyright 2011 Red Hat, Inc.
+ Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+ Copyright 2011, 2012 Red Hat, Inc.
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
@@ -112,13 +112,12 @@ gcc_python_make_wrapper_function(struct function *fun)
#endif
#endif
- obj = PyObject_New(struct PyGccFunction, &gcc_FunctionType);
+ obj = PyGccWrapper_New(struct PyGccFunction, &gcc_FunctionType);
if (!obj) {
goto error;
}
obj->fun = fun;
- /* FIXME: do we need to do something for the GCC GC? */
return (PyObject*)obj;
@@ -126,6 +125,13 @@ error:
return NULL;
}
+void
+wrtp_mark_for_PyGccFunction(PyGccFunction *wrapper)
+{
+ /* Mark the underlying object (recursing into its fields): */
+ gt_ggc_mx_function(wrapper->fun);
+}
+
/*
PEP-7
diff --git a/gcc-python-gimple.c b/gcc-python-gimple.c
index b461786..6a3b156 100644
--- a/gcc-python-gimple.c
+++ b/gcc-python-gimple.c
@@ -1,6 +1,6 @@
/*
- Copyright 2011 David Malcolm <dmalcolm@redhat.com>
- Copyright 2011 Red Hat, Inc.
+ Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+ Copyright 2011, 2012 Red Hat, Inc.
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
@@ -276,19 +276,18 @@ PyObject*
gcc_python_make_wrapper_gimple(gimple stmt)
{
struct PyGccGimple *gimple_obj = NULL;
- PyTypeObject* tp;
+ PyGccWrapperTypeObject* tp;
tp = gcc_python_autogenerated_gimple_type_for_stmt(stmt);
assert(tp);
//printf("tp:%p\n", tp);
- gimple_obj = PyObject_New(struct PyGccGimple, tp);
+ gimple_obj = PyGccWrapper_New(struct PyGccGimple, tp);
if (!gimple_obj) {
goto error;
}
gimple_obj->stmt = stmt;
- /* FIXME: do we need to do something for the GCC GC? */
return (PyObject*)gimple_obj;
@@ -296,6 +295,13 @@ error:
return NULL;
}
+void
+wrtp_mark_for_PyGccGimple(PyGccGimple *wrapper)
+{
+ /* Mark the underlying object (recursing into its fields): */
+ gt_ggc_mx_gimple_statement_d(wrapper->stmt);
+}
+
/*
PEP-7
Local variables:
diff --git a/gcc-python-location.c b/gcc-python-location.c
index 76a0a87..964c921 100644
--- a/gcc-python-location.c
+++ b/gcc-python-location.c
@@ -1,6 +1,6 @@
/*
- Copyright 2011 David Malcolm <dmalcolm@redhat.com>
- Copyright 2011 Red Hat, Inc.
+ Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+ Copyright 2011, 2012 Red Hat, Inc.
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
@@ -56,9 +56,9 @@ gcc_Location_richcompare(PyObject *o1, PyObject *o2, int op)
int cond;
PyObject *result_obj;
- assert(Py_TYPE(o1) == &gcc_LocationType);
+ assert(Py_TYPE(o1) == (PyTypeObject*)&gcc_LocationType);
- if (Py_TYPE(o1) != &gcc_LocationType) {
+ if (Py_TYPE(o1) != (PyTypeObject*)&gcc_LocationType) {
result_obj = Py_NotImplemented;
goto out;
}
@@ -95,13 +95,12 @@ gcc_python_make_wrapper_location(location_t loc)
Py_RETURN_NONE;
}
- location_obj = PyObject_New(struct PyGccLocation, &gcc_LocationType);
+ location_obj = PyGccWrapper_New(struct PyGccLocation, &gcc_LocationType);
if (!location_obj) {
goto error;
}
location_obj->loc = loc;
- /* FIXME: do we need to do something for the GCC GC? */
return (PyObject*)location_obj;
@@ -109,6 +108,12 @@ error:
return NULL;
}
+void
+wrtp_mark_for_PyGccLocation(PyGccLocation *wrapper)
+{
+ /* empty */
+}
+
/*
PEP-7
diff --git a/gcc-python-option.c b/gcc-python-option.c
index 31a58d0..04835f5 100644
--- a/gcc-python-option.c
+++ b/gcc-python-option.c
@@ -1,6 +1,6 @@
/*
- Copyright 2011 David Malcolm <dmalcolm@redhat.com>
- Copyright 2011 Red Hat, Inc.
+ Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+ Copyright 2011, 2012 Red Hat, Inc.
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
@@ -46,6 +46,11 @@ gcc_Option_init(PyGccOption * self, PyObject *args, PyObject *kwargs)
static char *kwlist[] = {"text", NULL};
int i;
+ /*
+ We need to call _track manually as we're not using PyGccWrapper_New():
+ */
+ gcc_python_wrapper_track(&self->head);
+
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist,
&text)) {
return -1;
@@ -152,7 +157,7 @@ gcc_python_make_wrapper_opt_code(enum opt_code opt_code)
{
struct PyGccOption *opt_obj = NULL;
- opt_obj = PyObject_New(struct PyGccOption, &gcc_OptionType);
+ opt_obj = PyGccWrapper_New(struct PyGccOption, &gcc_OptionType);
if (!opt_obj) {
goto error;
}
@@ -165,6 +170,12 @@ error:
return NULL;
}
+void
+wrtp_mark_for_PyGccOption(PyGccOption *wrapper)
+{
+ /* empty */
+}
+
/*
PEP-7
Local variables:
diff --git a/gcc-python-parameter.c b/gcc-python-parameter.c
index 8608634..9649539 100644
--- a/gcc-python-parameter.c
+++ b/gcc-python-parameter.c
@@ -1,6 +1,6 @@
/*
- Copyright 2011 David Malcolm <dmalcolm@redhat.com>
- Copyright 2011 Red Hat, Inc.
+ Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+ Copyright 2011, 2012 Red Hat, Inc.
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
@@ -31,7 +31,7 @@ gcc_python_make_wrapper_param_num(compiler_param param_num)
{
struct PyGccParameter *param_obj = NULL;
- param_obj = PyObject_New(struct PyGccParameter, &gcc_ParameterType);
+ param_obj = PyGccWrapper_New(struct PyGccParameter, &gcc_ParameterType);
if (!param_obj) {
goto error;
}
@@ -44,6 +44,12 @@ error:
return NULL;
}
+void
+wrtp_mark_for_PyGccParameter(PyGccParameter *wrapper)
+{
+ /* empty */
+}
+
/*
PEP-7
Local variables:
diff --git a/gcc-python-pass.c b/gcc-python-pass.c
index a54ea9b..5315df1 100644
--- a/gcc-python-pass.c
+++ b/gcc-python-pass.c
@@ -1,6 +1,6 @@
/*
- Copyright 2011 David Malcolm <dmalcolm@redhat.com>
- Copyright 2011 Red Hat, Inc.
+ Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+ Copyright 2011, 2012 Red Hat, Inc.
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
@@ -164,6 +164,11 @@ do_pass_init(PyObject *s, PyObject *args, PyObject *kwargs,
NULL};
struct opt_pass *pass;
+ /*
+ We need to call _track manually as we're not using PyGccWrapper_New():
+ */
+ gcc_python_wrapper_track(&self->head);
+
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"s:gcc.Pass.__init__", keywords,
&name)) {
@@ -196,7 +201,6 @@ do_pass_init(PyObject *s, PyObject *args, PyObject *kwargs,
return -1;
}
-
self->pass = pass;
return 0; // FIXME
}
@@ -438,7 +442,7 @@ gcc_Pass_replace(struct PyGccPass *self, PyObject *args, PyObject *kwargs)
"s|i:replace");
}
-static PyTypeObject *
+static PyGccWrapperTypeObject *
get_type_for_pass_type(enum opt_pass_type pt)
{
switch (pt) {
@@ -463,7 +467,7 @@ static PyObject *
real_make_pass_wrapper(void *p)
{
struct opt_pass *pass = (struct opt_pass *)p;
- PyTypeObject *type_obj;
+ PyGccWrapperTypeObject *type_obj;
struct PyGccPass *pass_obj = NULL;
if (NULL == pass) {
@@ -472,7 +476,7 @@ real_make_pass_wrapper(void *p)
type_obj = get_type_for_pass_type(pass->type);
- pass_obj = PyObject_New(struct PyGccPass, type_obj);
+ pass_obj = PyGccWrapper_New(struct PyGccPass, type_obj);
if (!pass_obj) {
goto error;
}
@@ -486,6 +490,16 @@ error:
return NULL;
}
+void
+wrtp_mark_for_PyGccPass(PyGccPass *wrapper)
+{
+ /*
+ This function is empty: struct opt_pass does not have a GTY()
+ and any (struct opt_pass*) is either statically-allocated, or
+ allocated by us within do_pass_init using PyMem_Malloc
+ */
+}
+
PyObject *
gcc_python_make_wrapper_pass(struct opt_pass *pass)
{
diff --git a/gcc-python-rtl.c b/gcc-python-rtl.c
index 54dc18c..919c165 100644
--- a/gcc-python-rtl.c
+++ b/gcc-python-rtl.c
@@ -1,6 +1,6 @@
/*
- Copyright 2011 David Malcolm <dmalcolm@redhat.com>
- Copyright 2011 Red Hat, Inc.
+ Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+ Copyright 2011, 2012 Red Hat, Inc.
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
@@ -172,7 +172,7 @@ PyObject*
gcc_python_make_wrapper_rtl(struct rtx_def *insn)
{
struct PyGccRtl *rtl_obj = NULL;
- PyTypeObject* tp;
+ PyGccWrapperTypeObject* tp;
if (!insn) {
Py_RETURN_NONE;
@@ -181,13 +181,11 @@ gcc_python_make_wrapper_rtl(struct rtx_def *insn)
tp = gcc_python_autogenerated_rtl_type_for_stmt(insn);
assert(tp);
- rtl_obj = PyObject_New(struct PyGccRtl, tp);
+ rtl_obj = PyGccWrapper_New(struct PyGccRtl, tp);
if (!rtl_obj) {
goto error;
}
-
rtl_obj->insn = insn;
- /* FIXME: do we need to do something for the GCC GC? */
return (PyObject*)rtl_obj;
@@ -195,6 +193,13 @@ error:
return NULL;
}
+void
+wrtp_mark_for_PyGccRtl(PyGccRtl *wrapper)
+{
+ /* Mark the underlying object (recursing into its fields): */
+ gt_ggc_mx_rtx_def(wrapper->insn);
+}
+
/*
PEP-7
Local variables:
diff --git a/gcc-python-tree.c b/gcc-python-tree.c
index a0af94e..983edd5 100644
--- a/gcc-python-tree.c
+++ b/gcc-python-tree.c
@@ -104,11 +104,11 @@ gcc_Tree_richcompare(PyObject *o1, PyObject *o2, int op)
int cond;
PyObject *result_obj;
- if (!PyObject_TypeCheck(o1, &gcc_TreeType)) {
+ if (!PyObject_TypeCheck(o1, (PyTypeObject*)&gcc_TreeType)) {
result_obj = Py_NotImplemented;
goto out;
}
- if (!PyObject_TypeCheck(o2, &gcc_TreeType)) {
+ if (!PyObject_TypeCheck(o2, (PyTypeObject*)&gcc_TreeType)) {
result_obj = Py_NotImplemented;
goto out;
}
@@ -581,7 +581,7 @@ real_make_tree_wrapper(void *t)
{
struct PyGccTree *tree_obj = NULL;
- PyTypeObject* tp;
+ PyGccWrapperTypeObject* tp;
if (NULL == t) {
Py_RETURN_NONE;
@@ -590,13 +590,12 @@ real_make_tree_wrapper(void *t)
tp = gcc_python_autogenerated_tree_type_for_tree(t, 1);
assert(tp);
- tree_obj = PyObject_New(struct PyGccTree, tp);
+ tree_obj = PyGccWrapper_New(struct PyGccTree, tp);
if (!tree_obj) {
goto error;
}
tree_obj->t = t;
- /* FIXME: do we need to do something for the GCC GC? */
return (PyObject*)tree_obj;
@@ -604,6 +603,13 @@ error:
return NULL;
}
+void
+wrtp_mark_for_PyGccTree(PyGccTree *wrapper)
+{
+ /* Mark the underlying object (recursing into its fields): */
+ gt_ggc_mx_tree_node(wrapper->t);
+}
+
/*
Ensure we have a unique PyGccTree per tree address (by maintaining a dict)
(what about lifetimes?)
@@ -618,6 +624,12 @@ gcc_python_make_wrapper_tree(tree t)
real_make_tree_wrapper);
}
+PyObject *
+gcc_python_make_wrapper_tree_unique(tree t)
+{
+ return real_make_tree_wrapper(t);
+}
+
/* Walk the chain of a tree, building a python list of wrapper gcc.Tree
instances */
PyObject *
diff --git a/gcc-python-variable.c b/gcc-python-variable.c
index 2fcabd2..13b35e2 100644
--- a/gcc-python-variable.c
+++ b/gcc-python-variable.c
@@ -30,13 +30,12 @@ gcc_python_make_wrapper_variable(struct varpool_node *node)
Py_RETURN_NONE;
}
- var_obj = PyObject_New(struct PyGccVariable, &gcc_VariableType);
+ var_obj = PyGccWrapper_New(struct PyGccVariable, &gcc_VariableType);
if (!var_obj) {
goto error;
}
var_obj->var = node;
- /* FIXME: do we need to do something for the GCC GC? */
return (PyObject*)var_obj;
@@ -44,6 +43,12 @@ error:
return NULL;
}
+void
+wrtp_mark_for_PyGccVariable(PyGccVariable *wrapper)
+{
+ /* Mark the underlying object (recursing into its fields): */
+ gt_ggc_mx_varpool_node(wrapper->var);
+}
/*
PEP-7
diff --git a/gcc-python-wrapper.c b/gcc-python-wrapper.c
new file mode 100644
index 0000000..93234b0
--- /dev/null
+++ b/gcc-python-wrapper.c
@@ -0,0 +1,264 @@
+/*
+ Copyright 2012 David Malcolm <dmalcolm@redhat.com>
+ Copyright 2012 Red Hat, Inc.
+
+ This 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 of the License, or
+ (at your option) any later version.
+
+ This program 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 this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ Low-level wrapper support, with integration with GCC's garbage
+ collector (aka "GGC")
+*/
+
+#include <Python.h>
+#include "gcc-python.h"
+#include "gcc-python-wrappers.h"
+#include "gcc-python-compat.h"
+
+/* Debugging, for use by selftest routine */
+static int debug_gcc_python_wrapper = 0;
+
+/* Maintain a circular linked list of PyGccWrapper instances: */
+static struct PyGccWrapper sentinel = {
+ PyObject_HEAD_INIT(NULL)
+ &sentinel,
+ &sentinel,
+};
+
+PyGccWrapper *
+_PyGccWrapper_New(PyGccWrapperTypeObject *typeobj)
+{
+ PyGccWrapper *obj;
+ assert(typeobj);
+
+ obj = PyObject_New(PyGccWrapper,
+ (PyTypeObject*)typeobj);
+ if (!obj) {
+ return NULL;
+ }
+
+ /* Add to list of live PyGccWrapper objects: */
+ gcc_python_wrapper_track(obj);
+
+ return obj;
+}
+
+extern void
+gcc_python_wrapper_track(struct PyGccWrapper *obj)
+{
+ assert(obj);
+ assert(sentinel.wr_next);
+ assert(sentinel.wr_prev);
+ /* obj is uninitialized, apart from ob_type and ob_refcnt */
+
+ if (debug_gcc_python_wrapper) {
+ printf(" gcc_python_wrapper_track: %s\n",
+ Py_TYPE(obj)->tp_name);
+ }
+
+ /*
+ obj's type must use correct delloc, so that obj removes itself from the
+ list. obj->ob_type->tp_dealloc should be either
+ gcc_python_wrapper_dealloc or subtype_dealloc
+ */
+
+ /* Add to end of list, immediately before sentinel: */
+ assert(sentinel.wr_prev->wr_next == &sentinel);
+ sentinel.wr_prev->wr_next = obj;
+ obj->wr_prev = sentinel.wr_prev;
+ obj->wr_next = &sentinel;
+ sentinel.wr_prev = obj;
+
+ assert(obj->wr_prev);
+ assert(obj->wr_next);
+}
+
+void
+gcc_python_wrapper_untrack(struct PyGccWrapper *obj)
+{
+ if (debug_gcc_python_wrapper) {
+ printf(" gcc_python_wrapper_untrack: %s\n", Py_TYPE(obj)->tp_name);
+ }
+
+ assert(obj);
+ assert(Py_REFCNT(obj) == 0);
+ assert(sentinel.wr_next);
+ assert(sentinel.wr_prev);
+ assert(obj->wr_prev);
+ assert(obj->wr_next);
+
+ /* Remove from linked list: */
+ obj->wr_prev->wr_next = obj->wr_next;
+ obj->wr_next->wr_prev = obj->wr_prev;
+ obj->wr_prev = NULL;
+ obj->wr_next = NULL;
+}
+
+void
+gcc_python_wrapper_dealloc(PyObject *obj)
+{
+ assert(obj);
+ assert(Py_REFCNT(obj) == 0);
+ if (debug_gcc_python_wrapper) {
+ printf(" gcc_python_wrapper_dealloc: %s\n",
+ Py_TYPE(obj)->tp_name);
+ }
+ gcc_python_wrapper_untrack((struct PyGccWrapper*)obj);
+ Py_TYPE(obj)->tp_free(obj);
+}
+
+static void
+my_walker(void *arg ATTRIBUTE_UNUSED)
+{
+ /*
+ Callback for use by GCC's garbage collector when marking
+
+ Walk all the PyGccWrapper objects here and if they reference
+ GCC GC objects, mark the underlying GCC objects so that they
+ don't get swept
+ */
+ struct PyGccWrapper *iter;
+
+ if (debug_gcc_python_wrapper) {
+ printf(" walking the live PyGccWrapper objects\n");
+ }
+ for (iter = sentinel.wr_next; iter != &sentinel; iter = iter->wr_next) {
+ wrtp_marker wrtp_mark;
+ if (debug_gcc_python_wrapper) {
+ printf(" marking inner object for: ");
+ PyObject_Print((PyObject*)iter, stdout, 0);
+ printf("\n");
+ }
+ wrtp_mark = ((PyGccWrapperTypeObject*)Py_TYPE(iter))->wrtp_mark;
+ assert(wrtp_mark);
+ wrtp_mark(iter);
+ }
+ if (debug_gcc_python_wrapper) {
+ printf(" finished walking the live PyGccWrapper objects\n");
+ }
+}
+
+static struct ggc_root_tab myroot = { "", 1, 1, my_walker, NULL };
+
+void
+gcc_python_wrapper_init(void)
+{
+ /* Register our GC root-walking callback: */
+ ggc_register_root_tab(&myroot);
+}
+
+static void
+force_gcc_gc(void)
+{
+ bool stored = ggc_force_collect;
+
+ ggc_force_collect = true;
+ ggc_collect();
+ ggc_force_collect = stored;
+}
+
+PyObject *
+gcc_python__force_garbage_collection(PyObject *self, PyObject *args)
+{
+ force_gcc_gc();
+ Py_RETURN_NONE;
+}
+
+#define MY_ASSERT(condition) \
+ if (!(condition)) { \
+ PyErr_SetString(PyExc_AssertionError, #condition); \
+ return NULL; \
+ }
+
+PyObject *
+gcc_python__gc_selftest(PyObject *self, PyObject *args)
+{
+ tree tree_intcst;
+ PyObject *wrapper_intcst;
+
+ tree tree_str;
+ PyObject *wrapper_str;
+
+ printf("gcc._gc_selftest() starting\n");
+
+ /* Enable verbose logging: */
+ debug_gcc_python_wrapper = 1;
+
+ /*
+ Approach: construct various GCC objects here, unreferenced by anything.
+ Wrap them in Python objects, then force the GCC GC, then verify that the
+ underlying objects were marked, and weren't collected.
+
+ See http://gcc.gnu.org/onlinedocs/gccint/Type-Information.html for some
+ notes on GCC's garbage collector.
+ */
+
+ printf("creating test GCC objects\n");
+
+ /* We're called from PLUGIN_FINISH, so integer_types[] should be ready: */
+ tree_intcst = build_int_cst(integer_types[itk_int], 42);
+ wrapper_intcst = gcc_python_make_wrapper_tree_unique(tree_intcst);
+ MY_ASSERT(wrapper_intcst);
+
+ #define MY_TEST_STRING "I am only referenced via a python wrapper"
+ tree_str = build_string(strlen(MY_TEST_STRING), MY_TEST_STRING);
+
+ /* We should now have a newly-allocated tree node; it should not
+ have been marked yet by the GC: */
+ MY_ASSERT(tree_str);
+ //MY_ASSERT(!ggc_marked_p(str)); // this fails, why? why is it being marked?
+
+ /* Wrap it with a Python object: */
+ wrapper_str = gcc_python_make_wrapper_tree_unique(tree_str);
+ MY_ASSERT(wrapper_str);
+
+ /* Force a garbage collection: */
+ printf("forcing a garbage collection:\n");
+ force_gcc_gc();
+ printf("completed the forced garbage collection\n");
+
+ /*
+ Verify that the various wrapped objects were marked (via the Python
+ wrapper).
+ If it was not marked, then we're accessing freed memory,
+ and this will likely fail with an Internal Compiler Error
+ */
+ printf("verifying that the underlying GCC objects were marked\n");
+ MY_ASSERT(ggc_marked_p(tree_intcst));
+ MY_ASSERT(ggc_marked_p(tree_str));
+ printf("all of the underlying GCC objects were indeed marked\n");
+
+ /* Clean up the wrapper objects: */
+ printf("invoking DECREF on Python wrapper objects\n");
+ Py_DECREF(wrapper_intcst);
+ Py_DECREF(wrapper_str);
+
+ /* FIXME: need to do this for all of our types (base classes, at least) */
+
+ printf("gcc._gc_selftest() complete\n");
+
+ /* Turn off verbose logging: */
+ debug_gcc_python_wrapper = 0;
+
+ Py_RETURN_NONE;
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/gcc-python-wrappers.h b/gcc-python-wrappers.h
index 7f5438b..a3a5b42 100644
--- a/gcc-python-wrappers.h
+++ b/gcc-python-wrappers.h
@@ -315,6 +315,16 @@ gcc_python_get_plugin_gcc_version(PyObject *self, PyObject *args);
PyObject *
gcc_python_get_gcc_version(PyObject *self, PyObject *args);
+/* gcc-python-wrappers.c: */
+void
+gcc_python_wrapper_init(void);
+
+PyObject *
+gcc_python__force_garbage_collection(PyObject *self, PyObject *args);
+
+PyObject *
+gcc_python__gc_selftest(PyObject *self, PyObject *args);
+
/*
PEP-7
Local variables:
diff --git a/gcc-python.c b/gcc-python.c
index fb5fba9..e838abd 100644
--- a/gcc-python.c
+++ b/gcc-python.c
@@ -412,6 +412,13 @@ static PyMethodDef GccMethods[] = {
{"get_dump_base_name", gcc_python_get_dump_base_name, METH_NOARGS,
"Get the base name used when writing dump files"},
+ /* Garbage collection */
+ {"_force_garbage_collection", gcc_python__force_garbage_collection, METH_VARARGS,
+ "Forcibly trigger a single run of GCC's garbage collector"},
+
+ {"_gc_selftest", gcc_python__gc_selftest, METH_VARARGS,
+ "Run a garbage-collection selftest"},
+
/* Sentinel: */
{NULL, NULL, 0, NULL}
};
@@ -707,7 +714,10 @@ plugin_init (struct plugin_name_args *plugin_info,
}
/* Init other modules */
+ gcc_python_wrapper_init();
+
/* FIXME: properly integrate them within the module hierarchy */
+
gcc_python_version_init(version);
autogenerated_callgraph_init_types(); /* FIXME: error checking! */
diff --git a/gcc-python.h b/gcc-python.h
index ce15adb..d57316d 100644
--- a/gcc-python.h
+++ b/gcc-python.h
@@ -1,6 +1,6 @@
/*
- Copyright 2011 David Malcolm <dmalcolm@redhat.com>
- Copyright 2011 Red Hat, Inc.
+ Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+ Copyright 2011, 2012 Red Hat, Inc.
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
@@ -55,6 +55,59 @@
#endif
/*
+ PyObject shared header for wrapping GCC objects, for integration
+ with GCC's garbage collector (so that things we wrap don't get collected
+ from under us)
+*/
+typedef struct PyGccWrapper
+{
+ PyObject_HEAD
+
+ /*
+ Keep track of a linked list of all live wrapper objects,
+ so that we can mark the wrapped objects for GCC's garbage
+ collector:
+ */
+ struct PyGccWrapper *wr_prev;
+ struct PyGccWrapper *wr_next;
+} PyGccWrapper;
+
+/*
+ PyTypeObject subclass for PyGccWrapper, adding a GC-marking callback:
+ */
+typedef void (*wrtp_marker) (PyGccWrapper *wrapper);
+
+typedef struct PyGccWrapperTypeObject
+{
+ PyTypeObject wrtp_base;
+
+ /* Callback for marking the wrapped objects when GCC's garbage
+ collector runs: */
+ wrtp_marker wrtp_mark;
+
+} PyGccWrapperTypeObject;
+
+/* gcc-python-wrapper.c */
+
+/*
+ Allocate a new PyGccWrapper of the given type, setting up:
+ - ob_refcnt
+ - ob_type
+ and calling gcc_python_wrapper_track() on it:
+*/
+#define PyGccWrapper_New(ARG_structname, ARG_typeobj) \
+ ( (ARG_structname*) _PyGccWrapper_New(ARG_typeobj) )
+
+extern PyGccWrapper *
+_PyGccWrapper_New(PyGccWrapperTypeObject *typeobj);
+
+extern void
+gcc_python_wrapper_track(PyGccWrapper *obj);
+
+extern void
+gcc_python_wrapper_dealloc(PyObject *obj);
+
+/*
Macro DECLARE_SIMPLE_WRAPPER():
ARG_structname:
the struct tag for the resulting python wrapper class,
@@ -77,7 +130,7 @@
*/
#define DECLARE_SIMPLE_WRAPPER(ARG_structname, ARG_typeobj, ARG_typename, ARG_wrappedtype, ARG_fieldname) \
struct ARG_structname { \
- PyObject_HEAD \
+ struct PyGccWrapper head; \
ARG_wrappedtype ARG_fieldname; \
}; \
\
@@ -86,9 +139,14 @@
extern PyObject * \
gcc_python_make_wrapper_##ARG_typename(ARG_wrappedtype ARG_fieldname); \
\
- extern PyTypeObject ARG_typeobj \
+ extern PyObject * \
+ gcc_python_make_wrapper_##ARG_typename##_unique(ARG_wrappedtype ARG_fieldname); \
+ \
+ extern PyGccWrapperTypeObject ARG_typeobj \
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF(#ARG_structname); \
\
+ extern void \
+ wrtp_mark_for_##ARG_structname(ARG_structname *wrapper); \
/* end of macro */
DECLARE_SIMPLE_WRAPPER(PyGccCallgraphEdge,
@@ -175,7 +233,7 @@ void autogenerated_function_add_types(PyObject *m);
/* autogenerated-gimple.c */
int autogenerated_gimple_init_types(void);
void autogenerated_gimple_add_types(PyObject *m);
-PyTypeObject* gcc_python_autogenerated_gimple_type_for_stmt(gimple g);
+PyGccWrapperTypeObject* gcc_python_autogenerated_gimple_type_for_stmt(gimple g);
/* autogenerated-location.c */
int autogenerated_location_init_types(void);
@@ -192,10 +250,10 @@ void autogenerated_parameter_add_types(PyObject *m);
/* autogenerated-pass.c */
int autogenerated_pass_init_types(void);
void autogenerated_pass_add_types(PyObject *m);
-extern PyTypeObject gcc_GimplePassType;
-extern PyTypeObject gcc_RtlPassType;
-extern PyTypeObject gcc_SimpleIpaPassType;
-extern PyTypeObject gcc_IpaPassType;
+extern PyGccWrapperTypeObject gcc_GimplePassType;
+extern PyGccWrapperTypeObject gcc_RtlPassType;
+extern PyGccWrapperTypeObject gcc_SimpleIpaPassType;
+extern PyGccWrapperTypeObject gcc_IpaPassType;
/* autogenerated-pretty-printer.c */
int autogenerated_pretty_printer_init_types(void);
@@ -205,17 +263,17 @@ void autogenerated_pretty_printer_add_types(PyObject *m);
/* autogenerated-rtl.c */
int autogenerated_rtl_init_types(void);
void autogenerated_rtl_add_types(PyObject *m);
-PyTypeObject * gcc_python_autogenerated_rtl_type_for_stmt(struct rtx_def *insn);
+PyGccWrapperTypeObject * gcc_python_autogenerated_rtl_type_for_stmt(struct rtx_def *insn);
/* autogenerated-tree.c */
int autogenerated_tree_init_types(void);
void autogenerated_tree_add_types(PyObject *m);
-PyTypeObject*
+PyGccWrapperTypeObject*
gcc_python_autogenerated_tree_type_for_tree(tree t, int borrow_ref);
-PyTypeObject*
+PyGccWrapperTypeObject*
gcc_python_autogenerated_tree_type_for_tree_code(enum tree_code code, int borrow_ref);
/* autogenerated-variable.c */
diff --git a/generate-callgraph-c.py b/generate-callgraph-c.py
index c2beb28..143ee34 100644
--- a/generate-callgraph-c.py
+++ b/generate-callgraph-c.py
@@ -1,5 +1,5 @@
-# Copyright 2011 David Malcolm <dmalcolm@redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+# Copyright 2011, 2012 Red Hat, Inc.
#
# This is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -16,6 +16,7 @@
# <http://www.gnu.org/licenses/>.
from cpybuilder import *
+from wrapperbuilder import PyGccWrapperTypeObject
cu = CompilationUnit()
cu.add_include('gcc-python.h')
@@ -50,14 +51,15 @@ def generate_callgraph_edge():
'The gcc.GimpleCall statememt for the function call')
cu.add_defn(getsettable.c_defn())
- pytype = PyTypeObject(identifier = 'gcc_CallgraphEdgeType',
+ pytype = PyGccWrapperTypeObject(identifier = 'gcc_CallgraphEdgeType',
localname = 'CallgraphEdge',
tp_name = 'gcc.CallgraphEdge',
- struct_name = 'struct PyGccCallgraphEdge',
+ struct_name = 'PyGccCallgraphEdge',
tp_new = 'PyType_GenericNew',
tp_getset = getsettable.identifier,
tp_repr = '(reprfunc)gcc_CallgraphEdge_repr',
tp_str = '(reprfunc)gcc_CallgraphEdge_str',
+ tp_dealloc = 'gcc_python_wrapper_dealloc',
)
cu.add_defn(pytype.c_defn())
modinit_preinit += pytype.c_invoke_type_ready()
@@ -92,14 +94,15 @@ def generate_callgraph_node():
# see gcc/cgraph.c: dump_cgraph_node (FILE *f, struct cgraph_node *node)
- pytype = PyTypeObject(identifier = 'gcc_CallgraphNodeType',
+ pytype = PyGccWrapperTypeObject(identifier = 'gcc_CallgraphNodeType',
localname = 'CallgraphNode',
tp_name = 'gcc.CallgraphNode',
- struct_name = 'struct PyGccCallgraphNode',
+ struct_name = 'PyGccCallgraphNode',
tp_new = 'PyType_GenericNew',
tp_getset = getsettable.identifier,
tp_repr = '(reprfunc)gcc_CallgraphNode_repr',
tp_str = '(reprfunc)gcc_CallgraphNode_str',
+ tp_dealloc = 'gcc_python_wrapper_dealloc',
)
cu.add_defn(pytype.c_defn())
modinit_preinit += pytype.c_invoke_type_ready()
diff --git a/generate-cfg-c.py b/generate-cfg-c.py
index 0de903d..f855316 100644
--- a/generate-cfg-c.py
+++ b/generate-cfg-c.py
@@ -1,5 +1,5 @@
-# Copyright 2011 David Malcolm <dmalcolm@redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+# Copyright 2011, 2012 Red Hat, Inc.
#
# This is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -16,6 +16,7 @@
# <http://www.gnu.org/licenses/>.
from cpybuilder import *
+from wrapperbuilder import PyGccWrapperTypeObject
cu = CompilationUnit()
cu.add_include('gcc-python.h')
@@ -61,10 +62,11 @@ def generate_edge():
'Boolean, corresponding to flag %s' % flag)
cu.add_defn(getsettable.c_defn())
- pytype = PyTypeObject(identifier = 'gcc_EdgeType',
+ pytype = PyGccWrapperTypeObject(identifier = 'gcc_EdgeType',
localname = 'Edge',
tp_name = 'gcc.Edge',
- struct_name = 'struct PyGccEdge',
+ tp_dealloc = 'gcc_python_wrapper_dealloc',
+ struct_name = 'PyGccEdge',
tp_new = 'PyType_GenericNew',
#tp_repr = '(reprfunc)gcc_Edge_repr',
#tp_str = '(reprfunc)gcc_Edge_repr',
@@ -113,10 +115,11 @@ def generate_basic_block():
None)
cu.add_defn(getsettable.c_defn())
- pytype = PyTypeObject(identifier = 'gcc_BasicBlockType',
+ pytype = PyGccWrapperTypeObject(identifier = 'gcc_BasicBlockType',
localname = 'BasicBlock',
tp_name = 'gcc.BasicBlock',
- struct_name = 'struct PyGccBasicBlock',
+ tp_dealloc = 'gcc_python_wrapper_dealloc',
+ struct_name = 'PyGccBasicBlock',
tp_new = 'PyType_GenericNew',
#tp_repr = '(reprfunc)gcc_BasicBlock_repr',
#tp_str = '(reprfunc)gcc_BasicBlock_repr',
@@ -154,10 +157,11 @@ def generate_cfg():
'The final gcc.BasicBlock in this graph'),
])
cu.add_defn(getsettable.c_defn())
- pytype = PyTypeObject(identifier = 'gcc_CfgType',
+ pytype = PyGccWrapperTypeObject(identifier = 'gcc_CfgType',
localname = 'Cfg',
tp_name = 'gcc.Cfg',
- struct_name = 'struct PyGccCfg',
+ tp_dealloc = 'gcc_python_wrapper_dealloc',
+ struct_name = 'PyGccCfg',
tp_new = 'PyType_GenericNew',
#tp_repr = '(reprfunc)gcc_Cfg_repr',
#tp_str = '(reprfunc)gcc_Cfg_repr',
diff --git a/generate-function-c.py b/generate-function-c.py
index e62231e..6aea87e 100644
--- a/generate-function-c.py
+++ b/generate-function-c.py
@@ -1,5 +1,5 @@
-# Copyright 2011 David Malcolm <dmalcolm@redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+# Copyright 2011, 2012 Red Hat, Inc.
#
# This is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -16,6 +16,7 @@
# <http://www.gnu.org/licenses/>.
from cpybuilder import *
+from wrapperbuilder import PyGccWrapperTypeObject
cu = CompilationUnit()
cu.add_include('gcc-python.h')
@@ -67,14 +68,16 @@ def generate_function():
'Location of the end of the function')
cu.add_defn(getsettable.c_defn())
- pytype = PyTypeObject(identifier = 'gcc_FunctionType',
+ pytype = PyGccWrapperTypeObject(identifier = 'gcc_FunctionType',
localname = 'Function',
tp_name = 'gcc.Function',
- struct_name = 'struct PyGccFunction',
+ tp_dealloc = 'gcc_python_wrapper_dealloc',
+ struct_name = 'PyGccFunction',
tp_new = 'PyType_GenericNew',
tp_repr = '(reprfunc)gcc_Function_repr',
tp_str = '(reprfunc)gcc_Function_repr',
- tp_getset = getsettable.identifier)
+ tp_getset = getsettable.identifier,
+ )
cu.add_defn(pytype.c_defn())
modinit_preinit += pytype.c_invoke_type_ready()
modinit_postinit += pytype.c_invoke_add_to_module()
diff --git a/generate-gimple-c.py b/generate-gimple-c.py
index 3a82e67..7f5fde8 100644
--- a/generate-gimple-c.py
+++ b/generate-gimple-c.py
@@ -1,5 +1,5 @@
-# Copyright 2011 David Malcolm <dmalcolm@redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+# Copyright 2011, 2012 Red Hat, Inc.
#
# This is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -18,6 +18,7 @@
from maketreetypes import iter_gimple_types, iter_gimple_struct_types
from cpybuilder import *
+from wrapperbuilder import PyGccWrapperTypeObject
cu = CompilationUnit()
cu.add_include('gcc-python.h')
@@ -160,10 +161,11 @@ def generate_gimple_struct_subclasses():
for gt in gimple_struct_types:
#print gimple_types
cc = gt.camel_cased_string()
- pytype = PyTypeObject(identifier = 'gcc_GimpleStructType%sType' % cc,
+ pytype = PyGccWrapperTypeObject(identifier = 'gcc_GimpleStructType%sType' % cc,
localname = 'GimpleStructType' + cc,
tp_name = 'gcc.GimpleStructType%s' % cc,
- struct_name = 'struct PyGccGimple',
+ tp_dealloc = 'gcc_python_wrapper_dealloc',
+ struct_name = 'PyGccGimple',
tp_new = 'PyType_GenericNew',
tp_base = '&gcc_GimpleType',
#tp_getset = getsettable.identifier,
@@ -216,14 +218,16 @@ gcc_Gimple_get_block(struct PyGccGimple *self, void *closure)
])
cu.add_defn(getsettable.c_defn())
- pytype = PyTypeObject(identifier = 'gcc_GimpleType',
+ pytype = PyGccWrapperTypeObject(identifier = 'gcc_GimpleType',
localname = 'Gimple',
tp_name = 'gcc.Gimple',
- struct_name = 'struct PyGccGimple',
+ tp_dealloc = 'gcc_python_wrapper_dealloc',
+ struct_name = 'PyGccGimple',
tp_new = 'PyType_GenericNew',
tp_getset = getsettable.identifier,
tp_repr = '(reprfunc)gcc_Gimple_repr',
tp_str = '(reprfunc)gcc_Gimple_str',
+ tp_flags = 'Py_TPFLAGS_BASETYPE',
)
methods = PyMethodTable('gcc_Gimple_methods', [])
methods.add_method('walk_tree',
@@ -386,10 +390,11 @@ def generate_gimple_subclasses():
cu.add_defn(getsettable.c_defn())
- pytype = PyTypeObject(identifier = 'gcc_%sType' % cc,
+ pytype = PyGccWrapperTypeObject(identifier = 'gcc_%sType' % cc,
localname = cc,
tp_name = 'gcc.%s' % cc,
- struct_name = 'struct PyGccGimple',
+ tp_dealloc = 'gcc_python_wrapper_dealloc',
+ struct_name = 'PyGccGimple',
tp_new = 'PyType_GenericNew',
tp_base = '&gcc_GimpleType',
tp_getset = getsettable.identifier if getsettable else None,
@@ -404,14 +409,14 @@ generate_gimple_subclasses()
def generate_gimple_code_map():
cu.add_defn('\n/* Map from GCC gimple codes to PyTypeObject* */\n')
- cu.add_defn('PyTypeObject *pytype_for_gimple_code[] = {\n')
+ cu.add_defn('PyGccWrapperTypeObject *pytype_for_gimple_code[] = {\n')
for gt in gimple_types:
cc = gt.camel_cased_string()
cu.add_defn(' &gcc_%sType, /* %s */\n' % (cc, gt.gimple_symbol))
cu.add_defn('};\n\n')
cu.add_defn("""
-PyTypeObject*
+PyGccWrapperTypeObject*
gcc_python_autogenerated_gimple_type_for_stmt(gimple g)
{
enum gimple_code code = gimple_code(g);
diff --git a/generate-location-c.py b/generate-location-c.py
index b12a200..2fdf308 100644
--- a/generate-location-c.py
+++ b/generate-location-c.py
@@ -1,5 +1,5 @@
-# Copyright 2011 David Malcolm <dmalcolm@redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+# Copyright 2011, 2012 Red Hat, Inc.
#
# This is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -16,6 +16,7 @@
# <http://www.gnu.org/licenses/>.
from cpybuilder import *
+from wrapperbuilder import PyGccWrapperTypeObject
cu = CompilationUnit()
cu.add_include('gcc-python.h')
@@ -66,15 +67,16 @@ gcc_Location_get_column(struct PyGccLocation *self, void *closure)
])
cu.add_defn(getsettable.c_defn())
- pytype = PyTypeObject(identifier = 'gcc_LocationType',
+ pytype = PyGccWrapperTypeObject(identifier = 'gcc_LocationType',
localname = 'Location',
tp_name = 'gcc.Location',
- struct_name = 'struct PyGccLocation',
+ struct_name = 'PyGccLocation',
tp_new = 'PyType_GenericNew',
tp_getset = getsettable.identifier,
tp_repr = '(reprfunc)gcc_Location_repr',
tp_str = '(reprfunc)gcc_Location_str',
- tp_richcompare = 'gcc_Location_richcompare')
+ tp_richcompare = 'gcc_Location_richcompare',
+ tp_dealloc = 'gcc_python_wrapper_dealloc')
cu.add_defn(pytype.c_defn())
modinit_preinit += pytype.c_invoke_type_ready()
modinit_postinit += pytype.c_invoke_add_to_module()
diff --git a/generate-option-c.py b/generate-option-c.py
index 131b0e0..1ac2f00 100644
--- a/generate-option-c.py
+++ b/generate-option-c.py
@@ -1,5 +1,5 @@
-# Copyright 2011 David Malcolm <dmalcolm@redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+# Copyright 2011, 2012 Red Hat, Inc.
#
# This is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -16,6 +16,7 @@
# <http://www.gnu.org/licenses/>.
from cpybuilder import *
+from wrapperbuilder import PyGccWrapperTypeObject
cu = CompilationUnit()
cu.add_include('gcc-python.h')
@@ -67,10 +68,11 @@ def generate_option():
cu.add_defn(getsettable.c_defn())
- pytype = PyTypeObject(identifier = 'gcc_OptionType',
+ pytype = PyGccWrapperTypeObject(identifier = 'gcc_OptionType',
localname = 'Option',
tp_name = 'gcc.Option',
- struct_name = 'struct PyGccOption',
+ tp_dealloc = 'gcc_python_wrapper_dealloc',
+ struct_name = 'PyGccOption',
tp_init = 'gcc_Option_init',
tp_getset = getsettable.identifier,
tp_repr = '(reprfunc)gcc_Option_repr',
diff --git a/generate-parameter-c.py b/generate-parameter-c.py
index ca0bb4b..875e37c 100644
--- a/generate-parameter-c.py
+++ b/generate-parameter-c.py
@@ -1,5 +1,5 @@
-# Copyright 2011 David Malcolm <dmalcolm@redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+# Copyright 2011, 2012 Red Hat, Inc.
#
# This is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -16,6 +16,7 @@
# <http://www.gnu.org/licenses/>.
from cpybuilder import *
+from wrapperbuilder import PyGccWrapperTypeObject
cu = CompilationUnit()
cu.add_include('gcc-python.h')
@@ -76,10 +77,11 @@ def generate_param():
cu.add_defn(getsettable.c_defn())
- pytype = PyTypeObject(identifier = 'gcc_ParameterType',
+ pytype = PyGccWrapperTypeObject(identifier = 'gcc_ParameterType',
localname = 'Parameter',
tp_name = 'gcc.Parameter',
- struct_name = 'struct PyGccParameter',
+ tp_dealloc = 'gcc_python_wrapper_dealloc',
+ struct_name = 'PyGccParameter',
tp_new = 'PyType_GenericNew',
tp_getset = getsettable.identifier,
#tp_repr = '(reprfunc)gcc_Parameter_repr',
diff --git a/generate-pass-c.py b/generate-pass-c.py
index bca32de..40706d8 100644
--- a/generate-pass-c.py
+++ b/generate-pass-c.py
@@ -1,5 +1,5 @@
-# Copyright 2011 David Malcolm <dmalcolm@redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+# Copyright 2011, 2012 Red Hat, Inc.
#
# This is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -16,6 +16,7 @@
# <http://www.gnu.org/licenses/>.
from cpybuilder import *
+from wrapperbuilder import PyGccWrapperTypeObject
cu = CompilationUnit()
cu.add_include('gcc-python.h')
@@ -87,15 +88,17 @@ def generate_pass():
cu.add_defn(methods.c_defn())
- pytype = PyTypeObject(identifier = 'gcc_PassType',
+ pytype = PyGccWrapperTypeObject(identifier = 'gcc_PassType',
localname = 'Pass',
tp_name = 'gcc.Pass',
- struct_name = 'struct PyGccPass',
+ tp_dealloc = 'gcc_python_wrapper_dealloc',
+ struct_name = 'PyGccPass',
tp_new = 'PyType_GenericNew',
tp_getset = getsettable.identifier,
tp_repr = '(reprfunc)gcc_Pass_repr',
tp_str = '(reprfunc)gcc_Pass_repr',
tp_methods = methods.identifier,
+ tp_flags = '(Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE)',
)
cu.add_defn(pytype.c_defn())
modinit_preinit += pytype.c_invoke_type_ready()
@@ -110,10 +113,11 @@ def generate_pass_subclasses():
for opt_pass_type in ('GIMPLE_PASS', 'RTL_PASS',
'SIMPLE_IPA_PASS', 'IPA_PASS'):
cc = camel_case(opt_pass_type)
- pytype = PyTypeObject(identifier = 'gcc_%sType' % cc,
+ pytype = PyGccWrapperTypeObject(identifier = 'gcc_%sType' % cc,
localname = cc,
tp_name = 'gcc.%s' % cc,
- struct_name = 'struct PyGccPass',
+ tp_dealloc = 'gcc_python_wrapper_dealloc',
+ struct_name = 'PyGccPass',
tp_new = 'PyType_GenericNew',
tp_init = 'gcc_%s_init' % cc,
tp_base = '&gcc_PassType',
diff --git a/generate-rtl-c.py b/generate-rtl-c.py
index a391385..6270298 100644
--- a/generate-rtl-c.py
+++ b/generate-rtl-c.py
@@ -1,5 +1,5 @@
-# Copyright 2011 David Malcolm <dmalcolm@redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+# Copyright 2011, 2012 Red Hat, Inc.
#
# This is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -18,6 +18,7 @@
from maketreetypes import iter_rtl_expr_types #, iter_rtl_struct_types
from cpybuilder import *
+from wrapperbuilder import PyGccWrapperTypeObject
cu = CompilationUnit()
cu.add_include('gcc-python.h')
@@ -64,10 +65,11 @@ gcc_Rtl_get_block(struct PyGccRtl *self, void *closure)
'Operands of this expression, as a tuple')
cu.add_defn(getsettable.c_defn())
- pytype = PyTypeObject(identifier = 'gcc_RtlType',
+ pytype = PyGccWrapperTypeObject(identifier = 'gcc_RtlType',
localname = 'Rtl',
tp_name = 'gcc.Rtl',
- struct_name = 'struct PyGccRtl',
+ tp_dealloc = 'gcc_python_wrapper_dealloc',
+ struct_name = 'PyGccRtl',
tp_new = 'PyType_GenericNew',
tp_getset = getsettable.identifier,
tp_repr = '(reprfunc)gcc_Rtl_repr',
@@ -100,10 +102,10 @@ def generate_intermediate_rtx_class_subclasses():
for rtx_class in enum_rtx_class:
cc = camel_case(rtx_class)
- pytype = PyTypeObject(identifier = 'gcc_RtlClassType%sType' % cc,
+ pytype = PyGccWrapperTypeObject(identifier = 'gcc_RtlClassType%sType' % cc,
localname = 'RtlClassType' + cc,
tp_name = 'gcc.%s' % cc,
- struct_name = 'struct PyGccRtl',
+ struct_name = 'PyGccRtl',
tp_new = 'PyType_GenericNew',
tp_base = '&gcc_RtlType',
#tp_getset = getsettable.identifier,
@@ -129,10 +131,10 @@ def generate_concrete_rtx_code_subclasses():
if getsettable:
cu.add_defn(getsettable.c_defn())
- pytype = PyTypeObject(identifier = 'gcc_%sType' % cc,
+ pytype = PyGccWrapperTypeObject(identifier = 'gcc_%sType' % cc,
localname = cc,
tp_name = 'gcc.%s' % cc,
- struct_name = 'struct PyGccRtl',
+ struct_name = 'PyGccRtl',
tp_new = 'PyType_GenericNew',
#tp_base = '&gcc_RtlType',
tp_base = ('&gcc_RtlClassType%sType'
@@ -148,15 +150,15 @@ def generate_concrete_rtx_code_subclasses():
generate_concrete_rtx_code_subclasses()
def generate_rtl_code_map():
- cu.add_defn('\n/* Map from GCC rtl codes to PyTypeObject* */\n')
- cu.add_defn('PyTypeObject *pytype_for_rtx_code[] = {\n')
+ cu.add_defn('\n/* Map from GCC rtl codes to PyGccWrapperTypeObject* */\n')
+ cu.add_defn('PyGccWrapperTypeObject *pytype_for_rtx_code[] = {\n')
for expr_type in rtl_expr_types:
cc = expr_type.camel_cased_string()
cu.add_defn(' &gcc_%sType, /* %s */\n' % (cc, expr_type.ENUM))
cu.add_defn('};\n\n')
cu.add_defn("""
-PyTypeObject*
+PyGccWrapperTypeObject*
gcc_python_autogenerated_rtl_type_for_stmt(struct rtx_def *insn)
{
enum rtx_code code = insn->code;
diff --git a/generate-tree-c.py b/generate-tree-c.py
index 738f343..9e32924 100644
--- a/generate-tree-c.py
+++ b/generate-tree-c.py
@@ -1,5 +1,5 @@
-# Copyright 2011 David Malcolm <dmalcolm@redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+# Copyright 2011, 2012 Red Hat, Inc.
#
# This is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -18,6 +18,7 @@
from maketreetypes import iter_tree_types
from cpybuilder import *
+from wrapperbuilder import PyGccWrapperTypeObject
tree_types = list(iter_tree_types())
# FIXME: truncate the list, for ease of development:
@@ -69,10 +70,11 @@ gcc_Tree_get_addr(struct PyGccTree *self, void *closure)
cu.add_defn(getsettable.c_defn())
- pytype = PyTypeObject(identifier = 'gcc_TreeType',
+ pytype = PyGccWrapperTypeObject(identifier = 'gcc_TreeType',
localname = 'Tree',
tp_name = 'gcc.Tree',
- struct_name = 'struct PyGccTree',
+ tp_dealloc = 'gcc_python_wrapper_dealloc',
+ struct_name = 'PyGccTree',
tp_new = 'PyType_GenericNew',
tp_getset = 'gcc_Tree_getset_table',
tp_hash = '(hashfunc)gcc_Tree_hash',
@@ -138,10 +140,10 @@ def generate_intermediate_tree_classes():
methods = PyMethodTable('gcc_%s_methods' % localname, [])
- pytype = PyTypeObject(identifier = code_type,
+ pytype = PyGccWrapperTypeObject(identifier = code_type,
localname = localname,
tp_name = 'gcc.%s' % localname,
- struct_name = 'struct PyGccTree',
+ struct_name = 'PyGccTree',
tp_new = 'PyType_GenericNew',
tp_base = '&gcc_TreeType',
tp_getset = getsettable.identifier,
@@ -536,10 +538,10 @@ def generate_tree_code_classes():
cu.add_defn(getsettable.c_defn())
- pytype = PyTypeObject(identifier = 'gcc_%sType' % cc,
+ pytype = PyGccWrapperTypeObject(identifier = 'gcc_%sType' % cc,
localname = cc,
tp_name = 'gcc.%s' % cc,
- struct_name = 'struct PyGccTree',
+ struct_name = 'PyGccTree',
tp_new = 'PyType_GenericNew',
tp_base = '&%s' % base_type,
tp_getset = getsettable.identifier,
@@ -553,13 +555,13 @@ def generate_tree_code_classes():
modinit_postinit += pytype.c_invoke_add_to_module()
- cu.add_defn('\n/* Map from GCC tree codes to PyTypeObject* */\n')
- cu.add_defn('PyTypeObject *pytype_for_tree_code[] = {\n')
+ cu.add_defn('\n/* Map from GCC tree codes to PyGccWrapperTypeObject* */\n')
+ cu.add_defn('PyGccWrapperTypeObject *pytype_for_tree_code[] = {\n')
for tree_type in tree_types:
cu.add_defn(' &gcc_%sType, /* %s */\n' % (tree_type.camel_cased_string(), tree_type.SYM))
cu.add_defn('};\n\n')
- cu.add_defn('\n/* Map from PyTypeObject* to GCC tree codes*/\n')
+ cu.add_defn('\n/* Map from PyGccWrapperTypeObject* to GCC tree codes*/\n')
cu.add_defn('int \n')
cu.add_defn('gcc_python_tree_type_object_as_tree_code(PyObject *cls, enum tree_code *out)\n')
cu.add_defn('{\n')
@@ -573,10 +575,10 @@ def generate_tree_code_classes():
cu.add_defn('}\n')
cu.add_defn("""
-PyTypeObject*
+PyGccWrapperTypeObject*
gcc_python_autogenerated_tree_type_for_tree_code(enum tree_code code, int borrow_ref)
{
- PyTypeObject *result;
+ PyGccWrapperTypeObject *result;
assert(code >= 0);
assert(code < MAX_TREE_CODES);
@@ -589,7 +591,7 @@ gcc_python_autogenerated_tree_type_for_tree_code(enum tree_code code, int borrow
return result;
}
-PyTypeObject*
+PyGccWrapperTypeObject*
gcc_python_autogenerated_tree_type_for_tree(tree t, int borrow_ref)
{
enum tree_code code = TREE_CODE(t);
diff --git a/generate-variable-c.py b/generate-variable-c.py
index 8db19af..75bf69b 100644
--- a/generate-variable-c.py
+++ b/generate-variable-c.py
@@ -1,5 +1,5 @@
-# Copyright 2011 David Malcolm <dmalcolm@redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm@redhat.com>
+# Copyright 2011, 2012 Red Hat, Inc.
#
# This is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -16,6 +16,7 @@
# <http://www.gnu.org/licenses/>.
from cpybuilder import *
+from wrapperbuilder import PyGccWrapperTypeObject
cu = CompilationUnit()
cu.add_include('gcc-python.h')
@@ -48,10 +49,11 @@ def generate_variable():
cu.add_defn(getsettable.c_defn())
- pytype = PyTypeObject(identifier = 'gcc_VariableType',
+ pytype = PyGccWrapperTypeObject(identifier = 'gcc_VariableType',
localname = 'Variable',
tp_name = 'gcc.Variable',
- struct_name = 'struct PyGccVariable',
+ tp_dealloc = 'gcc_python_wrapper_dealloc',
+ struct_name = 'PyGccVariable',
tp_new = 'PyType_GenericNew',
tp_getset = getsettable.identifier,
#tp_repr = '(reprfunc)gcc_Variable_repr',
diff --git a/tests/plugin/gc/_force_garbage_collection/input.c b/tests/plugin/gc/_force_garbage_collection/input.c
new file mode 100644
index 0000000..8a8142d
--- /dev/null
+++ b/tests/plugin/gc/_force_garbage_collection/input.c
@@ -0,0 +1,28 @@
+/*
+ Copyright 2012 David Malcolm <dmalcolm@redhat.com>
+ Copyright 2012 Red Hat, Inc.
+
+ This 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 of the License, or
+ (at your option) any later version.
+
+ This program 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 this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+/* empty */
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/plugin/gc/_force_garbage_collection/script.py b/tests/plugin/gc/_force_garbage_collection/script.py
new file mode 100644
index 0000000..02d1859
--- /dev/null
+++ b/tests/plugin/gc/_force_garbage_collection/script.py
@@ -0,0 +1,55 @@
+# Copyright 2012 David Malcolm <dmalcolm@redhat.com>
+# Copyright 2012 Red Hat, Inc.
+#
+# This 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 of the License, or
+# (at your option) any later version.
+#
+# This program 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 this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+# Verify that we can forcibly invoke GCC's garbage collector,
+# (for selftest purposes)
+
+import gcc
+
+# Count the number of garbage collections:
+num_ggc_collections = 0
+def on_ggc_start():
+ global num_ggc_collections
+ num_ggc_collections += 1
+
+gcc.register_callback(gcc.PLUGIN_GGC_START,
+ on_ggc_start)
+
+def on_finish():
+ # Now traverse all of the data seen at every previous pass
+ print('on_finish')
+
+ if 0:
+ print('num_ggc_collections: %i ' % num_ggc_collections)
+
+ # Call gcc._force_garbage_collection(), and verify that on_ggc_start
+ # gets called:
+ old_collections = num_ggc_collections
+ gcc._force_garbage_collection()
+
+ # num_ggc_collections should have increased by 1:
+ assert num_ggc_collections > 0
+ assert num_ggc_collections == old_collections + 1
+ print('num_ggc_collections: new - old: %i '
+ % (num_ggc_collections - old_collections))
+
+ if 0:
+ print('num_ggc_collections: %i ' % num_ggc_collections)
+
+gcc.register_callback(gcc.PLUGIN_FINISH,
+ on_finish)
+
diff --git a/tests/plugin/gc/_force_garbage_collection/stdout.txt b/tests/plugin/gc/_force_garbage_collection/stdout.txt
new file mode 100644
index 0000000..046d8c7
--- /dev/null
+++ b/tests/plugin/gc/_force_garbage_collection/stdout.txt
@@ -0,0 +1,2 @@
+on_finish
+num_ggc_collections: new - old: 1
diff --git a/tests/plugin/gc/_gc_selftest/input.c b/tests/plugin/gc/_gc_selftest/input.c
new file mode 100644
index 0000000..769d1a6
--- /dev/null
+++ b/tests/plugin/gc/_gc_selftest/input.c
@@ -0,0 +1,55 @@
+/*
+ Copyright 2011 David Malcolm <dmalcolm@redhat.com>
+ Copyright 2011 Red Hat, Inc.
+
+ This 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 of the License, or
+ (at your option) any later version.
+
+ This program 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 this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ Trivial example code to be compiled, for testing purposes
+ */
+
+#include <stdio.h>
+
+int
+helper_function(void)
+{
+ printf("I am a helper function\n");
+ return 42;
+}
+
+int
+main(int argc, char **argv)
+{
+ int i;
+
+ printf("argc: %i\n", argc);
+
+ for (i = 0; i < argc; i++) {
+ printf("argv[%i]: %s\n", argv[i]);
+ }
+
+ helper_function();
+
+ return 0;
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/plugin/gc/_gc_selftest/script.py b/tests/plugin/gc/_gc_selftest/script.py
new file mode 100644
index 0000000..4d8322e
--- /dev/null
+++ b/tests/plugin/gc/_gc_selftest/script.py
@@ -0,0 +1,25 @@
+# Copyright 2012 David Malcolm <dmalcolm@redhat.com>
+# Copyright 2012 Red Hat, Inc.
+#
+# This 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 of the License, or
+# (at your option) any later version.
+#
+# This program 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 this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+# Invoke C-based selftest of integration with GCC's garbage collector
+import gcc
+
+def on_finish():
+ gcc._gc_selftest()
+
+gcc.register_callback(gcc.PLUGIN_FINISH,
+ on_finish)
diff --git a/tests/plugin/gc/_gc_selftest/stdout.txt b/tests/plugin/gc/_gc_selftest/stdout.txt
new file mode 100644
index 0000000..640cf3b
--- /dev/null
+++ b/tests/plugin/gc/_gc_selftest/stdout.txt
@@ -0,0 +1,18 @@
+gcc._gc_selftest() starting
+creating test GCC objects
+ gcc_python_wrapper_track: gcc.IntegerCst
+ gcc_python_wrapper_track: gcc.StringCst
+forcing a garbage collection:
+ walking the live PyGccWrapper objects
+ marking inner object for: gcc.IntegerCst(42)
+ marking inner object for: gcc.StringCst('I am only referenced via a python wrapper')
+ finished walking the live PyGccWrapper objects
+completed the forced garbage collection
+verifying that the underlying GCC objects were marked
+all of the underlying GCC objects were indeed marked
+invoking DECREF on Python wrapper objects
+ gcc_python_wrapper_dealloc: gcc.IntegerCst
+ gcc_python_wrapper_untrack: gcc.IntegerCst
+ gcc_python_wrapper_dealloc: gcc.StringCst
+ gcc_python_wrapper_untrack: gcc.StringCst
+gcc._gc_selftest() complete
diff --git a/wrapperbuilder.py b/wrapperbuilder.py
new file mode 100644
index 0000000..01cab62
--- /dev/null
+++ b/wrapperbuilder.py
@@ -0,0 +1,43 @@
+# Copyright 2012 David Malcolm <dmalcolm@redhat.com>
+# Copyright 2012 Red Hat, Inc.
+#
+# This 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 of the License, or
+# (at your option) any later version.
+#
+# This program 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 this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+# Shared code for gcc-python-plugin's generate-*-c.py, where the code
+# is specific to gcc-python-plugin
+
+from cpybuilder import PyTypeObject, with_gcc_extensions
+
+def indent(lines):
+ return '\n'.join(' %s' % line for line in lines.splitlines())
+
+class PyGccWrapperTypeObject(PyTypeObject):
+ """
+ A PyTypeObject that's also a PyGccWrapperTypeObject
+ (with metaclass PyGccWrapperMetaType)
+ """
+ def c_defn(self):
+ result = '\n'
+ result += 'PyGccWrapperTypeObject %(identifier)s = {\n' % self.__dict__
+ result += self.c_src_field_value('wrtp_base',
+ '{\n%s}' % indent(self.c_initializer()))
+ result += self.c_src_field_value('wrtp_mark',
+ 'wrtp_mark_for_%s' % self.struct_name,
+ cast='wrtp_marker')
+ result += '};\n' % self.__dict__
+ result +='\n'
+ return result
+
+