[pypy-svn] r26678 - in pypy/dist/pypy: objspace/cpy objspace/cpy/test rpython/rctypes rpython/rctypes/test
arigo at codespeak.net
arigo at codespeak.net
Tue May 2 17:50:15 CEST 2006
Author: arigo
Date: Tue May 2 17:50:12 2006
New Revision: 26678
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/objspace.py
pypy/dist/pypy/objspace/cpy/test/test_compile.py
pypy/dist/pypy/objspace/cpy/wrappable.py
pypy/dist/pypy/rpython/rctypes/afunc.py
pypy/dist/pypy/rpython/rctypes/test/test_rfunc.py
Log:
Support exceptions in the CPyObjSpace, both when running on top of
CPython and when translated. When translated, an extra call to
rctypes_pyerrchecker() is inserted, which does the PyErr_Occurred() and
PyErr_Fetch() magic to turn it into an OperationError. With some hacks
the existing trampoline() function is able to do the converse: turn an
OperationError into the CPython exception it contains.
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 17:50:12 2006
@@ -2,7 +2,7 @@
from pypy.annotation.pairtype import pair
from pypy.annotation import model as annmodel
from pypy.interpreter.error import OperationError
-from pypy.objspace.cpy.ctypes_base import W_Object
+from pypy.objspace.cpy.ctypes_base import W_Object, rctypes_pyerrchecker
class CPyAnnotatorPolicy(PyPyAnnotatorPolicy):
"""Annotation policy to compile CPython extension modules with
@@ -30,8 +30,15 @@
# could have found new objects
# force w_type, w_value attributes into the OperationError class
- classdef = annotator.bookkeeper.getuniqueclassdef(OperationError)
+ bk = annotator.bookkeeper
+ classdef = bk.getuniqueclassdef(OperationError)
s_instance = annmodel.SomeInstance(classdef=classdef)
for name in ['w_type', 'w_value']:
- s_instance.setattr(annotator.bookkeeper.immutablevalue(name),
- annotator.bookkeeper.valueoftype(W_Object))
+ s_instance.setattr(bk.immutablevalue(name),
+ bk.valueoftype(W_Object))
+
+ # annotate rctypes_pyerrchecker()
+ uniquekey = rctypes_pyerrchecker
+ s_pyerrchecker = bk.immutablevalue(rctypes_pyerrchecker)
+ s_result = bk.emulate_pbc_call(uniquekey, s_pyerrchecker, [])
+ assert annmodel.s_None.contains(s_result)
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 17:50:12 2006
@@ -86,6 +86,14 @@
PyIter_Next.argtypes = [W_Object]
PyIter_Next.restype = W_Object
+PyObject_IsTrue = cpyapi.PyObject_IsTrue
+PyObject_IsTrue.argtypes = [W_Object]
+PyObject_IsTrue.restype = c_int
+
+PyObject_Type = cpyapi.PyObject_Type
+PyObject_Type.argtypes = [W_Object]
+PyObject_Type.restype = W_Object
+
###########################################################
# ____________________ Number Protocol ____________________
@@ -111,6 +119,14 @@
PySequence_SetItem.restype = c_int
+########################################################
+# ____________________ Type Objects ____________________
+
+PyType_IsSubtype = cpyapi.PyType_IsSubtype
+PyType_IsSubtype.argtypes = [W_Object, W_Object]
+PyType_IsSubtype.restype = c_int
+
+
###########################################################
# ____________________ Numeric Objects ____________________
@@ -178,13 +194,6 @@
PyImport_ImportModule.argtypes = [c_char_p]
PyImport_ImportModule.restype = W_Object
-# "RAW" because it comes from pythonapi instead of cpyapi
-# which makes it raise the set exception directly instead
-# of wrapping it into an OperationError
-RAW_PyErr_SetObject = pythonapi.PyErr_SetObject
-RAW_PyErr_SetObject.argtypes = [W_Object, W_Object]
-RAW_PyErr_SetObject.restype = None
-
##############################################################
# ____________________ Built-in functions ____________________
@@ -201,3 +210,27 @@
##PyCFunction_NewEx = cpyapi.PyCFunction_NewEx
##PyCFunction_NewEx.argtypes = [POINTER(PyMethodDef), W_Object, W_Object]
##PyCFunction_NewEx.restype = W_Object
+
+
+##############################################################
+# ____________________ Exception handling ____________________
+
+# "RAW" because it comes from pythonapi instead of cpyapi.
+# The normal error handling (wrapping CPython exceptions into
+# an OperationError) is disabled.
+RAW_PyErr_SetObject = pythonapi.PyErr_SetObject
+RAW_PyErr_SetObject.argtypes = [W_Object, W_Object]
+RAW_PyErr_SetObject.restype = None
+RAW_PyErr_SetObject._rctypes_pyerrchecker_ = None
+
+RAW_PyErr_Occurred = pythonapi.PyErr_Occurred
+RAW_PyErr_Occurred.argtypes = []
+RAW_PyErr_Occurred.restype = c_int
+RAW_PyErr_Occurred._rctypes_pyerrchecker_ = None
+
+RAW_PyErr_Fetch = pythonapi.PyErr_Fetch
+RAW_PyErr_Fetch.argtypes = [POINTER(W_Object),
+ POINTER(W_Object),
+ POINTER(W_Object)]
+RAW_PyErr_Fetch.restype = None
+RAW_PyErr_Fetch._rctypes_pyerrchecker_ = None
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 17:50:12 2006
@@ -26,6 +26,15 @@
class LevelError(Exception):
pass
+def rctypes_pyerrchecker():
+ from pypy.objspace.cpy.capi import RAW_PyErr_Occurred, RAW_PyErr_Fetch
+ if RAW_PyErr_Occurred():
+ w_exc = W_Object()
+ 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
+
class CPyAPI(PyDLL):
"""Class of the singleton 'cpyapi' object, out of which C functions
are getattr'd. It returns C function whose exception behavior matches
@@ -34,6 +43,7 @@
"""
class _FuncPtr(PyDLL._FuncPtr):
_flags_ = PyDLL._FuncPtr._flags_
+ _rctypes_pyerrchecker_ = staticmethod(rctypes_pyerrchecker)
def __call__(*args, **kwds):
try:
@@ -43,8 +53,7 @@
except:
exc, val, tb = sys.exc_info()
raise OperationError(W_Object(exc),
- W_Object(val),
- W_Object(tb))
+ W_Object(val)) # XXX traceback
cpyapi = CPyAPI.__new__(CPyAPI)
cpyapi.__dict__ = pythonapi.__dict__.copy()
Modified: pypy/dist/pypy/objspace/cpy/objspace.py
==============================================================================
--- pypy/dist/pypy/objspace/cpy/objspace.py (original)
+++ pypy/dist/pypy/objspace/cpy/objspace.py Tue May 2 17:50:12 2006
@@ -10,6 +10,7 @@
def initialize(self):
self.options.geninterp = True
self.w_int = W_Object(int)
+ self.w_tuple = W_Object(tuple)
self.w_None = W_Object(None)
self.w_False = W_Object(False)
self.w_True = W_Object(True)
@@ -66,6 +67,7 @@
int_w = staticmethod(PyInt_AsLong)
str_w = staticmethod(PyString_AsString)
iter = staticmethod(PyObject_GetIter)
+ type = staticmethod(PyObject_Type)
add = staticmethod(PyNumber_Add)
sub = staticmethod(PyNumber_Subtract)
@@ -135,3 +137,12 @@
if not w_res:
raise OperationError(self.w_StopIteration, self.w_None)
return w_res
+
+ def is_true(self, w_obj):
+ return PyObject_IsTrue(w_obj) != 0
+
+ def issubtype(self, w_type1, w_type2):
+ if PyType_IsSubtype(w_type1, w_type2):
+ return self.w_True
+ else:
+ return self.w_False
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 17:50:12 2006
@@ -5,6 +5,7 @@
from pypy.objspace.cpy.ann_policy import CPyAnnotatorPolicy
from pypy.objspace.cpy.objspace import CPyObjSpace
import pypy.rpython.rctypes.implementation
+from pypy.interpreter.error import OperationError
from pypy.interpreter.function import BuiltinFunction
from pypy.interpreter.gateway import interp2app, ObjSpace, W_Root
from pypy import conftest
@@ -104,3 +105,65 @@
annotatorpolicy = CPyAnnotatorPolicy(space))
res = fn(10, complex)
assert isinstance(res, int)
+
+# ____________________________________________________________
+
+def test_compile_exception_to_rpython():
+ space = CPyObjSpace()
+ def entrypoint(n):
+ w_sys = space.getbuiltinmodule('sys')
+ w_n = space.wrap(n)
+ try:
+ space.call_method(w_sys, 'exit', w_n)
+ except OperationError, e:
+ # a bit fragile: this test assumes that the OperationError
+ # is *not* normalized
+ return space.newtuple([e.w_type, e.w_value])
+ else:
+ return space.wrap('did not raise??')
+
+ fn = compile(entrypoint, [int],
+ annotatorpolicy = CPyAnnotatorPolicy(space))
+ result = fn(5)
+ assert result == (SystemExit, 5)
+
+def test_compile_exception_from_rpython():
+ space = CPyObjSpace()
+ w_SystemExit = space.W_Object(SystemExit)
+ def myfunc(n):
+ if n > 0:
+ raise OperationError(w_SystemExit, space.wrap(n))
+ else:
+ return space.wrap(n)
+ myfunc.unwrap_spec = [int]
+ w_myfunc = space.wrap(interp2app(myfunc))
+
+ def entrypoint():
+ return w_myfunc
+
+ fn = compile(entrypoint, [],
+ annotatorpolicy = CPyAnnotatorPolicy(space))
+ myfunc1 = fn()
+ e = py.test.raises(SystemExit, myfunc1, 5)
+ ex = e.value
+ assert ex.args == (5,)
+
+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)
+ return space.w_None # should not actually reach this point
+ myfunc.unwrap_spec = [int]
+ w_myfunc = space.wrap(interp2app(myfunc))
+
+ def entrypoint():
+ return w_myfunc
+
+ fn = compile(entrypoint, [],
+ annotatorpolicy = CPyAnnotatorPolicy(space))
+ myfunc1 = fn()
+ e = py.test.raises(SystemExit, myfunc1, 5)
+ ex = e.value
+ assert ex.args == (5,)
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 17:50:12 2006
@@ -78,9 +78,11 @@
sourcelines.append(' except ___OperationError, e:')
sourcelines.append(' ___PyErr_SetObject(e.w_type.value,')
sourcelines.append(' e.w_value.value)')
- sourcelines.append(' return None') # should never be seen
- sourcelines.append(' #except ___Exception, e:')
- sourcelines.append(' # raise ___RPythonError(XXX)')
+ # 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()')
+ #sourcelines.append(' except ___Exception, e:')
+ #sourcelines.append(' raise ___RPythonError(XXX)')
sourcelines.append(' return w_result.value')
sourcelines.append('')
Modified: pypy/dist/pypy/rpython/rctypes/afunc.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/afunc.py (original)
+++ pypy/dist/pypy/rpython/rctypes/afunc.py Tue May 2 17:50:12 2006
@@ -114,7 +114,12 @@
kwds = {}
if hasattr(cfuncptr, 'llinterp_friendly_version'):
kwds['_callable'] = cfuncptr.llinterp_friendly_version
+ suppress_pyerr_occurred = False
if (cfuncptr._flags_ & ctypes._FUNCFLAG_PYTHONAPI) == 0:
+ suppress_pyerr_occurred = True
+ if hasattr(cfuncptr, '_rctypes_pyerrchecker_'):
+ suppress_pyerr_occurred = True
+ if suppress_pyerr_occurred:
kwds['includes'] = getattr(cfuncptr, 'includes', ())
#else:
# no 'includes': hack to trigger in GenC a PyErr_Occurred() check
@@ -132,6 +137,19 @@
last_op.args[0].value._set_T(FUNCTYPE)
last_op.args[0].value._obj._TYPE = FUNCTYPE
+ if getattr(cfuncptr, '_rctypes_pyerrchecker_', None):
+ # special extension to support the CPyObjSpace
+ # XXX hackish: someone else -- like the annotator policy --
+ # must ensure that this extra function has been annotated
+ from pypy.translator.translator import graphof
+ func = cfuncptr._rctypes_pyerrchecker_
+ graph = graphof(hop.rtyper.annotator.translator, func)
+ hop.llops.record_extra_call(graph)
+ # build the 'direct_call' operation
+ f = hop.rtyper.getcallable(graph)
+ c = hop.inputconst(lltype.typeOf(f), f)
+ hop.genop('direct_call', [c])
+
if RESTYPE is lltype.Void:
return None
else:
Modified: pypy/dist/pypy/rpython/rctypes/test/test_rfunc.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/test/test_rfunc.py (original)
+++ pypy/dist/pypy/rpython/rctypes/test/test_rfunc.py Tue May 2 17:50:12 2006
@@ -323,6 +323,36 @@
assert res == 34
py.test.raises(OverflowError, 'fn(sys.maxint, 1)')
+ def test_compile_pyerrchecker(self):
+ from pypy.rpython.rctypes import apyobject
+ class W_Object(py_object):
+ pass
+ apyobject.register_py_object_subclass(W_Object)
+
+ def mypyerrchecker():
+ # for this test, always raises
+ raise ZeroDivisionError
+
+ PyNumber_Add = pythonapi.PyNumber_Add
+ PyNumber_Add.argtypes = [W_Object, W_Object]
+ PyNumber_Add.restype = W_Object
+ assert PyNumber_Add._flags_ & _FUNCFLAG_PYTHONAPI
+ PyNumber_Add._rctypes_pyerrchecker_ = mypyerrchecker
+ # special extension ^^^ to support the CPyObjSpace
+ try:
+ def fn1(n):
+ if n < 0:
+ # for this test, force mypyerrchecker() to be annotated
+ # using this trick
+ mypyerrchecker()
+ pyobj = W_Object(n)
+ return PyNumber_Add(pyobj, pyobj)
+
+ fn = compile(fn1, [int])
+ py.test.raises(ZeroDivisionError, fn, 64)
+ finally:
+ del PyNumber_Add._rctypes_pyerrchecker_
+
def test_compile_ctime(self):
import time
N = 123456789
More information about the Pypy-commit
mailing list