[pypy-commit] pypy cpyext-gc-support: slowly-in-progress
arigo
noreply at buildbot.pypy.org
Tue Oct 20 05:42:28 EDT 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: cpyext-gc-support
Changeset: r80349:8294b8657c71
Date: 2015-10-20 11:42 +0200
http://bitbucket.org/pypy/pypy/changeset/8294b8657c71/
Log: slowly-in-progress
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -681,9 +681,11 @@
print 'Fatal error in cpyext, CPython compatibility layer, calling', callable.__name__
print 'Either report a bug or consider not using this particular extension'
if not we_are_translated():
+ tb = sys.exc_info()[2]
import traceback
traceback.print_exc()
- print str(e)
+ if sys.stdout == sys.__stdout__:
+ import pdb; pdb.post_mortem(tb)
# we can't do much here, since we're in ctypes, swallow
else:
print str(e)
@@ -728,9 +730,9 @@
compilation_info=eci, _nowrapper=True)
def init_types(space):
from pypy.module.cpyext.typeobject import py_type_ready
- #py_type_ready(space, get_buffer_type()) ZZZ
- #py_type_ready(space, get_cobject_type()) ZZZ
- #py_type_ready(space, get_capsule_type()) ZZZ
+ py_type_ready(space, get_buffer_type())
+ py_type_ready(space, get_cobject_type())
+ py_type_ready(space, get_capsule_type())
INIT_FUNCTIONS.append(init_types)
from pypy.module.posix.interp_posix import add_fork_hook
reinit_tls = rffi.llexternal('%sThread_ReInitTLS' % prefix, [], lltype.Void,
diff --git a/pypy/module/cpyext/intobject.py b/pypy/module/cpyext/intobject.py
--- a/pypy/module/cpyext/intobject.py
+++ b/pypy/module/cpyext/intobject.py
@@ -23,7 +23,7 @@
setup_class_for_cpyext(W_AbstractIntObject,
basestruct=PyIntObject.TO,
fill_pyobj=int_fill_pyobj,
- realize=int_realize,
+ fill_pypy=int_fill_pypy,
realize_subclass_of=W_IntObject)
def int_fill_pyobj(space, w_obj, py_int):
@@ -33,8 +33,12 @@
"""
py_int.c_ob_ival = space.int_w(w_obj)
-def int_realize(space, w_obj, py_obj):
- intval = rffi.cast(lltype.Signed, rffi.cast(PyIntObject, py_obj).c_ob_ival)
+def int_fill_pypy(space, w_obj, py_obj):
+ """
+ Fills a W_IntObject from a PyIntObject.
+ """
+ py_int = rffi.cast(PyIntObject, py_obj)
+ intval = rffi.cast(lltype.Signed, py_int.c_ob_ival)
W_IntObject.__init__(w_obj, intval)
PyInt_Check, PyInt_CheckExact = build_type_checkers("Int")
diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py
--- a/pypy/module/cpyext/methodobject.py
+++ b/pypy/module/cpyext/methodobject.py
@@ -12,7 +12,7 @@
METH_STATIC, METH_VARARGS, PyObject, PyObjectFields, bootstrap_function,
build_type_checkers, cpython_api, cpython_struct, generic_cpy_call)
from pypy.module.cpyext.pyobject import (
- Py_DecRef, from_ref, make_ref, make_typedescr)
+ Py_DecRef, from_pyobj, make_ref, make_typedescr)
PyCFunction_typedef = rffi.COpaquePtr(typedef='PyCFunction')
PyCFunction = lltype.Ptr(lltype.FuncType([PyObject, PyObject], PyObject))
diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py
--- a/pypy/module/cpyext/pyobject.py
+++ b/pypy/module/cpyext/pyobject.py
@@ -142,16 +142,18 @@
"""NOT_RPYTHON
basestruct: The basic structure to allocate
- alloc_pyobj: default create_pyobj calls this to get the PyObject
- fill_pyobj: default create_pyobj calls this after attaching is done
- realize : Function called to create a pypy object from a PyObject
+ alloc_pyobj: function called to get the PyObject
+ fill_pyobj: called to fill the PyObject after attaching is done
+ alloc_pypy: function called to create a PyPy object from a PyObject
+ fill_pypy: called to fill the PyPy object after attaching is done
dealloc : a cpython_api(external=False), similar to PyObject_dealloc
"""
tp_basestruct = kw.pop('basestruct', PyObject.TO)
tp_alloc_pyobj = kw.pop('alloc_pyobj', None)
tp_fill_pyobj = kw.pop('fill_pyobj', None)
- tp_realize = kw.pop('realize', None)
+ tp_alloc_pypy = kw.pop('alloc_pypy', None)
+ tp_fill_pypy = kw.pop('fill_pypy', None)
force_create_pyobj = kw.pop('force_create_pyobj', False)
realize_subclass_of = kw.pop('realize_subclass_of', None)
#tp_dealloc = kw.pop('dealloc', None)
@@ -173,10 +175,10 @@
pass
#
def cpyext_create_pyobj(self, space):
- py_obj, light = tp_alloc_pyobj(space, self)
+ py_obj, is_light = tp_alloc_pyobj(space, self)
ob = rffi.cast(PyObject, py_obj)
ob_type = get_c_ob_type(space, space.type(self))
- init_link_pypy(self, ob, ob_type, light)
+ init_link_from_pypy(self, ob, ob_type, is_light)
tp_fill_pyobj(space, self, py_obj)
return ob
W_Class.cpyext_create_pyobj = cpyext_create_pyobj
@@ -190,37 +192,56 @@
keepalive_until_here(self)
W_Class.cpyext_fill_prebuilt_pyobj = cpyext_fill_prebuilt_pyobj
- if tp_realize or realize_subclass_of:
- W_CPyExtPlaceHolder = get_cpyextplaceholder_subclass(
- realize_subclass_of or W_Class)
- if tp_realize:
- tp_realize._always_inline_ = True
+ if tp_alloc_pyobj or tp_fill_pyobj or realize_subclass_of:
+ if realize_subclass_of is None:
+ realize_subclass_of = W_Class
+ assert 'typedef' in realize_subclass_of.__dict__, (
+ "no 'typedef' exactly on %s" % (realize_subclass_of,))
#
- def cpyext_realize(space, pyobj):
- w_obj = W_CPyExtPlaceHolder(pyobj)
- if tp_realize:
- tp_realize(space, w_obj, pyobj)
+ if not tp_alloc_pypy:
+ W_CPyExtPlaceHolder = get_cpyextplaceholder_subclass(
+ realize_subclass_of)
+ def tp_alloc_pypy(space, pyobj):
+ w_obj = W_CPyExtPlaceHolder(pyobj)
+ return w_obj, True
+ tp_alloc_pypy._always_inline_ = True
+ #
+ if not tp_fill_pypy:
+ def tp_fill_pypy(space, w_obj, pyobj):
+ pass
+ #
+ def cpyext_create_pypy(space, pyobj):
+ w_obj, is_transient = tp_alloc_pypy(space, pyobj)
+ init_link_from_pyobj(w_obj, pyobj, is_transient)
+ tp_fill_pypy(space, w_obj, pyobj)
return w_obj
#
typedef = realize_subclass_of.typedef
- assert not hasattr(typedef, 'cpyext_realize')
- typedef.cpyext_realize = cpyext_realize
+ assert 'cpyext_create_pypy' not in typedef.__dict__
+ typedef.cpyext_create_pypy = cpyext_create_pypy
W_Class.cpyext_basestruct = tp_basestruct
-def init_link_pypy(w_obj, ob, ob_type, light):
- if light:
+def init_link_from_pypy(w_obj, ob, ob_type, is_light):
+ if is_light:
ob.c_ob_refcnt = rawrefcount.REFCNT_FROM_PYPY_LIGHT
else:
ob.c_ob_refcnt = rawrefcount.REFCNT_FROM_PYPY
- ob.c_ob_pypy_link = 0
ob.c_ob_type = ob_type
rawrefcount.create_link_pypy(w_obj, ob)
+def init_link_from_pyobj(w_obj, ob, is_transient):
+ if is_transient:
+ rawrefcount.create_link_pyobj(w_obj, ob)
+ else:
+ rawrefcount.create_link_pypy(w_obj, ob)
+ ob.c_ob_refcnt += rawrefcount.REFCNT_FROM_PYPY
+
def setup_prebuilt_pyobj(w_obj, py_obj):
assert lltype.typeOf(py_obj) == PyObject
- init_link_pypy(w_obj, py_obj, lltype.nullptr(PyTypeObjectPtr.TO), False)
+ init_link_from_pypy(w_obj, py_obj, lltype.nullptr(PyTypeObjectPtr.TO),
+ False)
if isinstance(w_obj, W_TypeObject):
w_obj.cpyext_c_type_object = rffi.cast(PyTypeObjectPtr, py_obj)
@@ -236,6 +257,9 @@
def init_pyobject(space):
setup_class_for_cpyext(W_Root, force_create_pyobj=True,
realize_subclass_of=W_ObjectObject)
+ # use this cpyext_create_pypy as the default for all other TypeDefs
+ from pypy.interpreter.typedef import TypeDef
+ TypeDef.cpyext_create_pypy = W_ObjectObject.typedef.cpyext_create_pypy
#________________________________________________________
@@ -262,6 +286,8 @@
def cpyext_as_pyobj(self, space):
return self.cpyext_pyobj
+ # ZZZ getclass(), getweakref(), etc.? like interpreter/typedef.py
+
W_CPyExtPlaceHolder.__name__ = W_Class.__name__ + '_CPyExtPlaceHolder'
W_Class._cpyextplaceholder_subclass = W_CPyExtPlaceHolder
return W_CPyExtPlaceHolder
@@ -284,8 +310,8 @@
W_TypeObject._cpyextplaceholder_subclass = W_TypeObject
def _create_w_obj_from_pyobj(space, pyobj):
- w_type = from_pyobj(pyobj.c_ob_type)
- return w_type.instancetypedef.cpyext_realize(space, pyobj)
+ w_type = from_pyobj(space, pyobj.c_ob_type)
+ return w_type.instancetypedef.cpyext_create_pypy(space, pyobj)
#________________________________________________________
# refcounted object support
diff --git a/pypy/module/cpyext/state.py b/pypy/module/cpyext/state.py
--- a/pypy/module/cpyext/state.py
+++ b/pypy/module/cpyext/state.py
@@ -82,8 +82,8 @@
if we_are_translated():
refcountstate = space.fromcache(RefcountState)
refcountstate.init_r2w_from_w2r()
+ rawrefcount.init(lambda ob: ZZZ)
- rawrefcount.init(lambda ob: ZZZ)
for func in INIT_FUNCTIONS:
func(space)
self.check_and_raise_exception()
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -1,7 +1,7 @@
import os
from rpython.rlib import jit
-from rpython.rlib.objectmodel import specialize
+from rpython.rlib.objectmodel import specialize, instantiate
from rpython.rlib.rstring import rsplit
from rpython.rtyper.annlowlevel import llhelper
from rpython.rtyper.lltypesystem import rffi, lltype
@@ -280,34 +280,13 @@
check_descr(space, w_self, self.w_type)
PyMember_SetOne(space, w_self, self.member, w_value)
-class W_PyCTypeObject(W_TypeObject):
- @jit.dont_look_inside
- def __init__(self, space, pto):
- bases_w = space.fixedview(from_ref(space, pto.c_tp_bases))
- dict_w = {}
-
- add_operators(space, dict_w, pto)
- convert_method_defs(space, dict_w, pto.c_tp_methods, self)
- convert_getset_defs(space, dict_w, pto.c_tp_getset, self)
- convert_member_defs(space, dict_w, pto.c_tp_members, self)
-
- name = rffi.charp2str(pto.c_tp_name)
-
- W_TypeObject.__init__(self, space, name,
- bases_w or [space.w_object], dict_w)
- if not space.is_true(space.issubtype(self, space.w_type)):
- self.flag_cpytype = True
- self.flag_heaptype = False
- if pto.c_tp_doc:
- self.w_doc = space.wrap(rffi.charp2str(pto.c_tp_doc))
-
@bootstrap_function
def init_typeobject(space):
setup_class_for_cpyext(W_TypeObject,
basestruct=PyTypeObject,
alloc_pyobj=type_alloc_pyobj,
- fill_pyobj=type_fill_pyobj)
- #realize=type_realize,
+ fill_pyobj=type_fill_pyobj,
+ alloc_pypy=type_alloc_pypy)
#dealloc=type_dealloc)
# some types are difficult to create because of cycles.
@@ -482,6 +461,7 @@
def type_alloc_pyobj(space, w_type):
pto = lltype.malloc(PyTypeObject, flavor='raw', zero=True,
track_allocation=False)
+ pto.c_tp_flags |= Py_TPFLAGS_READYING
return pto, False
def type_fill_pyobj(space, w_type, pto):
@@ -489,6 +469,9 @@
Fills a newly allocated PyTypeObject from an existing w_type.
"""
from pypy.module.cpyext.object import PyObject_Del
+ from rpython.rlib import rawrefcount
+
+ assert w_type == rawrefcount.to_obj(W_Root, pto)
assert isinstance(w_type, W_TypeObject)
w_type.cpyext_c_type_object = pto
@@ -526,39 +509,99 @@
w_base = best_base(space, w_type.bases_w)
pto.c_tp_base = rffi.cast(PyTypeObjectPtr,
get_pyobj_and_xincref(space, w_base))
+ w_bases = space.newtuple(w_type.bases_w)
+ pto.c_tp_bases = get_pyobj_and_incref(space, w_bases)
- finish_type_1(space, pto, w_type)
finish_type_2(space, pto, w_type)
#pto.c_tp_basicsize = rffi.sizeof(typedescr.basestruct) ZZZ
+ pto.c_tp_basicsize = rffi.sizeof(PyObject.TO) # ZZZ
if pto.c_tp_base:
if pto.c_tp_base.c_tp_basicsize > pto.c_tp_basicsize:
pto.c_tp_basicsize = pto.c_tp_base.c_tp_basicsize
update_all_slots(space, w_type, pto)
+ pto.c_tp_flags &= ~Py_TPFLAGS_READYING
pto.c_tp_flags |= Py_TPFLAGS_READY
def py_type_ready(space, pto):
- if pto.c_tp_flags & Py_TPFLAGS_READY:
- return
- type_realize(space, rffi.cast(PyObject, pto))
+ if pto.c_tp_flags & Py_TPFLAGS_READY == 0:
+ # this builds the W_TypeObject, and in doing so makes sure the
+ # PyTypeObject is ready.
+ if not pto.c_ob_type:
+ typetype = get_pyobj_and_incref(space, space.w_type)
+ pto.c_ob_type = rffi.cast(PyTypeObjectPtr, typetype)
+ from_pyobj(space, pto)
+ assert pto.c_tp_flags & Py_TPFLAGS_READY
@cpython_api([PyTypeObjectPtr], rffi.INT_real, error=-1)
def PyType_Ready(space, pto):
py_type_ready(space, pto)
return 0
-def type_realize(space, py_obj):
- ZZZ
+ at jit.dont_look_inside
+def type_alloc_pypy(space, py_obj):
pto = rffi.cast(PyTypeObjectPtr, py_obj)
+ assert pto.c_tp_flags & Py_TPFLAGS_READY == 0
assert pto.c_tp_flags & Py_TPFLAGS_READYING == 0
pto.c_tp_flags |= Py_TPFLAGS_READYING
try:
- w_obj = _type_realize(space, py_obj)
+ w_type = _type_realize(space, pto)
finally:
pto.c_tp_flags &= ~Py_TPFLAGS_READYING
pto.c_tp_flags |= Py_TPFLAGS_READY
- return w_obj
+ return w_type, False
+
+def _type_realize(space, pto):
+ assert pto.c_ob_type
+ # ^^^ we can't reach this place if c_ob_type is still NULL
+
+ if not pto.c_tp_base:
+ base = get_pyobj_and_incref(space, space.w_object)
+ pto.c_tp_base = rffi.cast(PyTypeObjectPtr, base)
+ PyType_Ready(space, pto.c_tp_base)
+
+ if not pto.c_tp_bases:
+ w_bases = space.newtuple([from_pyobj(space, pto.c_tp_base)])
+ pto.c_tp_bases = get_pyobj_and_incref(space, w_bases)
+ else:
+ w_bases = from_pyobj(space, pto.c_tp_bases)
+
+ w_metatype = from_pyobj(space, pto.c_ob_type)
+ w_type = space.allocate_instance(W_TypeObject, w_metatype)
+
+ bases_w = space.fixedview(w_bases) or [space.w_object]
+ name = rffi.charp2str(pto.c_tp_name)
+ dict_w = {}
+
+ # best we can do about tp_dict: copy all its string keys into dict_w,
+ # and ignore any non-string key
+ if pto.c_tp_dict:
+ w_org_dict = from_pyobj(space, pto.c_tp_dict)
+ for w_key in space.unpackiterable(w_org_dict):
+ try:
+ key = space.str_w(w_key)
+ dict_w[key] = space.getitem(w_org_dict, w_key)
+ except OperationError, e:
+ if e.async(self):
+ raise
+
+ add_operators(space, dict_w, pto)
+ convert_method_defs(space, dict_w, pto.c_tp_methods, w_type)
+ convert_getset_defs(space, dict_w, pto.c_tp_getset, w_type)
+ convert_member_defs(space, dict_w, pto.c_tp_members, w_type)
+
+ W_TypeObject.__init__(w_type, space, name, bases_w, dict_w)
+
+ if not space.is_true(space.issubtype(self, space.w_type)):
+ w_type.flag_cpytype = True
+ w_type.flag_heaptype = False
+ if pto.c_tp_doc:
+ w_type.w_doc = space.wrap(rffi.charp2str(pto.c_tp_doc))
+
+ finish_type_2(space, pto, w_type)
+ w_type.ready()
+ return w_type
def solid_base(space, w_type):
typedef = w_type.instancetypedef
@@ -584,58 +627,12 @@
if not pto.c_tp_setattro:
pto.c_tp_setattro = base.c_tp_setattro
-def _type_realize(space, py_obj):
- """
- Creates an interpreter type from a PyTypeObject structure.
- """
- # missing:
- # inheriting tp_as_* slots
- # unsupported:
- # tp_mro, tp_subclasses
- py_type = rffi.cast(PyTypeObjectPtr, py_obj)
-
- if not py_type.c_tp_base:
- base = get_pyobj_and_incref(space, space.w_object)
- py_type.c_tp_base = rffi.cast(PyTypeObjectPtr, base)
-
- finish_type_1(space, py_type)
-
- w_metatype = from_ref(space, rffi.cast(PyObject, py_type.c_ob_type))
-
- w_obj = space.allocate_instance(W_PyCTypeObject, w_metatype)
- track_reference(space, py_obj, w_obj)
- w_obj.__init__(space, py_type)
- w_obj.ready()
-
- finish_type_2(space, py_type, w_obj)
-
- state = space.fromcache(RefcountState)
- state.non_heaptypes_w.append(w_obj)
-
- return w_obj
-
-def finish_type_1(space, pto, w_type):
- """
- Sets up tp_bases, necessary before creating the interpreter type.
- """
- #ZZZ
- #base = pto.c_tp_base
- #base_pyo = rffi.cast(PyObject, pto.c_tp_base)
- #if base and not base.c_tp_flags & Py_TPFLAGS_READY:
- # type_realize(space, base_pyo)
- #if base and not pto.c_ob_type: # will be filled later
- # pto.c_ob_type = base.c_ob_type
- assert pto.c_ob_type # ZZZ
- if not pto.c_tp_bases:
- w_bases = space.newtuple(w_type.bases_w)
- pto.c_tp_bases = get_pyobj_and_incref(space, w_bases)
-
-def finish_type_2(space, pto, w_obj):
+def finish_type_2(space, pto, w_type):
"""
Sets up other attributes, when the interpreter type has been created.
"""
if not pto.c_tp_mro:
- pto.c_tp_mro = get_pyobj_and_incref(space, space.newtuple(w_obj.mro_w))
+ pto.c_tp_mro = get_pyobj_and_incref(space, space.newtuple(w_type.mro_w))
base = pto.c_tp_base
if base:
inherit_special(space, pto, base)
@@ -648,11 +645,11 @@
PyObject_GenericSetAttr.api_func.functype,
PyObject_GenericSetAttr.api_func.get_wrapper(space))
- if w_obj.is_cpytype():
- xxxxxxxx
- Py_DecRef(space, pto.c_tp_dict)
- w_dict = w_obj.getdict(space)
- pto.c_tp_dict = make_ref(space, w_dict)
+ w_dict = w_type.getdict(space)
+ old = pto.c_tp_dict
+ pto.c_tp_dict = get_pyobj_and_incref(space, w_dict)
+ if old:
+ Py_DecRef(old)
@cpython_api([PyTypeObjectPtr, PyTypeObjectPtr], rffi.INT_real, error=CANNOT_FAIL)
def PyType_IsSubtype(space, a, b):
diff --git a/rpython/rlib/rawrefcount.py b/rpython/rlib/rawrefcount.py
--- a/rpython/rlib/rawrefcount.py
+++ b/rpython/rlib/rawrefcount.py
@@ -32,8 +32,9 @@
def create_link_pypy(p, ob):
"NOT_RPYTHON: a link where the PyPy object contains some or all the data"
+ #print 'create_link_pypy\n\t%s\n\t%s' % (p, ob)
assert p not in _pypy2ob
- assert not ob.c_ob_pypy_link
+ #assert not ob.c_ob_pypy_link
ob.c_ob_pypy_link = _build_pypy_link(p)
_pypy2ob[p] = ob
_p_list.append(ob)
@@ -41,8 +42,9 @@
def create_link_pyobj(p, ob):
"""NOT_RPYTHON: a link where the PyObject contains all the data.
from_obj() will not work on this 'p'."""
+ #print 'create_link_pyobj\n\t%s\n\t%s' % (p, ob)
assert p not in _pypy2ob
- assert not ob.c_ob_pypy_link
+ #assert not ob.c_ob_pypy_link
ob.c_ob_pypy_link = _build_pypy_link(p)
_o_list.append(ob)
More information about the pypy-commit
mailing list