[pypy-svn] r12881 - in pypy/dist/pypy/translator/c: . test
arigo at codespeak.net
arigo at codespeak.net
Mon May 30 14:04:58 CEST 2005
Author: arigo
Date: Mon May 30 14:04:58 2005
New Revision: 12881
Modified:
pypy/dist/pypy/translator/c/database.py
pypy/dist/pypy/translator/c/funcgen.py
pypy/dist/pypy/translator/c/ll_include.h
pypy/dist/pypy/translator/c/node.py
pypy/dist/pypy/translator/c/test/test_database.py
Log:
Reference counting and deallocators.
Modified: pypy/dist/pypy/translator/c/database.py
==============================================================================
--- pypy/dist/pypy/translator/c/database.py (original)
+++ pypy/dist/pypy/translator/c/database.py Mon May 30 14:04:58 2005
@@ -102,6 +102,28 @@
else:
raise Exception("don't know about %r" % (obj,))
+ def cincrefstmt(self, expr, T):
+ if isinstance(T, _PtrType) and 'gc' in T.flags:
+ if T.TO == PyObject:
+ return 'Py_INCREF(%s);' % expr
+ else:
+ defnode = self.gettypedefnode(T.TO)
+ if defnode.refcount is not None:
+ return '%s->%s++;' % (expr, defnode.refcount)
+ return ''
+
+ def cdecrefstmt(self, expr, T):
+ if isinstance(T, _PtrType) and 'gc' in T.flags:
+ if T.TO == PyObject:
+ return 'Py_DECREF(%s);' % expr
+ else:
+ defnode = self.gettypedefnode(T.TO)
+ if defnode.refcount is not None:
+ return 'if (!--%s->%s) %s(%s);' % (expr, defnode.refcount,
+ defnode.deallocator or 'OP_FREE',
+ expr)
+ return ''
+
def complete(self):
i = 0
while True:
Modified: pypy/dist/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/dist/pypy/translator/c/funcgen.py (original)
+++ pypy/dist/pypy/translator/c/funcgen.py Mon May 30 14:04:58 2005
@@ -3,7 +3,7 @@
from pypy.translator.c.support import llvalue_from_constant
from pypy.objspace.flow.model import Variable, Constant, Block
from pypy.objspace.flow.model import traverse, uniqueitems, last_exception
-from pypy.rpython.lltype import GcPtr, NonGcPtr, PyObject, Void, Primitive
+from pypy.rpython.lltype import GcPtr, NonGcPtr, PyObject, Void
from pypy.rpython.lltype import pyobjectptr, Struct, Array
@@ -292,32 +292,49 @@
r, args[0], ', '.join(args[1:]), err)
# low-level operations
- def OP_GETFIELD(self, op, err):
+ def OP_GETFIELD(self, op, err, ampersand=''):
assert isinstance(op.args[1], Constant)
STRUCT = self.lltypemap[op.args[0]].TO
structdef = self.db.gettypedefnode(STRUCT)
fieldname = structdef.c_struct_field_name(op.args[1].value)
- return '%s = %s->%s;' % (self.expr(op.result),
- self.expr(op.args[0]),
- fieldname)
+ newvalue = self.expr(op.result)
+ result = ['%s = %s%s->%s;' % (newvalue,
+ ampersand,
+ self.expr(op.args[0]),
+ fieldname)]
+ # need to adjust the refcount of the result
+ T = self.lltypemap[op.result]
+ increfstmt = self.db.cincrefstmt(newvalue, T)
+ if increfstmt:
+ result.append(increfstmt)
+ return '\t'.join(result)
def OP_SETFIELD(self, op, err):
assert isinstance(op.args[1], Constant)
STRUCT = self.lltypemap[op.args[0]].TO
structdef = self.db.gettypedefnode(STRUCT)
fieldname = structdef.c_struct_field_name(op.args[1].value)
- return '%s->%s = %s;' % (self.expr(op.args[0]),
- fieldname,
- self.expr(op.args[2]))
+ oldvalue = '%s->%s' % (self.expr(op.args[0]),
+ fieldname)
+ newvalue = self.expr(op.args[2])
+ result = ['%s = %s;' % (oldvalue, newvalue)]
+
+ # need to adjust some refcounts
+ T = structdef.c_struct_field_type(op.args[1].value)
+ decrefstmt = self.db.cdecrefstmt('prev', T)
+ increfstmt = self.db.cincrefstmt(newvalue, T)
+ if increfstmt:
+ result.append(increfstmt)
+ if decrefstmt:
+ result.insert(0, '{ %s = %s;' % (
+ cdecl(self.typemap[op.args[2]], 'prev'),
+ oldvalue))
+ result.append('if (prev) ' + decrefstmt)
+ result.append('}')
+ return '\t'.join(result)
def OP_GETSUBSTRUCT(self, op, err):
- assert isinstance(op.args[1], Constant)
- STRUCT = self.lltypemap[op.args[0]].TO
- structdef = self.db.gettypedefnode(STRUCT)
- fieldname = structdef.c_struct_field_name(op.args[1].value)
- return '%s = &%s->%s;' % (self.expr(op.result),
- self.expr(op.args[0]),
- fieldname)
+ return self.OP_GETFIELD(op, err, ampersand='&')
def OP_GETARRAYITEM(self, op, err):
return '%s = %s->items + %s;' % (self.expr(op.result),
@@ -335,7 +352,9 @@
result = ['OP_ZERO_MALLOC(sizeof(%s), %s, %s)' % (cdecl(typename, ''),
eresult,
err),
- self.cincref(op.result)]
+ '%s->%s = 1;' % (eresult,
+ self.db.gettypedefnode(TYPE).refcount),
+ ]
return '\t'.join(result)
def OP_MALLOC_VARSIZE(self, op, err):
@@ -355,25 +374,15 @@
err),
'%s->length = %s;' % (eresult,
elength),
- self.cincref(op.result)]
+ '%s->%s = 1;' % (eresult,
+ self.db.gettypedefnode(TYPE).refcount),
+ ]
return '\t'.join(result)
def cincref(self, v):
T = self.lltypemap[v]
- if not isinstance(T, Primitive) and 'gc' in T.flags:
- if T.TO == PyObject:
- return 'Py_INCREF(%s);' % v.name
- else:
- return '/*XXX INCREF %s*/' % v.name
- else:
- return ''
+ return self.db.cincrefstmt(v.name, T)
def cdecref(self, v, expr=None):
T = self.lltypemap[v]
- if not isinstance(T, Primitive) and 'gc' in T.flags:
- if T.TO == PyObject:
- return 'Py_DECREF(%s);' % v.name
- else:
- return '/*XXX DECREF %s*/' % v.name
- else:
- return ''
+ return self.db.cdecrefstmt(expr or v.name, T)
Modified: pypy/dist/pypy/translator/c/ll_include.h
==============================================================================
--- pypy/dist/pypy/translator/c/ll_include.h (original)
+++ pypy/dist/pypy/translator/c/ll_include.h Mon May 30 14:04:58 2005
@@ -8,3 +8,5 @@
if (r == NULL) { PyErr_NoMemory(); FAIL(err) } \
memset((void*) r, 0, size); \
}
+
+#define OP_FREE(p) PyObject_Free(p);
Modified: pypy/dist/pypy/translator/c/node.py
==============================================================================
--- pypy/dist/pypy/translator/c/node.py (original)
+++ pypy/dist/pypy/translator/c/node.py Mon May 30 14:04:58 2005
@@ -1,7 +1,7 @@
from __future__ import generators
from pypy.rpython.lltype import Struct, Array, FuncType, PyObjectType, typeOf
from pypy.rpython.lltype import GcStruct, GcArray, GC_CONTAINER, ContainerType
-from pypy.rpython.lltype import parentlink
+from pypy.rpython.lltype import parentlink, _PtrType
from pypy.translator.c.funcgen import FunctionCodeGenerator
from pypy.translator.c.support import cdecl, somelettersfrom
@@ -11,13 +11,16 @@
return False
if isinstance(T, GcStruct):
if T._names and isinstance(T._flds[T._names[0]], GC_CONTAINER):
- return False # refcount already in the first first
+ return False # refcount already in the first field
return True
class StructDefNode:
+ refcount = None
+ deallocator = None
def __init__(self, db, STRUCT, varlength=1):
+ self.db = db
self.STRUCT = STRUCT
if varlength == 1:
basename = STRUCT._name
@@ -29,16 +32,34 @@
self.fields = []
self.prefix = somelettersfrom(STRUCT._name) + '_'
for name in STRUCT._names:
- T = STRUCT._flds[name]
+ T = self.c_struct_field_type(name)
if name == STRUCT._arrayfld:
typename = db.gettype(T, varlength=varlength, who_asks=self)
else:
typename = db.gettype(T, who_asks=self)
self.fields.append((self.c_struct_field_name(name), typename))
+ # look up the reference counter field
+ if needs_refcount(STRUCT):
+ self.refcount = 'refcount'
+ elif isinstance(STRUCT, GcStruct):
+ # refcount in the first field
+ T = self.c_struct_field_type(STRUCT._names[0])
+ assert isinstance(T, GC_CONTAINER)
+ firstfieldname, firstfieldtype = self.fields[0]
+ firstdefnode = db.gettypedefnode(T)
+ self.refcount = '%s.%s' % (firstfieldname, firstdefnode.refcount)
+
+ # is a specific deallocator needed?
+ if self.refcount and varlength == 1 and list(self.deallocator_lines('')):
+ self.deallocator = db.namespace.uniquename('dealloc_'+self.name)
+
def c_struct_field_name(self, name):
return self.prefix + name
+ def c_struct_field_type(self, name):
+ return self.STRUCT._flds[name]
+
def access_expr(self, baseexpr, fldname):
fldname = self.c_struct_field_name(fldname)
return '%s.%s' % (baseexpr, fldname)
@@ -50,11 +71,35 @@
for name, typename in self.fields:
yield '\t%s;' % cdecl(typename, name)
yield '};'
+ if self.deallocator:
+ yield 'void %s(struct %s *p) {' % (self.deallocator, self.name)
+ for line in self.deallocator_lines('p->'):
+ yield '\t' + line
+ yield '\tOP_FREE(p);'
+ yield '}'
+
+ def deallocator_lines(self, prefix):
+ STRUCT = self.STRUCT
+ for name in STRUCT._names:
+ FIELD_T = self.c_struct_field_type(name)
+ if isinstance(FIELD_T, _PtrType) and 'gc' in FIELD_T.flags:
+ cname = self.c_struct_field_name(name)
+ line = self.db.cdecrefstmt('%s%s' % (prefix, cname), FIELD_T)
+ if line:
+ yield line
+ elif isinstance(FIELD_T, ContainerType):
+ defnode = self.db.gettypedefnode(FIELD_T)
+ cname = self.c_struct_field_name(name)
+ for line in defnode.deallocator_lines('%s%s.' %(prefix, cname)):
+ yield line
class ArrayDefNode:
+ refcount = None
+ deallocator = None
def __init__(self, db, ARRAY, varlength=1):
+ self.db = db
self.ARRAY = ARRAY
if varlength == 1:
basename = 'array'
@@ -66,6 +111,14 @@
self.structname = db.gettype(ARRAY.OF, who_asks=self)
self.varlength = varlength
+ # look up the reference counter field
+ if needs_refcount(ARRAY):
+ self.refcount = 'refcount'
+
+ # is a specific deallocator needed?
+ if self.refcount and varlength == 1 and list(self.deallocator_lines('')):
+ self.deallocator = db.namespace.uniquename('dealloc_'+self.name)
+
def access_expr(self, baseexpr, index):
return '%s.items[%d]' % (baseexpr, index)
@@ -76,6 +129,33 @@
yield '\tlong length;'
yield '\t%s;' % cdecl(self.structname, 'items[%d]' % self.varlength)
yield '};'
+ if self.deallocator:
+ yield 'void %s(struct %s *a) {' % (self.deallocator, self.name)
+ for line in self.deallocator_lines('a->'):
+ yield '\t' + line
+ yield '\tOP_FREE(a);'
+ yield '}'
+
+ def deallocator_lines(self, prefix):
+ ARRAY = self.ARRAY
+ defnode = self.db.gettypedefnode(ARRAY.OF)
+ varname = 'p%d' % len(prefix)
+ body = list(defnode.deallocator_lines('%s->' % varname))
+ if body:
+ yield '{'
+ yield '\tstruct %s *%s = %sitems;' % (defnode.name,
+ varname,
+ prefix)
+ yield '\tstruct %s *%s_end = %s + %slength;' % (defnode.name,
+ varname,
+ varname,
+ prefix)
+ yield '\twhile (%s != %s_end) {' % (varname, varname)
+ for line in body:
+ yield '\t\t' + line
+ yield '\t\t%s++;' % varname
+ yield '\t}'
+ yield '}'
# ____________________________________________________________
Modified: pypy/dist/pypy/translator/c/test/test_database.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_database.py (original)
+++ pypy/dist/pypy/translator/c/test/test_database.py Mon May 30 14:04:58 2005
@@ -193,3 +193,72 @@
db.get(pyobjectptr(f))
db.complete()
dump_on_stdout(db)
+
+
+def test_malloc():
+ S = GcStruct('testing', ('x', Signed), ('y', Signed))
+ def ll_f(x):
+ p = malloc(S)
+ p.x = x
+ p.y = x+1
+ return p.x * p.y
+ t = Translator(ll_f)
+ a = t.annotate([int])
+ rtyper = RPythonTyper(t.annotator)
+ rtyper.specialize()
+ db = LowLevelDatabase(rtyper)
+ db.get(rtyper.getfunctionptr(ll_f))
+ db.complete()
+ dump_on_stdout(db)
+
+def test_multiple_malloc():
+ S1 = GcStruct('testing1', ('x', Signed), ('y', Signed))
+ S = GcStruct('testing', ('ptr1', GcPtr(S1)),
+ ('ptr2', GcPtr(S1)),
+ ('z', Signed))
+ def ll_f(x):
+ ptr1 = malloc(S1)
+ ptr1.x = x
+ ptr2 = malloc(S1)
+ ptr2.x = x+1
+ s = malloc(S)
+ s.ptr1 = ptr1
+ s.ptr2 = ptr2
+ return s.ptr1.x * s.ptr2.x
+ t = Translator(ll_f)
+ a = t.annotate([int])
+ rtyper = RPythonTyper(t.annotator)
+ rtyper.specialize()
+ db = LowLevelDatabase(rtyper)
+ db.get(rtyper.getfunctionptr(ll_f))
+ db.complete()
+ dump_on_stdout(db)
+
+def test_nested_gcstruct():
+ S1 = GcStruct('inlined', ('x', Signed), ('y', GcPtr(PyObject)))
+ S = GcStruct('testing', ('head', S1),
+ ('ptr2', GcPtr(S1)),
+ ('z', Signed))
+ def ll_f(x):
+ ptr2 = malloc(S1)
+ ptr2.x = x+1
+ s = malloc(S)
+ s.head.x = x
+ s.ptr2 = ptr2
+ return s.head.x * s.ptr2.x
+ t = Translator(ll_f)
+ a = t.annotate([int])
+ rtyper = RPythonTyper(t.annotator)
+ rtyper.specialize()
+ db = LowLevelDatabase(rtyper)
+ db.get(rtyper.getfunctionptr(ll_f))
+ db.complete()
+ dump_on_stdout(db)
+
+def test_array():
+ A = GcArray(('obj', GcPtr(PyObject)))
+ a = malloc(A, 10)
+ db = LowLevelDatabase()
+ db.get(a)
+ db.complete()
+ dump_on_stdout(db)
More information about the Pypy-commit
mailing list