[pypy-commit] pypy cpyext-gc-support: Starting to rewrite cpyext, add a lot of ZZZ

arigo noreply at buildbot.pypy.org
Wed Oct 14 14:05:55 EDT 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cpyext-gc-support
Changeset: r80215:8e73db7caf49
Date: 2015-10-14 20:06 +0200
http://bitbucket.org/pypy/pypy/changeset/8e73db7caf49/

Log:	Starting to rewrite cpyext, add a lot of ZZZ

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
@@ -286,75 +286,67 @@
             @specialize.ll()
             def unwrapper(space, *args):
                 from pypy.module.cpyext.pyobject import Py_DecRef
-                from pypy.module.cpyext.pyobject import make_ref, from_ref
+                from pypy.module.cpyext.pyobject import as_pyobj, is_pyobj
                 from pypy.module.cpyext.pyobject import Reference
                 newargs = ()
-                to_decref = []
                 assert len(args) == len(api_function.argtypes)
                 for i, (ARG, is_wrapped) in types_names_enum_ui:
                     input_arg = args[i]
                     if is_PyObject(ARG) and not is_wrapped:
-                        # build a reference
-                        if input_arg is None:
-                            arg = lltype.nullptr(PyObject.TO)
-                        elif isinstance(input_arg, W_Root):
-                            ref = make_ref(space, input_arg)
-                            to_decref.append(ref)
-                            arg = rffi.cast(ARG, ref)
+                        # build a 'PyObject *' (not holding a reference)
+                        if not is_pyobj(input_arg):
+                            input_arg = as_pyobj(input_arg)
+                        arg = rffi.cast(ARG, input_arg)
+                    elif is_PyObject(ARG) and is_wrapped:
+                        # convert to a wrapped object
+                        if is_pyobj(input_arg):
+                            arg = from_ref(input_arg)
                         else:
                             arg = input_arg
-                    elif is_PyObject(ARG) and is_wrapped:
-                        # convert to a wrapped object
-                        if input_arg is None:
-                            arg = input_arg
-                        elif isinstance(input_arg, W_Root):
-                            arg = input_arg
-                        else:
-                            try:
-                                arg = from_ref(space,
-                                           rffi.cast(PyObject, input_arg))
-                            except TypeError, e:
-                                err = OperationError(space.w_TypeError,
-                                         space.wrap(
-                                        "could not cast arg to PyObject"))
-                                if not catch_exception:
-                                    raise err
-                                state = space.fromcache(State)
-                                state.set_exception(err)
-                                if is_PyObject(restype):
-                                    return None
-                                else:
-                                    return api_function.error_value
+
+                            ## ZZZ: for is_pyobj:
+                            ## try:
+                            ##     arg = from_ref(space,
+                            ##                rffi.cast(PyObject, input_arg))
+                            ## except TypeError, e:
+                            ##     err = OperationError(space.w_TypeError,
+                            ##              space.wrap(
+                            ##             "could not cast arg to PyObject"))
+                            ##     if not catch_exception:
+                            ##         raise err
+                            ##     state = space.fromcache(State)
+                            ##     state.set_exception(err)
+                            ##     if is_PyObject(restype):
+                            ##         return None
+                            ##     else:
+                            ##         return api_function.error_value
                     else:
-                        # convert to a wrapped object
+                        # arg is not declared as PyObject, no magic
                         arg = input_arg
                     newargs += (arg, )
                 try:
-                    try:
-                        res = func(space, *newargs)
-                    except OperationError, e:
-                        if not catch_exception:
-                            raise
-                        if not hasattr(api_function, "error_value"):
-                            raise
-                        state = space.fromcache(State)
-                        state.set_exception(e)
-                        if is_PyObject(restype):
-                            return None
-                        else:
-                            return api_function.error_value
-                    if not we_are_translated():
-                        got_integer = isinstance(res, (int, long, float))
-                        assert got_integer == expect_integer,'got %r not integer' % res
-                    if res is None:
+                    res = func(space, *newargs)
+                except OperationError, e:
+                    if not catch_exception:
+                        raise
+                    if not hasattr(api_function, "error_value"):
+                        raise
+                    state = space.fromcache(State)
+                    state.set_exception(e)
+                    if is_PyObject(restype):
                         return None
