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

xoraxax at codespeak.net xoraxax at codespeak.net
Sun Mar 21 19:30:58 CET 2010


Author: xoraxax
Date: Sun Mar 21 19:30:56 2010
New Revision: 72506

Modified:
   pypy/trunk/pypy/module/cpyext/api.py
   pypy/trunk/pypy/module/cpyext/include/methodobject.h
   pypy/trunk/pypy/module/cpyext/methodobject.py
   pypy/trunk/pypy/module/cpyext/modsupport.py
   pypy/trunk/pypy/module/cpyext/object.py
   pypy/trunk/pypy/module/cpyext/test/test_cpyext.py
   pypy/trunk/pypy/module/cpyext/typeobject.py
Log:
General progress: added correct allocation code respecting basesize, fix instantiation of objects, extend module support code.

Modified: pypy/trunk/pypy/module/cpyext/api.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/api.py	(original)
+++ pypy/trunk/pypy/module/cpyext/api.py	Sun Mar 21 19:30:56 2010
@@ -40,6 +40,10 @@
 #globals().update(rffi_platform.configure(CConfig_constants))
 Py_TPFLAGS_READY = (1L<<12)
 Py_TPFLAGS_READYING = (1L<<13)
+METH_COEXIST = 0x0040
+METH_STATIC = 0x0020
+METH_CLASS = 0x0010
+METH_NOARGS = 0x0004
 
 
 class ApiFunction:
@@ -75,7 +79,7 @@
     'PyExc_Exception': ('PyObject*', 'space.w_Exception'),
     'PyExc_TypeError': ('PyObject*', 'space.w_TypeError'),
     'PyType_Type': ('PyTypeObject*', 'space.w_type'),
-    'PyBaseObject_Type': ('PyTypeObject*', 'space.w_object'),
+    'PyBaseObject_Type#': ('PyTypeObject*', 'space.w_object'),
     }
 
 # It is important that these PyObjects are allocated in a raw fashion
@@ -84,8 +88,10 @@
 PyObjectStruct = lltype.ForwardReference()
 PyObject = lltype.Ptr(PyObjectStruct)
 PyObjectFields = (("obj_refcnt", lltype.Signed), ("obj_type", PyObject))
+PyVarObjectFields = PyObjectFields + (("obj_size", Py_ssize_t), )
 cpython_struct('struct _object', PyObjectFields, PyObjectStruct)
 
+
 def configure():
     for name, TYPE in rffi_platform.configure(CConfig).iteritems():
         if name in TYPES:
@@ -97,13 +103,38 @@
 class InvalidPointerException(Exception):
     pass
 
+def get_padded_type(T, size):
+    fields = T._flds.copy()
+    hints = T._hints.copy()
+    hints["size"] = size
+    del hints["fieldoffsets"]
+    pad_fields = []
+    new_fields = []
+    for name in T._names:
+        new_fields.append((name, fields[name]))
+    for i in xrange(size - rffi.sizeof(T)):
+        new_fields.append(("custom%i" % (i, ), lltype.Char))
+    hints["padding"] = hints["padding"] + tuple(pad_fields)
+    return lltype.Struct(hints["c_name"], *new_fields, hints=hints)
+
 def make_ref(space, w_obj, borrowed=False):
+    if w_obj is None:
+        return lltype.nullptr(PyObject.TO)
+        #raise NullPointerException("Trying to pass a NULL reference")
     state = space.fromcache(State)
     py_obj = state.py_objects_w2r.get(w_obj)
     if py_obj is None:
+        from pypy.module.cpyext.typeobject import allocate_type_obj,\
+                W_PyCTypeObject, W_PyCObject
         if space.is_w(space.type(w_obj), space.w_type):
-            from pypy.module.cpyext.typeobject import allocate_type_obj
             py_obj = allocate_type_obj(space, w_obj)
+        elif isinstance(w_obj, W_PyCObject):
+            w_type = space.type(w_obj)
+            assert isinstance(w_type, W_PyCTypeObject)
+            pto = w_type.pto
+            basicsize = pto._obj.c_tp_basicsize
+            T = get_padded_type(PyObject.TO, basicsize)
+            py_obj = lltype.malloc(T, None, flavor="raw")
         else:
             py_obj = lltype.malloc(PyObject.TO, None, flavor="raw")
         py_obj.c_obj_refcnt = 1
@@ -124,6 +155,7 @@
     try:
         obj = state.py_objects_r2w[ptr]
     except KeyError:
+        import pdb; pdb.set_trace()
         raise InvalidPointerException("Got invalid reference to a PyObject")
     return obj
 
@@ -146,8 +178,13 @@
         pypy_rename = []
         renamed_symbols = []
         for name in export_symbols:
+            if "#" in name:
+                deref = "*"
+            else:
+                deref = ""
+            name = name.replace("#", "")
             newname = name.replace('Py', 'PyPy')
-            pypy_rename.append('#define %s %s' % (name, newname))
+            pypy_rename.append('#define %s %s%s' % (name, deref, newname))
             renamed_symbols.append(newname)
         export_symbols = renamed_symbols
         pypy_rename_h = udir.join('pypy_rename.h')
@@ -188,7 +225,7 @@
 
     global_objects = []
     for name, (type, expr) in GLOBALS.iteritems():
-        global_objects.append('%s %s = NULL;' % (type, name))
+        global_objects.append('%s %s = NULL;' % (type, name.replace("#", "")))
     global_code = '\n'.join(global_objects)
     code = (prologue +
             struct_declaration_code +
@@ -216,6 +253,7 @@
 
     # populate static data
     for name, (type, expr) in GLOBALS.iteritems():
+        name = name.replace("#", "")
         if rename:
             name = name.replace('Py', 'PyPy')
         w_obj = eval(expr)

Modified: pypy/trunk/pypy/module/cpyext/include/methodobject.h
==============================================================================
--- pypy/trunk/pypy/module/cpyext/include/methodobject.h	(original)
+++ pypy/trunk/pypy/module/cpyext/include/methodobject.h	Sun Mar 21 19:30:56 2010
@@ -29,6 +29,20 @@
 #define METH_NOARGS   0x0004
 #define METH_O        0x0008
 
+/* METH_CLASS and METH_STATIC are a little different; these control
+   the construction of methods for a class.  These cannot be used for
+   functions in modules. */
+#define METH_CLASS    0x0010
+#define METH_STATIC   0x0020
+
+/* METH_COEXIST allows a method to be entered eventhough a slot has
+   already filled the entry.  When defined, the flag allows a separate
+   method, "__contains__" for example, to coexist with a defined 
+   slot like sq_contains. */
+
+#define METH_COEXIST   0x0040
+
+
 
 #ifdef __cplusplus
 }

Modified: pypy/trunk/pypy/module/cpyext/methodobject.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/methodobject.py	(original)
+++ pypy/trunk/pypy/module/cpyext/methodobject.py	Sun Mar 21 19:30:56 2010
@@ -5,7 +5,7 @@
 from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import PyObject, from_ref, NullPointerException, \
-        InvalidPointerException
+        InvalidPointerException, make_ref
 from pypy.module.cpyext.state import State
 from pypy.rlib.objectmodel import we_are_translated
 
@@ -19,10 +19,14 @@
 def cfunction_descr_call(space, w_self, __args__):
     self = space.interp_w(W_PyCFunctionObject, w_self)
     args_w, kw_w = __args__.unpack()
-    null = lltype.nullptr(PyObject.TO) # XXX for the moment
+    w_kw = space.newdict()
+    for key, w_value in kw_w:
+        space.setitem(w_kw, space.wrap(key), w_value)
+    args_tuple = space.newtuple([space.wrap(args_w), w_kw])
+    #null = lltype.nullptr(PyObject.TO) # XXX for the moment
 
     # Call the C function
-    result = self.ml.c_ml_meth(null, null)
+    result = self.ml.c_ml_meth(make_ref(space, self.w_self), make_ref(space, args_tuple))
     try:
         ret = from_ref(space, result)
     except NullPointerException:

Modified: pypy/trunk/pypy/module/cpyext/modsupport.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/modsupport.py	(original)
+++ pypy/trunk/pypy/module/cpyext/modsupport.py	Sun Mar 21 19:30:56 2010
@@ -1,5 +1,6 @@
 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import cpython_api, cpython_struct, PyObject
+from pypy.module.cpyext.api import cpython_api, cpython_struct, PyObject, \
+        METH_STATIC, METH_CLASS, METH_COEXIST
 from pypy.interpreter.module import Module
 from pypy.module.cpyext.methodobject import PyCFunction_NewEx
 from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
@@ -25,26 +26,43 @@
 def Py_InitModule(space, name, methods):
     modname = rffi.charp2str(name)
     w_mod = PyImport_AddModule(space, modname)
-    dict_w = convert_method_defs(space, methods)
+    dict_w = convert_method_defs(space, methods, None)
     for key, w_value in dict_w.items():
         space.setattr(w_mod, space.wrap(key), w_value)
     return w_mod
 
 
-def convert_method_defs(space, methods):
+def convert_method_defs(space, methods, pto):
     methods = rffi.cast(rffi.CArrayPtr(PyMethodDef), methods)
     dict_w = {}
     if methods:
-        i = 0
+        i = -1
         while True:
+            i = i + 1
             method = methods[i]
             if not method.c_ml_name: break
 
             methodname = rffi.charp2str(method.c_ml_name)
             flags = method.c_ml_flags
