[pypy-svn] r45021 - in pypy/dist/pypy/rpython/lltypesystem: . test
arigo at codespeak.net
arigo at codespeak.net
Fri Jul 13 15:27:34 CEST 2007
Author: arigo
Date: Fri Jul 13 15:27:33 2007
New Revision: 45021
Modified:
pypy/dist/pypy/rpython/lltypesystem/compactlltype.py
pypy/dist/pypy/rpython/lltypesystem/lltype.py
pypy/dist/pypy/rpython/lltypesystem/test/test_compactlltype.py
Log:
(lac, arigo)
First test passes: allocating and freeing ctypes-based structs and arrays.
Modified: pypy/dist/pypy/rpython/lltypesystem/compactlltype.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/compactlltype.py (original)
+++ pypy/dist/pypy/rpython/lltypesystem/compactlltype.py Fri Jul 13 15:27:33 2007
@@ -1,51 +1,46 @@
-import ctypes, sys, weakref
-from pypy.rpython.lltypesystem.lltype import Signed, Struct, GcStruct, Ptr
-from pypy.rpython.lltypesystem.lltype import ContainerType, Array, GcArray
-from pypy.rpython.lltypesystem.lltype import typeOf, castable
+import sys
+import ctypes
+from pypy.rpython.lltypesystem import lltype
+from pypy.tool.uid import fixid
_Ctypes_PointerType = type(ctypes.POINTER(ctypes.c_int))
-
-def cast_pointer(PTRTYPE, ptr):
- CURTYPE = typeOf(ptr)
- if not isinstance(CURTYPE, Ptr) or not isinstance(PTRTYPE, Ptr):
- raise TypeError, "can only cast pointers to other pointers"
- return ptr._cast_to(PTRTYPE)
-
-
-class _parentable(ctypes.Structure): # won't work with Union
- __slots__ = ()
+def uaddressof(obj):
+ return fixid(ctypes.addressof(obj))
# ____________________________________________________________
+_allocated = []
+
_ctypes_cache = {
- Signed: ctypes.c_long,
+ lltype.Signed: ctypes.c_long,
}
-def _build_ctypes_struct(S, max_n=None):
+def build_ctypes_struct(S, max_n=None):
fields = []
for fieldname in S._names:
FIELDTYPE = S._flds[fieldname]
if max_n is not None and fieldname == S._arrayfld:
- cls = _build_ctypes_array(FIELDTYPE, max_n)
+ cls = build_ctypes_array(FIELDTYPE, max_n)
else:
- cls = _get_ctypes_type(FIELDTYPE)
+ cls = get_ctypes_type(FIELDTYPE)
fields.append((fieldname, cls))
- class CStruct(_parentable):
+ class CStruct(ctypes.Structure):
_fields_ = fields
- _TYPE = S
def malloc(cls, n=None):
- S = cls._TYPE
if S._arrayfld is None:
if n is not None:
raise TypeError("%r is not variable-sized" % (S,))
- return ctypes.pointer(cls())
+ storage = cls()
+ _allocated.append(storage)
+ return _ctypes_struct(S, storage)
else:
+ XXX
if n is None:
raise TypeError("%r is variable-sized" % (S,))
- smallercls = _build_ctypes_struct(S, n)
+ smallercls = build_ctypes_struct(S, n)
smallstruct = smallercls()
getattr(smallstruct, S._arrayfld).length = n
structptr = ctypes.cast(ctypes.pointer(smallstruct),
@@ -56,150 +51,152 @@
CStruct.__name__ = 'ctypes_%s' % (S,)
return CStruct
-def _build_ctypes_array(A, max_n=None):
+def build_ctypes_array(A, max_n=0):
+ assert max_n >= 0
ITEM = A.OF
- ctypes_item = _get_ctypes_type(ITEM)
- if max_n is None:
- max_n = sys.maxint // ctypes.sizeof(ctypes_item)
- max_n //= 2 # XXX better safe than sorry about ctypes bugs
+ ctypes_item = get_ctypes_type(ITEM)
- class CArray(_parentable):
+ class CArray(ctypes.Structure):
_fields_ = [('length', ctypes.c_int),
('items', max_n * ctypes_item)]
- _TYPE = A
def malloc(cls, n=None):
if not isinstance(n, int):
raise TypeError, "array length must be an int"
- smallercls = _build_ctypes_array(cls._TYPE, n)
- smallarray = smallercls()
- smallarray.length = n
- arrayptr = ctypes.cast(ctypes.pointer(smallarray),
- ctypes.POINTER(cls))
- return arrayptr
+ biggercls = build_ctypes_array(A, n)
+ bigarray = biggercls()
+ _allocated.append(bigarray)
+ bigarray.length = n
+ return _ctypes_array(A, bigarray)
malloc = classmethod(malloc)
- CArray.__name__ = 'ctypes_%s' % (A,)
+ CArray.__name__ = 'ctypes_%s*%d' % (A, max_n)
return CArray
-def _get_ctypes_type(T):
+def get_ctypes_type(T):
try:
return _ctypes_cache[T]
except KeyError:
- if isinstance(T, Ptr):
- cls = ctypes.POINTER(_get_ctypes_type(T.TO))
- elif isinstance(T, Struct):
- cls = _build_ctypes_struct(T)
- elif isinstance(T, Array):
- cls = _build_ctypes_array(T)
+ if isinstance(T, lltype.Ptr):
+ cls = ctypes.POINTER(get_ctypes_type(T.TO))
+ elif isinstance(T, lltype.Struct):
+ cls = build_ctypes_struct(T)
+ elif isinstance(T, lltype.Array):
+ cls = build_ctypes_array(T)
else:
raise NotImplementedError(T)
_ctypes_cache[T] = cls
return cls
-def _expose(val):
- if isinstance(type(val), _Ctypes_PointerType):
- val = val.contents
- T = typeOf(val)
- if isinstance(T, ContainerType):
- val = _ptr(ctypes.pointer(val))
+def ctypes2lltype(val, RESTYPE):
+ if isinstance(RESTYPE, lltype.Struct):
+ return _ctypes_struct(RESTYPE, val)
+ if isinstance(RESTYPE, lltype.Array):
+ return _ctypes_array(RESTYPE, val)
+ if isinstance(RESTYPE, lltype.Ptr):
+ if isinstance(RESTYPE.TO, lltype.Array):
+ ArrayType = build_ctypes_array(RESTYPE.TO,
+ max_n=val.contents.length)
+ val = ctypes.cast(val, ctypes.POINTER(ArrayType))
+ obj = ctypes2lltype(val.contents, RESTYPE.TO)
+ return lltype._ptr(RESTYPE, obj, solid=True)
return val
-def _lltype2ctypes(val):
- T = typeOf(val)
- if isinstance(T, Ptr):
- return val._storageptr
+def lltype2ctypes(val):
+ T = lltype.typeOf(val)
+ if isinstance(T, lltype.Ptr):
+ return val._obj._convert_to_ctypes_pointer()
return val
-class _ptr(object):
- __slots__ = ['_storageptr', '_TYPE']
- def __init__(self, storageptr):
- assert isinstance(type(storageptr), _Ctypes_PointerType)
- _ptr._storageptr.__set__(self, storageptr)
- _ptr._TYPE.__set__(self, Ptr(type(storageptr)._type_._TYPE))
+class _ctypes_parentable(lltype._parentable):
- def __getattr__(self, field_name):
- if isinstance(self._TYPE.TO, Struct):
- if field_name in self._TYPE.TO._flds:
- return _expose(getattr(self._storageptr.contents, field_name))
- raise AttributeError("%r instance has no field %r" % (self._TYPE.TO,
- field_name))
+ __slots__ = ('_ctypes_storage',)
+
+ def __init__(self, TYPE, ctypes_storage):
+ lltype._parentable.__init__(self, TYPE)
+ self._ctypes_storage = ctypes_storage
+
+ def _free(self):
+ # XXX REALLY SLOW!
+ myaddress = ctypes.addressof(self._ctypes_storage)
+ for i, obj in enumerate(_allocated):
+ if ctypes.addressof(obj) == myaddress:
+ # found it
+ del _allocated[i]
+ lltype._parentable._free(self)
+ break
+ else:
+ raise RuntimeError("lltype.free() on a pointer that was not "
+ "obtained by lltype.malloc()")
+
+
+class _ctypes_struct(_ctypes_parentable):
+ _kind = "structure"
+ __slots__ = ()
+
+ def __repr__(self):
+ return '<ctypes struct %s at 0x%x>' % (
+ self._TYPE._name,
+ uaddressof(self._ctypes_storage))
def __setattr__(self, field_name, value):
- if isinstance(self._TYPE.TO, Struct):
- if field_name in self._TYPE.TO._flds:
- setattr(self._storageptr.contents, field_name,
- _lltype2ctypes(value))
- return
- raise AttributeError("%r instance has no field %r" % (self._TYPE.TO,
- field_name))
-
- def __nonzero__(self):
- return bool(self._storageptr)
-
- def __len__(self):
- T = self._TYPE.TO
- if isinstance(T, Array):# ,FixedSizeArray)):
- #if self._T._hints.get('nolength', False):
- # raise TypeError("%r instance has no length attribute" %
- # (self._T,))
- return self._storageptr.contents.length
- raise TypeError("%r instance is not an array" % (T,))
-
- def __getitem__(self, i):
- T = self._TYPE.TO
- if isinstance(T, Array):
- start, stop = 0, self._storageptr.contents.length
- if not (start <= i < stop):
- if isinstance(i, slice):
- raise TypeError("array slicing not supported")
- raise IndexError("array index out of bounds")
- return _expose(self._storageptr.contents.items[i])
- raise TypeError("%r instance is not an array" % (T,))
-
- def _cast_to(self, PTRTYPE):
- CURTYPE = self._TYPE
- down_or_up = castable(PTRTYPE, CURTYPE)
- if down_or_up == 0:
- return self
- if not self: # null pointer cast
- return PTRTYPE._defl()
- WAAA
- if isinstance(self._obj, int):
- return _ptr(PTRTYPE, self._obj, solid=True)
- if down_or_up > 0:
- p = self
- while down_or_up:
- p = getattr(p, typeOf(p).TO._names[0])
- down_or_up -= 1
- return _ptr(PTRTYPE, p._obj, solid=self._solid)
- u = -down_or_up
- struc = self._obj
- while u:
- parent = struc._parentstructure()
- if parent is None:
- raise RuntimeError("widening to trash: %r" % self)
- PARENTTYPE = struc._parent_type
- if getattr(parent, PARENTTYPE._names[0]) is not struc:
- raise InvalidCast(CURTYPE, PTRTYPE) # xxx different exception perhaps?
- struc = parent
- u -= 1
- if PARENTTYPE != PTRTYPE.TO:
- raise RuntimeError("widening %r inside %r instead of %r" % (CURTYPE, PARENTTYPE, PTRTYPE.TO))
- return _ptr(PTRTYPE, struc, solid=self._solid)
+ if field_name.startswith('_'):
+ lltype._parentable.__setattr__(self, field_name, value)
+ else:
+ setattr(self._ctypes_storage, field_name, lltype2ctypes(value))
+
+ def _getattr(self, field_name, uninitialized_ok=False):
+ return getattr(self, field_name)
+
+ def __getattr__(self, field_name):
+ if field_name.startswith('_'):
+ return lltype._parentable.__getattr__(self, field_name)
+ else:
+ return ctypes2lltype(getattr(self._ctypes_storage, field_name),
+ getattr(self._TYPE, field_name))
+
+ def _convert_to_ctypes_pointer(self):
+ return ctypes.pointer(self._ctypes_storage)
+
+class _ctypes_array(_ctypes_parentable):
+ _kind = "array"
+ __slots__ = ()
+
+ def __init__(self, TYPE, ctypes_storage):
+ _ctypes_parentable.__init__(self, TYPE, ctypes_storage)
+ assert ctypes_storage.length == len(ctypes_storage.items)
+
+ def __repr__(self):
+ return '<ctypes array at 0x%x>' % (
+ uaddressof(self._ctypes_storage),)
+
+ def getlength(self):
+ length = self._ctypes_storage.length
+ assert length == len(self._ctypes_storage.items)
+ return length
+
+ def getbounds(self):
+ return 0, self.getlength()
+
+ def getitem(self, index):
+ return ctypes2lltype(self._ctypes_storage.items[index],
+ self._TYPE.OF)
+
+ def _convert_to_ctypes_pointer(self):
+ PtrType = ctypes.POINTER(get_ctypes_type(self._TYPE))
+ return ctypes.cast(ctypes.pointer(self._ctypes_storage), PtrType)
# ____________________________________________________________
-def malloc(T, n=None, immortal=False):
- if T._gckind != 'gc' and not immortal:# and flavor.startswith('gc'):
- raise TypeError, "gc flavor malloc of a non-GC non-immortal structure"
- if isinstance(T, (Struct, Array)):
- cls = _get_ctypes_type(T)
- return _ptr(cls.malloc(n))
- else:
- raise TypeError, "malloc for Structs and Arrays only"
-
-def nullptr(T):
- cls = _get_ctypes_type(T)
- return _ptr(ctypes.POINTER(cls)())
+def malloc(T, n=None, flavor='gc', immortal=False):
+ # XXX for now, let's only worry about raw malloc
+ assert flavor == 'raw'
+ assert T._gckind == 'raw'
+ assert isinstance(T, (lltype.Struct, lltype.Array))
+ cls = get_ctypes_type(T)
+ container = cls.malloc(n)
+ return lltype._ptr(lltype.Ptr(T), container, solid=True)
+
+def getobjcount():
+ return len(_allocated)
Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/lltype.py (original)
+++ pypy/dist/pypy/rpython/lltypesystem/lltype.py Fri Jul 13 15:27:33 2007
@@ -1199,6 +1199,7 @@
self._dead = False
def _free(self):
+ self._check() # no double-frees
self._dead = True
def _setparentstructure(self, parent, parentindex):
@@ -1664,7 +1665,7 @@
T = typeOf(p)
if not isinstance(T, Ptr) or p._togckind() != 'raw':
raise TypeError, "free(): only for pointers to non-gc containers"
- p._obj._free()
+ p._obj0._free()
def functionptr(TYPE, name, **attrs):
if not isinstance(TYPE, FuncType):
Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_compactlltype.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/test/test_compactlltype.py (original)
+++ pypy/dist/pypy/rpython/lltypesystem/test/test_compactlltype.py Fri Jul 13 15:27:33 2007
@@ -1,64 +1,69 @@
-import py
-from pypy.rpython.lltypesystem.compactlltype import *
+from pypy.rpython.lltypesystem.lltype import *
+from pypy.rpython.lltypesystem.compactlltype import malloc, getobjcount
-def isweak(p, T):
- return True# p._weak and typeOf(p).TO == T
+py.test.skip("in-progress")
-def test_nullptr():
- S = Struct('s')
- p0 = nullptr(S)
- assert not p0
- assert typeOf(p0) == Ptr(S)
+def isctypes(p):
+ return hasattr(p._obj, '_ctypes_storage')
def test_basics():
- S0 = GcStruct("s0", ('a', Signed), ('b', Signed))
+ objcount = getobjcount()
+ S0 = Struct("s0", ('a', Signed), ('b', Signed))
assert S0.a == Signed
assert S0.b == Signed
- s0 = malloc(S0)
+ s0 = malloc(S0, flavor='raw')
print s0
+ assert isctypes(s0)
assert typeOf(s0) == Ptr(S0)
- #py.test.raises(UninitializedMemoryAccess, "s0.a") XXX!
+ #py.test.raises(UninitializedMemoryAccess, "s0.a")
s0.a = 1
s0.b = s0.a
assert s0.a == 1
assert s0.b == 1
assert typeOf(s0.a) == Signed
+ free(s0, flavor='raw')
+ py.test.raises(RuntimeError, "s0.a") # accessing freed struct s0
+ py.test.raises(RuntimeError, "free(s0, flavor='raw')") # double free
# simple array
- Ar = GcArray(('v', Signed))
- x = malloc(Ar,0)
+ Ar = Array(('v', Signed))
+ x = malloc(Ar, 0, flavor='raw')
print x
+ assert isctypes(x)
assert len(x) == 0
- x = malloc(Ar,3)
+ free(x, flavor='raw')
+ x = malloc(Ar, 3, flavor='raw')
print x
+ assert isctypes(x)
assert typeOf(x) == Ptr(Ar)
assert len(x) == 3
- assert isweak(x[0], Ar.OF)
assert typeOf(x[0]) == Ptr(Ar.OF)
x[0].v = 1
x[1].v = 2
x[2].v = 3
assert typeOf(x[0].v) == Signed
assert [x[z].v for z in range(3)] == [1, 2, 3]
+ free(x, flavor='raw')
#
def define_list(T):
- List_typ = GcStruct("list",
- ("items", Ptr(GcArray(('item',T)))))
+ List_typ = Struct("list",
+ ("items", Ptr(Array(('item',T)))))
def newlist():
- l = malloc(List_typ)
- items = malloc(List_typ.items.TO, 0)
+ l = malloc(List_typ, flavor='raw')
+ items = malloc(List_typ.items.TO, 0, flavor='raw')
l.items = items
return l
def append(l, newitem):
length = len(l.items)
print 'append! length', length, 'newitem', newitem
- newitems = malloc(List_typ.items.TO, length+1)
+ newitems = malloc(List_typ.items.TO, length+1, flavor='raw')
i = 0
while i<length:
newitems[i].item = l.items[i].item
i += 1
newitems[length].item = newitem
print len(newitems)
+ free(l.items, flavor='raw')
l.items = newitems
del newitems
print len(l.items)
@@ -66,9 +71,13 @@
def item(l, i):
return l.items[i].item
- return List_typ, newlist, append, item
+ def freelist(l):
+ free(l.items, flavor='raw')
+ free(l, flavor='raw')
- List_typ, inewlist, iappend, iitem = define_list(Signed)
+ return List_typ, newlist, append, item, freelist
+
+ List_typ, inewlist, iappend, iitem, ifreelist = define_list(Signed)
l = inewlist()
assert typeOf(l) == Ptr(List_typ)
@@ -77,14 +86,15 @@
assert len(l.items) == 2
assert iitem(l, 0) == 2
assert iitem(l, 1) == 3
+ ifreelist(l)
- IWrap = GcStruct("iwrap", ('v', Signed))
- List_typ, iwnewlist, iwappend, iwitem = define_list(Ptr(IWrap))
+ IWrap = Struct("iwrap", ('v', Signed))
+ List_typ, iwnewlist, iwappend, iwitem, iwfreelist = define_list(Ptr(IWrap))
l = iwnewlist()
assert typeOf(l) == Ptr(List_typ)
- iw2 = malloc(IWrap)
- iw3 = malloc(IWrap)
+ iw2 = malloc(IWrap, flavor='raw')
+ iw3 = malloc(IWrap, flavor='raw')
iw2.v = 2
iw3.v = 3
assert iw3.v == 3
@@ -93,13 +103,21 @@
assert len(l.items) == 2
assert iwitem(l, 0).v == 2
assert iwitem(l, 1).v == 3
+ iwfreelist(l)
+ free(iw2, flavor='raw')
+ free(iw3, flavor='raw')
+
+ assert objcount == getobjcount() # test for leak
# not allowed
S = Struct("s", ('v', Signed))
- List_typ, iwnewlistzzz, iwappendzzz, iwitemzzz = define_list(S) # works but
+ List_typ, iwnewlistzzz, iwappendzzz, iwitemzzz, iwfreelist = define_list(S)
+ # ^^^ works but
l = iwnewlistzzz()
- S1 = GcStruct("strange", ('s', S))
- py.test.raises(TypeError, "iwappendzzz(l, malloc(S1).s)")
+ s1 = malloc(S, flavor='raw')
+ py.test.raises(TypeError, "iwappendzzz(l, s1)") # a leak - too bad for now
+ free(s1, flavor='raw')
+ iwfreelist(l)
def test_varsizestruct():
S1 = GcStruct("s1", ('a', Signed), ('rest', Array(('v', Signed))))
More information about the Pypy-commit
mailing list