[gcc-python-plugin] patch to add ArrayType.range
by David Hugh Malcolm
commit 5252121bd513a34214dde4bac9c618fe72fe1748
Author: Tom Tromey <tromey(a)redhat.com>
Date: Mon Jan 23 07:51:21 2012 -0700
patch to add ArrayType.range
I needed to be able to access the range of an array's type for a project
I'm working on.
This patch adds ArrayType.range, plus documentation and a test case.
Tom
>From 9c6e8dc36597f830331e073b86186ddda2fb9432 Mon Sep 17 00:00:00 2001
From: Tom Tromey <tromey(a)redhat.com>
Date: Mon, 23 Jan 2012 07:49:59 -0700
Subject: [PATCH] Add ArrayType.range attribute
docs/tree.rst | 18 +++++++++++++++++
generate-tree-c.py | 5 ++++
tests/plugin/array-type/input.c | 37 ++++++++++++++++++++++++++++++++++++
tests/plugin/array-type/script.py | 36 +++++++++++++++++++++++++++++++++++
tests/plugin/array-type/stdout.txt | 3 ++
5 files changed, 99 insertions(+), 0 deletions(-)
---
diff --git a/docs/tree.rst b/docs/tree.rst
index 316d8c4..cd3090f 100644
--- a/docs/tree.rst
+++ b/docs/tree.rst
@@ -459,6 +459,24 @@ Types
The :py:class:`gcc.Type` that this type points to. In the above
example, this would be the `char` type.
+ .. py:attribute:: range
+
+ The :py:class:`gcc.Type` that represents the range of the
+ array's indices. If the array has a known range, then this will
+ ordinarily be an :py:class:`gcc.IntegerType` whose `min_value`
+ and `max_value` are the (inclusive) bounds of the array. If the
+ array does not have a known range, then this attribute will be
+ `None`.
+
+ That is, in the example above, `range.min_val` is `0`, and
+ `range.max_val` is `15`.
+
+ But, for a C declaration like::
+
+ extern char array[];
+
+ the type's `range` would be `None`.
+
.. py:class:: gcc.VectorType
.. py:attribute:: dereference
diff --git a/generate-tree-c.py b/generate-tree-c.py
index 9e32924..9cf8f82 100644
--- a/generate-tree-c.py
+++ b/generate-tree-c.py
@@ -399,6 +399,11 @@ def generate_tree_code_classes():
'gcc_python_make_wrapper_tree(TREE_TYPE(self->t))',
"The gcc.Type that this type points to'")
+ if tree_type.SYM == 'ARRAY_TYPE':
+ add_simple_getter('range',
+ 'gcc_python_make_wrapper_tree(TYPE_DOMAIN(self->t))',
+ "The gcc.Type that is the range of this array type")
+
if tree_type.SYM == 'ARRAY_REF':
add_simple_getter('array',
'gcc_python_make_wrapper_tree(TREE_OPERAND(self->t, 0))',
diff --git a/tests/plugin/array-type/input.c b/tests/plugin/array-type/input.c
new file mode 100644
index 0000000..992d06d
--- /dev/null
+++ b/tests/plugin/array-type/input.c
@@ -0,0 +1,37 @@
+/*
+ Copyright 2012 Tom Tromey <tromey(a)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/>.
+*/
+
+/* Test some array attributes. */
+
+int arr[37];
+
+extern int arr2[];
+
+int function(void)
+{
+ return 23;
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/plugin/array-type/script.py b/tests/plugin/array-type/script.py
new file mode 100644
index 0000000..5736323
--- /dev/null
+++ b/tests/plugin/array-type/script.py
@@ -0,0 +1,36 @@
+# -*- coding: utf-8 -*-
+# Copyright 2012 Tom Tromey <tromey(a)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/>.
+
+import gcc
+from gccutils import pprint
+
+def on_pass_execution(p, fn):
+ if p.name == '*warn_function_return':
+ assert isinstance(fn, gcc.Function)
+
+ for u in gcc.get_translation_units():
+ for v in u.block.vars:
+ if v.name == 'arr':
+ print('arr-range-min:%s' % v.type.range.min_value)
+ print('arr-range-max:%s' % v.type.range.max_value)
+ if v.name == 'arr2':
+ print('arr2-range:%s' % v.type.range)
+
+gcc.register_callback(gcc.PLUGIN_PASS_EXECUTION,
+ on_pass_execution)
+
diff --git a/tests/plugin/array-type/stdout.txt b/tests/plugin/array-type/stdout.txt
new file mode 100644
index 0000000..9dc5628
--- /dev/null
+++ b/tests/plugin/array-type/stdout.txt
@@ -0,0 +1,3 @@
+arr-range-min:0
+arr-range-max:36
+arr2-range:None
12 years, 4 months
[gcc-python-plugin] exclude PyString_Concat[AndDel] selftests on Python 3
by David Hugh Malcolm
commit 2564f11a35ff36fd057fc50bd21db2f9dcdc2efc
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Wed Jan 18 13:28:17 2012 -0500
exclude PyString_Concat[AndDel] selftests on Python 3
run-test-suite.py | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
---
diff --git a/run-test-suite.py b/run-test-suite.py
index cd36a4a..baa424f 100644
--- a/run-test-suite.py
+++ b/run-test-suite.py
@@ -350,6 +350,8 @@ if six.PY3:
# Similarly for the PyString_ API:
exclude_tests_below('tests/cpychecker/refcounts/PyString_AsString')
+ exclude_tests_below('tests/cpychecker/refcounts/PyString_Concat')
+ exclude_tests_below('tests/cpychecker/refcounts/PyString_ConcatAndDel')
exclude_tests_below('tests/cpychecker/refcounts/PyString_FromStringAndSize')
exclude_tests_below('tests/cpychecker/refcounts/PyString_Size')
12 years, 4 months
[gcc-python-plugin] tidy up insides of gcc_python_wrapper_meta_tp_new
by David Hugh Malcolm
commit 24e72a4b91b193edc5f2e6103c5c211766942b11
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Wed Jan 18 12:10:18 2012 -0500
tidy up insides of gcc_python_wrapper_meta_tp_new
gcc-python-wrapper.c | 14 +++++++++-----
1 files changed, 9 insertions(+), 5 deletions(-)
---
diff --git a/gcc-python-wrapper.c b/gcc-python-wrapper.c
index a4a394c..fd06f7f 100644
--- a/gcc-python-wrapper.c
+++ b/gcc-python-wrapper.c
@@ -108,10 +108,11 @@ static int debug_gcc_python_wrapper = 0;
static PyObject*
gcc_python_wrapper_meta_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
- PyTypeObject *new_type;
+ PyGccWrapperTypeObject* new_type;
+ PyGccWrapperTypeObject* base_type;
- /* Use PyType_Type's tp_new */
- new_type = (PyTypeObject*)PyType_Type.tp_new(type, args, kwds);
+ /* Use PyType_Type's tp_new to do most of the work: */
+ new_type = (PyGccWrapperTypeObject*)PyType_Type.tp_new(type, args, kwds);
if (!new_type) {
return NULL;
}
@@ -120,9 +121,12 @@ gcc_python_wrapper_meta_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwd
will thus be large enough for our extra information: */
assert(Py_TYPE(new_type)->tp_basicsize >= sizeof(PyGccWrapperTypeObject));
+ base_type = (PyGccWrapperTypeObject*)((PyTypeObject*)new_type)->tp_base;
+ assert(base_type);
+
/* Inherit wrtp_mark: */
- ((PyGccWrapperTypeObject*)new_type)->wrtp_mark = \
- ((PyGccWrapperTypeObject*)new_type->tp_base)->wrtp_mark;
+ assert(base_type->wrtp_mark);
+ new_type->wrtp_mark = base_type->wrtp_mark;
return (PyObject*)new_type;
}
12 years, 4 months
[gcc-python-plugin] add metaclass to PyGccWrapper to fix garbage-collection segfault on user-defined classes
by David Hugh Malcolm
commit eef8891a6efd628e9d5b9f47b7335be31b25c6e1
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Wed Jan 18 12:04:59 2012 -0500
add metaclass to PyGccWrapper to fix garbage-collection segfault on user-defined classes
Previously, all PyGccWrapper instances assumed that their ob_type was a
PyTypeObject that was also a PyGccWrapperTypeObject, a PyTypeObject extended
to hold a wrtp_mark callback.
This worked for predefined types, where the type object was statically
allocated, but led to crashes with user-defined types, where the new type is
a PyHeapTypeObject: I believe that upon casting to
*(PyGccWrapperTypeObject*)typeobj)->wrtp_mark
we were actually accessing the as_number field:
/* The *real* layout of a type object when allocated on the heap */
typedef struct _heaptypeobject {
PyTypeObject ht_type;
PyNumberMethods as_number; <--- this field i.e. the:
[...snip...]
} PyHeapTypeObject;
thus receiving the first field of PyNumberMethods:
binaryfunc nb_add;
(casting it with the wrong signature) which happened to be NULL.
With this change, we increase PyGccWrapperTypeObject to be a PyHeapTypeObject
(even for those that aren't on the heap) so that user-defined types have enough
room.
We introduce a metaclass: PyGccWrapperMetaType, the ob_type of our various
PyGccWrapperTypeObject instances. This has a tp_basicsize that ensures that
subclasses have room for the extra field in PyGccWrapperTypeObject, and a
tp_new implementation that propagates the wrtp_mark callback when creating
new subtypes.
Fixes the issue reported as:
https://fedorahosted.org/pipermail/gcc-python-plugin/2012-January/000152....
and adds a reproducer for it as:
tests/plugin/gc/segfault-on-instance-of-pass-subclass/
cpybuilder.py | 6 +-
gcc-python-wrapper.c | 110 ++++++++++++++++++++
gcc-python.h | 3 +-
tests/plugin/callgraph/stdout.txt | 4 +-
.../segfault-on-instance-of-pass-subclass/input.c | 1 +
.../script.py | 10 ++
tests/plugin/options/stdout.txt | 2 +-
tests/plugin/parameters/stdout.txt | 2 +-
tests/plugin/rtl/stdout.txt | 2 +-
wrapperbuilder.py | 9 ++-
10 files changed, 140 insertions(+), 9 deletions(-)
---
diff --git a/cpybuilder.py b/cpybuilder.py
index ec22706..41f613d 100644
--- a/cpybuilder.py
+++ b/cpybuilder.py
@@ -246,7 +246,11 @@ class PyTypeObject(NamedEntity):
return result
def c_initializer(self):
- result = ' PyVarObject_HEAD_INIT(0, 0)\n'
+ if hasattr(self, 'ob_type'):
+ ob_type_str = getattr(self, 'ob_type')
+ else:
+ ob_type_str = 'NULL'
+ result = ' PyVarObject_HEAD_INIT(%s, 0)\n' % ob_type_str
result += ' "%(tp_name)s", /*tp_name*/\n' % self.__dict__
result += ' sizeof(%(struct_name)s), /*tp_basicsize*/\n' % self.__dict__
result += ' 0, /*tp_itemsize*/\n'
diff --git a/gcc-python-wrapper.c b/gcc-python-wrapper.c
index 93234b0..a4a394c 100644
--- a/gcc-python-wrapper.c
+++ b/gcc-python-wrapper.c
@@ -20,6 +20,74 @@
/*
Low-level wrapper support, with integration with GCC's garbage
collector (aka "GGC")
+
+ High-level overview
+ ===================
+
+ We keep track of all "live" wrapper objects, and each one knows how
+ to mark the object it wraps; we register a hook into GCC"s GC so that
+ when it starts marking, we iterate through all our live wrapper objects,
+ marking the underlying GCC objects.
+
+
+ Implementation details
+ ======================
+
+ All of our wrapper types are subclasses of PyGccWrapper, which adds
+ a doubly-linked list to the top of the objects, so that we can track
+ all live wrapper objects. This list is updated via their PyTypeObject's
+ tp_alloc and tp_dealloc.
+
+ Each has a PyTypeObject that's actually a PyGccWrapperTypeObject, which adds
+ a "wrtp_mark" hook to a PyTypeObject, so that it can participate in
+ GCC's garbage collector. It actually has to add it to PyHeapTypeObject,
+ given that that's the (larger) in-memory layout of a user-defined type.
+
+ In order to correctly inherit this wrtp_mark slot, we need to override the
+ creation of any user-defined subclases of these PyTypeObjects, adding the
+ "inherit the wrtp_mark callback" logic. We do this by setting the ob_type
+ of our PyGccWrapperTypeObject to be PyGccWrapperMetaType, which supplies
+ a custom tp_new hook: analogous to setting a __metaclass__:
+
+ http://docs.python.org/reference/datamodel.html#customizing-class-creation
+
+ Thus, given e.g.
+
+ class MyPass(gcc.GimplePass):
+ ...etc...
+ p = MyPass('mypass')
+
+ p is a PyGccPass
+ ob_type == address on heap of user-defined type ("MyPass")
+
+ "MyPass" is this heap-allocated PyGccWrapperTypeObject:
+ ob_type == &PyGccWrapperMetaType
+ tp_base == &gcc_GimplePassType (the parent class: "gcc.GimplePass")
+ wrtp_mark == wrtp_mark_for_PyGccPass (inherited from tp_base via
+ PyGccWrapperMetaType.tp_new)
+
+ gcc_GimplePassType is a statically-allocated PyGccWrapperTypeObject (in
+ autogenerated-pass.c):
+ ob_type == &PyGccWrapperMetaType
+ tp_base == &gcc_PassType (the parent class: "gcc.Pass")
+ wrtp_mark == wrtp_mark_for_PyGccPass ("manually" set up by
+ generate-pass-c.py)
+
+ gcc_PassType is a statically-allocated PyGccWrapperTypeObject (in
+ autogenerated-pass.c):
+ ob_type == &PyGccWrapperMetaType
+ tp_base == NULL, but becomes &PyBaseObject_Type aka "object"
+ wrtp_mark == wrtp_mark_for_PyGccPass ("manually" set up by
+ generate-pass-c.py)
+
+ PyGccWrapperMetaType is the statically-allocated metaclass for the above
+ type objects ("gcc.WrapperMeta")
+
+ (as it happens, gcc.Pass wraps an object that doesn't participate in the
+ GCC garbage collector, so this is somewhat redundant. However, it should
+ matter when creating user-defined subclasses of types that *do* wrap a
+ GC-managed object)
+
*/
#include <Python.h>
@@ -27,9 +95,49 @@
#include "gcc-python-wrappers.h"
#include "gcc-python-compat.h"
+static void
+force_gcc_gc(void);
+
/* Debugging, for use by selftest routine */
static int debug_gcc_python_wrapper = 0;
+/*
+ This is the overriden tp_new in our metatype: when we create new subtypes,
+ it copies up our added slots:
+*/
+static PyObject*
+gcc_python_wrapper_meta_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyTypeObject *new_type;
+
+ /* Use PyType_Type's tp_new */
+ new_type = (PyTypeObject*)PyType_Type.tp_new(type, args, kwds);
+ if (!new_type) {
+ return NULL;
+ }
+
+ /* Verify that the metaclass is sane, and that the created type object
+ will thus be large enough for our extra information: */
+ assert(Py_TYPE(new_type)->tp_basicsize >= sizeof(PyGccWrapperTypeObject));
+
+ /* Inherit wrtp_mark: */
+ ((PyGccWrapperTypeObject*)new_type)->wrtp_mark = \
+ ((PyGccWrapperTypeObject*)new_type->tp_base)->wrtp_mark;
+
+ return (PyObject*)new_type;
+}
+
+PyTypeObject PyGccWrapperMetaType = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "gcc.WrapperMeta", /*tp_name*/
+ sizeof(PyGccWrapperTypeObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_base = &PyType_Type,
+ .tp_new = gcc_python_wrapper_meta_tp_new,
+};
+
/* Maintain a circular linked list of PyGccWrapper instances: */
static struct PyGccWrapper sentinel = {
PyObject_HEAD_INIT(NULL)
@@ -157,6 +265,8 @@ gcc_python_wrapper_init(void)
{
/* Register our GC root-walking callback: */
ggc_register_root_tab(&myroot);
+
+ PyType_Ready(&PyGccWrapperMetaType);
}
static void
diff --git a/gcc-python.h b/gcc-python.h
index d57316d..ffb88a8 100644
--- a/gcc-python.h
+++ b/gcc-python.h
@@ -79,7 +79,7 @@ typedef void (*wrtp_marker) (PyGccWrapper *wrapper);
typedef struct PyGccWrapperTypeObject
{
- PyTypeObject wrtp_base;
+ PyHeapTypeObject wrtp_base;
/* Callback for marking the wrapped objects when GCC's garbage
collector runs: */
@@ -107,6 +107,7 @@ gcc_python_wrapper_track(PyGccWrapper *obj);
extern void
gcc_python_wrapper_dealloc(PyObject *obj);
+extern PyTypeObject PyGccWrapperMetaType;
/*
Macro DECLARE_SIMPLE_WRAPPER():
ARG_structname:
diff --git a/tests/plugin/callgraph/stdout.txt b/tests/plugin/callgraph/stdout.txt
index f9560e3..2c7f7f9 100644
--- a/tests/plugin/callgraph/stdout.txt
+++ b/tests/plugin/callgraph/stdout.txt
@@ -24,7 +24,7 @@ class CallgraphNode(__builtin__.object)
| ----------------------------------------------------------------------
| Data and other attributes defined here:
|
- | __new__ = <built-in method __new__ of type object>
+ | __new__ = <built-in method __new__ of gcc.WrapperMeta object>
| T.__new__(S, ...) -> a new object with type S, a subtype of T
Help on class CallgraphEdge in module gcc:
@@ -53,7 +53,7 @@ class CallgraphEdge(__builtin__.object)
| ----------------------------------------------------------------------
| Data and other attributes defined here:
|
- | __new__ = <built-in method __new__ of type object>
+ | __new__ = <built-in method __new__ of gcc.WrapperMeta object>
| T.__new__(S, ...) -> a new object with type S, a subtype of T
cgn:
diff --git a/tests/plugin/gc/segfault-on-instance-of-pass-subclass/input.c b/tests/plugin/gc/segfault-on-instance-of-pass-subclass/input.c
new file mode 100644
index 0000000..40a8c17
--- /dev/null
+++ b/tests/plugin/gc/segfault-on-instance-of-pass-subclass/input.c
@@ -0,0 +1 @@
+/* empty */
diff --git a/tests/plugin/gc/segfault-on-instance-of-pass-subclass/script.py b/tests/plugin/gc/segfault-on-instance-of-pass-subclass/script.py
new file mode 100644
index 0000000..d447bf8
--- /dev/null
+++ b/tests/plugin/gc/segfault-on-instance-of-pass-subclass/script.py
@@ -0,0 +1,10 @@
+import gcc
+
+class UnusedArg(gcc.GimplePass):
+ def execute(self, fun):
+ pass
+
+ps = UnusedArg(name='UnusedArg')
+ps.register_after('lower')
+
+gcc._force_garbage_collection()
diff --git a/tests/plugin/options/stdout.txt b/tests/plugin/options/stdout.txt
index 14a92f4..81cc833 100644
--- a/tests/plugin/options/stdout.txt
+++ b/tests/plugin/options/stdout.txt
@@ -36,7 +36,7 @@ class Option(__builtin__.object)
| ----------------------------------------------------------------------
| Data and other attributes defined here:
|
- | __new__ = <built-in method __new__ of type object>
+ | __new__ = <built-in method __new__ of gcc.WrapperMeta object>
| T.__new__(S, ...) -> a new object with type S, a subtype of T
gcc.Option('-funroll-loops')
diff --git a/tests/plugin/parameters/stdout.txt b/tests/plugin/parameters/stdout.txt
index 3bb724f..bdae602 100644
--- a/tests/plugin/parameters/stdout.txt
+++ b/tests/plugin/parameters/stdout.txt
@@ -24,7 +24,7 @@ class Parameter(__builtin__.object)
| ----------------------------------------------------------------------
| Data and other attributes defined here:
|
- | __new__ = <built-in method __new__ of type object>
+ | __new__ = <built-in method __new__ of gcc.WrapperMeta object>
| T.__new__(S, ...) -> a new object with type S, a subtype of T
struct-reorg-cold-struct-ratio
diff --git a/tests/plugin/rtl/stdout.txt b/tests/plugin/rtl/stdout.txt
index 2720e05..46f5ad7 100644
--- a/tests/plugin/rtl/stdout.txt
+++ b/tests/plugin/rtl/stdout.txt
@@ -21,6 +21,6 @@ class Rtl(__builtin__.object)
| ----------------------------------------------------------------------
| Data and other attributes defined here:
|
- | __new__ = <built-in method __new__ of type object>
+ | __new__ = <built-in method __new__ of gcc.WrapperMeta object>
| T.__new__(S, ...) -> a new object with type S, a subtype of T
diff --git a/wrapperbuilder.py b/wrapperbuilder.py
index 01cab62..d369f31 100644
--- a/wrapperbuilder.py
+++ b/wrapperbuilder.py
@@ -28,15 +28,20 @@ class PyGccWrapperTypeObject(PyTypeObject):
A PyTypeObject that's also a PyGccWrapperTypeObject
(with metaclass PyGccWrapperMetaType)
"""
+ def __init__(self, *args, **kwargs):
+ PyTypeObject.__init__(self, *args, **kwargs)
+ self.ob_type = '&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()))
+ '{\n .ht_type = {\n%s}' % indent(indent(self.c_initializer())))
+ result += ' },\n'
result += self.c_src_field_value('wrtp_mark',
'wrtp_mark_for_%s' % self.struct_name,
cast='wrtp_marker')
- result += '};\n' % self.__dict__
+ result += '};\n'
result +='\n'
return result
12 years, 4 months
[gcc-python-plugin] cpychecker: extend detection of PyObject* subclasses
by David Hugh Malcolm
commit 5e1157c35c3ef57cba1615ffe706583d80f4a04d
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Tue Jan 17 16:04:21 2012 -0500
cpychecker: extend detection of PyObject* subclasses
The checker was treating any struct beginning with "ob_refcnt" and "ob_type"
as a Python object (with some tweaks for python 3 and debug builds).
Extend this to also cover structs that begin with a field that's a PyObject
(or subclass), since these are likely to also be PyObject subclasses.
libcpychecker/refcounts.py | 9 +++-
.../refcounts/subclass/detection/script.py | 1 +
.../refcounts/subclass/detection/stdout.txt | 5 ++
.../subclass/incorrect-subclass-ptr/input.c | 61 ++++++++++++++++++++
.../subclass/incorrect-subclass-ptr/metadata.ini | 3 +
.../subclass/incorrect-subclass-ptr/script.py | 22 +++++++
.../subclass/incorrect-subclass-ptr/stderr.txt | 11 ++++
.../subclass/incorrect-subclass-ptr/stdout.txt | 10 +++
8 files changed, 121 insertions(+), 1 deletions(-)
---
diff --git a/libcpychecker/refcounts.py b/libcpychecker/refcounts.py
index a239c96..701c7b6 100644
--- a/libcpychecker/refcounts.py
+++ b/libcpychecker/refcounts.py
@@ -64,7 +64,14 @@ def type_is_pyobjptr_subclass(t):
if not isinstance(t.dereference, gcc.RecordType):
return False
- fieldnames = [f.name for f in t.dereference.fields]
+ fields = t.dereference.fields
+
+ # if first field is a PyObject subclass, then we're good:
+ if type_is_pyobjptr_subclass(fields[0].type.pointer):
+ return True
+
+ fieldnames = [f.name for f in fields]
+
if is_py3k():
# For Python 3, the first field must be "ob_base", or it must be "PyObject":
if str(t) == 'struct PyObject *':
diff --git a/tests/cpychecker/refcounts/subclass/detection/script.py b/tests/cpychecker/refcounts/subclass/detection/script.py
index a014fbb..5ec99a5 100644
--- a/tests/cpychecker/refcounts/subclass/detection/script.py
+++ b/tests/cpychecker/refcounts/subclass/detection/script.py
@@ -63,6 +63,7 @@ def on_pass_execution(p, fn):
check_typedef('PyTypeObject')
check_struct('FooObject')
check_struct('BarObject')
+ check_struct('BazObject')
check_struct('NotAnObject')
gcc.register_callback(gcc.PLUGIN_PASS_EXECUTION,
diff --git a/tests/cpychecker/refcounts/subclass/detection/stdout.txt b/tests/cpychecker/refcounts/subclass/detection/stdout.txt
index 66b5147..a214528 100644
--- a/tests/cpychecker/refcounts/subclass/detection/stdout.txt
+++ b/tests/cpychecker/refcounts/subclass/detection/stdout.txt
@@ -22,6 +22,11 @@ typename: 'BarObject'
ptr_type: struct BarObject *
is PyObject* subclass?: True
+typename: 'BazObject'
+ struct_type: struct BazObject
+ ptr_type: struct BazObject *
+ is PyObject* subclass?: True
+
typename: 'NotAnObject'
struct_type: struct NotAnObject
ptr_type: struct NotAnObject *
diff --git a/tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/input.c b/tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/input.c
new file mode 100644
index 0000000..163c70e
--- /dev/null
+++ b/tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/input.c
@@ -0,0 +1,61 @@
+/*
+ Copyright 2012 David Malcolm <dmalcolm(a)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/>.
+*/
+
+#include <Python.h>
+
+/*
+ Verify that the checker detects reference-count errors on PyObject
+ subclasses where the object is referred to via a subclass pointer,
+ and where the subclass embeds ob_refcnt and ob_type only indirectly
+*/
+
+/* The checker should treat this as a PyObject subclass */
+struct FooObject {
+ PyObject_HEAD
+ int i;
+};
+
+/* The checker should treat this as a PyObject subclass also: */
+struct BarObject {
+ struct FooObject ba_head;
+ int ba_int;
+ char ba_char;
+};
+
+void
+test_function(struct BarObject *self)
+{
+ /*
+ The checker ought to check the refcount of self, and complain that it
+ erroneously gains 5 references:
+ */
+ Py_INCREF(self);
+ Py_INCREF(self);
+ Py_INCREF(self);
+ Py_INCREF(self);
+ Py_INCREF(self);
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/metadata.ini b/tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/metadata.ini
new file mode 100644
index 0000000..0d5711c
--- /dev/null
+++ b/tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/metadata.ini
@@ -0,0 +1,3 @@
+[ExpectedBehavior]
+# We expect only compilation *warnings*, so we expect a 0 exit code
+exitcode = 0
diff --git a/tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/script.py b/tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/script.py
new file mode 100644
index 0000000..fdd5ba3
--- /dev/null
+++ b/tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/script.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Copyright 2011 David Malcolm <dmalcolm(a)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/>.
+
+from libcpychecker import main
+main(verify_refcounting=True,
+ dump_traces=True,
+ show_traces=False)
diff --git a/tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/stderr.txt b/tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/stderr.txt
new file mode 100644
index 0000000..55c5f11
--- /dev/null
+++ b/tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/stderr.txt
@@ -0,0 +1,11 @@
+tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/input.c: In function 'test_function':
+tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/input.c:53:1: warning: ob_refcnt of '*self' is 5 too high [enabled by default]
+tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/input.c:53:1: note: was expecting final ob_refcnt to be N + 0 (for some unknown N)
+tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/input.c:53:1: note: but final ob_refcnt is N + 5
+tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/input.c:48:5: note: ob_refcnt is now refs: 1 + N where N >= 1
+tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/input.c:49:5: note: ob_refcnt is now refs: 2 + N where N >= 1
+tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/input.c:50:5: note: ob_refcnt is now refs: 3 + N where N >= 1
+tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/input.c:51:5: note: ob_refcnt is now refs: 4 + N where N >= 1
+tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/input.c:52:5: note: ob_refcnt is now refs: 5 + N where N >= 1
+tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/input.c:53:1: note: returning at: }
+tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/input.c:43:1: note: graphical error report for function 'test_function' written out to 'tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/input.c.test_function-refcount-errors.html'
diff --git a/tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/stdout.txt b/tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/stdout.txt
new file mode 100644
index 0000000..742b4e7
--- /dev/null
+++ b/tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/stdout.txt
@@ -0,0 +1,10 @@
+Trace 0:
+ Transitions:
+ 'returning'
+ Region("region-for-arg-gcc.ParmDecl('self')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('self')")
+ str(): Region("region-for-arg-gcc.ParmDecl('self')")
+ r->ob_refcnt: refs: 5 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/input.c', line=42), region=Region("region-for-type-of-arg-gcc.ParmDecl('self')"))
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/refcounts/subclass/incorrect-subclass-ptr/input.c:43
12 years, 4 months
[gcc-python-plugin] Makefile: add -fno-strict-aliasing to CFLAGS
by David Hugh Malcolm
commit 6b633d4d5159ddd1024ab5b66ff1feeb133184ed
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Tue Jan 17 12:17:08 2012 -0500
Makefile: add -fno-strict-aliasing to CFLAGS
See https://fedorahosted.org/pipermail/gcc-python-plugin/2012-January/000149....
Python 2's implementation of various macros including Py_INCREF() relies on
undefined C behavior. See PEP 3123:
http://www.python.org/dev/peps/pep-3123/
Thus on modern GCCs it *needs* "-fno-strict-aliasing" in the build flags to
avoid this warning (as an error) from gcc; gcc could potentially
"over-optimize" such code and generate machine code that doesn't do what we
expect: see also e.g.
http://codespeak.net/pipermail/cython-dev/2008-April/000380.html
http://bugs.python.org/issue969718
The plugin is getting its build flags from $(python-config --cflags), which
*ought* to contain "-fno-strict-aliasing", but this doesn't seem to be the case
on this user's sysmtem.
Explicilty add "-fno-strict-aliasing" to CFLAGS in our Makefile to make sure.
Makefile | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
---
diff --git a/Makefile b/Makefile
index 9cb244d..3805f1b 100644
--- a/Makefile
+++ b/Makefile
@@ -93,7 +93,7 @@ PYTHON_CONFIG=python-config
PYTHON_CFLAGS=$(shell $(PYTHON_CONFIG) --cflags)
PYTHON_LDFLAGS=$(shell $(PYTHON_CONFIG) --ldflags)
-CFLAGS+= -I$(GCCPLUGINS_DIR)/include -fPIC -O2 -Wall -Werror -g $(PYTHON_CFLAGS) $(PYTHON_LDFLAGS)
+CFLAGS+= -I$(GCCPLUGINS_DIR)/include -fPIC -fno-strict-aliasing -O2 -Wall -Werror -g $(PYTHON_CFLAGS) $(PYTHON_LDFLAGS)
ifneq "$(PLUGIN_PYTHONPATH)" ""
CFLAGS+= -DPLUGIN_PYTHONPATH='"$(PLUGIN_PYTHONPATH)"'
endif
12 years, 4 months
[gcc-python-plugin] docs: remove note about garbage collector
by David Hugh Malcolm
commit 50214ad8eab16fae6f98bacf04f7320b08633c0e
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Sat Jan 14 07:02:26 2012 -0500
docs: remove note about garbage collector
docs/index.rst | 4 ----
1 files changed, 0 insertions(+), 4 deletions(-)
---
diff --git a/docs/index.rst b/docs/index.rst
index b12fc3b..7b4267c 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -64,10 +64,6 @@ within them, I've only wrapped properties that seemed useful to me. There may
well be plenty of interesting class and properties for instances that can be
added (patches most welcome!). I may also have misunderstood how things work.
-Caveat: I'm currently blithely ignoring GCC's garbage collector, which works for
-now, but will probably lead to crashes if the collector runs. I hope to fix
-that soon.
-
Most of my development has been against Python 2 (2.7, actually), but I've tried
to make the source code of the plugin buildable against both Python 2 and
Python 3 (3.2), giving separate python2.so and python3.so plugins. (I suspect
12 years, 4 months
[gcc-python-plugin] integrate with GCC's garbage collector (ticket #1)
by David Hugh Malcolm
commit 58d65a1b353220efbcf8d908b0946ef5d1c4fafd
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Fri Jan 13 19:26:43 2012 -0500
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
Makefile | 27 ++-
cpybuilder.py | 30 ++-
gcc-python-callgraph.c | 27 ++-
gcc-python-cfg.c | 31 ++-
gcc-python-compat.h | 6 +-
gcc-python-diagnostics.c | 2 +-
gcc-python-function.c | 14 +-
gcc-python-gimple.c | 16 +-
gcc-python-location.c | 17 +-
gcc-python-option.c | 17 +-
gcc-python-parameter.c | 12 +-
gcc-python-pass.c | 26 ++-
gcc-python-rtl.c | 17 +-
gcc-python-tree.c | 22 ++-
gcc-python-variable.c | 9 +-
gcc-python-wrapper.c | 264 ++++++++++++++++++++
gcc-python-wrappers.h | 10 +
gcc-python.c | 10 +
gcc-python.h | 82 +++++-
generate-callgraph-c.py | 15 +-
generate-cfg-c.py | 20 +-
generate-function-c.py | 13 +-
generate-gimple-c.py | 25 ++-
generate-location-c.py | 12 +-
generate-option-c.py | 10 +-
generate-parameter-c.py | 10 +-
generate-pass-c.py | 16 +-
generate-rtl-c.py | 24 +-
generate-tree-c.py | 30 ++-
generate-variable-c.py | 10 +-
tests/plugin/gc/_force_garbage_collection/input.c | 28 ++
.../plugin/gc/_force_garbage_collection/script.py | 55 ++++
.../plugin/gc/_force_garbage_collection/stdout.txt | 2 +
tests/plugin/gc/_gc_selftest/input.c | 55 ++++
tests/plugin/gc/_gc_selftest/script.py | 25 ++
tests/plugin/gc/_gc_selftest/stdout.txt | 18 ++
wrapperbuilder.py | 43 ++++
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(a)redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)redhat.com>
- Copyright 2011 Red Hat, Inc.
+ Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)redhat.com>
- Copyright 2011 Red Hat, Inc.
+ Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)redhat.com>
- Copyright 2011 Red Hat, Inc.
+ Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)redhat.com>
- Copyright 2011 Red Hat, Inc.
+ Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)redhat.com>
- Copyright 2011 Red Hat, Inc.
+ Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)redhat.com>
- Copyright 2011 Red Hat, Inc.
+ Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)redhat.com>
- Copyright 2011 Red Hat, Inc.
+ Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)redhat.com>
- Copyright 2011 Red Hat, Inc.
+ Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)redhat.com>
- Copyright 2011 Red Hat, Inc.
+ Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)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(a)redhat.com>
- Copyright 2011 Red Hat, Inc.
+ Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)redhat.com>
-# Copyright 2011 Red Hat, Inc.
+# Copyright 2011, 2012 David Malcolm <dmalcolm(a)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(a)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(a)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(a)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(a)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(a)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
+
+
12 years, 4 months
[gcc-python-plugin] allow registration of callbacks on gcc.PLUGIN_GGC_{START, MARKING, FINISH}
by David Hugh Malcolm
commit e75f80d759f42a24f564952dd393568c5a83b529
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Fri Jan 13 19:05:53 2012 -0500
allow registration of callbacks on gcc.PLUGIN_GGC_{START,MARKING,FINISH}
gcc-python-callbacks.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 54 insertions(+), 0 deletions(-)
---
diff --git a/gcc-python-callbacks.c b/gcc-python-callbacks.c
index c7296e4..d4bca14 100644
--- a/gcc-python-callbacks.c
+++ b/gcc-python-callbacks.c
@@ -253,6 +253,41 @@ gcc_python_callback_for_FINISH_UNIT(void *gcc_data, void *user_data)
user_data);
}
+static void
+gcc_python_callback_for_GGC_START(void *gcc_data, void *user_data)
+{
+ PyGILState_STATE gstate;
+
+ gstate = PyGILState_Ensure();
+
+ gcc_python_finish_invoking_callback(gstate,
+ 0, NULL,
+ user_data);
+}
+
+static void
+gcc_python_callback_for_GGC_MARKING(void *gcc_data, void *user_data)
+{
+ PyGILState_STATE gstate;
+
+ gstate = PyGILState_Ensure();
+
+ gcc_python_finish_invoking_callback(gstate,
+ 0, NULL,
+ user_data);
+}
+
+static void
+gcc_python_callback_for_GGC_END(void *gcc_data, void *user_data)
+{
+ PyGILState_STATE gstate;
+
+ gstate = PyGILState_Ensure();
+
+ gcc_python_finish_invoking_callback(gstate,
+ 0, NULL,
+ user_data);
+}
PyObject*
@@ -318,6 +353,25 @@ gcc_python_register_callback(PyObject *self, PyObject *args, PyObject *kwargs)
closure);
break;
+ case PLUGIN_GGC_START:
+ register_callback("python", // FIXME
+ (enum plugin_event)event,
+ gcc_python_callback_for_GGC_START,
+ closure);
+ break;
+ case PLUGIN_GGC_MARKING:
+ register_callback("python", // FIXME
+ (enum plugin_event)event,
+ gcc_python_callback_for_GGC_MARKING,
+ closure);
+ break;
+ case PLUGIN_GGC_END:
+ register_callback("python", // FIXME
+ (enum plugin_event)event,
+ gcc_python_callback_for_GGC_END,
+ closure);
+ break;
+
default:
PyErr_Format(PyExc_ValueError, "event type %i invalid (or not wired up yet)", event);
return NULL;
12 years, 4 months
[gcc-python-plugin] tidy up selftests for callbacks
by David Hugh Malcolm
commit 6133f8ce881b7e1d4bc80b749940abe78e608d40
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Fri Jan 13 12:01:33 2012 -0500
tidy up selftests for callbacks
Move the callback tests below tests/plugin/callbacks:
tests/plugin/callback-args -> tests/plugin/callbacks/args
tests/plugin/callback-exception -> tests/plugin/callbacks/exception
tests/plugin/callback-refs -> tests/plugin/callbacks/refs
tests/plugin/callback-exception/stderr.txt | 5 -----
.../{callback-args => callbacks/args}/input.c | 0
.../{callback-args => callbacks/args}/script.py | 0
.../{callback-args => callbacks/args}/stdout.txt | 0
.../exception}/input.c | 0
.../exception}/script.py | 0
tests/plugin/callbacks/exception/stderr.txt | 5 +++++
.../{callback-refs => callbacks/refs}/input.c | 0
.../{callback-refs => callbacks/refs}/script.py | 0
.../{callback-refs => callbacks/refs}/stdout.txt | 0
10 files changed, 5 insertions(+), 5 deletions(-)
---
diff --git a/tests/plugin/callback-args/input.c b/tests/plugin/callbacks/args/input.c
similarity index 100%
rename from tests/plugin/callback-args/input.c
rename to tests/plugin/callbacks/args/input.c
diff --git a/tests/plugin/callback-args/script.py b/tests/plugin/callbacks/args/script.py
similarity index 100%
rename from tests/plugin/callback-args/script.py
rename to tests/plugin/callbacks/args/script.py
diff --git a/tests/plugin/callback-args/stdout.txt b/tests/plugin/callbacks/args/stdout.txt
similarity index 100%
rename from tests/plugin/callback-args/stdout.txt
rename to tests/plugin/callbacks/args/stdout.txt
diff --git a/tests/plugin/callback-exception/input.c b/tests/plugin/callbacks/exception/input.c
similarity index 100%
rename from tests/plugin/callback-exception/input.c
rename to tests/plugin/callbacks/exception/input.c
diff --git a/tests/plugin/callback-exception/script.py b/tests/plugin/callbacks/exception/script.py
similarity index 100%
rename from tests/plugin/callback-exception/script.py
rename to tests/plugin/callbacks/exception/script.py
diff --git a/tests/plugin/callbacks/exception/stderr.txt b/tests/plugin/callbacks/exception/stderr.txt
new file mode 100644
index 0000000..939aa7d
--- /dev/null
+++ b/tests/plugin/callbacks/exception/stderr.txt
@@ -0,0 +1,5 @@
+tests/plugin/callbacks/exception/input.c:1:0: error: Unhandled Python exception raised within callback
+Traceback (most recent call last):
+ File "tests/plugin/callbacks/exception/script.py", line 22, in my_callback
+ raise RuntimeError("This is a test of raising an exception")
+RuntimeError: This is a test of raising an exception
diff --git a/tests/plugin/callback-refs/input.c b/tests/plugin/callbacks/refs/input.c
similarity index 100%
rename from tests/plugin/callback-refs/input.c
rename to tests/plugin/callbacks/refs/input.c
diff --git a/tests/plugin/callback-refs/script.py b/tests/plugin/callbacks/refs/script.py
similarity index 100%
rename from tests/plugin/callback-refs/script.py
rename to tests/plugin/callbacks/refs/script.py
diff --git a/tests/plugin/callback-refs/stdout.txt b/tests/plugin/callbacks/refs/stdout.txt
similarity index 100%
rename from tests/plugin/callback-refs/stdout.txt
rename to tests/plugin/callbacks/refs/stdout.txt
12 years, 4 months