Author: Armin Rigo <[email protected]>
Branch: cpyext-gc-support-2
Changeset: r81953:3d1f9e7d01e1
Date: 2016-01-26 19:10 +0100
http://bitbucket.org/pypy/pypy/changeset/3d1f9e7d01e1/
Log: in-progress
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
@@ -2,9 +2,11 @@
from pypy.interpreter.baseobjspace import W_Root, SpaceCache
from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rtyper.extregistry import ExtRegistryEntry
from pypy.module.cpyext.api import (
cpython_api, bootstrap_function, PyObject, PyObjectP, ADDR,
- CANNOT_FAIL, Py_TPFLAGS_HEAPTYPE, PyTypeObjectPtr)
+ CANNOT_FAIL, Py_TPFLAGS_HEAPTYPE, PyTypeObjectPtr,
+ INTERPLEVEL_API)
from pypy.module.cpyext.state import State
from pypy.objspace.std.typeobject import W_TypeObject
from pypy.objspace.std.objectobject import W_ObjectObject
@@ -151,10 +153,9 @@
def create_ref(space, w_obj, itemcount=0):
"""
Allocates a PyObject, and fills its fields with info from the given
- intepreter object.
+ interpreter object.
"""
- GOES_AWAY
- state = space.fromcache(RefcountState)
+ #state = space.fromcache(RefcountState)
w_type = space.type(w_obj)
if w_type.is_cpytype():
py_obj = state.get_from_lifeline(w_obj)
@@ -173,18 +174,16 @@
"""
Ties together a PyObject and an interpreter object.
"""
- GOES_AWAY
# XXX looks like a PyObject_GC_TRACK
- ptr = rffi.cast(ADDR, py_obj)
- state = space.fromcache(RefcountState)
+ assert py_obj.c_ob_refcnt < rawrefcount.REFCNT_FROM_PYPY
+ py_obj.c_ob_refcnt += rawrefcount.REFCNT_FROM_PYPY
if DEBUG_REFCOUNT:
debug_refcount("MAKREF", py_obj, w_obj)
+ assert w_obj
+ assert py_obj
if not replace:
assert w_obj not in state.py_objects_w2r
- assert ptr not in state.py_objects_r2w
- state.py_objects_w2r[w_obj] = py_obj
- if ptr: # init_typeobject() bootstraps with NULL references
- state.py_objects_r2w[ptr] = w_obj
+ rawrefcount.create_link_pypy(py_obj, w_obj)
def make_ref(space, w_obj):
"""
@@ -232,6 +231,124 @@
return get_typedescr(w_type.instancetypedef).realize(space, ref)
+def debug_collect():
+ rawrefcount._collect(track_allocation=False)
+
+
+def as_pyobj(space, w_obj):
+ """
+ Returns a 'PyObject *' representing the given intepreter object.
+ This doesn't give a new reference, but the returned 'PyObject *'
+ is valid at least as long as 'w_obj' is. To be safe, you should
+ use keepalive_until_here(w_obj) some time later.
+
+ NOTE: get_pyobj_and_incref() is safer.
+ """
+ if w_obj is not None:
+ assert not is_pyobj(w_obj)
+ return XXXXXXXXXXX
+ else:
+ return lltype.nullptr(PyObject.TO)
+as_pyobj._always_inline_ = 'try'
+INTERPLEVEL_API['as_pyobj'] = as_pyobj
+
+def pyobj_has_w_obj(pyobj):
+ return rawrefcount.to_obj(W_Root, pyobj) is not None
+INTERPLEVEL_API['pyobj_has_w_obj'] = staticmethod(pyobj_has_w_obj)
+
[email protected]()
+def from_pyobj(space, pyobj):
+ assert is_pyobj(pyobj)
+ if pyobj:
+ pyobj = rffi.cast(PyObject, pyobj)
+ w_obj = rawrefcount.to_obj(W_Root, pyobj)
+ if w_obj is None:
+ XXXXXXXXXXX
+ return w_obj
+ else:
+ return None
+from_pyobj._always_inline_ = 'try'
+INTERPLEVEL_API['from_pyobj'] = from_pyobj
+
+
+def is_pyobj(x):
+ if x is None or isinstance(x, W_Root):
+ return False
+ elif is_PyObject(lltype.typeOf(x)):
+ return True
+ else:
+ raise TypeError(repr(type(x)))
+INTERPLEVEL_API['is_pyobj'] = staticmethod(is_pyobj)
+
+class Entry(ExtRegistryEntry):
+ _about_ = is_pyobj
+ def compute_result_annotation(self, s_x):
+ from rpython.rtyper.llannotation import SomePtr
+ return self.bookkeeper.immutablevalue(isinstance(s_x, SomePtr))
+ def specialize_call(self, hop):
+ hop.exception_cannot_occur()
+ return hop.inputconst(lltype.Bool, hop.s_result.const)
+
[email protected]()
+def get_pyobj_and_incref(space, obj):
+ """Increment the reference counter of the PyObject and return it.
+ Can be called with either a PyObject or a W_Root.
+ """
+ if obj:
+ if is_pyobj(obj):
+ pyobj = rffi.cast(PyObject, obj)
+ else:
+ pyobj = as_pyobj(space, obj)
+ assert pyobj.c_ob_refcnt > 0
+ pyobj.c_ob_refcnt += 1
+ if not is_pyobj(obj):
+ keepalive_until_here(obj)
+ return pyobj
+ else:
+ return lltype.nullptr(PyObject.TO)
+INTERPLEVEL_API['get_pyobj_and_incref'] = get_pyobj_and_incref
+
+
[email protected]()
+def get_w_obj_and_decref(space, obj):
+ """Decrement the reference counter of the PyObject and return the
+ corresponding W_Root object (so the reference count is at least
+ REFCNT_FROM_PYPY and cannot be zero). Can be called with either
+ a PyObject or a W_Root.
+ """
+ if is_pyobj(obj):
+ pyobj = rffi.cast(PyObject, obj)
+ w_obj = from_pyobj(space, pyobj)
+ else:
+ w_obj = obj
+ pyobj = as_pyobj(space, w_obj)
+ if pyobj:
+ pyobj.c_ob_refcnt -= 1
+ assert pyobj.c_ob_refcnt >= rawrefcount.REFCNT_FROM_PYPY
+ keepalive_until_here(w_obj)
+ return w_obj
+INTERPLEVEL_API['get_w_obj_and_decref'] = get_w_obj_and_decref
+
+
[email protected]()
+def incref(space, obj):
+ get_pyobj_and_incref(space, obj)
+INTERPLEVEL_API['incref'] = incref
+
[email protected]()
+def decref(space, obj):
+ if is_pyobj(obj):
+ obj = rffi.cast(PyObject, obj)
+ if obj:
+ assert obj.c_ob_refcnt > 0
+ obj.c_ob_refcnt -= 1
+ if obj.c_ob_refcnt == 0:
+ _Py_Dealloc(space, obj)
+ else:
+ get_w_obj_and_decref(space, obj)
+INTERPLEVEL_API['decref'] = decref
+
+
@cpython_api([PyObject], lltype.Void)
def Py_IncRef(space, obj):
incref(obj)
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
@@ -21,7 +21,8 @@
from pypy.module.cpyext.modsupport import convert_method_defs
from pypy.module.cpyext.pyobject import (
PyObject, make_ref, create_ref, from_ref, get_typedescr, make_typedescr,
- track_reference, RefcountState, borrow_from, Py_DecRef)
+ track_reference, RefcountState, borrow_from, Py_DecRef,
+ get_pyobj_and_incref)
from pypy.module.cpyext.slotdefs import (
slotdefs_for_tp_slots, slotdefs_for_wrappers, get_slot_tp_function)
from pypy.module.cpyext.state import State
@@ -320,13 +321,13 @@
# - object.tp_bases is a tuple
# - tuple.tp_bases is a tuple
- # insert null placeholders to please create_ref()
- track_reference(space, lltype.nullptr(PyObject.TO), space.w_type)
- track_reference(space, lltype.nullptr(PyObject.TO), space.w_object)
- track_reference(space, lltype.nullptr(PyObject.TO), space.w_tuple)
- track_reference(space, lltype.nullptr(PyObject.TO), space.w_str)
-
- # create the objects
+ # we create the types manually here
+ py_type = _type_alloc(space, lltype.nullptr(PyTypeObject))
+ py_object = _type_alloc(space, lltype.nullptr(PyTypeObject))
+ py_tuple = _type_alloc(space, lltype.nullptr(PyTypeObject))
+ py_str = _type_alloc(space, lltype.nullptr(PyTypeObject))
+ ...
+
py_type = create_ref(space, space.w_type)
py_object = create_ref(space, space.w_object)
py_tuple = create_ref(space, space.w_tuple)
@@ -459,13 +460,16 @@
def type_alloc(space, w_metatype):
- metatype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_metatype))
+ metatype = get_pyobj_and_incref(space, w_metatype)
+ metatype = rffi.cast(PyTypeObjectPtr, metatype)
+ assert metatype
# Don't increase refcount for non-heaptypes
- if metatype:
- flags = rffi.cast(lltype.Signed, metatype.c_tp_flags)
- if not flags & Py_TPFLAGS_HEAPTYPE:
- Py_DecRef(space, w_metatype)
+ flags = rffi.cast(lltype.Signed, metatype.c_tp_flags)
+ if not flags & Py_TPFLAGS_HEAPTYPE:
+ Py_DecRef(space, w_metatype)
+ return _type_alloc(space, metatype)
+def _type_alloc(space, metatype):
heaptype = lltype.malloc(PyHeapTypeObject.TO,
flavor='raw', zero=True)
pto = heaptype.c_ht_type
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit