[pypy-svn] r62071 - in pypy/branch/pyjitpl5/pypy/rpython: . lltypesystem lltypesystem/test

fijal at codespeak.net fijal at codespeak.net
Sat Feb 21 09:30:25 CET 2009


Author: fijal
Date: Sat Feb 21 09:30:23 2009
New Revision: 62071

Modified:
   pypy/branch/pyjitpl5/pypy/rpython/llinterp.py
   pypy/branch/pyjitpl5/pypy/rpython/lltypesystem/ll2ctypes.py
   pypy/branch/pyjitpl5/pypy/rpython/lltypesystem/lltype.py
   pypy/branch/pyjitpl5/pypy/rpython/lltypesystem/rclass.py
   pypy/branch/pyjitpl5/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
   pypy/branch/pyjitpl5/pypy/rpython/rtyper.py
Log:
Port manually changes from the oo-jit branch. One test of ll2ctypes still
fails, no clue why :(


Modified: pypy/branch/pyjitpl5/pypy/rpython/llinterp.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/rpython/llinterp.py	(original)
+++ pypy/branch/pyjitpl5/pypy/rpython/llinterp.py	Sat Feb 21 09:30:23 2009
@@ -42,6 +42,8 @@
 class LLInterpreter(object):
     """ low level interpreter working with concrete values. """
 
+    current_interpreter = None
+
     def __init__(self, typer, tracing=True, exc_data_ptr=None,
                  malloc_check=True):
         self.bindings = {}
@@ -66,6 +68,8 @@
         retval = None
         self.traceback_frames = []
         old_frame_stack = self.frame_stack[:]
+        prev_interpreter = LLInterpreter.current_interpreter
+        LLInterpreter.current_interpreter = self
         try:
             try:
                 retval = llframe.eval()
@@ -88,6 +92,7 @@
                     self.tracer.dump(line + '\n')
                 raise
         finally:
+            LLInterpreter.current_interpreter = prev_interpreter
             assert old_frame_stack == self.frame_stack
             if self.tracer:
                 if retval is not None:

Modified: pypy/branch/pyjitpl5/pypy/rpython/lltypesystem/ll2ctypes.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/rpython/lltypesystem/ll2ctypes.py	(original)
+++ pypy/branch/pyjitpl5/pypy/rpython/lltypesystem/ll2ctypes.py	Sat Feb 21 09:30:23 2009
@@ -7,13 +7,18 @@
     ctypes = None
 
 import os
+from pypy import conftest
 from pypy.rpython.lltypesystem import lltype, llmemory
 from pypy.rpython.extfunc import ExtRegistryEntry
-from pypy.rlib.objectmodel import Symbolic
+from pypy.rlib.objectmodel import Symbolic, ComputedIntSymbolic
 from pypy.tool.uid import fixid
 from pypy.tool.tls import tlsobject
 from pypy.rlib.rarithmetic import r_uint, r_singlefloat
 from pypy.annotation import model as annmodel
+from pypy.rpython.llinterp import LLInterpreter
+from pypy.rpython.lltypesystem.rclass import OBJECT
+from pypy.rpython.annlowlevel import base_ptr_lltype
+from pypy.rpython import raddress
 
 def uaddressof(obj):
     return fixid(ctypes.addressof(obj))
@@ -41,6 +46,9 @@
         rffi.LONGLONG:   ctypes.c_longlong,
         rffi.ULONGLONG:  ctypes.c_ulonglong,
         rffi.SIZE_T:     ctypes.c_size_t,
+        lltype.Bool:     ctypes.c_long, # XXX
+        llmemory.Address:  ctypes.c_void_p,
+        llmemory.GCREF:    ctypes.c_void_p,
         })
 
     # for unicode strings, do not use ctypes.c_wchar because ctypes
@@ -173,7 +181,8 @@
 def build_new_ctypes_type(T, delayed_builders):
     if isinstance(T, lltype.Ptr):
         if isinstance(T.TO, lltype.FuncType):
-            argtypes = [get_ctypes_type(ARG) for ARG in T.TO.ARGS]
+            argtypes = [get_ctypes_type(ARG) for ARG in T.TO.ARGS
+                        if ARG is not lltype.Void]
             if T.TO.RESULT is lltype.Void:
                 restype = None
             else:
@@ -181,11 +190,15 @@
             return ctypes.CFUNCTYPE(restype, *argtypes)
         else:
             return ctypes.POINTER(get_ctypes_type(T.TO, delayed_builders))
+    elif T is lltype.Void:
+        return ctypes.c_long # opaque pointer
     elif isinstance(T, lltype.Struct):
         return build_ctypes_struct(T, delayed_builders)
     elif isinstance(T, lltype.Array):
         return build_ctypes_array(T, delayed_builders)
     elif isinstance(T, lltype.OpaqueType):
+        if T is lltype.RuntimeTypeInfo:
+            return ctypes.c_char * 2
         if T.hints.get('external', None) != 'C':
             raise TypeError("%s is not external" % T)
         return ctypes.c_char * T.hints['getsize']()
