[pypy-svn] r26681 - in pypy/dist/pypy/objspace/cpy: . test

arigo at codespeak.net arigo at codespeak.net
Tue May 2 20:17:36 CEST 2006


Author: arigo
Date: Tue May  2 20:17:33 2006
New Revision: 26681

Added:
   pypy/dist/pypy/objspace/cpy/refcount.py   (contents, props changed)
   pypy/dist/pypy/objspace/cpy/test/test_refcount.py   (contents, props changed)
Modified:
   pypy/dist/pypy/objspace/cpy/ann_policy.py
   pypy/dist/pypy/objspace/cpy/capi.py
   pypy/dist/pypy/objspace/cpy/ctypes_base.py
   pypy/dist/pypy/objspace/cpy/test/test_compile.py
   pypy/dist/pypy/objspace/cpy/wrappable.py
Log:
(pedronis, arigo)  Preserve tracebacks through the RPython code.
Added necessary support to manipulate the refcounts directly.


Modified: pypy/dist/pypy/objspace/cpy/ann_policy.py
==============================================================================
--- pypy/dist/pypy/objspace/cpy/ann_policy.py	(original)
+++ pypy/dist/pypy/objspace/cpy/ann_policy.py	Tue May  2 20:17:33 2006
@@ -29,11 +29,11 @@
             # restart this loop: for all we know follow_annotations()
             # could have found new objects
 
-        # force w_type, w_value attributes into the OperationError class
+        # force w_type/w_value/w_traceback attrs into the OperationError class
         bk = annotator.bookkeeper
         classdef = bk.getuniqueclassdef(OperationError)
         s_instance = annmodel.SomeInstance(classdef=classdef)
-        for name in ['w_type', 'w_value']:
+        for name in ['w_type', 'w_value', 'w_traceback']:
             s_instance.setattr(bk.immutablevalue(name),
                                bk.valueoftype(W_Object))
 

Modified: pypy/dist/pypy/objspace/cpy/capi.py
==============================================================================
--- pypy/dist/pypy/objspace/cpy/capi.py	(original)
+++ pypy/dist/pypy/objspace/cpy/capi.py	Tue May  2 20:17:33 2006
@@ -223,6 +223,12 @@
 RAW_PyErr_SetObject.restype = None
 RAW_PyErr_SetObject._rctypes_pyerrchecker_ = None
 
+# WARNING: consumes references
+RAW_PyErr_Restore = pythonapi.PyErr_Restore
+RAW_PyErr_Restore.argtypes = [W_Object, W_Object, W_Object]
+RAW_PyErr_Restore.restype = None
+RAW_PyErr_Restore._rctypes_pyerrchecker_ = None
+
 RAW_PyErr_Occurred = pythonapi.PyErr_Occurred
 RAW_PyErr_Occurred.argtypes = []
 RAW_PyErr_Occurred.restype = c_int

Modified: pypy/dist/pypy/objspace/cpy/ctypes_base.py
==============================================================================
--- pypy/dist/pypy/objspace/cpy/ctypes_base.py	(original)
+++ pypy/dist/pypy/objspace/cpy/ctypes_base.py	Tue May  2 20:17:33 2006
@@ -33,7 +33,7 @@
         w_val = W_Object()
         w_tb  = W_Object()
         RAW_PyErr_Fetch(byref(w_exc), byref(w_val), byref(w_tb))
