[pypy-svn] r30852 - in pypy/dist/pypy: doc rpython rpython/rctypes rpython/rctypes/test
arigo at codespeak.net
arigo at codespeak.net
Tue Aug 1 17:34:20 CEST 2006
Author: arigo
Date: Tue Aug 1 17:34:17 2006
New Revision: 30852
Added:
pypy/dist/pypy/rpython/rctypes/atype.py (contents, props changed)
pypy/dist/pypy/rpython/rctypes/rtype.py (contents, props changed)
Modified:
pypy/dist/pypy/doc/rctypes.txt
pypy/dist/pypy/rpython/extregistry.py
pypy/dist/pypy/rpython/rctypes/aarray.py
pypy/dist/pypy/rpython/rctypes/astringbuf.py
pypy/dist/pypy/rpython/rctypes/implementation.py
pypy/dist/pypy/rpython/rctypes/rarray.py
pypy/dist/pypy/rpython/rctypes/rmodel.py
pypy/dist/pypy/rpython/rctypes/test/test_rarray.py
Log:
Support for 'ctype*int' at run-time, to build arrays of a length which is not
a constant during annotation.
Modified: pypy/dist/pypy/doc/rctypes.txt
==============================================================================
--- pypy/dist/pypy/doc/rctypes.txt (original)
+++ pypy/dist/pypy/doc/rctypes.txt Tue Aug 1 17:34:17 2006
@@ -68,10 +68,11 @@
rule that types should not be manipulated at run-time. You can only
call it with a constant type, as in ``POINTER(c_int)``.
-The create_string_buffer() function allows you to build variable-size
-arrays of chars, but there is no way to build other variable-sized
-arrays: an expression like ``c_int * n`` can only appear at
-bootstrapping-time. (This restriction should be lifted at some point.)
+*New:* an expression like ``c_int * n`` can appear at run-time. It can
+be used to create variable-sized array instances, i.e. arrays whose
+length is not a static constant, as in ``my_array = (c_int * n)()``.
+Similarly, the create_string_buffer() function returns a variable-size
+array of chars.
NOTE: in order to translate an RPython program using ctypes, the module
``pypy.rpython.rctypes.implementation`` must be imported! This is
Modified: pypy/dist/pypy/rpython/extregistry.py
==============================================================================
--- pypy/dist/pypy/rpython/extregistry.py (original)
+++ pypy/dist/pypy/rpython/extregistry.py Tue Aug 1 17:34:17 2006
@@ -19,16 +19,28 @@
del selfcls._metatype_
def _register_value(selfcls, key):
- assert key not in EXT_REGISTRY_BY_VALUE
- EXT_REGISTRY_BY_VALUE[key] = selfcls
+ if isinstance(key, (tuple, list)):
+ for k in key:
+ selfcls._register_value(k)
+ else:
+ assert key not in EXT_REGISTRY_BY_VALUE
+ EXT_REGISTRY_BY_VALUE[key] = selfcls
def _register_type(selfcls, key):
- assert key not in EXT_REGISTRY_BY_TYPE
- EXT_REGISTRY_BY_TYPE[key] = selfcls
+ if isinstance(key, (tuple, list)):
+ for k in key:
+ selfcls._register_type(k)
+ else:
+ assert key not in EXT_REGISTRY_BY_TYPE
+ EXT_REGISTRY_BY_TYPE[key] = selfcls
def _register_metatype(selfcls, key):
- assert key not in EXT_REGISTRY_BY_METATYPE
- EXT_REGISTRY_BY_METATYPE[key] = selfcls
+ if isinstance(key, (tuple, list)):
+ for k in key:
+ selfcls._register_metatype(k)
+ else:
+ assert key not in EXT_REGISTRY_BY_METATYPE
+ EXT_REGISTRY_BY_METATYPE[key] = selfcls
class ExtRegistryEntry(object):
Modified: pypy/dist/pypy/rpython/rctypes/aarray.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/aarray.py (original)
+++ pypy/dist/pypy/rpython/rctypes/aarray.py Tue Aug 1 17:34:17 2006
@@ -5,6 +5,28 @@
ArrayType = type(ARRAY(c_int, 10))
+class VarSizedArrayType(object):
+ """Placeholder for ctypes array types whose size is not an
+ annotation-time constant.
+ """
+ def __init__(self, itemtype):
+ self._type_ = itemtype
+ #self._length_ = unspecified
+ self.__name__ = itemtype.__name__ + '_Array'
+
+ def get_instance_annotation(self, *args_s):
+ return SomeCTypesObject(self, ownsmemory=True)
+
+ def __eq__(self, other):
+ return (self.__class__ is other.__class__ and
+ self._type_ == other._type_)
+
+ def __ne__(self, other):
+ return not (self == other)
+
+ def __hash__(self):
+ return hash(self._type_)
+
class CallEntry(CTypesCallEntry):
"Annotation and rtyping of calls to array types."
@@ -19,16 +41,14 @@
if hop.nb_args > r_array.length:
raise TyperError("too many arguments for an array of length %d" % (
r_array.length,))
- for i in range(hop.nb_args):
- v_item = hop.inputarg(r_array.r_item, arg=i)
- c_index = inputconst(lltype.Signed, i)
- r_array.setitem(hop.llops, v_result, c_index, v_item)
+ items_v = hop.inputargs(*[r_array.r_item] * hop.nb_args)
+ r_array.initializeitems(hop.llops, v_result, items_v)
return v_result
class ObjEntry(CTypesObjEntry):
"Annotation and rtyping of array instances."
- _metatype_ = ArrayType
+ _metatype_ = ArrayType, VarSizedArrayType
def get_field_annotation(self, s_array, fieldname):
assert fieldname == 'value'
Modified: pypy/dist/pypy/rpython/rctypes/astringbuf.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/astringbuf.py (original)
+++ pypy/dist/pypy/rpython/rctypes/astringbuf.py Tue Aug 1 17:34:17 2006
@@ -4,6 +4,12 @@
from ctypes import create_string_buffer, c_char, sizeof
+######################################################################
+# NOTE: astringbuf and rstringbuf should be removed and replaced #
+# with a regular var-sized array of char, now that we #
+# support var-sized arrays. #
+######################################################################
+
class StringBufferType(object):
"""Placeholder for the result type of create_string_buffer(),
@@ -68,7 +74,7 @@
return r_arg.rtype_len(hop)
else:
if not s_arg.is_constant():
- raise TyperError("ctypes.sizeof(non_ctypes_object)")
+ raise TyperError("ctypes.sizeof(non_constant_type)")
# XXX check that s_arg.const is really a ctypes type
ctype = s_arg.const
s_arg = SomeCTypesObject(ctype, ownsmemory=True)
Added: pypy/dist/pypy/rpython/rctypes/atype.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/rctypes/atype.py Tue Aug 1 17:34:17 2006
@@ -0,0 +1,47 @@
+"""
+Var-sized arrays, i.e. arrays whose size is not known at annotation-time.
+"""
+
+from pypy.annotation.model import SomeCTypesObject
+from pypy.annotation.model import SomeBuiltin, SomeInteger, SomeString
+from pypy.annotation.pairtype import pair, pairtype
+from pypy.rpython.extregistry import ExtRegistryEntry
+
+
+class SomeCTypesType(SomeBuiltin):
+ """A ctypes type behaves like a built-in function, because it can only
+ be called -- with the exception of 'ctype*int' to build array types.
+ """
+ def rtyper_makerepr(self, rtyper):
+ from pypy.rpython.rctypes.rtype import TypeRepr
+ return TypeRepr(self)
+
+ def rtyper_makekey(self):
+ return SomeCTypesType, getattr(self, 'const', None)
+
+
+class SomeVarSizedCTypesType(SomeBuiltin):
+ """A ctypes built at runtime as 'ctype*int'.
+ Note that at the moment 'ctype*int*int' is not supported.
+ """
+ def __init__(self, ctype_item):
+ from pypy.rpython.rctypes.aarray import VarSizedArrayType
+ ctype_array = VarSizedArrayType(ctype_item)
+ SomeBuiltin.__init__(self, ctype_array.get_instance_annotation)
+ self.ctype_array = ctype_array
+
+ def rtyper_makerepr(self, rtyper):
+ assert self.s_self is None
+ from pypy.rpython.rctypes.rtype import VarSizedTypeRepr
+ return VarSizedTypeRepr()
+
+ def rtyper_makekey(self):
+ return SomeVarSizedCTypesType, self.ctype_array
+
+
+class __extend__(pairtype(SomeCTypesType, SomeInteger)):
+ def mul((s_ctt, s_int)):
+ entry = s_ctt.analyser.im_self # fish fish
+ ctype_item = entry.instance
+ return SomeVarSizedCTypesType(ctype_item)
+ mul.can_only_throw = []
Modified: pypy/dist/pypy/rpython/rctypes/implementation.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/implementation.py (original)
+++ pypy/dist/pypy/rpython/rctypes/implementation.py Tue Aug 1 17:34:17 2006
@@ -92,7 +92,14 @@
## annotation, e.g. callback functions."""
class CTypesCallEntry(CTypesEntry):
- "Annotation and rtyping of calls to ctypes types."
+ "Annotation and rtyping of ctypes types (mostly their calls)."
+
+ def compute_annotation(self):
+ ctype = self.instance
+ assert ctype is not None
+ analyser = self.compute_result_annotation
+ methodname = ctype.__name__
+ return SomeCTypesType(analyser, methodname=methodname)
def compute_result_annotation(self, *args_s, **kwds_s):
ctype = self.instance # the ctype is the called object
@@ -108,6 +115,7 @@
# Importing for side effect of registering types with extregistry
+from pypy.rpython.rctypes.atype import SomeCTypesType
import pypy.rpython.rctypes.aprimitive
import pypy.rpython.rctypes.apointer
import pypy.rpython.rctypes.aarray
Modified: pypy/dist/pypy/rpython/rctypes/rarray.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/rarray.py (original)
+++ pypy/dist/pypy/rpython/rctypes/rarray.py Tue Aug 1 17:34:17 2006
@@ -7,6 +7,7 @@
from pypy.rpython.rctypes.rmodel import genreccopy_arrayitem, reccopy, C_ZERO
from pypy.rpython.rctypes.rprimitive import PrimitiveRepr
from pypy.rpython.rctypes.rpointer import PointerRepr
+from pypy.rpython.rctypes.aarray import VarSizedArrayType
from pypy.annotation.model import SomeCTypesObject
from pypy.objspace.flow.model import Constant
@@ -18,15 +19,22 @@
array_ctype = s_array.knowntype
item_ctype = array_ctype._type_
- self.length = array_ctype._length_
+ if isinstance(array_ctype, VarSizedArrayType):
+ self.length = None
+ else:
+ self.length = array_ctype._length_
# Find the repr and low-level type of items from their ctype
self.r_item = rtyper.getrepr(SomeCTypesObject(item_ctype,
ownsmemory=False))
# Here, self.c_data_type == self.ll_type
- c_data_type = lltype.FixedSizeArray(self.r_item.ll_type,
- self.length)
+ if self.length is not None:
+ c_data_type = lltype.FixedSizeArray(self.r_item.ll_type,
+ self.length)
+ else:
+ c_data_type = lltype.Array(self.r_item.ll_type,
+ hints={'nolength': True})
super(ArrayRepr, self).__init__(rtyper, s_array, c_data_type)
@@ -35,8 +43,11 @@
item_keepalive_type = self.r_item.get_content_keepalive_type()
if not item_keepalive_type:
return None
- else:
+ elif self.length is not None:
return lltype.FixedSizeArray(item_keepalive_type, self.length)
+ else:
+ raise NotImplementedError("XXX not supported yet: "
+ "var-sized arrays of pointers")
def initialize_const(self, p, value):
for i in range(self.length):
@@ -100,6 +111,11 @@
genreccopy_arrayitem(llops, v_newkeepalive,
v_keepalive_array, v_index)
+ def initializeitems(self, llops, v_array, items_v):
+ for i, v_item in enumerate(items_v):
+ c_index = inputconst(lltype.Signed, i)
+ self.setitem(llops, v_array, c_index, v_item)
+
class __extend__(pairtype(ArrayRepr, IntegerRepr)):
def rtype_getitem((r_array, r_int), hop):
Modified: pypy/dist/pypy/rpython/rctypes/rmodel.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/rmodel.py (original)
+++ pypy/dist/pypy/rpython/rctypes/rmodel.py Tue Aug 1 17:34:17 2006
@@ -115,9 +115,20 @@
self.r_memoryowner.lowleveltype)
def allocate_instance(self, llops):
- c1 = inputconst(lltype.Void, self.lowleveltype.TO)
+ TYPE = self.lowleveltype.TO
+ if TYPE._is_varsize():
+ raise TyperError("allocating array with unknown length")
+ c1 = inputconst(lltype.Void, TYPE)
return llops.genop("malloc", [c1], resulttype=self.lowleveltype)
+ def allocate_instance_varsize(self, llops, v_length):
+ TYPE = self.lowleveltype.TO
+ if not TYPE._is_varsize():
+ raise TyperError("allocating non-array with a specified length")
+ c1 = inputconst(lltype.Void, TYPE)
+ return llops.genop("malloc_varsize", [c1, v_length],
+ resulttype=self.lowleveltype)
+
def allocate_instance_ref(self, llops, v_c_data, v_c_data_owner=None):
"""Only if self.ownsmemory is false. This allocates a new instance
and initialize its c_data pointer."""
Added: pypy/dist/pypy/rpython/rctypes/rtype.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/rctypes/rtype.py Tue Aug 1 17:34:17 2006
@@ -0,0 +1,42 @@
+from pypy.objspace.flow.model import Constant
+from pypy.annotation.pairtype import pairtype
+from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.rmodel import Repr, IntegerRepr, inputconst
+from pypy.rpython.error import TyperError
+from pypy.rpython.rbuiltin import BuiltinFunctionRepr
+
+
+class TypeRepr(BuiltinFunctionRepr):
+
+ def __init__(self, s_ctype):
+ assert s_ctype.s_self is None
+ if not s_ctype.is_constant():
+ raise TyperError("non-constant ctypes type object")
+ ctype = s_ctype.const
+ BuiltinFunctionRepr.__init__(self, ctype)
+
+
+class __extend__(pairtype(TypeRepr, IntegerRepr)):
+
+ def rtype_mul((r_ctype, r_int), hop):
+ v_ctype, v_repeatcount = hop.inputargs(r_ctype, lltype.Signed)
+ assert isinstance(v_ctype, Constant)
+ return v_repeatcount
+
+
+class VarSizedTypeRepr(Repr):
+ """Repr of the var-sized array type built at runtime as 'ctype*int'.
+ The ctype must be a real constant ctype, so the var-sized type can
+ be represented as just the runtime length.
+ """
+ lowleveltype = lltype.Signed
+
+ def rtype_simple_call(self, hop):
+ r_array = hop.r_result
+ args_r = [self] + [r_array.r_item] * (hop.nb_args-1)
+ args_v = hop.inputargs(*args_r)
+ v_repeatcount = args_v[0]
+ hop.exception_cannot_occur()
+ v_result = r_array.allocate_instance_varsize(hop.llops, v_repeatcount)
+ r_array.initializeitems(hop.llops, v_result, args_v[1:])
+ return v_result
Modified: pypy/dist/pypy/rpython/rctypes/test/test_rarray.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/test/test_rarray.py (original)
+++ pypy/dist/pypy/rpython/rctypes/test/test_rarray.py Tue Aug 1 17:34:17 2006
@@ -163,6 +163,18 @@
a.translator.view()
assert s == annmodel.SomeString()
+ def test_annotate_varsize_array(self):
+ def func(n):
+ a = (c_int * n)()
+ a[n//2] = 12
+ return a[n//3]
+ t = TranslationContext()
+ a = t.buildannotator()
+ s = a.build_types(func, [int])
+ if conftest.option.view:
+ a.translator.view()
+ assert s.knowntype == int
+
class Test_specialization:
def test_specialize_array(self):
def create_array():
@@ -282,6 +294,27 @@
assert res.c_data[3] == 0
assert res.c_data[4] == 0
+ def test_specialize_varsize_array_constructor(self):
+ def func(n):
+ return (c_int * n)()
+ res = interpret(func, [12])
+ py.test.raises(TypeError, "len(res.c_data)") # nolength hint
+ assert res.c_data[0] == 0
+ assert res.c_data[11] == 0
+ py.test.raises(IndexError, "res.c_data[12]")
+
+ def test_specialize_varsize_array(self):
+ def func(n):
+ a = (c_int * n)(5)
+ for i in range(1, n):
+ a[i] = i
+ res = 0
+ for i in range(n):
+ res += a[i]
+ return res
+ res = interpret(func, [10])
+ assert res == 50
+
class Test_compilation:
def setup_class(self):
if not test_c_compile:
More information about the Pypy-commit
mailing list