@@ -199,6 +212,39 @@
     while delayed_builders:
         delayed_builders.pop()()
 
+def remove_regular_struct_content(container):
+    STRUCT = container._TYPE
+    for field_name in STRUCT._names:
+        FIELDTYPE = getattr(STRUCT, field_name)
+        if not isinstance(FIELDTYPE, lltype.ContainerType):
+            delattr(container, field_name)
+
+def convert_array(container, carray=None):
+    ARRAY = container._TYPE
+    if carray is None:
+        # if 'container' is an inlined substructure, convert the whole
+        # bigger structure at once
+        parent, parentindex = lltype.parentlink(container)
+        if parent is not None:
+            convert_struct(parent)
+            return
+        # regular case: allocate a new ctypes array of the proper type
+        cls = get_ctypes_type(ARRAY)
+        carray = cls._malloc(container.getlength())
+    add_storage(container, _array_mixin, carray)
+    if not isinstance(ARRAY.OF, lltype.ContainerType):
+        # fish that we have enough space
+        ctypes_array = ctypes.cast(carray.items,
+                                   ctypes.POINTER(carray.items._type_))
+        for i in range(container.getlength()):
+            item_value = container.items[i]    # fish fish
+            ctypes_array[i] = lltype2ctypes(item_value)
+        remove_regular_array_content(container)
+    else:
+        assert isinstance(ARRAY.OF, lltype.Struct)
+        for i in range(container.getlength()):
+            item_ptr = container.items[i]    # fish fish
+            convert_struct(item_ptr, carray.items[i])
 
 def convert_struct(container, cstruct=None):
     STRUCT = container._TYPE
@@ -211,8 +257,8 @@
             return
         # regular case: allocate a new ctypes Structure of the proper type
         cls = get_ctypes_type(STRUCT)
-        if STRUCT._arrayfld:
-            n = len(getattr(container, STRUCT._arrayfld).items)
+        if STRUCT._arrayfld is not None:
+            n = getattr(container, STRUCT._arrayfld).getlength()
         else:
             n = None
         cstruct = cls._malloc(n)
@@ -222,45 +268,20 @@
         field_value = getattr(container, field_name)
         if not isinstance(FIELDTYPE, lltype.ContainerType):
             # regular field
-            setattr(cstruct, field_name, lltype2ctypes(field_value))
+            if FIELDTYPE != lltype.Void:
+                setattr(cstruct, field_name, lltype2ctypes(field_value))
         else:
             # inlined substructure/subarray
             if isinstance(FIELDTYPE, lltype.Struct):
                 csubstruct = getattr(cstruct, field_name)
                 convert_struct(field_value, csubstruct)
-            else:
+            elif field_name == STRUCT._arrayfld:    # inlined var-sized part
                 csubarray = getattr(cstruct, field_name)
                 convert_array(field_value, csubarray)
-                #raise NotImplementedError('inlined field', FIELDTYPE)
+            else:
+                raise NotImplementedError('inlined field', FIELDTYPE)
     remove_regular_struct_content(container)
 
-def remove_regular_struct_content(container):
-    STRUCT = container._TYPE
-    for field_name in STRUCT._names:
-        FIELDTYPE = getattr(STRUCT, field_name)
-        if not isinstance(FIELDTYPE, lltype.ContainerType):
-            delattr(container, field_name)
-
-def convert_array(container, carray=None):
-    ARRAY = container._TYPE
-    cls = get_ctypes_type(ARRAY)
-    if carray is None:
-        carray = cls._malloc(container.getlength())
-    add_storage(container, _array_mixin, carray)
-    if not isinstance(ARRAY.OF, lltype.ContainerType):
-        # fish that we have enough space
-        ctypes_array = ctypes.cast(carray.items,
-                                   ctypes.POINTER(carray.items._type_))
-        for i in range(container.getlength()):
-            item_value = container.items[i]    # fish fish
-            ctypes_array[i] = lltype2ctypes(item_value)
-        remove_regular_array_content(container)
-    else:
-        assert isinstance(ARRAY.OF, lltype.Struct)
-        for i in range(container.getlength()):
-            item_ptr = container.items[i]    # fish fish
-            convert_struct(item_ptr, carray.items[i])
-
 def remove_regular_array_content(container):
     for i in range(container.getlength()):
         container.items[i] = None
@@ -272,12 +293,18 @@
     remove_regular_struct_content(container)
     for field_name in STRUCT._names:
         FIELDTYPE = getattr(STRUCT, field_name)
-        if isinstance(FIELDTYPE, lltype.Array):
-            convert_array(getattr(container, field_name),
-                          getattr(ctypes_storage, field_name))
-        elif isinstance(FIELDTYPE, lltype.ContainerType):
-            struct_use_ctypes_storage(getattr(container, field_name),
-                                      getattr(ctypes_storage, field_name))
+        if isinstance(FIELDTYPE, lltype.ContainerType):
+            if isinstance(FIELDTYPE, lltype.Struct):
+                struct_use_ctypes_storage(getattr(container, field_name),
+                                          getattr(ctypes_storage, field_name))
+            elif isinstance(FIELDTYPE, lltype.Array):
+                assert FIELDTYPE._hints.get('nolength', False) == False
+                arraycontainer = _array_of_known_length(FIELDTYPE)
+                arraycontainer._storage = getattr(ctypes_storage, field_name)
+                arraycontainer._setparentstructure(container, field_name)
+                object.__setattr__(container, field_name, arraycontainer)
+            else:
+                raise NotImplementedError(FIELDTYPE)
 
 # ____________________________________________________________
 # Ctypes-aware subclasses of the _parentable classes
@@ -343,6 +370,12 @@
     def __ne__(self, other):
         return not (self == other)
 
+    def __hash__(self):
+        if self._storage is not None:
+            return ctypes.addressof(self._storage)
+        else:
+            return object.__hash__(self)
+
     def __repr__(self):
         if self._storage is None:
             return '<freed C object %s>' % (self._TYPE,)
@@ -406,6 +439,15 @@
         
     items = property(getitems)
 
+class _array_of_known_length(_array_of_unknown_length):
+    __slots__ = ()
+
+    def getlength(self):
+        return self._storage.length
+
+    def getbounds(self):
+        return 0, self.getlength()
+
 # ____________________________________________________________
 
 def _find_parent(llobj):
@@ -423,12 +465,41 @@
         ofs = getattr(c_tp, parentindex).offset
         return next_p, next_i + ofs
 
+# ____________________________________________________________
 
 # XXX THIS IS A HACK XXX
 # ctypes does not keep callback arguments alive. So we do. Forever
 # we need to think deeper how to approach this problem
 # additionally, this adds mess to __del__ "semantics"