-        raise OperationError(w_exc, w_val)    # XXX traceback
+        raise OperationError(w_exc, w_val, w_tb)
 
 class CPyAPI(PyDLL):
     """Class of the singleton 'cpyapi' object, out of which C functions
@@ -53,7 +53,8 @@
             except:
                 exc, val, tb = sys.exc_info()
                 raise OperationError(W_Object(exc),
-                                     W_Object(val))   # XXX traceback
+                                     W_Object(val),
+                                     W_Object(tb))
 
 cpyapi = CPyAPI.__new__(CPyAPI)
 cpyapi.__dict__ = pythonapi.__dict__.copy()

Added: pypy/dist/pypy/objspace/cpy/refcount.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/objspace/cpy/refcount.py	Tue May  2 20:17:33 2006
@@ -0,0 +1,69 @@
+from pypy.annotation import model as annmodel
+from pypy.rpython.extregistry import ExtRegistryEntry
+from pypy.objspace.cpy.capi import *
+
+
+###################################################################
+# ____________________ Reference counter hacks ____________________
+
+_XX_PyObject_GetItem = pythonapi.PyObject_GetItem
+_XX_PyObject_GetItem.argtypes = [W_Object, W_Object]
+_XX_PyObject_GetItem.restype = None   # !
+
+_XX_PyList_SetItem = pythonapi.PyList_SetItem
+_XX_PyList_SetItem.argtypes = [W_Object, Py_ssize_t, W_Object]
+_XX_PyList_SetItem.restype = c_int
+
+def Py_Incref(w):
+    container = (w.value,)
+    _XX_PyObject_GetItem(W_Object(container), W_Object(0))
+    # the new reference returned by PyObject_GetItem is ignored and lost
+
+def Py_Decref(w):
+    lst = [None]
+    # consume a reference
+    _XX_PyList_SetItem(W_Object(lst), 0, w)
+
+def Py_XIncref(w):
+    if w:
+        Py_Incref(w)
+
+def Py_XDecref(w):
+    if w:
+        Py_Decref(w)
+
+
+class IncrefFnEntry(ExtRegistryEntry):
+    "Annotation and specialization of calls to Py_Incref()."
+    _about_ = Py_Incref
+
+    def compute_result_annotation(self, s_arg):
+        return annmodel.s_None
+
+    def specialize_call(self, hop):
+        from pypy.rpython.lltypesystem import lltype
+        s_pyobj = annmodel.SomeCTypesObject(W_Object,
+                                   annmodel.SomeCTypesObject.MEMORYALIAS)
+        r_pyobj = hop.rtyper.getrepr(s_pyobj)
+        [v_box] = hop.inputargs(r_pyobj)
+        v_value = r_pyobj.getvalue(hop.llops, v_box)
+        hop.genop('gc_push_alive_pyobj', [v_value])
+        return hop.inputconst(lltype.Void, None)
+
+
+class DecrefFnEntry(ExtRegistryEntry):
+    "Annotation and specialization of calls to Py_Decref()."
+    _about_ = Py_Decref
+
+    def compute_result_annotation(self, s_arg):
+        return annmodel.s_None
+
+    def specialize_call(self, hop):
+        from pypy.rpython.lltypesystem import lltype
+        s_pyobj = annmodel.SomeCTypesObject(W_Object,
+                                   annmodel.SomeCTypesObject.MEMORYALIAS)
+        r_pyobj = hop.rtyper.getrepr(s_pyobj)
+        [v_box] = hop.inputargs(r_pyobj)
+        v_value = r_pyobj.getvalue(hop.llops, v_box)
+        hop.genop('gc_pop_alive_pyobj', [v_value])
+        return hop.inputconst(lltype.Void, None)

Modified: pypy/dist/pypy/objspace/cpy/test/test_compile.py
==============================================================================
--- pypy/dist/pypy/objspace/cpy/test/test_compile.py	(original)
+++ pypy/dist/pypy/objspace/cpy/test/test_compile.py	Tue May  2 20:17:33 2006
@@ -150,12 +150,10 @@
 
 def test_compile_exception_through_rpython():
     space = CPyObjSpace()
-    def myfunc(n):
-        w_sys = space.getbuiltinmodule('sys')
-        w_n = space.wrap(n)
-        space.call_method(w_sys, 'exit', w_n)
+    def myfunc(w_callback):
+        space.call_function(w_callback, space.wrap(5))
         return space.w_None   # should not actually reach this point
-    myfunc.unwrap_spec = [int]
+    myfunc.unwrap_spec = [W_Root]
     w_myfunc = space.wrap(interp2app(myfunc))
 
     def entrypoint():
@@ -163,7 +161,13 @@
 
     fn = compile(entrypoint, [],
                  annotatorpolicy = CPyAnnotatorPolicy(space))
+
+    def mycallback(n):
+        assert n == 5
+        raise SystemExit(12)
+
     myfunc1 = fn()
-    e = py.test.raises(SystemExit, myfunc1, 5)
+    e = py.test.raises(SystemExit, myfunc1, mycallback)
     ex = e.value
-    assert ex.args == (5,)
+    assert ex.args == (12,)
+    assert e.traceback[-1].frame.code.name == 'mycallback'

Added: pypy/dist/pypy/objspace/cpy/test/test_refcount.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/objspace/cpy/test/test_refcount.py	Tue May  2 20:17:33 2006
@@ -0,0 +1,39 @@
+import sys
+from pypy.translator.c.test.test_genc import compile
+from pypy.objspace.cpy.refcount import *
+
+
+def test_reftricks():
+    x = object()
+    w_x = W_Object(x)
+    before = sys.getrefcount(x)
+    Py_Incref(w_x)
+    after = sys.getrefcount(x)
+    assert after == before+1
+    assert w_x.value is x
+
+    Py_Decref(w_x)
+    after = sys.getrefcount(x)
+    assert after == before
+    assert w_x.value is x
+
+
+def test_compile_reftricks():
+    def func(obj, flag):
+        w = W_Object(obj)
+        if flag > 0:
+            Py_Incref(w)
+        else:
+            Py_Decref(w)
+
+    fn = compile(func, [object, int])
+
+    x = object()
+    before = sys.getrefcount(x)
+    fn(x, +1)
+    after = sys.getrefcount(x)
+    assert after == before+1
+
+    fn(x, -1)
+    after = sys.getrefcount(x)
+    assert after == before

Modified: pypy/dist/pypy/objspace/cpy/wrappable.py
==============================================================================
--- pypy/dist/pypy/objspace/cpy/wrappable.py	(original)
+++ pypy/dist/pypy/objspace/cpy/wrappable.py	Tue May  2 20:17:33 2006
@@ -6,6 +6,7 @@
 import py
 from pypy.annotation.pairtype import pair, pairtype
 from pypy.objspace.cpy.capi import *
+from pypy.objspace.cpy.refcount import Py_XIncref
 from pypy.objspace.cpy.objspace import CPyObjSpace
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.function import Function
@@ -49,6 +50,19 @@
         self.passedargs = []
 
 
+def reraise(e):
+    w_type      = e.w_type
+    w_value     = e.w_value
+    w_traceback = e.application_traceback
+    if e.application_traceback is None:
+        w_traceback = W_Object()    # NULL
+    else:
+        Py_XIncref(w_traceback)
+    Py_XIncref(w_type)
+    Py_XIncref(w_value)
+    RAW_PyErr_Restore(e.w_type, e.w_value, w_traceback)
+
+
 class __extend__(pairtype(CPyObjSpace, Function)):
 
     def wrap((space, func)):
@@ -76,8 +90,7 @@
         sourcelines.append('        w_result = ___bltin(%s)' % (
             ', '.join(tramp.passedargs),))
         sourcelines.append('    except ___OperationError, e:')
-        sourcelines.append('        ___PyErr_SetObject(e.w_type.value,')
-        sourcelines.append('                           e.w_value.value)')
+        sourcelines.append('        ___reraise(e)')
         # the following line is not reached, unless we are translated
         # in which case it makes the function return (PyObject*)NULL.
         sourcelines.append('        w_result = ___W_Object()')
@@ -92,7 +105,7 @@
             '___PyInt_AsLong':    PyInt_AsLong,
             '___bltin':           bltin,
             '___OperationError':  OperationError,
-            '___PyErr_SetObject': RAW_PyErr_SetObject,
+            '___reraise':         reraise,
             }
         exec py.code.Source('\n'.join(sourcelines)).compile() in miniglobals
 



More information about the Pypy-commit mailing list