[pypy-commit] pypy cpyext-gc-support: Start to pass a few tests in test_intobject, after performance
arigo
noreply at buildbot.pypy.org
Tue Oct 20 12:31:17 EDT 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: cpyext-gc-support
Changeset: r80357:45142ab484f1
Date: 2015-10-20 18:18 +0200
http://bitbucket.org/pypy/pypy/changeset/45142ab484f1/
Log: Start to pass a few tests in test_intobject, after performance
improvements to intobject.py and other fixes
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
@@ -381,6 +381,14 @@
INTERPLEVEL_API = {}
FUNCTIONS = {}
+def constant_pyobj(space, name):
+ if we_are_translated():
+ ZZZ # should return the C symbol "Py" + name, constant-folded
+ else:
+ from pypy.module.cpyext.pyobject import as_pyobj
+ w_obj = INTERPLEVEL_API[name]
+ return as_pyobj(space, w_obj)
+
# These are C symbols which cpyext will export, but which are defined in .c
# files somewhere in the implementation of cpyext (rather than being defined in
# RPython).
@@ -496,7 +504,7 @@
GLOBALS['%s#' % (cpyname, )] = ('PyTypeObject*', pypyexpr)
for cpyname in '''PyMethodObject PyListObject PyLongObject
- PyDictObject PyTupleObject PyClassObject'''.split():
+ PyDictObject PyClassObject'''.split():
FORWARD_DECLS.append('typedef struct { PyObject_HEAD } %s'
% (cpyname, ))
build_exported_objects()
@@ -559,25 +567,31 @@
if name in TYPES:
TYPES[name].become(TYPE)
-def build_type_checkers(type_name, cls=None):
+def build_type_checkers3(type_name, cls=None):
"""
Builds two api functions: Py_XxxCheck() and Py_XxxCheckExact().
- if `cls` is None, the type is space.w_[type].
- if `cls` is a string, it is the name of a space attribute, e.g. 'w_str'.
- else `cls` must be a W_Class with a typedef.
"""
+ py_type_name = "Py" + type_name + "_Type"
+ check_name = "Py" + type_name + "_Check"
+
if cls is None:
- attrname = "w_" + type_name.lower()
- def get_w_type(space):
- return getattr(space, attrname)
- elif isinstance(cls, str):
+ cls = "w_" + type_name.lower()
+ if isinstance(cls, str):
def get_w_type(space):
return getattr(space, cls)
+ def _PyXxx_Type(space):
+ return rffi.cast(PyTypeObjectPtr,
+ constant_pyobj(space, py_type_name))
else:
@specialize.memo()
def get_w_type(space):
return space.gettypeobject(cls.typedef)
- check_name = "Py" + type_name + "_Check"
+ def _PyXxx_Type():
+ ZZZ
+ _PyXxx_Type = func_with_new_name(_PyXxx_Type, '_' + py_type_name)
def check(space, w_obj):
"Implements the Py_Xxx_Check function"
@@ -587,15 +601,18 @@
space.is_true(space.issubtype(w_obj_type, w_type)))
def check_exact(space, py_obj):
"Implements the Py_Xxx_CheckExact function"
- py_type = get_w_type(space).cpyext_c_type_object
- assert py_type
- return py_obj.c_ob_type == py_type
+ #py_type = get_w_type(space).cpyext_c_type_object
+ return py_obj.c_ob_type == _PyXxx_Type(space)
check = cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)(
func_with_new_name(check, check_name))
check_exact = cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)(
func_with_new_name(check_exact, check_name + "Exact"))
- return check, check_exact
+ return check, check_exact, _PyXxx_Type
+
+def build_type_checkers(type_name, cls=None):
+ # backward compatibility
+ return build_type_checkers3(type_name, cls=cls)[:2]
pypy_debug_catch_fatal_exception = rffi.llexternal('pypy_debug_catch_fatal_exception', [], lltype.Void)
@@ -793,7 +810,8 @@
struct PyPyAPI {
%(members)s
} _pypyAPI;
- RPY_EXTERN struct PyPyAPI* pypyAPI = &_pypyAPI;
+ RPY_EXTERN struct PyPyAPI* pypyAPI;
+ struct PyPyAPI* pypyAPI = &_pypyAPI;
""" % dict(members=structmembers)
functions = generate_decls_and_callbacks(db, export_symbols)
@@ -848,6 +866,7 @@
INTERPLEVEL_API[name] = w_obj
+ orgname = name
name = name.replace('Py', 'cpyexttest')
if isptr:
ptr = ctypes.c_void_p.in_dll(bridge, name)
diff --git a/pypy/module/cpyext/include/tupleobject.h b/pypy/module/cpyext/include/tupleobject.h
--- a/pypy/module/cpyext/include/tupleobject.h
+++ b/pypy/module/cpyext/include/tupleobject.h
@@ -7,6 +7,11 @@
extern "C" {
#endif
+typedef struct {
+ PyObject_VAR_HEAD
+ PyObject *ob_item[1];
+} PyTupleObject;
+
/* defined in varargswrapper.c */
PyAPI_FUNC(PyObject *) PyTuple_Pack(Py_ssize_t, ...);
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
@@ -2,10 +2,10 @@
from rpython.rtyper.lltypesystem import rffi, lltype
from pypy.interpreter.error import OperationError
from pypy.module.cpyext.api import (
- cpython_api, cpython_struct, build_type_checkers, bootstrap_function,
+ cpython_api, cpython_struct, build_type_checkers3, bootstrap_function,
PyObject, PyObjectFields, CONST_STRING, CANNOT_FAIL, Py_ssize_t)
-from pypy.module.cpyext.pyobject import (
- setup_class_for_cpyext, track_reference, RefcountState, from_ref)
+from pypy.module.cpyext.pyobject import (setup_class_for_cpyext, new_pyobj,
+ from_pyobj)
from rpython.rlib.rarithmetic import r_uint, intmask, LONG_TEST, r_ulonglong
from pypy.objspace.std.intobject import W_IntObject
import sys
@@ -16,15 +16,39 @@
(("ob_ival", rffi.LONG),)
cpython_struct("PyIntObject", PyIntObjectFields, PyIntObjectStruct)
+PyInt_Check, PyInt_CheckExact, _PyInt_Type = build_type_checkers3("Int")
+
+
@bootstrap_function
def init_intobject(space):
"Type description of PyIntObject"
from pypy.objspace.std.intobject import W_AbstractIntObject, W_IntObject
- setup_class_for_cpyext(W_AbstractIntObject,
- basestruct=PyIntObject.TO,
- fill_pyobj=int_fill_pyobj,
- fill_pypy=int_fill_pypy,
- realize_subclass_of=W_IntObject)
+ setup_class_for_cpyext(
+ # --the base class of all 'int' objects inside PyPy--
+ W_AbstractIntObject,
+
+ # --the structure type derived from PyObject--
+ basestruct=PyIntObjectStruct,
+
+ # --after a PyIntObject is allocated, we call this function to
+ # fill it. It gets attached as RRC_PERMANENT_LIGHT by default,
+ # which means the association is permanent (the PyIntObject is
+ # alive and won't appear to move as long as the W_IntObject is
+ # alive) and light (the PyIntObject can be freed with free()).--
+ fill_pyobj=int_fill_pyobj,
+
+ # --reverse direction: from a PyIntObject, we make a W_IntObject
+ # by instantiating a custom subclass of W_IntObject--
+ realize_subclass_of=W_IntObject,
+
+ # --and then we call this function to initialize the W_IntObject--
+ fill_pypy=int_fill_pypy,
+
+ # --in this case, and if PyInt_CheckExact() returns True, then
+ # the link can be light, i.e. the original PyIntObject might
+ # be freed with free() by the GC--
+ alloc_pypy_light_if=PyInt_CheckExact,
+ )
def int_fill_pyobj(space, w_obj, py_int):
"""
@@ -41,8 +65,6 @@
intval = rffi.cast(lltype.Signed, py_int.c_ob_ival)
W_IntObject.__init__(w_obj, intval)
-PyInt_Check, PyInt_CheckExact = build_type_checkers("Int")
-
@cpython_api([], lltype.Signed, error=CANNOT_FAIL)
def PyInt_GetMax(space):
"""Return the system's idea of the largest integer it can handle (LONG_MAX,
@@ -52,19 +74,23 @@
@cpython_api([lltype.Signed], PyObject)
def PyInt_FromLong(space, ival):
"""Create a new integer object with a value of ival.
-
"""
- return space.wrap(ival)
+ py_int = new_pyobj(PyIntObjectStruct, _PyInt_Type(space))
+ py_int.c_ob_ival = ival
+ return rffi.cast(PyObject, py_int)
@cpython_api([PyObject], lltype.Signed, error=-1)
-def PyInt_AsLong(space, w_obj):
+def PyInt_AsLong(space, py_obj):
"""Will first attempt to cast the object to a PyIntObject, if it is not
already one, and then return its value. If there is an error, -1 is
returned, and the caller should check PyErr_Occurred() to find out whether
there was an error, or whether the value just happened to be -1."""
- if w_obj is None:
+ if not py_obj:
raise OperationError(space.w_TypeError,
space.wrap("an integer is required, got NULL"))
+ if PyInt_Check(space, py_obj):
+ return PyInt_AS_LONG(space, py_obj)
+ w_obj = from_pyobj(space, py_obj)
return space.int_w(space.int(w_obj))
@cpython_api([PyObject], lltype.Unsigned, error=-1)
@@ -108,9 +134,10 @@
return num.ulonglongmask()
@cpython_api([PyObject], lltype.Signed, error=CANNOT_FAIL)
-def PyInt_AS_LONG(space, w_int):
+def PyInt_AS_LONG(space, py_obj):
"""Return the value of the object w_int. No error checking is performed."""
- return space.int_w(w_int)
+ py_int = rffi.cast(PyIntObject, py_obj)
+ return py_int.c_ob_ival
@cpython_api([PyObject], Py_ssize_t, error=-1)
def PyInt_AsSsize_t(space, w_obj):
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
@@ -14,130 +14,21 @@
from rpython.rtyper.annlowlevel import llhelper
from rpython.rlib import rawrefcount
-#________________________________________________________
-# type description ZZZ SEE BELOW
-
-class BaseCpyTypedescr(object):
- basestruct = PyObject.TO
- W_BaseObject = W_ObjectObject
-
- def get_dealloc(self, space):
- from pypy.module.cpyext.typeobject import subtype_dealloc
- return llhelper(
- subtype_dealloc.api_func.functype,
- subtype_dealloc.api_func.get_wrapper(space))
-
- def allocate(self, space, w_type, itemcount=0):
- # similar to PyType_GenericAlloc?
- # except that it's not related to any pypy object.
-
- pytype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_type))
- # Don't increase refcount for non-heaptypes
- if pytype:
- flags = rffi.cast(lltype.Signed, pytype.c_tp_flags)
- if not flags & Py_TPFLAGS_HEAPTYPE:
- Py_DecRef(space, w_type)
-
- if pytype:
- size = pytype.c_tp_basicsize
- else:
- size = rffi.sizeof(self.basestruct)
- if itemcount:
- size += itemcount * pytype.c_tp_itemsize
- buf = lltype.malloc(rffi.VOIDP.TO, size,
- flavor='raw', zero=True)
- pyobj = rffi.cast(PyObject, buf)
- pyobj.c_ob_refcnt = 1
- pyobj.c_ob_type = pytype
- return pyobj
-
- def attach(self, space, pyobj, w_obj):
- pass
-
- def realize(self, space, obj):
- w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
- w_obj = space.allocate_instance(self.W_BaseObject, w_type)
- track_reference(space, obj, w_obj)
- if w_type is not space.gettypefor(self.W_BaseObject):
- state = space.fromcache(RefcountState)
- state.set_lifeline(w_obj, obj)
- return w_obj
-
-def make_typedescr(typedef, **kw):
- return #ZZZ
- """NOT_RPYTHON
-
- basestruct: The basic structure to allocate
- alloc : allocate and basic initialization of a raw PyObject
- attach : Function called to tie a raw structure to a pypy object
- realize : Function called to create a pypy object from a raw struct
- dealloc : a cpython_api(external=False), similar to PyObject_dealloc
- """
-
- tp_basestruct = kw.pop('basestruct', PyObject.TO)
- tp_alloc = kw.pop('alloc', None)
- tp_attach = kw.pop('attach', None)
- tp_realize = kw.pop('realize', None)
- tp_dealloc = kw.pop('dealloc', None)
- assert not kw, "Extra arguments to make_typedescr"
-
- null_dealloc = lltype.nullptr(lltype.FuncType([PyObject], lltype.Void))
-
- class CpyTypedescr(BaseCpyTypedescr):
- basestruct = tp_basestruct
-
- if tp_alloc:
- def allocate(self, space, w_type, itemcount=0):
- return tp_alloc(space, w_type)
-
- if tp_dealloc:
- def get_dealloc(self, space):
- return llhelper(
- tp_dealloc.api_func.functype,
- tp_dealloc.api_func.get_wrapper(space))
-
- if tp_attach:
- def attach(self, space, pyobj, w_obj):
- tp_attach(space, pyobj, w_obj)
-
- if tp_realize:
- def realize(self, space, ref):
- return tp_realize(space, ref)
- if typedef:
- CpyTypedescr.__name__ = "CpyTypedescr_%s" % (typedef.name,)
-
- typedescr_cache[typedef] = CpyTypedescr()
-
-#@bootstrap_function ZZZ
-def init_pyobject(space):
- from pypy.module.cpyext.object import PyObject_dealloc
- # typedescr for the 'object' type
- make_typedescr(space.w_object.instancetypedef,
- dealloc=PyObject_dealloc)
- # almost all types, which should better inherit from object.
- make_typedescr(None)
-
- at specialize.memo()
-def _get_typedescr_1(typedef):
- ZZZ
- try:
- return typedescr_cache[typedef]
- except KeyError:
- if typedef.bases:
- return _get_typedescr_1(typedef.bases[0])
- return typedescr_cache[None]
-
-def get_typedescr(typedef):
- ZZZ
- if typedef is None:
- return typedescr_cache[None]
- else:
- return _get_typedescr_1(typedef)
-
#________________________________________________________
# type description
+def make_typedescr(arg0, *args, **kwds):
+ print "ZZZ: make_typedescr(%r)" % (arg0,)
+def get_typedescr(*args, **kwds):
+ ZZZ
+RefcountState = "ZZZ"
+
+RRC_PERMANENT = 'P' # the link pyobj<->pypy is permanent
+RRC_PERMANENT_LIGHT = 'p' # same, but tp_dealloc can be replaced with free()
+RRC_TRANSIENT = 'T' # the pypy object is transient and can go away
+RRC_TRANSIENT_LIGHT = 't' # same, but tp_dealloc can be replaced with free()
+
def setup_class_for_cpyext(W_Class, **kw):
"""NOT_RPYTHON
@@ -156,6 +47,7 @@
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)
+ alloc_pypy_light_if = kw.pop('alloc_pypy_light_if', None)
#tp_dealloc = kw.pop('dealloc', None)
assert not kw, "Extra arguments to make_typedescr: %s" % kw.keys()
@@ -167,7 +59,7 @@
def tp_alloc_pyobj(space, w_obj):
ob = lltype.malloc(tp_basestruct, flavor='raw',
track_allocation=False)
- return ob, True
+ return ob, RRC_PERMANENT_LIGHT
tp_alloc_pyobj._always_inline_ = True
#
if not tp_fill_pyobj:
@@ -175,10 +67,11 @@
pass
#
def cpyext_create_pyobj(self, space):
- py_obj, is_light = tp_alloc_pyobj(space, self)
+ py_obj, strength = tp_alloc_pyobj(space, self)
ob = rffi.cast(PyObject, py_obj)
- ob_type = get_c_ob_type(space, space.type(self))
- init_link_from_pypy(self, ob, ob_type, is_light)
+ ob.c_ob_refcnt = 0
+ ob.c_ob_type = get_c_ob_type(space, space.type(self))
+ rawrefcount_init_link(self, ob, strength)
tp_fill_pyobj(space, self, py_obj)
return ob
W_Class.cpyext_create_pyobj = cpyext_create_pyobj
@@ -203,7 +96,11 @@
realize_subclass_of)
def tp_alloc_pypy(space, pyobj):
w_obj = W_CPyExtPlaceHolder(pyobj)
- return w_obj, True
+ strength = RRC_TRANSIENT
+ if alloc_pypy_light_if is not None:
+ if alloc_pypy_light_if(space, pyobj):
+ strength = RRC_TRANSIENT_LIGHT
+ return w_obj, strength
tp_alloc_pypy._always_inline_ = True
#
if not tp_fill_pypy:
@@ -211,8 +108,8 @@
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)
+ w_obj, strength = tp_alloc_pypy(space, pyobj)
+ rawrefcount_init_link(w_obj, pyobj, strength)
tp_fill_pypy(space, w_obj, pyobj)
return w_obj
#
@@ -223,25 +120,30 @@
W_Class.cpyext_basestruct = tp_basestruct
-def init_link_from_pypy(w_obj, ob, ob_type, is_light):
- if is_light:
- ob.c_ob_refcnt = rawrefcount.REFCNT_FROM_PYPY_LIGHT
+def rawrefcount_init_link(w_obj, ob, strength):
+ if strength == RRC_PERMANENT:
+ ob.c_ob_refcnt += rawrefcount.REFCNT_FROM_PYPY
+ rawrefcount.create_link_pypy(w_obj, ob)
+ #
+ elif strength == RRC_PERMANENT_LIGHT:
+ ob.c_ob_refcnt += rawrefcount.REFCNT_FROM_PYPY_LIGHT
+ rawrefcount.create_link_pypy(w_obj, ob)
+ #
+ elif strength == RRC_TRANSIENT:
+ ob.c_ob_refcnt += rawrefcount.REFCNT_FROM_PYPY
+ rawrefcount.create_link_pyobj(w_obj, ob)
+ #
+ elif strength == RRC_TRANSIENT_LIGHT:
+ ob.c_ob_refcnt += rawrefcount.REFCNT_FROM_PYPY_LIGHT
+ rawrefcount.create_link_pyobj(w_obj, ob)
+ #
else:
- ob.c_ob_refcnt = rawrefcount.REFCNT_FROM_PYPY
- ob.c_ob_type = ob_type
- rawrefcount.create_link_pypy(w_obj, ob)
+ assert False, "rawrefcount_init_link: strength=%r" % (strength,)
-def init_link_from_pyobj(w_obj, ob, is_transient):
- ob.c_ob_refcnt += rawrefcount.REFCNT_FROM_PYPY
- if is_transient:
- rawrefcount.create_link_pyobj(w_obj, ob)
- else:
- rawrefcount.create_link_pypy(w_obj, ob)
def setup_prebuilt_pyobj(w_obj, py_obj):
assert lltype.typeOf(py_obj) == PyObject
- init_link_from_pypy(w_obj, py_obj, lltype.nullptr(PyTypeObjectPtr.TO),
- False)
+ rawrefcount_init_link(w_obj, py_obj, RRC_PERMANENT)
if isinstance(w_obj, W_TypeObject):
w_obj.cpyext_c_type_object = rffi.cast(PyTypeObjectPtr, py_obj)
@@ -316,108 +218,6 @@
#________________________________________________________
# refcounted object support
-class RefcountState:
- def __init__(self, space):
- ZZZ
- self.space = space
- self.py_objects_w2r = {} # { w_obj -> raw PyObject }
- self.py_objects_r2w = {} # { addr of raw PyObject -> w_obj }
-
- self.lifeline_dict = RWeakKeyDictionary(W_Root, PyOLifeline)
-
- self.borrow_mapping = {None: {}}
- # { w_container -> { w_containee -> None } }
- # the None entry manages references borrowed during a call to
- # generic_cpy_call()
-
- # For tests
- self.non_heaptypes_w = []
-
- def _cleanup_(self):
- assert self.borrow_mapping == {None: {}}
- self.py_objects_r2w.clear() # is not valid anymore after translation
-
- def init_r2w_from_w2r(self):
- """Rebuilds the dict py_objects_r2w on startup"""
- for w_obj, obj in self.py_objects_w2r.items():
- ptr = rffi.cast(ADDR, obj)
- self.py_objects_r2w[ptr] = w_obj
-
- def print_refcounts(self):
- print "REFCOUNTS"
- for w_obj, obj in self.py_objects_w2r.items():
- print "%r: %i" % (w_obj, obj.c_ob_refcnt)
-
- def get_from_lifeline(self, w_obj):
- lifeline = self.lifeline_dict.get(w_obj)
- 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
- return py_obj
- else:
- return lltype.nullptr(PyObject.TO)
-
- def set_lifeline(self, w_obj, py_obj):
- self.lifeline_dict.set(w_obj,
- PyOLifeline(self.space, py_obj))
-
- def make_borrowed(self, w_container, w_borrowed):
- """
- Create a borrowed reference, which will live as long as the container
- has a living reference (as a PyObject!)
- """
- ref = make_ref(self.space, w_borrowed)
- obj_ptr = rffi.cast(ADDR, ref)
-
- borrowees = self.borrow_mapping.setdefault(w_container, {})
- if w_borrowed in borrowees:
- Py_DecRef(self.space, w_borrowed) # cancel incref from make_ref()
- else:
- borrowees[w_borrowed] = None
-
- return ref
-
- def reset_borrowed_references(self):
- "Used in tests"
- for w_container, w_borrowed in self.borrow_mapping.items():
- Py_DecRef(self.space, w_borrowed)
- self.borrow_mapping = {None: {}}
-
- def delete_borrower(self, w_obj):
- """
- Called when a potential container for borrowed references has lost its
- last reference. Removes the borrowed references it contains.
- """
- if w_obj in self.borrow_mapping: # move to lifeline __del__
- for w_containee in self.borrow_mapping[w_obj]:
- self.forget_borrowee(w_containee)
- del self.borrow_mapping[w_obj]
-
- def swap_borrow_container(self, container):
- """switch the current default contained with the given one."""
- if container is None:
- old_container = self.borrow_mapping[None]
- self.borrow_mapping[None] = {}
- return old_container
- else:
- old_container = self.borrow_mapping[None]
- self.borrow_mapping[None] = container
- for w_containee in old_container:
- self.forget_borrowee(w_containee)
-
- def forget_borrowee(self, w_obj):
- "De-register an object from the list of borrowed references"
- ref = self.py_objects_w2r.get(w_obj, lltype.nullptr(PyObject.TO))
- if not ref:
- if DEBUG_REFCOUNT:
- print >>sys.stderr, "Borrowed object is already gone!"
- return
-
- Py_DecRef(self.space, ref)
-
-class InvalidPointerException(Exception):
- pass
-
DEBUG_REFCOUNT = False
def debug_refcount(*args, **kwargs):
@@ -568,6 +368,15 @@
return w_obj
+ at specialize.ll()
+def new_pyobj(PYOBJ_TYPE, ob_type):
+ ob = lltype.malloc(PYOBJ_TYPE, flavor='raw', track_allocation=False)
+ ob.c_ob_refcnt = 1
+ ob.c_ob_type = ob_type
+ ob.c_ob_pypy_link = 0
+ return ob
+
+
def make_ref(space, w_obj):
ZZZ
diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -15,7 +15,7 @@
from pypy.module.cpyext import api
from pypy.module.cpyext.state import State
from pypy.module.cpyext.pyobject import RefcountState, debug_collect
-from pypy.module.cpyext.pyobject import Py_DecRef, InvalidPointerException
+from pypy.module.cpyext.pyobject import Py_DecRef
from rpython.tool.identity_dict import identity_dict
from rpython.tool import leakfinder
from rpython.rlib import rawrefcount
diff --git a/pypy/module/cpyext/test/test_intobject.py b/pypy/module/cpyext/test/test_intobject.py
--- a/pypy/module/cpyext/test/test_intobject.py
+++ b/pypy/module/cpyext/test/test_intobject.py
@@ -1,3 +1,4 @@
+from pypy.module.cpyext.pyobject import from_pyobj
from pypy.module.cpyext.test.test_api import BaseApiTest
from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
import sys
@@ -12,7 +13,7 @@
y = api.PyInt_AS_LONG(space.wrap(i))
assert x == i
assert y == i
- w_x = api.PyInt_FromLong(x + 1)
+ w_x = from_pyobj(space, api.PyInt_FromLong(x + 1))
assert space.type(w_x) is space.w_int
assert space.eq_w(w_x, space.wrap(i + 1))
diff --git a/pypy/module/cpyext/tupleobject.py b/pypy/module/cpyext/tupleobject.py
--- a/pypy/module/cpyext/tupleobject.py
+++ b/pypy/module/cpyext/tupleobject.py
@@ -1,16 +1,33 @@
from pypy.interpreter.error import OperationError
from rpython.rtyper.lltypesystem import rffi, lltype
from pypy.module.cpyext.api import (cpython_api, Py_ssize_t, CANNOT_FAIL,
- build_type_checkers)
+ cpython_struct, PyObjectFields, build_type_checkers, bootstrap_function)
from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, Py_DecRef,
- borrow_from, make_ref, from_ref)
+ setup_class_for_cpyext)
from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
-from pypy.objspace.std.tupleobject import W_TupleObject
+from pypy.objspace.std.tupleobject import W_TupleObject, W_AbstractTupleObject
+
+PyTupleObjectStruct = lltype.ForwardReference()
+PyTupleObject = lltype.Ptr(PyTupleObjectStruct)
+PyTupleObjectFields = PyObjectFields + \
+ (("ob_item", rffi.CArray(PyObject)),)
+cpython_struct("PyTupleObject", PyTupleObjectFields, PyTupleObjectStruct)
PyTuple_Check, PyTuple_CheckExact = build_type_checkers("Tuple")
+ at bootstrap_function
+def init_intobject(space):
+ "Type description of PyTupleObject"
+ setup_class_for_cpyext(W_AbstractTupleObject,
+ basestruct=PyTupleObject.TO,
+ )
+ #fill_pyobj=int_fill_pyobj,
+ #fill_pypy=int_fill_pypy,
+ #realize_subclass_of=W_IntObject)
+
@cpython_api([Py_ssize_t], PyObject)
def PyTuple_New(space, size):
+ ZZZ
return W_TupleObject([space.w_None] * size)
@cpython_api([PyObject, Py_ssize_t, PyObject], rffi.INT_real, error=-1)
@@ -30,10 +47,13 @@
assert isinstance(w_t, W_TupleObject)
w_t.wrappeditems[pos] = w_obj
- at cpython_api([PyObject, Py_ssize_t], PyObject)
+ at cpython_api([PyObject, Py_ssize_t], PyObject, result_borrowed=True)
def PyTuple_GetItem(space, w_t, pos):
- if not PyTuple_Check(space, w_t):
+ if not isinstance(w_t, W_AbstractTupleObject):
PyErr_BadInternalCall(space)
+ #if w_t.cpyext_returned_items_can_be_borrowed:
+ ZZZ.x.x.x
+ xxxxxxx
w_obj = space.getitem(w_t, space.wrap(pos))
return borrow_from(w_t, w_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
@@ -2,6 +2,7 @@
from rpython.rlib import jit
from rpython.rlib.objectmodel import specialize, instantiate
+from rpython.rlib.objectmodel import keepalive_until_here
from rpython.rlib.rstring import rsplit
from rpython.rtyper.annlowlevel import llhelper
from rpython.rtyper.lltypesystem import rffi, lltype
@@ -22,7 +23,7 @@
from pypy.module.cpyext.pyobject import (
PyObject, make_ref, create_ref, get_typedescr, from_pyobj, as_pyobj,
setup_class_for_cpyext, get_pyobj_and_incref, get_pyobj_and_xincref,
- track_reference, RefcountState, borrow_from, Py_DecRef)
+ track_reference, RefcountState, borrow_from, Py_DecRef, RRC_PERMANENT)
from pypy.module.cpyext.slotdefs import (
slotdefs_for_tp_slots, slotdefs_for_wrappers, get_slot_tp_function)
from pypy.module.cpyext.state import State
@@ -200,11 +201,9 @@
w_subtype = args_w[0]
w_args = space.newtuple(args_w[1:])
- subtype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_subtype))
- try:
- w_obj = generic_cpy_call(space, tp_new, subtype, w_args, w_kwds)
- finally:
- Py_DecRef(space, w_subtype)
+ subtype = rffi.cast(PyTypeObjectPtr, as_pyobj(space, w_subtype))
+ w_obj = generic_cpy_call(space, tp_new, subtype, w_args, w_kwds)
+ keepalive_until_here(w_subtype)
return w_obj
@specialize.memo()
@@ -463,7 +462,7 @@
pto = lltype.malloc(PyTypeObject, flavor='raw', zero=True,
track_allocation=False)
pto.c_tp_flags |= Py_TPFLAGS_READYING
- return pto, False
+ return pto, RRC_PERMANENT
def type_fill_pyobj(space, w_type, pto):
"""
@@ -561,7 +560,7 @@
w_metatype = from_pyobj(space, pto.c_ob_type)
w_type = space.allocate_instance(W_TypeObject, w_metatype)
- return w_type, False
+ return w_type, RRC_PERMANENT
def type_fill_pypy(space, w_type, py_obj):
pto = rffi.cast(PyTypeObjectPtr, py_obj)
diff --git a/pypy/objspace/std/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py
--- a/pypy/objspace/std/specialisedtupleobject.py
+++ b/pypy/objspace/std/specialisedtupleobject.py
@@ -132,6 +132,8 @@
Cls_oo = make_specialised_class((object, object))
Cls_ff = make_specialised_class((float, float))
+Cls_oo.cpyext_returned_items_can_be_borrowed = True
+
def makespecialisedtuple(space, list_w):
from pypy.objspace.std.intobject import W_IntObject
from pypy.objspace.std.floatobject import W_FloatObject
diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py
--- a/pypy/objspace/std/tupleobject.py
+++ b/pypy/objspace/std/tupleobject.py
@@ -32,6 +32,7 @@
class W_AbstractTupleObject(W_Root):
__slots__ = ()
+ cpyext_returned_items_can_be_borrowed = False
def __repr__(self):
"""representation for debugging purposes"""
@@ -248,6 +249,7 @@
class W_TupleObject(W_AbstractTupleObject):
_immutable_fields_ = ['wrappeditems[*]']
+ cpyext_returned_items_can_be_borrowed = True
def __init__(self, wrappeditems):
make_sure_not_resized(wrappeditems)
diff --git a/rpython/rlib/rawrefcount.py b/rpython/rlib/rawrefcount.py
--- a/rpython/rlib/rawrefcount.py
+++ b/rpython/rlib/rawrefcount.py
@@ -112,8 +112,11 @@
else:
ob.c_ob_pypy_link = 0
if ob.c_ob_refcnt >= REFCNT_FROM_PYPY_LIGHT:
- assert ob.c_ob_refcnt == REFCNT_FROM_PYPY_LIGHT
- lltype.free(ob, flavor='raw', track_allocation=track_allocation)
+ ob.c_ob_refcnt -= REFCNT_FROM_PYPY_LIGHT
+ ob.c_ob_pypy_link = 0
+ if ob.c_ob_refcnt == 0:
+ lltype.free(ob, flavor='raw',
+ track_allocation=track_allocation)
else:
assert ob.c_ob_refcnt >= REFCNT_FROM_PYPY
assert ob.c_ob_refcnt < int(REFCNT_FROM_PYPY_LIGHT * 0.99)
More information about the pypy-commit
mailing list