-_all_callbacks = []
+_all_callbacks = {}
+_all_callbacks_results = []
+_callback2obj = {}
+
+# this is just another hack that passes around references to applevel types
+# disguised as base_ptr_lltype
+class Dummy(object):
+    pass
+
+_opaque_cache = {Dummy():0}
+_opaque_list = [Dummy()]
+
+def new_opaque_object(llobj):
+    try:
+        return _opaque_cache[llobj]
+    except KeyError:
+        assert len(_opaque_cache) == len(_opaque_list)
+        ctypes_type = get_ctypes_type(base_ptr_lltype())
+        val = ctypes.cast(len(_opaque_cache), ctypes_type)
+        _opaque_list.append(llobj)
+        _opaque_cache[llobj] = val
+        return val
+
+def get_rtyper():
+    llinterp = LLInterpreter.current_interpreter
+    if llinterp is not None:
+        return llinterp.typer
+    else:
+        return None
 
 def lltype2ctypes(llobj, normalize=True):
     """Convert the lltype object 'llobj' to its ctypes equivalent.
@@ -439,39 +510,91 @@
         return uninitialized2ctypes(llobj.TYPE)
 
     T = lltype.typeOf(llobj)
+
     if isinstance(T, lltype.Ptr):
         if not llobj:   # NULL pointer
             return get_ctypes_type(T)()
 
-        container = llobj._obj
+        if T is base_ptr_lltype():
+            return new_opaque_object(llobj)
+        if T == llmemory.GCREF:
+            if isinstance(llobj, _llgcref):
+                return ctypes.c_void_p(llobj.intval)
+            container = llobj._obj.container
+            T = lltype.Ptr(lltype.typeOf(container))
+            # otherwise it came from integer and we want a c_void_p with
+            # the same valu
+        else:
+            container = llobj._obj
         if isinstance(T.TO, lltype.FuncType):
-            if not hasattr(container, '_callable'):
-                raise NotImplementedError("ctypes wrapper for ll function "
-                                          "without a _callable")
-            else:
-                ctypes_func_type = get_ctypes_type(T)
-                def callback(*cargs):
-                    assert len(cargs) == len(T.TO.ARGS)
-                    llargs = [ctypes2lltype(ARG, cargs)
-                              for ARG, cargs in zip(T.TO.ARGS, cargs)]
-                    llres = container._callable(*llargs)
-                    assert lltype.typeOf(llres) == T.TO.RESULT
-                    if T.TO.RESULT is lltype.Void:
-                        return None
+            # XXX a temporary workaround for comparison of lltype.FuncType
+            key = llobj._obj.__dict__.copy()
+            key['_TYPE'] = repr(key['_TYPE'])
+            items = key.items()
+            items.sort()
+            key = tuple(items)
+            if key in _all_callbacks:
+                return _all_callbacks[key]
+            v1voidlist = [(i, getattr(container, '_void' + str(i), None))
+                             for i in range(len(T.TO.ARGS))
+                                 if T.TO.ARGS[i] is lltype.Void]
+            def callback(*cargs):
+                cargs = list(cargs)
+                for v1 in v1voidlist:
+                    cargs.insert(v1[0], v1[1])
+                assert len(cargs) == len(T.TO.ARGS)
+                llargs = []
+                for ARG, carg in zip(T.TO.ARGS, cargs):
+                    if ARG is lltype.Void:
+                        llargs.append(carg)
                     else:
-                        return lltype2ctypes(llres)
-                res = ctypes_func_type(callback)
-                _all_callbacks.append(res)
+                        llargs.append(ctypes2lltype(ARG, carg))
+                if hasattr(container, 'graph'):
+                    if LLInterpreter.current_interpreter is None:
+                        raise AssertionError
+                    llinterp = LLInterpreter.current_interpreter
+                    llres = llinterp.eval_graph(container.graph, llargs)
+                else:
+                    llres = container._callable(*llargs)
+                assert lltype.typeOf(llres) == T.TO.RESULT
+                if T.TO.RESULT is lltype.Void:
+                    return None
+                res = lltype2ctypes(llres)
+                if isinstance(T.TO.RESULT, lltype.Ptr):
+                    _all_callbacks_results.append(res)
+                    res = ctypes.cast(res, ctypes.c_void_p).value
+                    if res is None:
+                        return 0
                 return res
 
-        if T.TO._gckind != 'raw' and not T.TO._hints.get('callback', None):
-            raise Exception("can only pass 'raw' data structures to C, not %r"
-                            % (T.TO._gckind,))
+            if conftest.option.usepdb:
+                callback_original = callback
+                def callback(*cargs):
+                    try:
+                        return callback_original(*cargs)
+                    except:
+                        import pdb, sys; pdb.post_mortem(sys.exc_traceback)
+                        raise
+
+            if isinstance(T.TO.RESULT, lltype.Ptr):
+                TMod = lltype.Ptr(lltype.FuncType(T.TO.ARGS,
+                                                  lltype.Signed))
+                ctypes_func_type = get_ctypes_type(TMod)
+                res = ctypes_func_type(callback)
+                ctypes_func_type = get_ctypes_type(T)
+                res = ctypes.cast(res, ctypes_func_type)
+            else:
+                ctypes_func_type = get_ctypes_type(T)
+                res = ctypes_func_type(callback)
+            _callback2obj[ctypes.cast(res, ctypes.c_void_p).value] = container
+            _all_callbacks[key] = res
+            return res
 
         index = 0
         if isinstance(container, lltype._subarray):
             topmost, index = _find_parent(container)
             container = topmost
+
         if container._storage is None:
             raise RuntimeError("attempting to pass a freed structure to C")
         if container._storage is True:
@@ -481,7 +604,10 @@
             elif isinstance(T.TO, lltype.Array):
                 convert_array(container)
             elif isinstance(T.TO, lltype.OpaqueType):
-                cbuf = ctypes.create_string_buffer(T.TO.hints['getsize']())
+                if T.TO != lltype.RuntimeTypeInfo:
+                    cbuf = ctypes.create_string_buffer(T.TO.hints['getsize']())
+                else:
+                    cbuf = ctypes.create_string_buffer("\x00")
                 add_storage(container, _parentable_mixin, cbuf)
             else:
                 raise NotImplementedError(T)
@@ -505,6 +631,8 @@
     if isinstance(llobj, Symbolic):
         if isinstance(llobj, llmemory.ItemOffset):
             llobj = ctypes.sizeof(get_ctypes_type(llobj.TYPE)) * llobj.repeat
+        elif isinstance(llobj, ComputedIntSymbolic):
+            llobj = llobj.compute_fn()
         else:
             raise NotImplementedError(llobj)  # don't know about symbolic value
 
@@ -513,6 +641,7 @@
 
     if T is lltype.SingleFloat:
         return ctypes.c_float(float(llobj))
+
     return llobj
 
 def ctypes2lltype(T, cobj):
@@ -522,11 +651,24 @@
     if isinstance(T, lltype.Ptr):
         if not cobj:   # NULL pointer
             return lltype.nullptr(T.TO)
+        if T is base_ptr_lltype():
+            return _opaque_list[ctypes.cast(cobj, ctypes.c_void_p).value]
         if isinstance(T.TO, lltype.Struct):
             if T.TO._arrayfld is not None:
-                lgt = getattr(cobj.contents, T.TO._arrayfld).length
-                container = lltype._struct(T.TO, lgt)
+                carray = getattr(cobj.contents, T.TO._arrayfld)
+                container = lltype._struct(T.TO, carray.length)
             else:
+                # special treatment of 'OBJECT' subclasses
+                if get_rtyper() and lltype._castdepth(T.TO, OBJECT) > 0:
+                    ctypes_object = get_ctypes_type(lltype.Ptr(OBJECT))
+                    as_obj = ctypes2lltype(lltype.Ptr(OBJECT),
+                                           ctypes.cast(cobj, ctypes_object))
+                    TObj = get_rtyper().get_type_for_typeptr(as_obj.typeptr)
+                    if TObj != T.TO:
+                        ctypes_instance = get_ctypes_type(lltype.Ptr(TObj))
+                        return lltype.cast_pointer(T,
+                            ctypes2lltype(lltype.Ptr(TObj),
+                                          ctypes.cast(cobj, ctypes_instance)))
                 container = lltype._struct(T.TO)
             struct_use_ctypes_storage(container, cobj.contents)
         elif isinstance(T.TO, lltype.Array):
@@ -534,16 +676,30 @@
                 container = _array_of_unknown_length(T.TO)
                 container._storage = cobj.contents
             else:
-                raise NotImplementedError("array with an explicit length")
+                container = _array_of_known_length(T.TO)
+                container._storage = cobj.contents
         elif isinstance(T.TO, lltype.FuncType):
-            _callable = get_ctypes_trampoline(T.TO, cobj)
-            return lltype.functionptr(T.TO, getattr(cobj, '__name__', '?'),
-                                      _callable=_callable)
+            cobjkey = ctypes.cast(cobj, ctypes.c_void_p).value
+            if cobjkey in _callback2obj:
+                container = _callback2obj[cobjkey]
+            else:
+                _callable = get_ctypes_trampoline(T.TO, cobj)
+                return lltype.functionptr(T.TO, getattr(cobj, '__name__', '?'),
+                                          _callable=_callable)
         elif isinstance(T.TO, lltype.OpaqueType):
-            container = lltype._opaque(T.TO)
+            if T == llmemory.GCREF:
+                # XXX obscure hack
+                return _llgcref(cobj)
+            else:
+                container = lltype._opaque(T.TO)
         else:
             raise NotImplementedError(T)
         llobj = lltype._ptr(T, container, solid=True)
+    elif T is llmemory.Address:
+        if cobj is None:
+            llobj = llmemory.NULL
+        else:
+            llobj = _lladdress(cobj)
     elif T is lltype.Char:
         llobj = chr(cobj)
     elif T is lltype.UniChar:
@@ -554,6 +710,8 @@
         if isinstance(cobj, ctypes.c_float):
             cobj = cobj.value
         llobj = r_singlefloat(cobj)
+    elif T is lltype.Void:
+        llobj = cobj
     else:
         from pypy.rpython.lltypesystem import rffi
         try:
@@ -669,7 +827,8 @@
             funcname, place))
 
     # get_ctypes_type() can raise NotImplementedError too
-    cfunc.argtypes = [get_ctypes_type(T) for T in FUNCTYPE.ARGS]
+    cfunc.argtypes = [get_ctypes_type(T) for T in FUNCTYPE.ARGS
+                      if not T is lltype.Void]
     if FUNCTYPE.RESULT is lltype.Void:
         cfunc.restype = None
     else:
@@ -699,10 +858,18 @@
     for i in range(len(FUNCTYPE.ARGS)):
         if isinstance(FUNCTYPE.ARGS[i], lltype.ContainerType):
             container_arguments.append(i)
+    void_arguments = []
+    for i in range(len(FUNCTYPE.ARGS)):
+        if FUNCTYPE.ARGS[i] is lltype.Void:
+            void_arguments.append(i)
     def invoke_via_ctypes(*argvalues):
-        cargs = [lltype2ctypes(value) for value in argvalues]
-        for i in container_arguments:
-            cargs[i] = cargs[i].contents
+        cargs = []
+        for i in range(len(FUNCTYPE.ARGS)):
+            if i not in void_arguments:
+                cvalue = lltype2ctypes(argvalues[i])
+                if i in container_arguments:
+                    cvalue = cvalue.contents
+                cargs.append(cvalue)
         _restore_c_errno()
         cres = cfunc(*cargs)
         _save_c_errno()
@@ -750,12 +917,14 @@
         return annmodel.lltype_to_annotation(RESTYPE)
 
     def specialize_call(self, hop):
+        from pypy.rpython.rbuiltin import gen_cast
         hop.exception_cannot_occur()
         s_RESTYPE = hop.args_s[0]
         assert s_RESTYPE.is_constant()
         RESTYPE = s_RESTYPE.const
         v_arg = hop.inputarg(hop.args_r[1], arg=1)
-        return hop.genop('force_cast', [v_arg], resulttype = RESTYPE)
+        TYPE1 = v_arg.concretetype
+        return gen_cast(hop.llops, RESTYPE, v_arg)
 
 def typecheck_ptradd(T):
     # --- ptradd() is only for pointers to non-GC, no-length arrays.
@@ -779,7 +948,7 @@
     cptr = ctypes.cast(ctypes.c_void_p(addr), ctypes_arrayptr_type)
     return ctypes2lltype(T, cptr)
 
-class ForceCastEntry(ExtRegistryEntry):
+class ForcePtrAddEntry(ExtRegistryEntry):
     _about_ = force_ptradd
 
     def compute_result_annotation(self, s_ptr, s_n):
@@ -794,6 +963,84 @@
         return hop.genop('direct_ptradd', [v_ptr, v_n],
                          resulttype = v_ptr.concretetype)
 
+class _lladdress(long):
+    _TYPE = llmemory.Address
+
+    def __new__(cls, void_p):
+        self = long.__new__(cls, void_p.value)
+        self.void_p = void_p
+        self.intval = void_p.value
+        if self.intval > sys.maxint:
+            self.intval = int(self.intval - 2*(sys.maxint + 1))
+        return self
+
+    def _cast_to_ptr(self, TP):
+        return force_cast(TP, self.intval)
+
+    def __repr__(self):
+        return '<_lladdress %s>' % (self.void_p,)
+
+    def __eq__(self, other):
+        return cast_adr_to_int(other) == self.intval
+
+    def __ne__(self, other):
+        return not self == other
+
+class _llgcref(object):
+    _TYPE = llmemory.GCREF
+
+    def __init__(self, void_p):
+        self.intval = void_p.value
+
+    def __eq__(self, other):
+        if isinstance(other, _llgcref):
+            return self.intval == other.intval
+        return force_cast(lltype.Signed, other) == self.intval
+
+    def __ne__(self, other):
+        return not self == other
+
+    def __nonzero__(self):
+        return bool(self.intval)
+
+    def _cast_to_ptr(self, PTRTYPE):
+        return force_cast(PTRTYPE, self.intval)
+
+    def _cast_to_int(self):
+        return self.intval
+
+    def _cast_to_adr(self):
+        return _lladdress(ctypes.c_void_p(self.intval))
+
+def cast_adr_to_int(addr):
+    if isinstance(addr, llmemory.fakeaddress):
+        # use ll2ctypes to obtain a real ctypes-based representation of
+        # the memory, and cast that address as an integer
+        if addr.ptr is None:
+            res = 0
+        else:
+            res = force_cast(lltype.Signed, addr.ptr)
+    else:
+        res = addr._cast_to_int()
+    if res > sys.maxint:
+        res = res - 2*(sys.maxint + 1)
+        assert int(res) == res
+        return int(res)
+    return res
+
+class CastAdrToIntEntry(ExtRegistryEntry):
+    _about_ = cast_adr_to_int
+
+    def compute_result_annotation(self, s_addr):
+        return annmodel.SomeInteger()
+
+    def specialize_call(self, hop):
+        assert isinstance(hop.args_r[0], raddress.AddressRepr)
+        adr, = hop.inputargs(hop.args_r[0])
+        hop.exception_cannot_occur()
+        return hop.genop('cast_adr_to_int', [adr],
+                         resulttype = lltype.Signed)
+
 # ____________________________________________________________
 # errno
 

Modified: pypy/branch/pyjitpl5/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/rpython/lltypesystem/lltype.py	(original)
+++ pypy/branch/pyjitpl5/pypy/rpython/lltypesystem/lltype.py	Sat Feb 21 09:30:23 2009
@@ -798,6 +798,8 @@
                         "%s to %s" % (CURTYPE, PTRTYPE))
     if (isinstance(CURTYPE.TO, OpaqueType)
         and not isinstance(PTRTYPE.TO, OpaqueType)):
+        if hasattr(ptr, '_cast_to_ptr'):
+            return ptr._cast_to_ptr(PTRTYPE)
         if not ptr:
             return nullptr(PTRTYPE.TO)
         try:
@@ -809,6 +811,8 @@
         return cast_pointer(PTRTYPE, p)
     elif (not isinstance(CURTYPE.TO, OpaqueType)
           and isinstance(PTRTYPE.TO, OpaqueType)):
+        if hasattr(ptr, '_cast_to_opaque'):
+            return ptr._cast_to_opaque(PTRTYPE)
         if not ptr:
             return nullptr(PTRTYPE.TO)
         return opaqueptr(PTRTYPE.TO, 'hidden', container = ptr._obj,
@@ -1085,12 +1089,20 @@
         if isinstance(self._T, FuncType):
             if len(args) != len(self._T.ARGS):
                 raise TypeError,"calling %r with wrong argument number: %r" % (self._T, args)
-            for a, ARG in zip(args, self._T.ARGS):
+            for i, a, ARG in zip(range(len(self._T.ARGS)), args, self._T.ARGS):
                 if typeOf(a) != ARG:
+                    # ARG could be Void
+                    if ARG == Void:
+                        try:
+                            value = getattr(self._obj, '_void' + str(i))
+                        except AttributeError:
+                            pass
+                        else:
+                            assert a == value
                     # special case: ARG can be a container type, in which
                     # case a should be a pointer to it.  This must also be
                     # special-cased in the backends.
-                    if not (isinstance(ARG, ContainerType)
+                    elif not (isinstance(ARG, ContainerType)
                             and typeOf(a) == Ptr(ARG)):
                         args_repr = [typeOf(arg) for arg in args]
                         raise TypeError, ("calling %r with wrong argument "

Modified: pypy/branch/pyjitpl5/pypy/rpython/lltypesystem/rclass.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/rpython/lltypesystem/rclass.py	(original)
+++ pypy/branch/pyjitpl5/pypy/rpython/lltypesystem/rclass.py	Sat Feb 21 09:30:23 2009
@@ -386,7 +386,7 @@
                                                   ll_runtime_type_info,
                                                   OBJECT, destrptr)
             vtable = self.rclass.getvtable()
-            #self.rtyper.type_for_typeptr[vtable._obj] = self.lowleveltype.TO
+            self.rtyper.type_for_typeptr[vtable._obj] = self.lowleveltype.TO
 
     def common_repr(self): # -> object or nongcobject reprs
         return getinstancerepr(self.rtyper, None, self.gcflavor)

Modified: pypy/branch/pyjitpl5/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/rpython/lltypesystem/test/test_ll2ctypes.py	(original)
+++ pypy/branch/pyjitpl5/pypy/rpython/lltypesystem/test/test_ll2ctypes.py	Sat Feb 21 09:30:23 2009
@@ -7,11 +7,14 @@
 from pypy.rpython.lltypesystem.ll2ctypes import standard_c_lib
 from pypy.rpython.lltypesystem.ll2ctypes import uninitialized2ctypes
 from pypy.rpython.lltypesystem.ll2ctypes import ALLOCATED, force_cast
+from pypy.rpython.lltypesystem.ll2ctypes import cast_adr_to_int, get_ctypes_type
 from pypy.rpython.annlowlevel import llhelper
 from pypy.rlib import rposix
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from pypy.tool.udir import udir
 from pypy.rpython.test.test_llinterp import interpret
+from pypy.annotation.annrpython import RPythonAnnotator
+from pypy.rpython.rtyper import RPythonTyper
 
 class TestLL2Ctypes(object):
 
@@ -826,13 +829,152 @@
         c1 = lltype2ctypes(a1)
         c2 = lltype2ctypes(a2)
         assert type(c1) is type(c2)
+        lltype.free(a1, flavor='raw')
+        lltype.free(a2, flavor='raw')
+        assert not ALLOCATED     # detects memory leaks in the test
+
+    def test_varsized_struct(self):
+        S = lltype.Struct('S', ('x', lltype.Signed),
+                               ('a', lltype.Array(lltype.Char)))
+        s1 = lltype.malloc(S, 6, flavor='raw')
+        s1.x = 5
+        s1.a[2] = 'F'
+        sc = lltype2ctypes(s1, normalize=False)
+        assert isinstance(sc.contents, ctypes.Structure)
+        assert sc.contents.x == 5
+        assert sc.contents.a.length == 6
+        assert sc.contents.a.items[2] == ord('F')
+        sc.contents.a.items[3] = ord('P')
+        assert s1.a[3] == 'P'
+        s1.a[1] = 'y'
+        assert sc.contents.a.items[1] == ord('y')
+        # now go back to lltype...
+        res = ctypes2lltype(lltype.Ptr(S), sc)
+        assert res == s1
+        assert res.x == 5
+        assert len(res.a) == 6
+        lltype.free(s1, flavor='raw')
+        assert not ALLOCATED     # detects memory leaks in the test
+
+    def test_with_explicit_length(self):
+        A = lltype.Array(lltype.Signed)
+        a1 = lltype.malloc(A, 5, flavor='raw')
+        a1[0] = 42
+        c1 = lltype2ctypes(a1, normalize=False)
+        assert c1.contents.length == 5
+        assert c1.contents.items[0] == 42
+        res = ctypes2lltype(lltype.Ptr(A), c1)
+        assert res == a1
+        assert len(res) == 5
+        assert res[0] == 42
+        res[0] += 1
+        assert c1.contents.items[0] == 43
+        assert a1[0] == 43
+        a1[0] += 2
+        assert c1.contents.items[0] == 45
+        assert a1[0] == 45
+        c1.contents.items[0] += 3
+        assert res[0] == 48
+        assert a1[0] == 48
+        lltype.free(a1, flavor='raw')
+        assert not ALLOCATED     # detects memory leaks in the test
+
+    def test_c_callback_with_void_arg_2(self):
+        ftest = []
+        def f(x):
+            ftest.append(x)
+        F = lltype.FuncType([lltype.Void], lltype.Void)
+        fn = lltype.functionptr(F, 'askjh', _callable=f, _void0=-5)
+        fn(-5)
+        assert ftest == [-5]
+        fn2 = lltype2ctypes(fn)
+        fn2()
+        assert ftest == [-5, -5]
+        fn3 = ctypes2lltype(lltype.Ptr(F), fn2)
+        fn3(-5)
+        assert ftest == [-5, -5, -5]
+
+    def test_c_callback_with_void_arg_3(self):
+        import pypy
+        def f(i):
+            x = 'X' * i
+            return x[-2]
+        a = RPythonAnnotator()
+        r = a.build_types(f, [int])
+        rtyper = RPythonTyper(a)
+        rtyper.specialize()
+        a.translator.rtyper = rtyper
+        graph = a.translator.graphs[0]
+        op = graph.startblock.operations[-1]
+        assert op.opname == 'direct_call'
+        assert op.args[0].value._obj._callable == pypy.rpython.lltypesystem.rstr.LLHelpers.ll_stritem.im_func
+        assert op.args[1].value == pypy.rpython.lltypesystem.rstr.LLHelpers
+        assert op.args[3].value == -2
+
+    def test_pass_around_t_object(self):
+        from pypy.rpython.annlowlevel import base_ptr_lltype
+        T = base_ptr_lltype()
+        
+        class X(object):
+            _TYPE = T
+            x = 10
+
+        def callback(x):
+            return x.x
+
+        c_source = py.code.Source("""
+        int eating_callback(void *arg, int(*call)(int))
+        {
+            return call(arg);
+        }
+        """)
+
+        eci = ExternalCompilationInfo(separate_module_sources=[c_source])
+
+        args = [T, rffi.CCallback([T], rffi.INT)]
+        eating_callback = rffi.llexternal('eating_callback', args, rffi.INT,
+                                          compilation_info=eci)
+
+        res = eating_callback(X(), callback)
+        assert res == 10
 
-    def test_varsized_struct(self): 
-        STR = lltype.Struct('rpy_string', ('hash',  lltype.Signed),
-                            ('chars', lltype.Array(lltype.Char, hints={'immutable': True})))
-        s = lltype.malloc(STR, 3, flavor='raw')
-        one = force_cast(rffi.VOIDP, s)
-        # sanity check
-        #assert lltype2ctypes(one).contents.items._length_ > 0
-        two = force_cast(lltype.Ptr(STR), one)
-        assert s == two
+    def test_recursive_struct_more(self):
+        NODE = lltype.ForwardReference()
+        NODE.become(lltype.Struct('NODE', ('value', lltype.Signed),
+                                          ('next', lltype.Ptr(NODE))))
+        CNODEPTR = get_ctypes_type(NODE)
+        pc = CNODEPTR()
+        pc.value = 42
+        pc.next = ctypes.pointer(pc)
+        p = ctypes2lltype(lltype.Ptr(NODE), ctypes.pointer(pc))
+        assert p.value == 42
+        assert p.next == p
+        pc2 = lltype2ctypes(p)
+        assert pc2.contents.value == 42
+        assert pc2.contents.next.contents.value == 42
+
+    def test_cast_adr_to_int(self):
+        class someaddr(object):
+            def _cast_to_int(self):
+                return sys.maxint/2 * 3
+
+        res = cast_adr_to_int(someaddr())
+        assert isinstance(res, int)
+        assert res == -sys.maxint/2 - 3
+
+    def test_cast_gcref_back_and_forth(self):
+        NODE = lltype.GcStruct('NODE')
+        node = lltype.malloc(NODE)
+        ref = lltype.cast_opaque_ptr(llmemory.GCREF, node)
+        back = rffi.cast(llmemory.GCREF, rffi.cast(lltype.Signed, ref))
+        assert lltype.cast_opaque_ptr(lltype.Ptr(NODE), ref) == node
+
+    def test_gcref_forth_and_back(self):
+        cp = ctypes.c_void_p(1234)
+        v = ctypes2lltype(llmemory.GCREF, cp)
+        assert lltype2ctypes(v).value == cp.value
+        v1 = ctypes2lltype(llmemory.GCREF, cp)
+        assert v == v1
+        assert v
+        v2 = ctypes2lltype(llmemory.GCREF, ctypes.c_void_p(1235))
+        assert v2 != v

Modified: pypy/branch/pyjitpl5/pypy/rpython/rtyper.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/rpython/rtyper.py	(original)
+++ pypy/branch/pyjitpl5/pypy/rpython/rtyper.py	Sat Feb 21 09:30:23 2009
@@ -57,6 +57,7 @@
         self._dict_traits = {}
         self.class_reprs = {}
         self.instance_reprs = {}
+        self.type_for_typeptr = {}
         self.pbc_reprs = {}
         self.classes_with_wrapper = {}
         self.wrapper_context = None # or add an extra arg to convertvar?
@@ -131,6 +132,23 @@
             result[repr.lowleveltype] = classdef
         return result
 
+    def lltype_to_vtable_mapping(self):
+        result = {}
+        for repr in self.instance_reprs.itervalues():
+            result[repr.lowleveltype.TO] = repr.rclass.getvtable()
+        return result
+
+    def get_type_for_typeptr(self, typeptr):
+        try:
+            return self.type_for_typeptr[typeptr._obj]
+        except KeyError:
+            # rehash the dictionary
+            type_for_typeptr = {}
+            for key, value in self.type_for_typeptr.items():
+                type_for_typeptr[key] = value
+            self.type_for_typeptr = type_for_typeptr
+            return self.type_for_typeptr[typeptr._obj]
+
     def makekey(self, s_obj):
         return pair(self.type_system, s_obj).rtyper_makekey(self)
 



More information about the Pypy-commit mailing list