-            w_function = PyCFunction_NewEx(space, method, None)
-            dict_w[methodname] = w_function
-            i = i + 1
+            if pto is None:
+                if flags & METH_CLASS or flags & METH_STATIC:
+                    raise OperationError(space.w_ValueError,
+                            "module functions cannot set METH_CLASS or METH_STATIC")
+                w_obj = PyCFunction_NewEx(space, method, None)
+            else:
+                if methodname in dict_w and not (flags & METH_COEXIST):
+                    continue
+                if flags & METH_CLASS:
+                    if flags & METH_STATIC:
+                        raise OperationError(space.w_ValueError,
+                                "method cannot be both class and static")
+                    w_obj = PyDescr_NewClassMethod(pto, method)
+                elif flags & METH_STATIC:
+                    w_func = PyCFunction_NewEx(space, method, None)
+                    w_obj = PyStaticMethod_New(space, w_func)
+                else:
+                    w_obj = PyDescr_NewMethod(space, pto, method)
+            dict_w[methodname] = w_obj
     return dict_w
 
 

Modified: pypy/trunk/pypy/module/cpyext/object.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/object.py	(original)
+++ pypy/trunk/pypy/module/cpyext/object.py	Sun Mar 21 19:30:56 2010
@@ -3,14 +3,13 @@
 from pypy.module.cpyext.typeobject import PyTypeObjectPtr, W_PyCTypeObject, W_PyCObject
 from pypy.objspace.std.objectobject import W_ObjectObject
 
-def get_cls_for_type_object(space, w_type):
-    if isinstance(w_type, W_PyCTypeObject):
-        return space.allocate_instance(W_PyCObject, w_type)
-    assert False, "Please add more cases in get_cls_for_type_object!"
 
 @cpython_api([PyObject], PyObject)
 def _PyObject_New(space, w_type):
-    return get_cls_for_type_object(space, w_type)
+    if isinstance(w_type, W_PyCTypeObject):
+        w_pycobj = space.allocate_instance(W_PyCObject, w_type)
+        return w_pycobj
+    assert False, "Please add more cases in get_cls_for_type_object!"
 
 @cpython_api([rffi.VOIDP_real], lltype.Void)
 def PyObject_Del(space, w_obj):

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	Sun Mar 21 19:30:56 2010
@@ -25,6 +25,11 @@
         assert api.FUNCTIONS['Py_InitModule'].argtypes == [
             rffi.CCHARP, lltype.Ptr(api.TYPES['PyMethodDef'])]
 
+    def test_padding(self):
+        T = api.get_padded_type(api.PyObject.TO, 42)
+        assert rffi.sizeof(T) == 42
+        print T
+
 def compile_module(modname, **kwds):
     eci = ExternalCompilationInfo(
         export_symbols=['init%s' % (modname,)],

Modified: pypy/trunk/pypy/module/cpyext/typeobject.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/typeobject.py	(original)
+++ pypy/trunk/pypy/module/cpyext/typeobject.py	Sun Mar 21 19:30:56 2010
@@ -64,7 +64,7 @@
 traverseproc = P(FT([PyO, visitproc, rffi.VOIDP], rffi.INT))
 
 PyTypeObjectFields = []
-PyTypeObjectFields.extend(PyObjectFields)
+PyTypeObjectFields.extend(PyVarObjectFields)
 PyTypeObjectFields.extend([
     ("tp_name", rffi.CCHARP), # For printing, in format "<module>.<name>"
     ("tp_basicsize", Py_ssize_t), ("tp_itemsize", Py_ssize_t), # For allocation
@@ -143,9 +143,14 @@
 
 
 class W_PyCTypeObject(W_TypeObject):
-    pass
+    def __init__(self, space, pto):
+        self.pto = pto
+        bases_w = []
+        dict_w = convert_method_defs(space, pto.c_tp_methods, pto)
+        W_TypeObject.__init__(self, space, rffi.charp2str(pto.c_tp_name),
+            bases_w or [space.w_object], dict_w)
 
-class W_PyCObject(W_ObjectObject):
+class W_PyCObject(Wrappable):
     pass
 
 @unwrap_spec(ObjSpace, W_Root, W_Root)
@@ -160,12 +165,9 @@
     return pto
 
 def create_type_object(space, pto):
-    bases_w = []
-    dict_w = convert_method_defs(space, pto.c_tp_methods)
 
     w_type = space.allocate_instance(W_PyCTypeObject, space.gettypeobject(W_PyCTypeObject.typedef))
-    W_TypeObject.__init__(w_type, space, rffi.charp2str(pto.c_tp_name),
-            bases_w or [space.w_object], dict_w)
+    w_type.__init__(space, pto)
     w_type.ready()
     return w_type
 
@@ -180,10 +182,11 @@
         state.py_objects_w2r[w_obj] = pto
     return 1
 
-W_PyCObject.typedef = TypeDef(
-    'C_object',
-    #__getattrbute__ = interp2app(cobject_descr_getattribute),
-    )
+W_PyCObject.typedef = W_ObjectObject.typedef
+#TypeDef(
+#    'C_object',
+#    #__getattrbute__ = interp2app(cobject_descr_getattribute),
+#    )
 
 W_PyCTypeObject.typedef = TypeDef(
     'C_type', W_TypeObject.typedef



More information about the Pypy-commit mailing list