[pypy-svn] r73307 - in pypy/branch/cpython-extension/pypy/module/cpyext: . include test
xoraxax at codespeak.net
xoraxax at codespeak.net
Fri Apr 2 21:15:04 CEST 2010
Author: xoraxax
Date: Fri Apr 2 21:14:47 2010
New Revision: 73307
Added:
pypy/branch/cpython-extension/pypy/module/cpyext/include/unicodeobject.h (contents, props changed)
Modified:
pypy/branch/cpython-extension/pypy/module/cpyext/api.py
pypy/branch/cpython-extension/pypy/module/cpyext/include/Python.h
pypy/branch/cpython-extension/pypy/module/cpyext/object.py
pypy/branch/cpython-extension/pypy/module/cpyext/pyobject.py
pypy/branch/cpython-extension/pypy/module/cpyext/slotdefs.py
pypy/branch/cpython-extension/pypy/module/cpyext/test/foo.c
pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py
pypy/branch/cpython-extension/pypy/module/cpyext/test/test_typeobject.py
pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py
Log:
Reworked complete object model, added PyUnicodeType to globals, extended foo.c to contain a subtype of the unicode type, began to implement slot functions. The new object model requires a word on every W_Root object but I fear that is not avoidable.
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/api.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/api.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/api.py Fri Apr 2 21:14:47 2010
@@ -49,7 +49,7 @@
constant_names = """
Py_TPFLAGS_READY Py_TPFLAGS_READYING
METH_COEXIST METH_STATIC METH_CLASS METH_NOARGS
-Py_TPFLAGS_HEAPTYPE
+Py_TPFLAGS_HEAPTYPE Py_TPFLAGS_HAVE_CLASS
""".split()
for name in constant_names:
setattr(CConfig_constants, name, rffi_platform.ConstantInteger(name))
@@ -238,6 +238,7 @@
"Dict": "space.w_dict",
"Tuple": "space.w_tuple",
"List": "space.w_list",
+ "Unicode": "space.w_unicode",
}.items():
GLOBALS['Py%s_Type#' % (cpyname, )] = ('PyTypeObject*', pypyexpr)
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/include/Python.h
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/include/Python.h (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/include/Python.h Fri Apr 2 21:14:47 2010
@@ -63,6 +63,7 @@
#include "tupleobject.h"
#include "dictobject.h"
#include "intobject.h"
+#include "unicodeobject.h"
#include "eval.h"
// XXX This shouldn't be included here
Added: pypy/branch/cpython-extension/pypy/module/cpyext/include/unicodeobject.h
==============================================================================
--- (empty file)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/include/unicodeobject.h Fri Apr 2 21:14:47 2010
@@ -0,0 +1,3 @@
+typedef struct {
+ PyObject_HEAD
+} PyUnicodeObject;
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/object.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/object.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/object.py Fri Apr 2 21:14:47 2010
@@ -3,22 +3,16 @@
from pypy.module.cpyext.pyobject import PyObject, make_ref, from_ref
from pypy.module.cpyext.pyobject import Py_IncRef, Py_DecRef
from pypy.module.cpyext.state import State
-from pypy.module.cpyext.typeobject import PyTypeObjectPtr, W_PyCTypeObject, W_PyCObject,\
- W_PyCObjectDual
+from pypy.module.cpyext.typeobject import PyTypeObjectPtr, W_PyCTypeObject
from pypy.objspace.std.objectobject import W_ObjectObject
+from pypy.objspace.std.typeobject import W_TypeObject
import pypy.module.__builtin__.operation as operation
@cpython_api([PyObject], PyObject)
def _PyObject_New(space, w_type):
if isinstance(w_type, W_PyCTypeObject):
- w_pycobj = space.allocate_instance(W_PyCObject, w_type)
- w_pycobj.__init__(space)
- w_pycobjd = space.allocate_instance(W_PyCObjectDual, w_type)
- w_pycobjd.__init__(space)
- w_pycobjd.set_pycobject(w_pycobj)
- w_pycobj.set_dual(w_pycobjd)
- Py_IncRef(space, w_pycobj)
- return w_pycobj
+ w_obj = space.allocate_instance(W_ObjectObject, w_type)
+ return w_obj
assert False, "Please add more cases in get_cls_for_type_object!"
@cpython_api([rffi.VOIDP_real], lltype.Void)
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/pyobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/pyobject.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/pyobject.py Fri Apr 2 21:14:47 2010
@@ -2,7 +2,8 @@
from pypy.interpreter.baseobjspace import W_Root
from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import cpython_api, PyObject, PyStringObject, ADDR
+from pypy.module.cpyext.api import cpython_api, PyObject, PyStringObject, ADDR,\
+ Py_TPFLAGS_HEAPTYPE
from pypy.module.cpyext.state import State
from pypy.objspace.std.stringobject import W_StringObject
from pypy.rlib.objectmodel import we_are_translated
@@ -30,32 +31,40 @@
def make_ref(space, w_obj, borrowed=False, steal=False):
from pypy.module.cpyext.typeobject import allocate_type_obj,\
- W_PyCTypeObject, W_PyCObject, W_PyCObjectDual
+ W_PyCTypeObject, PyOLifeline
+ from pypy.module.cpyext.typeobjectdefs import PyTypeObjectPtr
if w_obj is None:
return lltype.nullptr(PyObject.TO)
assert isinstance(w_obj, W_Root)
state = space.fromcache(State)
- if isinstance(w_obj, W_PyCObject):
- w_obj = w_obj.w_dual
py_obj = state.py_objects_w2r.get(w_obj, lltype.nullptr(PyObject.TO))
if not py_obj:
+ assert not steal
w_type = space.type(w_obj)
- if space.is_w(w_type, space.w_type):
+ if space.is_w(w_type, space.w_type) or space.is_w(w_type,
+ space.gettypeobject(W_PyCTypeObject.typedef)):
pto = allocate_type_obj(space, w_obj)
py_obj = rffi.cast(PyObject, pto)
# c_ob_type and c_ob_refcnt are set by allocate_type_obj
- elif isinstance(w_obj, W_PyCObject):
- w_type = space.type(w_obj)
- assert isinstance(w_type, W_PyCTypeObject)
- pto = w_type.pto
- # Don't increase refcount for non-heaptypes
- # Py_IncRef(space, pto)
- basicsize = pto.c_tp_basicsize
- py_obj_pad = lltype.malloc(rffi.VOIDP.TO, basicsize,
- flavor="raw", zero=True)
- py_obj = rffi.cast(PyObject, py_obj_pad)
- py_obj.c_ob_refcnt = 1
- py_obj.c_ob_type = rffi.cast(PyObject, pto)
+ elif isinstance(w_type, W_PyCTypeObject):
+ lifeline = w_obj.get_pyolifeline()
+ if lifeline is not None: # make old PyObject ready for use in C code
+ py_obj = lifeline.pyo
+ assert py_obj.c_ob_refcnt == 0
+ Py_IncRef(space, py_obj)
+ else:
+ w_type_pyo = make_ref(space, w_type)
+ pto = rffi.cast(PyTypeObjectPtr, w_type_pyo)
+ # Don't increase refcount for non-heaptypes
+ if not rffi.cast(lltype.Signed, pto.c_tp_flags) & Py_TPFLAGS_HEAPTYPE:
+ Py_DecRef(space, pto)
+ basicsize = pto.c_tp_basicsize
+ py_obj_pad = lltype.malloc(rffi.VOIDP.TO, basicsize,
+ flavor="raw", zero=True)
+ py_obj = rffi.cast(PyObject, py_obj_pad)
+ py_obj.c_ob_refcnt = 1
+ py_obj.c_ob_type = rffi.cast(PyObject, pto)
+ w_obj.set_pyolifeline(PyOLifeline(space, py_obj))
elif isinstance(w_obj, W_StringObject):
py_obj_str = lltype.malloc(PyStringObject.TO, flavor='raw', zero=True)
py_obj_str.c_size = len(space.str_w(w_obj))
@@ -99,7 +108,6 @@
def from_ref(space, ref):
- from pypy.module.cpyext.typeobject import W_PyCObjectDual, W_PyCObject
assert lltype.typeOf(ref) == PyObject
if not ref:
return None
@@ -107,19 +115,6 @@
ptr = rffi.cast(ADDR, ref)
try:
w_obj = state.py_objects_r2w[ptr]
- if isinstance(w_obj, W_PyCObjectDual):
- w_obj_wr = w_obj.w_pycobject
- w_obj_or_None = w_obj_wr()
- if w_obj_or_None is None:
- # resurrect new PyCObject
- Py_IncRef(space, ref)
- w_obj_new = space.allocate_instance(W_PyCObject, space.type(w_obj))
- w_obj_new.__init__(space)
- w_obj_new.set_dual(w_obj)
- w_obj.set_pycobject(w_obj_new)
- w_obj = w_obj_new
- else:
- w_obj = w_obj_or_None
except KeyError:
ref_type = ref.c_ob_type
if ref != ref_type and space.is_w(from_ref(space, ref_type), space.w_str):
@@ -138,7 +133,7 @@
if not obj:
return
- from pypy.module.cpyext.typeobject import string_dealloc
+ from pypy.module.cpyext.typeobject import string_dealloc, W_PyCTypeObject
obj.c_ob_refcnt -= 1
if DEBUG_REFCOUNT:
debug_refcount("DECREF", obj, obj.c_ob_refcnt, frame_stackdepth=3)
@@ -153,9 +148,12 @@
else:
w_obj = state.py_objects_r2w[ptr]
del state.py_objects_r2w[ptr]
- _Py_Dealloc(space, obj)
+ w_type = space.type(w_obj)
+ w_typetype = space.type(w_type)
+ if not space.is_w(w_typetype, space.gettypeobject(W_PyCTypeObject.typedef)):
+ _Py_Dealloc(space, obj)
del state.py_objects_w2r[w_obj]
- if ptr in state.borrow_mapping:
+ if ptr in state.borrow_mapping: # move to lifeline __del__
for containee in state.borrow_mapping[ptr]:
w_containee = state.py_objects_r2w.get(containee, None)
if w_containee is not None:
@@ -188,7 +186,7 @@
from pypy.module.cpyext.api import generic_cpy_call_dont_decref
pto = obj.c_ob_type
pto = rffi.cast(PyTypeObjectPtr, pto)
- #print >>sys.stderr, "Calling dealloc slot of", obj, \
+ #print >>sys.stderr, "Calling dealloc slot", pto.c_tp_dealloc, "of", obj, \
# "'s type which is", rffi.charp2str(pto.c_tp_name)
generic_cpy_call_dont_decref(space, pto.c_tp_dealloc, obj)
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/slotdefs.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/slotdefs.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/slotdefs.py Fri Apr 2 21:14:47 2010
@@ -4,7 +4,8 @@
from pypy.module.cpyext.api import generic_cpy_call, cpython_api, \
PyObject
from pypy.module.cpyext.typeobjectdefs import unaryfunc, wrapperfunc,\
- ternaryfunc
+ ternaryfunc, PyTypeObjectPtr
+from pypy.module.cpyext.pyobject import from_ref
from pypy.module.cpyext.state import State
from pypy.interpreter.error import OperationError, operationerrfmt
from pypy.rlib.unroll import unrolling_iterable
@@ -32,12 +33,25 @@
func_target = rffi.cast(ternaryfunc, func)
return generic_cpy_call(space, func_target, w_self, w_args, w_kwds)
+ at cpython_api([PyTypeObjectPtr, PyObject, PyObject], PyObject, external=True)
+def slot_tp_new(space, type, w_args, w_kwds):
+ from pypy.module.cpyext.tupleobject import PyTuple_Check
+ pyo = rffi.cast(PyObject, type)
+ w_type = from_ref(space, pyo)
+ w_func = space.getattr(w_type, space.wrap("__new__"))
+ assert PyTuple_Check(space, w_args)
+ args_w = space.listview(w_args)[:]
+ args_w.insert(0, w_type)
+ w_args_new = space.newtuple(args_w)
+ return space.call(w_func, w_args_new, w_kwds)
+
PyWrapperFlag_KEYWORDS = 1
# adopted from typeobject.c
def FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, FLAGS):
wrapper = globals().get(WRAPPER, None)
+ function = globals().get(FUNCTION, None)
slotname = ("c_" + SLOT).split(".")
assert FLAGS == 0 or FLAGS == PyWrapperFlag_KEYWORDS
if FLAGS:
@@ -46,7 +60,7 @@
else:
wrapper1 = wrapper
wrapper2 = None
- return (NAME, slotname, FUNCTION, wrapper1, wrapper2, DOC)
+ return (NAME, slotname, function, wrapper1, wrapper2, DOC)
def TPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC):
return FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, 0)
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/foo.c
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/foo.c (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/foo.c Fri Apr 2 21:14:47 2010
@@ -136,6 +136,81 @@
foo_getseters, /*tp_getset*/
};
+typedef struct {
+ PyUnicodeObject HEAD;
+} FuuObject;
+
+static PyObject *
+Fuu_escape(PyTypeObject* type, PyObject *args)
+{
+ Py_RETURN_TRUE;
+}
+
+
+static PyMethodDef Fuu_methods[] = {
+ {"escape", (PyCFunction) Fuu_escape, METH_VARARGS, NULL},
+ {NULL} /* Sentinel */
+};
+
+PyTypeObject FuuType = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "foo.fuu",
+ sizeof(FuuObject),
+ 0,
+ 0, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+ 0, /*tp_doc*/
+
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+
+ /* Attribute descriptor and subclassing stuff */
+
+ Fuu_methods,/*tp_methods*/
+ 0, /*tp_members*/
+ 0, /*tp_getset*/
+ 0, /*tp_base*/
+ 0, /*tp_dict*/
+
+ 0, /*tp_descr_get*/
+ 0, /*tp_descr_set*/
+ 0, /*tp_dictoffset*/
+
+ 0, /*tp_init*/
+ 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/
+ 0, /*tp_new*/
+ 0, /*tp_free Low-level free-memory routine */
+ 0, /*tp_is_gc For PyObject_IS_GC */
+ 0, /*tp_bases*/
+ 0, /*tp_mro method resolution order */
+ 0, /*tp_cache*/
+ 0, /*tp_subclasses*/
+ 0 /*tp_weaklist*/
+};
+
/* foo functions */
@@ -167,13 +242,23 @@
PyObject *m, *d;
Py_TYPE(&footype) = &PyType_Type;
+
+ /* Workaround for quirk in Visual Studio, see
+ <http://www.python.it/faq/faq-3.html#3.24> */
+ FuuType.tp_base = &PyUnicode_Type;
+
if (PyType_Ready(&footype) < 0)
return;
+ if (PyType_Ready(&FuuType) < 0)
+ return;
m = Py_InitModule("foo", foo_functions);
if (m == NULL)
return;
d = PyModule_GetDict(m);
- if (d)
- PyDict_SetItemString(d, "fooType", (PyObject *)&footype);
+ if (d) {
+ if (PyDict_SetItemString(d, "fooType", (PyObject *)&footype) < 0)
+ return;
+ PyDict_SetItemString(d, "FuuType", (PyObject *) &FuuType);
+ }
/* No need to check the error here, the caller will do that */
}
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py Fri Apr 2 21:14:47 2010
@@ -157,6 +157,22 @@
if delta != 0:
leaking = True
print >>sys.stderr, "Leaking %r: %i references" % (w_obj, delta)
+ lifeline = w_obj.get_pyolifeline()
+ if lifeline is not None:
+ refcnt = lifeline.pyo.c_ob_refcnt
+ if refcnt > 0:
+ print >>sys.stderr, "\tThe object also held by C code."
+ else:
+ referrers_repr = []
+ for o in gc.get_referrers(w_obj):
+ try:
+ repr_str = repr(o)
+ except TypeError, e:
+ repr_str = "%s (type of o is %s)" % (str(e), type(o))
+ referrers_repr.append(repr_str)
+ referrers = ", ".join(referrers_repr)
+ print >>sys.stderr, "\tThe object is referenced by these objects:", \
+ referrers
for w_obj in lost_objects_w:
print >>sys.stderr, "Lost object %r" % (w_obj, )
leaking = True
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/test_typeobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/test_typeobject.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/test_typeobject.py Fri Apr 2 21:14:47 2010
@@ -36,3 +36,12 @@
raises(TypeError, "obj.int_member_readonly = 42")
raises(SystemError, "obj.broken_member")
raises(SystemError, "obj.broken_member = 42")
+ a = module.fooType
+ assert "cannot create" in raises(TypeError, "a()").value.message
+ skip("In Progress")
+ class bar(module.fooType):
+ pass
+ fuu = module.FuuType
+ fuu_inst = fuu(u"abc")
+ assert "cannot create" in raises(TypeError, "bar()").value.message
+
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py Fri Apr 2 21:14:47 2010
@@ -3,27 +3,31 @@
from weakref import ref
from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.tool.pairtype import extendabletype
from pypy.rpython.annlowlevel import llhelper
-from pypy.interpreter.gateway import ObjSpace, W_Root
+from pypy.interpreter.gateway import ObjSpace, W_Root, Arguments
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.baseobjspace import Wrappable
-from pypy.objspace.std.typeobject import W_TypeObject, _CPYTYPE
+from pypy.objspace.std.typeobject import W_TypeObject, _CPYTYPE, call__Type
+from pypy.objspace.std.typetype import _precheck_for_new
from pypy.objspace.std.objectobject import W_ObjectObject
from pypy.interpreter.typedef import TypeDef, GetSetProperty
from pypy.module.cpyext.api import cpython_api, cpython_api_c, cpython_struct, \
PyVarObjectFields, Py_ssize_t, Py_TPFLAGS_READYING, generic_cpy_call, \
- Py_TPFLAGS_READY, Py_TPFLAGS_HEAPTYPE, PyStringObject, ADDR
+ Py_TPFLAGS_READY, Py_TPFLAGS_HEAPTYPE, PyStringObject, ADDR, \
+ Py_TPFLAGS_HAVE_CLASS
from pypy.module.cpyext.pyobject import PyObject, make_ref, from_ref
from pypy.interpreter.module import Module
from pypy.module.cpyext import structmemberdefs
from pypy.module.cpyext.modsupport import convert_method_defs
from pypy.module.cpyext.state import State
from pypy.module.cpyext.methodobject import PyDescr_NewWrapper
-from pypy.module.cpyext.pyobject import Py_IncRef, Py_DecRef
+from pypy.module.cpyext.pyobject import Py_IncRef, Py_DecRef, _Py_Dealloc
from pypy.module.cpyext.structmember import PyMember_GetOne, PyMember_SetOne
from pypy.module.cpyext.typeobjectdefs import PyTypeObjectPtr, PyTypeObject, \
PyGetSetDef, PyMemberDef
from pypy.module.cpyext.slotdefs import slotdefs
+from pypy.interpreter.error import OperationError, operationerrfmt
from pypy.rlib.rstring import rsplit
@@ -35,11 +39,11 @@
if doc:
doc = rffi.charp2str(getset.c_doc)
if getset.c_get:
- get = W_PyCObject.getter
+ get = GettersAndSetters.getter.im_func
if getset.c_set:
- set = W_PyCObject.setter
+ set = GettersAndSetters.setter.im_func
GetSetProperty.__init__(self, get, set, None, doc,
- cls=W_PyCObject, use_closure=True,
+ cls=None, use_closure=True, # XXX cls?
tag="cpyext_1")
def PyDescr_NewGetSet(space, getset, pto):
@@ -53,11 +57,11 @@
doc = set = None
if doc:
doc = rffi.charp2str(getset.c_doc)
- get = W_PyCObject.member_getter
+ get = GettersAndSetters.member_getter.im_func
if not (flags & structmemberdefs.READONLY):
- set = W_PyCObject.member_setter
+ set = GettersAndSetters.member_setter.im_func
GetSetProperty.__init__(self, get, set, None, doc,
- cls=W_PyCObject, use_closure=True,
+ cls=None, use_closure=True, # XXX cls?
tag="cpyext_2")
def convert_getset_defs(space, dict_w, getsets, pto):
@@ -88,13 +92,38 @@
dict_w[name] = w_descr
i += 1
+def update_all_slots(space, w_obj, pto):
+ # XXX fill slots in pto
+ state = space.fromcache(State)
+ for method_name, slot_name, slot_func, _, _, doc in slotdefs:
+ w_descr = space.lookup(w_obj, method_name)
+ if w_descr is None:
+ # XXX special case iternext
+ continue
+ if slot_func is None:
+ os.write(2, method_name + " defined by the type but no slot function defined!\n")
+ continue
+ if method_name == "__new__" and "bar" in repr(w_obj):
+ import pdb; pdb.set_trace()
+ slot_func_helper = llhelper(slot_func.api_func.functype,
+ slot_func.api_func.get_wrapper(space))
+ # XXX special case wrapper-functions and use a "specific" slot func,
+ # XXX special case tp_new
+ if len(slot_name) == 1:
+ setattr(pto, slot_name[0], slot_func_helper)
+ else:
+ assert len(slot_name) == 2
+ struct = getattr(pto, slot_name[0])
+ if not struct:
+ continue
+ setattr(struct, slot_name[1], slot_func_helper)
+
def add_operators(space, dict_w, pto):
# XXX support PyObject_HashNotImplemented
state = space.fromcache(State)
for method_name, slot_name, _, wrapper_func, wrapper_func_kwds, doc in slotdefs:
if method_name in dict_w:
continue
- # XXX is this rpython?
if len(slot_name) == 1:
func = getattr(pto, slot_name[0])
else:
@@ -107,16 +136,26 @@
if not func:
continue
if wrapper_func is None and wrapper_func_kwds is None:
- os.write(2, method_name + " used by the type but no wrapper function defined!")
+ os.write(2, method_name + " used by the type but no wrapper function defined!\n")
continue
dict_w[method_name] = PyDescr_NewWrapper(space, pto, method_name, wrapper_func,
wrapper_func_kwds, doc, func_voidp)
+def inherit_special(space, pto, base_pto):
+ # XXX copy basicsize and flags in a magical way
+ flags = rffi.cast(lltype.Signed, pto.c_tp_flags)
+ if flags & Py_TPFLAGS_HAVE_CLASS:
+ base_object_pyo = make_ref(space, space.w_object, steal=True)
+ base_object_pto = rffi.cast(PyTypeObjectPtr, base_object_pyo)
+ if base_pto != base_object_pto or \
+ flags & Py_TPFLAGS_HEAPTYPE:
+ if not pto.c_tp_new:
+ pto.c_tp_new = base_pto.c_tp_new
+
class W_PyCTypeObject(W_TypeObject):
def __init__(self, space, pto):
- self.pto = pto
- bases_w = []
+ bases_w = [] # XXX fill
dict_w = {}
add_operators(space, dict_w, pto)
@@ -132,16 +171,28 @@
bases_w or [space.w_object], dict_w)
self.__flags__ = _CPYTYPE # mainly disables lookup optimizations
-class W_PyCObject(Wrappable):
- def __init__(self, space):
+class __extend__(W_Root):
+ __metaclass__ = extendabletype
+ __slots__ = ("_pyolifeline", )
+ _pyolifeline = None
+ def set_pyolifeline(self, lifeline):
+ self._pyolifeline = lifeline
+ def get_pyolifeline(self):
+ return self._pyolifeline
+
+class PyOLifeline(object):
+ def __init__(self, space, pyo):
+ self.pyo = pyo
self.space = space
- def set_dual(self, w_obj):
- self.w_dual = w_obj
-
def __del__(self):
- Py_DecRef(self.space, self)
+ if self.pyo:
+ assert self.pyo.c_ob_refcnt == 0
+ _Py_Dealloc(self.space, self.pyo)
+ self.pyo = lltype.nullptr(PyObject.TO)
+ # XXX handle borrowed objects here
+class GettersAndSetters:
def getter(self, space, w_self):
return generic_cpy_call(
space, self.getset.c_get, w_self,
@@ -158,15 +209,44 @@
def member_setter(self, space, w_self, w_value):
PyMember_SetOne(space, w_self, self.member, w_value)
-class W_PyCObjectDual(W_PyCObject):
- def __init__(self, space):
- self.space = space
+def c_type_descr__call__(space, w_type, __args__):
+ if isinstance(w_type, W_PyCTypeObject):
+ pyo = make_ref(space, w_type)
+ pto = rffi.cast(PyTypeObjectPtr, pyo)
+ tp_new = pto.c_tp_new
+ try:
+ if tp_new:
+ args_w, kw_w = __args__.unpack()
+ w_args = space.newtuple(args_w)
+ w_kw = space.newdict()
+ for key, w_obj in kw_w.items():
+ space.setitem(w_kw, space.wrap(key), w_obj)
+ return generic_cpy_call(space, tp_new, pto, w_args, w_kw)
+ else:
+ raise operationerrfmt(space.w_TypeError,
+ "cannot create '%s' instances", w_type.getname(space, '?'))
+ finally:
+ Py_DecRef(space, pyo)
+ else:
+ return call__Type(space, w_type, __args__)
- def set_pycobject(self, w_pycobject):
- self.w_pycobject = ref(w_pycobject)
+def c_type_descr__new__(space, w_typetype, w_name, w_bases, w_dict):
+ # copied from typetype.descr__new__, XXX missing logic: metaclass resolving
+ w_typetype = _precheck_for_new(space, w_typetype)
+
+ bases_w = space.fixedview(w_bases)
+ name = space.str_w(w_name)
+ dict_w = {}
+ dictkeys_w = space.listview(w_dict)
+ for w_key in dictkeys_w:
+ key = space.str_w(w_key)
+ dict_w[key] = space.getitem(w_dict, w_key)
+ w_type = space.allocate_instance(W_PyCTypeObject, w_typetype)
+ W_TypeObject.__init__(w_type, space, name, bases_w or [space.w_object],
+ dict_w)
+ w_type.ready()
+ return w_type
- def __del__(self): # ok, subclassing isnt so sensible here
- pass
@cpython_api([PyObject], lltype.Void, external=False)
def subtype_dealloc(space, obj):
@@ -202,12 +282,14 @@
def type_dealloc(space, obj):
state = space.fromcache(State)
obj_pto = rffi.cast(PyTypeObjectPtr, obj)
+ if not obj_pto.c_tp_name or "C_type" == rffi.charp2str(obj_pto.c_tp_name):
+ import pdb; pdb.set_trace()
type_pto = rffi.cast(PyTypeObjectPtr, obj.c_ob_type)
base_pyo = rffi.cast(PyObject, obj_pto.c_tp_base)
- Py_DecRef(space, base_pyo)
Py_DecRef(space, obj_pto.c_tp_bases)
Py_DecRef(space, obj_pto.c_tp_cache) # lets do it like cpython
if obj_pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE:
+ Py_DecRef(space, base_pyo)
lltype.free(obj_pto.c_tp_name, flavor="raw")
obj_pto_voidp = rffi.cast(rffi.VOIDP_real, obj_pto)
generic_cpy_call(space, type_pto.c_tp_free, obj_pto_voidp)
@@ -219,7 +301,6 @@
""" Allocates a pto from a w_type which must be a PyPy type. """
state = space.fromcache(State)
from pypy.module.cpyext.object import PyObject_dealloc, PyObject_Del
- assert not isinstance(w_type, W_PyCTypeObject)
assert isinstance(w_type, W_TypeObject)
pto = lltype.malloc(PyTypeObject, flavor="raw", zero=True)
@@ -264,9 +345,16 @@
PyPyType_Ready(space, pto, w_type)
else:
pto.c_ob_type = lltype.nullptr(PyObject.TO)
+ if space.is_w(w_type, space.w_object):
+ pto.c_tp_basicsize = rffi.sizeof(PyObject.TO)
+ elif space.is_w(w_type, space.w_type):
+ pto.c_tp_basicsize = rffi.sizeof(PyTypeObject)
+ elif space.is_w(w_type, space.w_str):
+ pto.c_tp_basicsize = rffi.sizeof(PyStringObject.TO)
+ elif pto.c_tp_base:
+ pto.c_tp_basicsize = pto.c_tp_base.c_tp_basicsize
- # XXX fill slots in pto
- # would look like fixup_slot_dispatchers()
+ update_all_slots(space, w_type, pto)
return pto
@cpython_api([PyTypeObjectPtr], rffi.INT_real, error=-1)
@@ -283,7 +371,7 @@
base = pto.c_tp_base
if not base and not (w_obj is not None and
space.is_w(w_obj, space.w_object)):
- base_pyo = make_ref(space, space.w_object)
+ base_pyo = make_ref(space, space.w_object, steal=True)
base = pto.c_tp_base = rffi.cast(PyTypeObjectPtr, base_pyo)
else:
base_pyo = rffi.cast(PyObject, base)
@@ -301,7 +389,9 @@
if w_obj is None:
PyPyType_Register(space, pto)
# missing:
- # inherit_special, inherit_slots, setting __doc__ if not defined and tp_doc defined
+ if base:
+ inherit_special(space, pto, base)
+ # inherit_slots, setting __doc__ if not defined and tp_doc defined
# inheriting tp_as_* slots
# unsupported:
# tp_mro, tp_subclasses
@@ -324,8 +414,8 @@
w_obj.ready()
return 1
-W_PyCObject.typedef = W_ObjectObject.typedef
-
W_PyCTypeObject.typedef = TypeDef(
- 'C_type', W_TypeObject.typedef
+ 'C_type', W_TypeObject.typedef,
+ __call__ = interp2app(c_type_descr__call__, unwrap_spec=[ObjSpace, W_Root, Arguments]),
+ __new__ = interp2app(c_type_descr__new__),
)
More information about the Pypy-commit
mailing list