[pypy-svn] r45879 - in pypy/branch/pypy-more-rtti-inprogress/rpython: . lltypesystem

arigo at codespeak.net arigo at codespeak.net
Mon Aug 20 16:57:25 CEST 2007


Author: arigo
Date: Mon Aug 20 16:57:24 2007
New Revision: 45879

Modified:
   pypy/branch/pypy-more-rtti-inprogress/rpython/annlowlevel.py
   pypy/branch/pypy-more-rtti-inprogress/rpython/extfunc.py
   pypy/branch/pypy-more-rtti-inprogress/rpython/lltypesystem/ll2ctypes.py
   pypy/branch/pypy-more-rtti-inprogress/rpython/lltypesystem/lltype.py
   pypy/branch/pypy-more-rtti-inprogress/rpython/lltypesystem/rffi.py
   pypy/branch/pypy-more-rtti-inprogress/rpython/typesystem.py
Log:
Fix for an issue where multiple _func objects have the same graph.
They were created by multiple calls to rtyper.getcallable(), once
without particular arguments, and once from annlowlevel.py with
extra **fnobjattrs.

In details:

* getcallable() now always reads extra fnobj attributes from the Python
  function object's '_fnobjattrs_' attribute, if any, so that it always
  return an equal _func object.
* this allows us to revert the recently-introduced **fnobjattrs
  arguments in annlowlevel.py.
* make _func objects really immutable, to avoid surprizes with hash().
* shuffle things around in ll2ctypes to cope with this.

translator/c/test/test_newgc is now passing.


Modified: pypy/branch/pypy-more-rtti-inprogress/rpython/annlowlevel.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/rpython/annlowlevel.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/rpython/annlowlevel.py	Mon Aug 20 16:57:24 2007
@@ -156,8 +156,7 @@
         self.pending.append((ll_function, graph, args_s, s_result))
         return graph
 
-    def delayedfunction(self, ll_function, args_s, s_result, needtype=False,
-                        **fnobjattrs):
+    def delayedfunction(self, ll_function, args_s, s_result, needtype=False):
         # get a delayed pointer to the low-level function, annotated as
         # specified.  The pointer is only valid after finish() was called.
         graph = self.getgraph(ll_function, args_s, s_result)
@@ -168,13 +167,13 @@
             FUNCTYPE = lltype.FuncType(ARGS, RESULT)
         else:
             FUNCTYPE = None
-        return self.graph2delayed(graph, FUNCTYPE, **fnobjattrs)
+        return self.graph2delayed(graph, FUNCTYPE)
 
     def constfunc(self, ll_function, args_s, s_result):
         p = self.delayedfunction(ll_function, args_s, s_result)
         return Constant(p, lltype.typeOf(p))
 
-    def graph2delayed(self, graph, FUNCTYPE=None, **fnobjattrs):
+    def graph2delayed(self, graph, FUNCTYPE=None):
         if FUNCTYPE is None:
             FUNCTYPE = lltype.ForwardReference()
         # obscure hack: embed the name of the function in the string, so
@@ -182,7 +181,7 @@
         # is really computed
         name = "delayed!%s" % (graph.name,)
         delayedptr = lltype._ptr(lltype.Ptr(FUNCTYPE), name, solid=True)
-        self.delayedfuncs.append((delayedptr, graph, fnobjattrs))
+        self.delayedfuncs.append((delayedptr, graph))
         return delayedptr
 
     def graph2const(self, graph):
@@ -260,10 +259,8 @@
         for p, repr, obj in self.delayedconsts:
             p._become(repr.convert_const(obj))
         rtyper.call_all_setups()
-        for p, graph, fnobjattrs in self.delayedfuncs:
+        for p, graph in self.delayedfuncs:
             real_p = rtyper.getcallable(graph)
-            for key, value in fnobjattrs.items():
-                setattr(rtyper.type_system.deref(real_p), key, value)
             REAL = lltype.typeOf(real_p).TO
             FUNCTYPE = lltype.typeOf(p).TO
             if isinstance(FUNCTYPE, lltype.ForwardReference):

Modified: pypy/branch/pypy-more-rtti-inprogress/rpython/extfunc.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/rpython/extfunc.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/rpython/extfunc.py	Mon Aug 20 16:57:24 2007
@@ -106,10 +106,15 @@
         if impl:
             if rtyper.annotator.translator.config.translation.sandbox:
                 impl.dont_inline = True
+            # store some attributes to the 'impl' function, where
+            # the eventual call to rtyper.getcallable() will find them
+            # and transfer them to the final lltype.functionptr().
+            impl._llfnobjattrs_ = {
+                '_name': self.name,
+                '_safe_not_sandboxed': self.safe_not_sandboxed,
+                }
             obj = rtyper.getannmixlevel().delayedfunction(
-                impl, signature_args, hop.s_result,
-                _name=self.name,
-                _safe_not_sandboxed=self.safe_not_sandboxed)
+                impl, signature_args, hop.s_result)
         else:
             #if not self.safe_not_sandboxed:
             #    print '>>>>>>>>>>>>>-----------------------------------'

Modified: pypy/branch/pypy-more-rtti-inprogress/rpython/lltypesystem/ll2ctypes.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/rpython/lltypesystem/ll2ctypes.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/rpython/lltypesystem/ll2ctypes.py	Mon Aug 20 16:57:24 2007
@@ -377,9 +377,9 @@
             else:
                 raise NotImplementedError("array with an explicit length")
         elif isinstance(T.TO, lltype.FuncType):
-            funcptr = lltype.functionptr(T.TO, getattr(cobj, '__name__', '?'))
-            make_callable_via_ctypes(funcptr, cfunc=cobj)
-            return funcptr
+            _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)
         else:
@@ -465,25 +465,29 @@
         cfunc.restype = get_ctypes_type(FUNCTYPE.RESULT)
     return cfunc
 
-def make_callable_via_ctypes(funcptr, cfunc=None):
-    RESULT = lltype.typeOf(funcptr).TO.RESULT
-    if cfunc is None:
-        cfunc1 = []
-    else:
-        cfunc1 = [cfunc]
+class LL2CtypesCallable(object):
+    # a special '_callable' object that invokes ctypes
 
-    def invoke_via_ctypes(*argvalues):
-        if cfunc1:
-            cfunc = cfunc1[0]
-        else:
+    def __init__(self, FUNCTYPE):
+        self.FUNCTYPE = FUNCTYPE
+        self.trampoline = None
+        #self.funcptr = ...  set later
+
+    def __call__(self, *argvalues):
+        if self.trampoline is None:
             # lazily build the corresponding ctypes function object
-            cfunc = get_ctypes_callable(funcptr)
-            cfunc1.append(cfunc)    # cache
+            cfunc = get_ctypes_callable(self.funcptr)
+            self.trampoline = get_ctypes_trampoline(self.FUNCTYPE, cfunc)
         # perform the call
+        return self.trampoline(*argvalues)
+
+def get_ctypes_trampoline(FUNCTYPE, cfunc):
+    RESULT = FUNCTYPE.RESULT
+    def invoke_via_ctypes(*argvalues):
         cargs = [lltype2ctypes(value) for value in argvalues]
         cres = cfunc(*cargs)
         return ctypes2lltype(RESULT, cres)
-    funcptr._obj._callable = invoke_via_ctypes
+    return invoke_via_ctypes
 
 def force_cast(RESTYPE, value):
     """Cast a value to a result type, trying to use the same rules as C."""

Modified: pypy/branch/pypy-more-rtti-inprogress/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/rpython/lltypesystem/lltype.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/rpython/lltypesystem/lltype.py	Mon Aug 20 16:57:24 2007
@@ -1538,9 +1538,9 @@
 
 class _func(_container):
     def __init__(self, TYPE, **attrs):
-        self._TYPE = TYPE
-        self._name = "?"
-        self._callable = None
+        attrs.setdefault('_TYPE', TYPE)
+        attrs.setdefault('_name', '?')
+        attrs.setdefault('_callable', None)
         self.__dict__.update(attrs)
 
     def __repr__(self):
@@ -1567,6 +1567,9 @@
         else:
             return id(self)
 
+    def __setattr__(self, attr, value):
+        raise AttributeError("cannot change the attributes of %r" % (self,))
+
 class _opaque(_parentable):
     def __init__(self, TYPE, parent=None, parentindex=None, **attrs):
         _parentable.__init__(self, TYPE)

Modified: pypy/branch/pypy-more-rtti-inprogress/rpython/lltypesystem/rffi.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/rpython/lltypesystem/rffi.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/rpython/lltypesystem/rffi.py	Mon Aug 20 16:57:24 2007
@@ -24,6 +24,8 @@
 def llexternal(name, args, result, _callable=None, sources=[], includes=[],
                libraries=[], include_dirs=[], sandboxsafe=False):
     ext_type = lltype.FuncType(args, result)
+    if _callable is None:
+        _callable = ll2ctypes.LL2CtypesCallable(ext_type)
     funcptr = lltype.functionptr(ext_type, name, external='C',
                                  sources=tuple(sources),
                                  includes=tuple(includes),
@@ -32,8 +34,8 @@
                                  _callable=_callable,
                                  _safe_not_sandboxed=sandboxsafe,
                                  _debugexc=True)  # on top of llinterp
-    if _callable is None:
-        ll2ctypes.make_callable_via_ctypes(funcptr)
+    if isinstance(_callable, ll2ctypes.LL2CtypesCallable):
+        _callable.funcptr = funcptr
     return funcptr
 
 from pypy.rpython.tool.rfficache import platform

Modified: pypy/branch/pypy-more-rtti-inprogress/rpython/typesystem.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/rpython/typesystem.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/rpython/typesystem.py	Mon Aug 20 16:57:24 2007
@@ -57,9 +57,22 @@
         
         FT = typ(llinputs, lloutput)
         if hasattr(graph, 'func') and callable(graph.func):
-            return constr(FT, graph.name, graph = graph, _callable = graph.func)
+            # the Python function object can have _llfnobjattrs_, specifying
+            # attributes that are forced upon the functionptr().  The idea
+            # for not passing these extra attributes as arguments to
+            # getcallable() itself is that multiple calls to getcallable()
+            # for the same graph should return equal functionptr() objects.
+            name = graph.name
+            if hasattr(graph.func, '_llfnobjattrs_'):
+                fnobjattrs = graph.func._llfnobjattrs_.copy()
+                # can specify a '_name', but use graph.name by default
+                name = fnobjattrs.pop('_name', name)
+            else:
+                fnobjattrs = {}
+            return constr(FT, name, graph = graph, _callable = graph.func,
+                          **fnobjattrs)
         else:
-            return constr(FT, graph.name, graph = graph)
+            return constr(FT, name, graph = graph, **fnobjattrs)
 
     def getexternalcallable(self, ll_args, ll_result, name, **kwds):
         typ, constr = self.callable_trait



More information about the Pypy-commit mailing list