[pypy-svn] r13327 - in pypy/dist/pypy: objspace/flow rpython rpython/test
arigo at codespeak.net
arigo at codespeak.net
Mon Jun 13 01:33:24 CEST 2005
Author: arigo
Date: Mon Jun 13 01:33:20 2005
New Revision: 13327
Added:
pypy/dist/pypy/rpython/exceptiondata.py (contents, props changed)
Modified:
pypy/dist/pypy/objspace/flow/model.py
pypy/dist/pypy/rpython/rclass.py
pypy/dist/pypy/rpython/rptr.py
pypy/dist/pypy/rpython/rtyper.py
pypy/dist/pypy/rpython/test/test_exception.py
Log:
Bordering on the insane, here is the start of rtyper support for exceptions,
including converting from an exception set by CPython to an instance of the
corresponding RPython class. More general fun with strange code all around
the place.
Modified: pypy/dist/pypy/objspace/flow/model.py
==============================================================================
--- pypy/dist/pypy/objspace/flow/model.py (original)
+++ pypy/dist/pypy/objspace/flow/model.py Mon Jun 13 01:33:20 2005
@@ -75,7 +75,7 @@
class Link(object):
- __slots__ = """args target exitcase prevblock
+ __slots__ = """args target exitcase llexitcase prevblock
last_exception last_exc_value""".split()
def __init__(self, args, target, exitcase=None):
Added: pypy/dist/pypy/rpython/exceptiondata.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/exceptiondata.py Mon Jun 13 01:33:20 2005
@@ -0,0 +1,108 @@
+from pypy.annotation import model as annmodel
+from pypy.rpython import rclass
+from pypy.rpython.annlowlevel import annotate_lowlevel_helper
+from pypy.rpython.lltype import *
+
+
+class ExceptionData:
+ """Public information for the code generators to help with exceptions."""
+
+ def __init__(self, rtyper):
+ # (NB. rclass identifies 'Exception' and 'object')
+ r_type = rclass.getclassrepr(rtyper, None)
+ r_instance = rclass.getinstancerepr(rtyper, None)
+ r_type.setup()
+ r_instance.setup()
+ self.lltype_of_exception_type = r_type.lowleveltype
+ self.lltype_of_exception_value = r_instance.lowleveltype
+
+ # create helper functions
+ self.ll_exception_match = self.make_exception_matcher(rtyper)
+ self.ll_type_of_exc_inst = self.make_type_of_exc_inst(rtyper)
+ self.ll_pyexcclass2exc = self.make_pyexcclass2exc(rtyper)
+
+
+ def make_exception_matcher(self, rtyper):
+ # ll_exception_matcher(real_exception_vtable, match_exception_vtable)
+ s_typeptr = annmodel.SomePtr(self.lltype_of_exception_type)
+ dontcare, spec_function = annotate_lowlevel_helper(
+ rtyper.annotator, rclass.ll_issubclass, [s_typeptr, s_typeptr])
+ return spec_function
+
+
+ def make_type_of_exc_inst(self, rtyper):
+ # ll_type_of_exc_inst(exception_instance) -> exception_vtable
+ s_excinst = annmodel.SomePtr(self.lltype_of_exception_value)
+ dontcare, spec_function = annotate_lowlevel_helper(
+ rtyper.annotator, rclass.ll_type, [s_excinst])
+ return spec_function
+
+
+ def make_pyexcclass2exc(self, rtyper):
+ # ll_pyexcclass2exc(python_exception_class) -> exception_instance
+ table = {}
+ for clsdef in rtyper.class_reprs:
+ if (clsdef and clsdef.cls is not Exception
+ and issubclass(clsdef.cls, Exception)):
+ cls = clsdef.cls
+ if not clsdef.attrs:
+ r_inst = rclass.getinstancerepr(rtyper, clsdef)
+ r_inst.setup()
+ example = malloc(r_inst.lowleveltype.TO, immortal=True)
+ example = rclass.ll_cast_to_object(example)
+ example.typeptr = r_inst.rclass.getvtable()
+ table[cls] = example
+ else:
+ assert cls.__module__ != 'exceptions', (
+ "built-in exceptions should not grow attributes")
+ r_inst = rclass.getinstancerepr(rtyper, None)
+ r_inst.setup()
+ default_excinst = malloc(self.lltype_of_exception_value.TO,
+ immortal=True)
+ default_excinst.typeptr = r_inst.rclass.getvtable()
+
+ # build the table in order base classes first, subclasses last
+ sortedtable = []
+ def add_class(cls):
+ if cls in table:
+ for base in cls.__bases__:
+ add_class(base)
+ sortedtable.append((cls, table[cls]))
+ del table[cls]
+ for cls in table.keys():
+ add_class(cls)
+ assert table == {}
+ print sortedtable
+
+ A = Array(('pycls', Ptr(PyObject)),
+ ('excinst', self.lltype_of_exception_value))
+ pycls2excinst = malloc(A, len(sortedtable), immortal=True)
+ for i in range(len(sortedtable)):
+ cls, example = sortedtable[i]
+ pycls2excinst[i].pycls = pyobjectptr(cls)
+ pycls2excinst[i].excinst = example
+
+ FUNCTYPE = FuncType([Ptr(PyObject), Ptr(PyObject)], Signed)
+ PyErr_GivenExceptionMatches = functionptr(
+ FUNCTYPE, "PyErr_GivenExceptionMatches", external="C",
+ _callable=lambda pyobj1, pyobj2:
+ int(issubclass(pyobj1._obj.value, pyobj2._obj.value)))
+
+ initial_value_of_i = len(pycls2excinst)-1
+
+ def ll_pyexcclass2exc(python_exception_class):
+ """Return an RPython instance of the best approximation of the
+ Python exception identified by its Python class.
+ """
+ i = initial_value_of_i
+ while i >= 0:
+ if PyErr_GivenExceptionMatches(python_exception_class,
+ pycls2excinst[i].pycls):
+ return pycls2excinst[i].excinst
+ i -= 1
+ return default_excinst
+
+ s_pyobj = annmodel.SomePtr(Ptr(PyObject))
+ dontcare, spec_function = annotate_lowlevel_helper(
+ rtyper.annotator, ll_pyexcclass2exc, [s_pyobj])
+ return spec_function
Modified: pypy/dist/pypy/rpython/rclass.py
==============================================================================
--- pypy/dist/pypy/rpython/rclass.py (original)
+++ pypy/dist/pypy/rpython/rclass.py Mon Jun 13 01:33:20 2005
@@ -37,20 +37,36 @@
OBJECT_VTABLE.become(Struct('object_vtable', ('parenttypeptr', TYPEPTR)))
OBJECT = GcStruct('object', ('typeptr', TYPEPTR))
-
+OBJECTPTR = Ptr(OBJECT)
def getclassrepr(rtyper, classdef):
try:
result = rtyper.class_reprs[classdef]
except KeyError:
- result = rtyper.class_reprs[classdef] = ClassRepr(rtyper, classdef)
+ if classdef and classdef.cls is Exception:
+ # skip Exception as a base class and go directly to 'object'.
+ # the goal is to allow any class anywhere in the hierarchy
+ # to have Exception as a second base class. It should be an
+ # empty class anyway.
+ if classdef.attrs:
+ raise TyperError("the Exception class should not "
+ "have any attribute attached to it")
+ result = getclassrepr(rtyper, None)
+ else:
+ result = ClassRepr(rtyper, classdef)
+ rtyper.class_reprs[classdef] = result
return result
def getinstancerepr(rtyper, classdef):
try:
result = rtyper.instance_reprs[classdef]
except KeyError:
- result = rtyper.instance_reprs[classdef] = InstanceRepr(rtyper,classdef)
+ if classdef and classdef.cls is Exception:
+ # see getclassrepr()
+ result = getinstancerepr(rtyper, None)
+ else:
+ result = InstanceRepr(rtyper,classdef)
+ rtyper.instance_reprs[classdef] = result
return result
class MissingRTypeAttribute(TyperError):
@@ -467,3 +483,25 @@
classdef = hop.rtyper.annotator.getuserclasses()[cls]
rinstance = getinstancerepr(hop.rtyper, classdef)
return rinstance.new_instance(hop.llops)
+
+# ____________________________________________________________
+#
+# Low-level implementation of operations on classes and instances
+
+def ll_cast_to_object(obj):
+ # This strange recursive version is type-safe :-)
+ # Each ll_cast_to_object() call below is done with a different type.
+ if typeOf(obj) == OBJECTPTR:
+ return obj
+ else:
+ return ll_cast_to_object(obj.super)
+
+def ll_type(obj):
+ return ll_cast_to_object(obj).typeptr
+
+def ll_issubclass(subcls, cls):
+ while subcls != cls:
+ if not subcls:
+ return False
+ subcls = subcls.parenttypeptr
+ return True
Modified: pypy/dist/pypy/rpython/rptr.py
==============================================================================
--- pypy/dist/pypy/rpython/rptr.py (original)
+++ pypy/dist/pypy/rpython/rptr.py Mon Jun 13 01:33:20 2005
@@ -1,18 +1,18 @@
from pypy.annotation.pairtype import pairtype
from pypy.annotation import model as annmodel
from pypy.rpython.lltype import Ptr, _ptr
-from pypy.rpython.lltype import ContainerType, Void, Signed, Bool
+from pypy.rpython.lltype import ContainerType, Void, Signed, Bool, FuncType
from pypy.rpython.rmodel import Repr, TyperError, IntegerRepr, inputconst
class __extend__(annmodel.SomePtr):
def rtyper_makerepr(self, rtyper):
- if self.is_constant(): # constant NULL
+ if self.is_constant() and not self.const: # constant NULL
return nullptr_repr
else:
return PtrRepr(self.ll_ptrtype)
def rtyper_makekey(self):
- if self.is_constant():
+ if self.is_constant() and not self.const:
return None
else:
return self.ll_ptrtype
@@ -51,6 +51,13 @@
vlist = hop.inputargs(self)
return hop.genop('ptr_nonzero', vlist, resulttype=Bool)
+ def rtype_simple_call(self, hop):
+ if not isinstance(self.lowleveltype.TO, FuncType):
+ raise TyperError("calling a non-function %r", self.lowleveltype.TO)
+ vlist = hop.inputargs(*hop.args_r)
+ return hop.genop('direct_call', vlist,
+ resulttype = self.lowleveltype.TO.RESULT)
+
class __extend__(pairtype(PtrRepr, IntegerRepr)):
Modified: pypy/dist/pypy/rpython/rtyper.py
==============================================================================
--- pypy/dist/pypy/rpython/rtyper.py (original)
+++ pypy/dist/pypy/rpython/rtyper.py Mon Jun 13 01:33:20 2005
@@ -2,7 +2,7 @@
from pypy.annotation.pairtype import pair
from pypy.annotation import model as annmodel
from pypy.objspace.flow.model import Variable, Constant, Block, Link
-from pypy.objspace.flow.model import SpaceOperation
+from pypy.objspace.flow.model import SpaceOperation, last_exception
from pypy.rpython.lltype import Signed, Unsigned, Float, Char, Bool, Void
from pypy.rpython.lltype import LowLevelType, Ptr, ContainerType
from pypy.rpython.lltype import FuncType, functionptr, typeOf
@@ -11,6 +11,7 @@
from pypy.rpython.rmodel import Repr, inputconst, TyperError, getfunctionptr
from pypy.rpython.normalizecalls import perform_normalizations
from pypy.rpython.annlowlevel import annotate_lowlevel_helper
+from pypy.rpython.exceptiondata import ExceptionData
debug = False
@@ -36,6 +37,9 @@
r = self.getrepr(s_primitive)
self.primitive_to_repr[r.lowleveltype] = r
+ def getexceptiondata(self):
+ return self.exceptiondata # built at the end of specialize()
+
def getrepr(self, s_obj):
# s_objs are not hashable... try hard to find a unique key anyway
key = s_obj.__class__, s_obj.rtyper_makekey()
@@ -69,17 +73,25 @@
# new blocks can be created as a result of specialize_block(), so
# we need to be careful about the loop here.
already_seen = {}
- pending = self.annotator.annotated.keys()
- while pending:
- # specialize all blocks in the 'pending' list
- for block in pending:
- self.specialize_block(block)
- already_seen[block] = True
- # make sure all reprs so far have had their setup() called
- self.call_all_setups()
- # look for newly created blocks
- pending = [block for block in self.annotator.annotated
- if block not in already_seen]
+
+ def specialize_more_blocks():
+ while True:
+ # look for blocks not specialized yet
+ pending = [block for block in self.annotator.annotated
+ if block not in already_seen]
+ if not pending:
+ break
+ # specialize all blocks in the 'pending' list
+ for block in pending:
+ self.specialize_block(block)
+ already_seen[block] = True
+ # make sure all reprs so far have had their setup() called
+ self.call_all_setups()
+
+ specialize_more_blocks()
+ self.exceptiondata = ExceptionData(self)
+ specialize_more_blocks()
+
if self.typererror:
exc, value, tb = self.typererror
self.typererror = None
@@ -128,6 +140,13 @@
# insert the needed conversions on the links
can_insert_here = block.exitswitch is None and len(block.exits) == 1
for link in block.exits:
+ if block.exitswitch is not None and link.exitcase is not None:
+ if isinstance(block.exitswitch, Variable):
+ r_case = self.bindingrepr(block.exitswitch)
+ else:
+ assert block.exitswitch == Constant(last_exception)
+ r_case = rclass.get_type_repr(self)
+ link.llexitcase = r_case.convert_const(link.exitcase)
for a in [link.last_exception, link.last_exc_value]:
if isinstance(a, Variable):
self.setconcretetype(a)
@@ -282,8 +301,7 @@
self.s_result = rtyper.binding(spaceop.result)
self.args_r = [rtyper.getrepr(s_a) for s_a in self.args_s]
self.r_result = rtyper.getrepr(self.s_result)
- for r in self.args_r + [self.r_result]:
- r.setup()
+ rtyper.call_all_setups() # compute ForwardReferences now
def inputarg(self, converted_to, arg):
"""Returns the arg'th input argument of the current operation,
@@ -402,5 +420,5 @@
from pypy.rpython import rint, rbool, rfloat
from pypy.rpython import rslice
from pypy.rpython import rlist, rstr, rtuple
-from pypy.rpython import rbuiltin, rpbc
+from pypy.rpython import rclass, rbuiltin, rpbc
from pypy.rpython import rptr
Modified: pypy/dist/pypy/rpython/test/test_exception.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_exception.py (original)
+++ pypy/dist/pypy/rpython/test/test_exception.py Mon Jun 13 01:33:20 2005
@@ -6,6 +6,9 @@
class MyException(Exception):
pass
+class MyStrangeException: # no (Exception) here
+ pass
+
def test_simple():
def g():
@@ -23,3 +26,27 @@
typer.specialize()
#t.view()
t.checkgraphs()
+
+
+def test_exception_data():
+ def f(n):
+ raise OverflowError()
+
+ t = Translator(f)
+ a = t.annotate([int])
+ t.specialize()
+ data = t.rtyper.getexceptiondata()
+ #t.view()
+ ovferr_inst = data.ll_pyexcclass2exc(pyobjectptr(OverflowError))
+ classdef = a.bookkeeper.getclassdef(OverflowError)
+ assert ovferr_inst.typeptr == t.rtyper.class_reprs[classdef].getvtable()
+
+ keyerr_inst = data.ll_pyexcclass2exc(pyobjectptr(KeyError))
+ classdef = a.bookkeeper.getclassdef(StandardError) # most precise class seen
+ assert keyerr_inst.typeptr == t.rtyper.class_reprs[classdef].getvtable()
+
+ myerr_inst = data.ll_pyexcclass2exc(pyobjectptr(MyException))
+ assert myerr_inst.typeptr == t.rtyper.class_reprs[None].getvtable()
+
+ strgerr_inst = data.ll_pyexcclass2exc(pyobjectptr(MyStrangeException))
+ assert strgerr_inst.typeptr == t.rtyper.class_reprs[None].getvtable()
More information about the Pypy-commit
mailing list