-                    elif isinstance(res, Reference):
-                        return res.get_wrapped(space)
                     else:
-                        return res
-                finally:
-                    for arg in to_decref:
-                        Py_DecRef(space, arg)
+                        return api_function.error_value
+                if not we_are_translated():
+                    got_integer = isinstance(res, (int, long, float))
+                    assert got_integer == expect_integer,'got %r not integer' % res
+                ZZZ   # where is the logic to return PyObject??
+                if res is None:
+                    return None
+                elif isinstance(res, Reference):
+                    return res.get_wrapped(space)
+                else:
+                    return res
             unwrapper.func = func
             unwrapper.api_func = api_function
             unwrapper._always_inline_ = 'try'
@@ -730,9 +722,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())
-        py_type_ready(space, get_cobject_type())
-        py_type_ready(space, get_capsule_type())
+        #py_type_ready(space, get_buffer_type()) ZZZ
+        #py_type_ready(space, get_cobject_type()) ZZZ
+        #py_type_ready(space, get_capsule_type()) ZZZ
     INIT_FUNCTIONS.append(init_types)
     from pypy.module.posix.interp_posix import add_fork_hook
     reinit_tls = rffi.llexternal('%sThread_ReInitTLS' % prefix, [], lltype.Void,
@@ -831,7 +823,8 @@
     space.fromcache(State).install_dll(eci)
 
     # populate static data
-    for name, (typ, expr) in GLOBALS.iteritems():
+    if 0:   # ZZZ
+      for name, (typ, expr) in GLOBALS.iteritems():
         from pypy.module import cpyext
         w_obj = eval(expr)
         if name.endswith('#'):
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
@@ -1,16 +1,16 @@
 import sys
 
 from pypy.interpreter.baseobjspace import W_Root, SpaceCache
-from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
 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, is_PyObject)
 from pypy.module.cpyext.state import State
 from pypy.objspace.std.typeobject import W_TypeObject
 from pypy.objspace.std.objectobject import W_ObjectObject
 from rpython.rlib.objectmodel import specialize, we_are_translated
-from rpython.rlib.rweakref import RWeakKeyDictionary
 from rpython.rtyper.annlowlevel import llhelper
+from rpython.rlib import rawrefcount
 
 #________________________________________________________
 # type description
@@ -136,6 +136,7 @@
 
 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 }
@@ -251,6 +252,7 @@
     Allocates a PyObject, and fills its fields with info from the given
     intepreter object.
     """
+    ZZZ
     state = space.fromcache(RefcountState)
     w_type = space.type(w_obj)
     if w_type.is_cpytype():
@@ -270,6 +272,7 @@
     """
     Ties together a PyObject and an interpreter object.
     """
+    ZZZ
     # XXX looks like a PyObject_GC_TRACK
     ptr = rffi.cast(ADDR, py_obj)
     state = space.fromcache(RefcountState)
@@ -282,12 +285,62 @@
     if ptr: # init_typeobject() bootstraps with NULL references
         state.py_objects_r2w[ptr] = w_obj
 
-def make_ref(space, w_obj):
+
+NULL_GCREF = lltype.nullptr(llmemory.GCREF.TO)
+
+def _create_pyobj_from_w_obj(w_obj):
+    # XXX temp, needs cases
+    ob = lltype.malloc(PyObject, flavor='raw', track_allocation=False)
+    ob.ob_refcnt = 0
+    ob.ob_pypy_link = NULL_GCREF
+    rawrefcount.create_link_pypy(w_obj, ob)
+    return ob
+
+
+def as_pyobj(w_obj):
     """
