[pypy-svn] r72433 - in pypy/trunk/pypy/module/cpyext: . include test

xoraxax at codespeak.net xoraxax at codespeak.net
Sat Mar 20 05:23:00 CET 2010


Author: xoraxax
Date: Sat Mar 20 05:22:58 2010
New Revision: 72433

Added:
   pypy/trunk/pypy/module/cpyext/state.py
Modified:
   pypy/trunk/pypy/module/cpyext/__init__.py
   pypy/trunk/pypy/module/cpyext/api.py
   pypy/trunk/pypy/module/cpyext/floatobject.py
   pypy/trunk/pypy/module/cpyext/include/Python.h
   pypy/trunk/pypy/module/cpyext/test/test_cpyext.py
Log:
After hours of fighting with ll2ctypes (probably should be implemented differently anyway with Addresses - are those hashable?), here is PyObject support for cpyext.

Modified: pypy/trunk/pypy/module/cpyext/__init__.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/__init__.py	(original)
+++ pypy/trunk/pypy/module/cpyext/__init__.py	Sat Mar 20 05:22:58 2010
@@ -1,13 +1,8 @@
 from pypy.interpreter.mixedmodule import MixedModule
 from pypy.rlib.objectmodel import we_are_translated
 import pypy.module.cpyext.api
+from pypy.module.cpyext.state import State
 
-class State:
-    def __init__(self, space):
-        if not we_are_translated():
-            self.api_lib = str(api.build_bridge(space))
-        else:
-            XXX # build an import library when translating pypy.
 
 class Module(MixedModule):
     interpleveldefs = {
@@ -30,5 +25,4 @@
 import pypy.module.cpyext.floatobject
 import pypy.module.cpyext.modsupport
 import pypy.module.cpyext.pythonrun
-from pypy.module.cpyext import api
 api.configure()

Modified: pypy/trunk/pypy/module/cpyext/api.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/api.py	(original)
+++ pypy/trunk/pypy/module/cpyext/api.py	Sat Mar 20 05:22:58 2010
@@ -1,3 +1,7 @@
+import py
+import autopath
+import ctypes
+
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rpython.tool import rffi_platform
 from pypy.rpython.lltypesystem import ll2ctypes
@@ -6,8 +10,8 @@
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from pypy.tool.udir import udir
 from pypy.translator import platform
+from pypy.module.cpyext.state import State
 
-import py, autopath
 
 include_dirs = [
     py.path.local(autopath.pypydir).join('module', 'cpyext', 'include'),
@@ -29,7 +33,9 @@
 
 def cpython_api(argtypes, restype):
     def decorate(func):
-        FUNCTIONS[func.func_name] = ApiFunction(argtypes, restype, func)
+        api_function = ApiFunction(argtypes, restype, func)
+        FUNCTIONS[func.func_name] = api_function
+        func.api_func = api_function
         return func
     return decorate
 
@@ -43,19 +49,34 @@
 FUNCTIONS = {}
 TYPES = {}
 
-PyObject = lltype.Ptr(cpython_struct('struct _object', []))
+# It is important that these PyObjects are allocated in a raw fashion
+# Thus we cannot save a forward pointer to the wrapped object
+# So we need a forward and backward mapping in our State instance
+PyObject = lltype.Ptr(cpython_struct('struct _object', [("refcnt", lltype.Signed)]))
 
 def configure():
     for name, TYPE in rffi_platform.configure(CConfig).iteritems():
         TYPES[name].become(TYPE)
 
-def make_ref(w_obj):
-    return lltype.nullptr(PyObject.TO) # XXX for the moment
+def make_ref(space, w_obj):
+    state = space.fromcache(State)
+    py_obj = state.py_objects_w2r.get(w_obj)
+    if py_obj is None:
+        py_obj = lltype.malloc(PyObject.TO, None, flavor="raw")
+        ctypes_obj = ll2ctypes.lltype2ctypes(py_obj)
+        ptr = ctypes.cast(ctypes_obj, ctypes.c_void_p).value
+        py_obj = ll2ctypes.ctypes2lltype(PyObject, ctypes_obj)
+        state.py_objects_w2r[w_obj] = py_obj
+        state.py_objects_r2w[ptr] = w_obj
+    return py_obj
 
 def from_ref(space, ref):
+    state = space.fromcache(State)
     if not ref:
-        return space.w_None # XXX for the moment, should be an exception
-    assert False
+        raise RuntimeError("Null pointer dereference!")
+    ptr = ctypes.addressof(ref._obj._storage)
+    obj = state.py_objects_r2w[ptr]
+    return obj
 
 #_____________________________________________________
 # Build the bridge DLL, Allow extension DLLs to call
@@ -138,7 +159,16 @@
 
     def make_wrapper(callable):
         def wrapper(*args):
-            return callable(space, *args)
+            boxed_args = []
+            # XXX use unrolling_iterable here
+            for typ, arg in zip(callable.api_func.argtypes, args):
+                if typ is PyObject:
+                    arg = from_ref(space, arg)
+                boxed_args.append(arg)
+            retval = callable(space, *boxed_args)
+            if callable.api_func.restype is PyObject:
+                retval = make_ref(space, retval)
+            return retval
         return wrapper
 
     # implement structure initialization code

Modified: pypy/trunk/pypy/module/cpyext/floatobject.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/floatobject.py	(original)
+++ pypy/trunk/pypy/module/cpyext/floatobject.py	Sat Mar 20 05:22:58 2010
@@ -3,4 +3,4 @@
 
 @cpython_api([lltype.Float], PyObject)
 def PyFloat_FromDouble(space, value):
-    return make_ref(space.wrap(value))
+    return space.wrap(value)

Modified: pypy/trunk/pypy/module/cpyext/include/Python.h
==============================================================================
--- pypy/trunk/pypy/module/cpyext/include/Python.h	(original)
+++ pypy/trunk/pypy/module/cpyext/include/Python.h	Sat Mar 20 05:22:58 2010
@@ -2,7 +2,7 @@
 #define Py_PYTHON_H
 
 typedef struct _object {
-    int __dummy;
+    long refcnt;
 } PyObject;
 
 #include <stdio.h>

Added: pypy/trunk/pypy/module/cpyext/state.py
==============================================================================
--- (empty file)
+++ pypy/trunk/pypy/module/cpyext/state.py	Sat Mar 20 05:22:58 2010
@@ -0,0 +1,14 @@
+from pypy.rlib.objectmodel import we_are_translated
+from pypy.lib.identity_dict import identity_dict
+
+
+class State:
+    def __init__(self, space):
+        from pypy.module.cpyext import api
+        self.py_objects_w2r = identity_dict() # w_obj -> raw PyObject
+        self.py_objects_r2w = {} # addr of raw PyObject -> w_obj
+        if not we_are_translated():
+            self.api_lib = str(api.build_bridge(space))
+        else:
+            XXX # build an import library when translating pypy.
+

Modified: pypy/trunk/pypy/module/cpyext/test/test_cpyext.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/test/test_cpyext.py	(original)
+++ pypy/trunk/pypy/module/cpyext/test/test_cpyext.py	Sat Mar 20 05:22:58 2010
@@ -94,4 +94,4 @@
         assert 'foo' in sys.modules
         assert 'return_pi' in dir(module)
         assert module.return_pi is not None
-        assert module.return_pi() is None # XXX for the moment
+        assert module.return_pi() == 3.14



More information about the Pypy-commit mailing list