-    Returns a new reference to an intepreter object.
+    Returns a 'PyObject *' representing the given intepreter object.
+    'None' is returned as a NULL.  This doesn't give a new reference, but
+    the returned 'PyObject *' is valid at least as long as 'w_obj' is.
     """
+    assert is_wrapped(w_obj)
     if w_obj is None:
         return lltype.nullptr(PyObject.TO)
+    #if isinstance(w_obj, W_CPyExtPlaceHolderObject):
+    #    xxx
+    ob = rawrefcount.from_obj(PyObject.TO, w_obj)
+    if not ob:
+        ob = _create_pyobj_from_w_obj(w_obj)
+    return ob
+as_pyobj._always_inline_ = True
+
+
+ at specialize.ll()
+def from_ref(pyobj):
+    assert not is_wrapped(pyobj)
+    if not pyobj:
+        return None
+    pyobj = rffi.cast(PyObject, pyobj)
+    w_obj = rawrefcount.to_obj(W_Root, pyobj)
+    if w_obj is None:
+        w_obj = _create_w_obj_from_pyobj(pyobj)
+    return w_obj
+from_ref._always_inline_ = True
+
+
+def is_pyobj(x):
+    "NOT_RPYTHON"
+    if x is None or isinstance(x, W_Root):
+        return False
+    else:
+        assert is_PyObject(lltype.typeOf(x))
+        return True
+
+# ZZZ: use an ExtRegistryEntry to constant-fold is_pyobj()
+
+
+def make_ref(space, w_obj):
+    ZZZ
     assert isinstance(w_obj, W_Root)
     state = space.fromcache(RefcountState)
     try:
@@ -300,7 +353,7 @@
     return py_obj
 
 
-def from_ref(space, ref):
+def ZZZ_from_ref(space, ref):
     """
     Finds the interpreter object corresponding to the given reference.  If the
     object is not yet realized (see stringobject.py), creates it.
@@ -390,6 +443,7 @@
 
 class PyOLifeline(object):
     def __init__(self, space, pyo):
+        ZZZ
         self.pyo = pyo
         self.space = space
 
@@ -408,6 +462,7 @@
     Create a borrowed reference, which will live as long as the container
     has a living reference (as a PyObject!)
     """
+    ZZZ
     if w_borrowed is None:
         return lltype.nullptr(PyObject.TO)
 
@@ -416,6 +471,7 @@
 
 class Reference:
     def __init__(self, pyobj):
+        ZZZ
         assert not isinstance(pyobj, W_Root)
         self.pyobj = pyobj
 
@@ -430,6 +486,7 @@
     Delays the creation of a borrowed reference.
     """
     def __init__(self, w_container, w_borrowed):
+        ZZZ
         self.w_container = w_container
         self.w_borrowed = w_borrowed
 
diff --git a/pypy/module/cpyext/test/test_api.py b/pypy/module/cpyext/test/test_api.py
--- a/pypy/module/cpyext/test/test_api.py
+++ b/pypy/module/cpyext/test/test_api.py
@@ -49,21 +49,24 @@
         return state.clear_exception()
 
     def setup_method(self, func):
+        return   # ZZZ
         freeze_refcnts(self)
 
     def teardown_method(self, func):
-        state = self.space.fromcache(State)
-        try:
-            state.check_and_raise_exception()
-        except OperationError, e:
-            print e.errorstr(self.space)
-            raise
+        if 0:   # ZZZ
+            state = self.space.fromcache(State)
+            try:
+                state.check_and_raise_exception()
+            except OperationError, e:
+                print e.errorstr(self.space)
+                raise
 
         try:
             del self.space.getexecutioncontext().cpyext_threadstate
         except AttributeError:
             pass
 
+        return   # ZZZ
         if self.check_and_print_leaks():
             assert False, "Test leaks or loses object(s)."
 
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
@@ -92,6 +92,7 @@
     return str(pydname)
 
 def freeze_refcnts(self):
+    ZZZ
     state = self.space.fromcache(RefcountState)
     self.frozen_refcounts = {}
     for w_obj, obj in state.py_objects_w2r.iteritems():
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
@@ -320,6 +320,8 @@
     # - object.tp_bases is a tuple
     # - tuple.tp_bases is a tuple
 
+    return  # ZZZ
+
     # 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)


More information about the pypy-commit mailing list