[pypy-svn] r46032 - in pypy/branch/pypy-more-rtti-inprogress: config translator/cli translator/cli/src translator/cli/test translator/jvm translator/oosupport translator/oosupport/test_template

antocuni at codespeak.net antocuni at codespeak.net
Mon Aug 27 16:08:53 CEST 2007


Author: antocuni
Date: Mon Aug 27 16:08:52 2007
New Revision: 46032

Removed:
   pypy/branch/pypy-more-rtti-inprogress/translator/cli/stackopt.py
   pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_stackopt.py
Modified:
   pypy/branch/pypy-more-rtti-inprogress/config/translationoption.py
   pypy/branch/pypy-more-rtti-inprogress/translator/cli/class_.py
   pypy/branch/pypy-more-rtti-inprogress/translator/cli/conftest.py
   pypy/branch/pypy-more-rtti-inprogress/translator/cli/constant.py
   pypy/branch/pypy-more-rtti-inprogress/translator/cli/cts.py
   pypy/branch/pypy-more-rtti-inprogress/translator/cli/function.py
   pypy/branch/pypy-more-rtti-inprogress/translator/cli/gencli.py
   pypy/branch/pypy-more-rtti-inprogress/translator/cli/ilgenerator.py
   pypy/branch/pypy-more-rtti-inprogress/translator/cli/metavm.py
   pypy/branch/pypy-more-rtti-inprogress/translator/cli/option.py
   pypy/branch/pypy-more-rtti-inprogress/translator/cli/prebuiltnodes.py
   pypy/branch/pypy-more-rtti-inprogress/translator/cli/record.py
   pypy/branch/pypy-more-rtti-inprogress/translator/cli/src/pypylib.cs
   pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/runtest.py
   pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_dotnet.py
   pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_exception.py
   pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_runtest.py
   pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_snippet.py
   pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_string.py
   pypy/branch/pypy-more-rtti-inprogress/translator/jvm/node.py
   pypy/branch/pypy-more-rtti-inprogress/translator/oosupport/function.py
   pypy/branch/pypy-more-rtti-inprogress/translator/oosupport/test_template/snippets.py
Log:
merge translator/{cli,jvm,oosupport} and config from dist



Modified: pypy/branch/pypy-more-rtti-inprogress/config/translationoption.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/config/translationoption.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/config/translationoption.py	Mon Aug 27 16:08:52 2007
@@ -196,7 +196,8 @@
 
     OptionDescription("cli", "GenCLI options", [
         BoolOption("trace_calls", "Trace function calls", default=False,
-                   cmdline="--cli-trace-calls")
+                   cmdline="--cli-trace-calls"),
+        BoolOption("exception_transformer", "Use exception transformer", default=False),
     ]),
 ])
 

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/cli/class_.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/cli/class_.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/cli/class_.py	Mon Aug 27 16:08:52 2007
@@ -84,7 +84,7 @@
         for f_name, (f_type, f_default) in self.INSTANCE._fields.iteritems():
             cts_type = self.cts.lltype_to_cts(f_type)
             f_name = self.cts.escape_name(f_name)
-            if cts_type != 'void':
+            if cts_type != CTS.types.void:
                 ilasm.field(f_name, cts_type)
 
         self._ctor()
@@ -134,7 +134,7 @@
             INSTANCE_DEF, _ = self.INSTANCE._lookup_field(f_name)
             cts_type = self.cts.lltype_to_cts(F_TYPE)
             f_name = self.cts.escape_name(f_name)
-            if cts_type != 'void':
+            if cts_type != CTS.types.void:
                 self.ilasm.opcode('ldarg.0')
                 push_constant(self.db, F_TYPE, f_default, self.gen)
                 class_name = self.db.class_name(INSTANCE_DEF)

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/cli/conftest.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/cli/conftest.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/cli/conftest.py	Mon Aug 27 16:08:52 2007
@@ -26,8 +26,8 @@
           Option('--norun', action='store_true', dest="norun", default=False,
                  help="don't run the compiled executable"),
 
-          Option('--nostackopt', action='store_true', dest='nostackopt', default=False,
-                 help="don't optimize stack load/store operations"),
+          Option('--trace', action='store_true', dest='trace', default=False,
+                 help='Trace execution of generated code'),
           )
 
 

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/cli/constant.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/cli/constant.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/cli/constant.py	Mon Aug 27 16:08:52 2007
@@ -265,9 +265,9 @@
 class CLIBaseConstMixin(object):
     """ A mix-in with a few extra methods the CLI backend uses """
     
-    def get_type(self, include_class=True):
+    def get_type(self):
         """ Returns the CLI type for this constant's representation """
-        return self.cts.lltype_to_cts(self.value._TYPE, include_class)
+        return self.cts.lltype_to_cts(self.value._TYPE)
     
     def push_inline(self, gen, TYPE):
         """ Overload the oosupport version so that we use the CLI opcode

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/cli/cts.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/cli/cts.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/cli/cts.py	Mon Aug 27 16:08:52 2007
@@ -4,61 +4,146 @@
 
 import exceptions
 
-from pypy.rpython.lltypesystem.lltype import SignedLongLong, UnsignedLongLong
+from py.builtin import set
 from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.ootypesystem import ootype
 from pypy.rpython.lltypesystem.llmemory import WeakGcAddress
 from pypy.translator.cli.option import getoption
 from pypy.translator.cli import oopspec
 
-try:
-    set
-except NameError:
-    from sets import Set as set
-
 from pypy.tool.ansi_print import ansi_log
 import py
 log = py.log.Producer("cli") 
 py.log.setconsumer("cli", ansi_log) 
 
-WEAKREF = '[mscorlib]System.WeakReference'
-PYPY_LIST = '[pypylib]pypy.runtime.List`1<%s>'
-PYPY_LIST_OF_VOID = '[pypylib]pypy.runtime.ListOfVoid'
-PYPY_DICT = '[pypylib]pypy.runtime.Dict`2<%s, %s>'
+class CliType(object):
+    def typename(self):
+        raise NotImplementedError
+
+    def __str__(self):
+        return self.typename()
+
+    def __hash__(self):
+        return hash(self.typename())
+
+    def __eq__(self, other):
+        return self.typename() == other.typename()
+
+    def __ne__(self, other):
+        return self.typename() != other.typename()
+
+
+class CliPrimitiveType(CliType):
+    def __init__(self, name):
+        self.name = name
+
+    def typename(self):
+        return self.name
+
+
+class CliReferenceType(CliType):
+    def typename(self):
+        return 'class ' + self.classname()
+
+    def classname(self):
+        raise NotImplementedError
+
+
+class CliClassType(CliReferenceType):
+    def __init__(self, assembly, name):
+        self.assembly = assembly
+        self.name = name
+
+    def classname(self):
+        if self.assembly:
+            return '[%s]%s' % (self.assembly, self.name)
+        else:
+            return self.name
+
+
+class CliGenericType(CliReferenceType):
+    def __init__(self, assembly, name, numparam):
+        self.assembly = assembly
+        self.name = name
+        self.numparam = numparam
+
+    def classname(self):
+        paramtypes = [self.paramtype(i) for i in range(self.numparam)]
+        thistype = self.specialize(*paramtypes)
+        return thistype.classname()
+
+    def specialize(self, *types):
+        assert len(types) == self.numparam
+        return CliSpecializedType(self, types)
+
+    def paramtype(self, num):
+        assert 0 <= num < self.numparam
+        return CliPrimitiveType('!%d' % num)
+
+class CliSpecializedType(CliReferenceType):
+    def __init__(self, generic_type, arg_types):
+        self.generic_type = generic_type
+        self.arg_types = arg_types
+
+    def classname(self):
+        assembly = self.generic_type.assembly
+        name = self.generic_type.name
+        numparam = self.generic_type.numparam
+        arglist = ', '.join([arg.typename() for arg in self.arg_types])
+        return '[%s]%s`%d<%s>' % (assembly, name, numparam, arglist)
+
+
+T = CliPrimitiveType
+class types:
+    void =    T('void')
+    int32 =   T('int32')
+    uint32 =  T('unsigned int32')
+    int64 =   T('int64')
+    uint64 =  T('unsigned int64')
+    bool =    T('bool')
+    float64 = T('float64')
+    char =    T('char')
+    string =  T('string')
+
+    weakref = CliClassType('mscorlib', 'System.WeakReference')
+    type = CliClassType('mscorlib', 'System.Type')
+    object = CliClassType('mscorlib', 'System.Object')
+    list = CliGenericType('pypylib', 'pypy.runtime.List', 1)
+    list_of_void = CliClassType('pypylib', 'pypy.runtime.ListOfVoid')
+    dict = CliGenericType('pypylib', 'pypy.runtime.Dict', 2)
+    dict_void_void = CliClassType('pypylib', 'pypy.runtime.DictVoidVoid')
+    dict_items_iterator = CliGenericType('pypylib', 'pypy.runtime.DictItemsIterator', 2)
+    string_builder = CliClassType('pypylib', 'pypy.runtime.StringBuilder')
+del T
+
+WEAKREF = types.weakref.classname()
 PYPY_DICT_OF_VOID = '[pypylib]pypy.runtime.DictOfVoid`2<%s, int32>'
-PYPY_DICT_VOID_VOID = '[pypylib]pypy.runtime.DictVoidVoid'
-PYPY_DICT_ITEMS_ITERATOR = '[pypylib]pypy.runtime.DictItemsIterator`2<%s, %s>'
-PYPY_STRING_BUILDER = '[pypylib]pypy.runtime.StringBuilder'
+
 
 _lltype_to_cts = {
-    ootype.Void: 'void',
-    ootype.Signed: 'int32',    
-    ootype.Unsigned: 'unsigned int32',
-    SignedLongLong: 'int64',
-    UnsignedLongLong: 'unsigned int64',
-    ootype.Bool: 'bool',
-    ootype.Float: 'float64',
-    ootype.Char: 'char',
-    ootype.UniChar: 'char',
-    ootype.Class: 'class [mscorlib]System.Type',
-    ootype.String: 'string',
-    ootype.StringBuilder: 'class ' + PYPY_STRING_BUILDER,
-    WeakGcAddress: 'class ' + WEAKREF,
+    ootype.Void: types.void,
+    ootype.Signed: types.int32,    
+    ootype.Unsigned: types.uint32,
+    ootype.SignedLongLong: types.int64,
+    ootype.UnsignedLongLong: types.uint64,
+    ootype.Bool: types.bool,
+    ootype.Float: types.float64,
+    ootype.Char: types.char,
+    ootype.UniChar: types.char,
+    ootype.Class: types.type,
+    ootype.String: types.string,
+    ootype.StringBuilder: types.string_builder,
+    WeakGcAddress: types.weakref,
 
     # maps generic types to their ordinal
-    ootype.List.SELFTYPE_T: 'class ' + (PYPY_LIST % '!0'),
-    ootype.List.ITEMTYPE_T: '!0',
-    ootype.Dict.SELFTYPE_T: 'class ' + (PYPY_DICT % ('!0', '!1')),
-    ootype.Dict.KEYTYPE_T: '!0',
-    ootype.Dict.VALUETYPE_T: '!1',
-    ootype.DictItemsIterator.SELFTYPE_T: 'class ' + (PYPY_DICT_ITEMS_ITERATOR % ('!0', '!1')),
-    ootype.DictItemsIterator.KEYTYPE_T: '!0',
-    ootype.DictItemsIterator.VALUETYPE_T: '!1',
-    }
-
-_pyexception_to_cts = {
-    exceptions.Exception: '[mscorlib]System.Exception',
-    exceptions.OverflowError: '[mscorlib]System.OverflowException'
+    ootype.List.SELFTYPE_T: types.list,
+    ootype.List.ITEMTYPE_T: types.list.paramtype(0),
+    ootype.Dict.SELFTYPE_T: types.dict,
+    ootype.Dict.KEYTYPE_T: types.dict.paramtype(0),
+    ootype.Dict.VALUETYPE_T: types.dict.paramtype(1),
+    ootype.DictItemsIterator.SELFTYPE_T: types.dict_items_iterator,
+    ootype.DictItemsIterator.KEYTYPE_T: types.dict_items_iterator.paramtype(0),
+    ootype.DictItemsIterator.VALUETYPE_T: types.dict_items_iterator.paramtype(1),
     }
 
 
@@ -122,17 +207,14 @@
     "readonly", "refanytype", "refanyval", "rem", "ret", "rethrow",
     "shl", "shr", "sizeof", "starg", "stelem", "stfld", "stind",
     "stloc", "stobj", "stsfld", "sub", "switch", "tail", "throw",
-    "unaligned", "unbox", "volatile", "xor"])
+    "unaligned", "unbox", "volatile", "xor", "ole"])
+    # ole is not a keyword, but mono ilasm fails if you use it as a field/method name
+
+    types = types # for convenience
 
     def __init__(self, db):
         self.db = db
 
-    def __class(self, result, include_class):
-        if include_class:
-            return 'class ' + result
-        else:
-            return result
-
     def escape_name(self, name):
         """Mangle then name if it's a ilasm reserved word"""
         if name in self.ILASM_KEYWORDS:
@@ -140,46 +222,47 @@
         else:
             return name
 
-    def lltype_to_cts(self, t, include_class=True):
+    def lltype_to_cts(self, t):
         if t is ootype.ROOT:
-            return self.__class('[mscorlib]System.Object', include_class)
+            return types.object
         elif isinstance(t, lltype.Ptr) and isinstance(t.TO, lltype.OpaqueType):
-            return self.__class('[mscorlib]System.Object', include_class)
+            return types.object
         elif isinstance(t, ootype.Instance):
             NATIVE_INSTANCE = t._hints.get('NATIVE_INSTANCE', None)
             if NATIVE_INSTANCE:
-                return self.__class(NATIVE_INSTANCE._name, include_class)
+                return CliClassType(None, NATIVE_INSTANCE._name)
             else:
                 name = self.db.pending_class(t)
-                return self.__class(name, include_class)
+                return CliClassType(None, name)
         elif isinstance(t, ootype.Record):
             name = self.db.pending_record(t)
-            return self.__class(name, include_class)
+            return CliClassType(None, name)
         elif isinstance(t, ootype.StaticMethod):
             delegate = self.db.record_delegate(t)
-            return self.__class(delegate, include_class)
+            return CliClassType(None, delegate)
         elif isinstance(t, ootype.List):
             item_type = self.lltype_to_cts(t._ITEMTYPE)
-            if item_type == 'void': # special case: List of Void
-                return self.__class(PYPY_LIST_OF_VOID, include_class)
-            return self.__class(PYPY_LIST % item_type, include_class)
+            if item_type == types.void: # special case: List of Void
+                return types.list_of_void
+            return types.list.specialize(item_type)
         elif isinstance(t, ootype.Dict):
             key_type = self.lltype_to_cts(t._KEYTYPE)
             value_type = self.lltype_to_cts(t._VALUETYPE)
-            if value_type == 'void': # special cases: Dict with voids
-                if key_type == 'void':
-                    return self.__class(PYPY_DICT_VOID_VOID, include_class)
+            if value_type == types.void: # special cases: Dict with voids
+                if key_type == types.void:
+                    return types.dict_void_void
                 else:
-                    return self.__class(PYPY_DICT_OF_VOID % key_type, include_class)
-            return self.__class(PYPY_DICT % (key_type, value_type), include_class)
+                    # XXX
+                    return CliClassType(None, PYPY_DICT_OF_VOID % key_type)
+            return types.dict.specialize(key_type, value_type)
         elif isinstance(t, ootype.DictItemsIterator):
             key_type = self.lltype_to_cts(t._KEYTYPE)
             value_type = self.lltype_to_cts(t._VALUETYPE)
-            if key_type == 'void':
-                key_type = 'int32' # placeholder
-            if value_type == 'void':
-                value_type = 'int32' # placeholder
-            return self.__class(PYPY_DICT_ITEMS_ITERATOR % (key_type, value_type), include_class)
+            if key_type == types.void:
+                key_type = types.int32 # placeholder
+            if value_type == types.void:
+                value_type = types.int32 # placeholder
+            return types.dict_items_iterator.specialize(key_type, value_type)
 
         return _get_from_dict(_lltype_to_cts, t, 'Unknown type %s' % t)
 
@@ -204,7 +287,7 @@
         if is_method:
             args = args[1:]
 
-        arg_types = [self.lltype_to_cts(arg.concretetype) for arg in args]
+        arg_types = [self.lltype_to_cts(arg.concretetype).typename() for arg in args]
         arg_list = ', '.join(arg_types)
 
         return '%s %s(%s)' % (ret_type, func_name, arg_list)
@@ -216,7 +299,7 @@
         args = [arg for arg in op.args[1:]
                     if arg.concretetype is not ootype.Void]
 
-        arg_types = [self.lltype_to_cts(arg.concretetype) for arg in args]
+        arg_types = [self.lltype_to_cts(arg.concretetype).typename() for arg in args]
         arg_list = ', '.join(arg_types)
 
         return '%s %s(%s)' % (ret_type, func_name, arg_list)
@@ -235,9 +318,9 @@
                 METH = meth._TYPE
                 virtual = getattr(meth, '_virtual', True)
             class_name = self.db.class_name(TYPE)
-            full_name = 'class %s::%s' % (class_name, name)
+            full_name = 'class %s::%s' % (class_name, self.escape_name(name))
             returntype = self.lltype_to_cts(METH.RESULT)
-            arg_types = [self.lltype_to_cts(ARG) for ARG in METH.ARGS if ARG is not ootype.Void]
+            arg_types = [self.lltype_to_cts(ARG).typename() for ARG in METH.ARGS if ARG is not ootype.Void]
             arg_list = ', '.join(arg_types)
             return '%s %s(%s)' % (returntype, full_name, arg_list), virtual
 
@@ -255,16 +338,16 @@
                 name = name_or_desc
                 if KEY is ootype.Void and VALUE is ootype.Void and name == 'll_get_items_iterator':
                     # ugly, ugly special case
-                    ret_type = 'class ' + PYPY_DICT_ITEMS_ITERATOR % ('int32', 'int32')
+                    ret_type = types.dict_items_iterator.specialize(types.int32, types.int32)
                 elif VALUE is ootype.Void and METH.RESULT is ootype.Dict.VALUETYPE_T:
-                    ret_type = 'void'
+                    ret_type = types.void
                 else:
                     ret_type = self.lltype_to_cts(METH.RESULT)
                     ret_type = dict_of_void_ll_copy_hack(TYPE, ret_type)
             else:
                 ret_type = self.lltype_to_cts(METH.RESULT)
             generic_types = getattr(TYPE, '_generic_types', {})
-            arg_types = [self.lltype_to_cts(arg) for arg in METH.ARGS if
+            arg_types = [self.lltype_to_cts(arg).typename() for arg in METH.ARGS if
                          arg is not ootype.Void and \
                          generic_types.get(arg, arg) is not ootype.Void]
             arg_list = ', '.join(arg_types)
@@ -277,6 +360,6 @@
     # XXX: ugly hack to make the ll_copy signature correct when
     # CustomDict is special-cased to DictOfVoid.
     if isinstance(TYPE, ootype.CustomDict) and TYPE._VALUETYPE is ootype.Void:
-        return ret_type.replace('Dict`2', 'DictOfVoid`2')
+        return ret_type.typename().replace('Dict`2', 'DictOfVoid`2')
     else:
         return ret_type

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/cli/function.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/cli/function.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/cli/function.py	Mon Aug 27 16:08:52 2007
@@ -18,163 +18,17 @@
 from pypy.translator.cli.support import log
 from pypy.translator.cli.ilgenerator import CLIBaseGenerator
 
-USE_LAST = False
+class Function(OOFunction, Node, CLIBaseGenerator):
 
-class NativeExceptionHandler(object):
-    def begin_try(self):
-        self.ilasm.begin_try()
-
-    def end_try(self, target_label):
-        self.ilasm.leave(target_label)
-        self.ilasm.end_try()
-
-    def begin_catch(self, llexitcase):
-        ll_meta_exc = llexitcase
-        ll_exc = ll_meta_exc._inst.class_._INSTANCE
-        cts_exc = self.cts.lltype_to_cts(ll_exc, False)
-        self.ilasm.begin_catch(cts_exc)
-
-    def end_catch(self, target_label):
-        self.ilasm.leave(target_label)
-        self.ilasm.end_catch()
-
-    def render_raise_block(self, block):
-        exc = block.inputargs[1]
-        self.load(exc)
-        self.ilasm.opcode('throw')
-
-    def store_exception_and_link(self, link):
-        if self._is_raise_block(link.target):
-            # the exception value is on the stack, use it as the 2nd target arg
-            assert len(link.args) == 2
-            assert len(link.target.inputargs) == 2
-            self.store(link.target.inputargs[1])
-        else:
-            # the exception value is on the stack, store it in the proper place
-            if isinstance(link.last_exception, flowmodel.Variable):
-                self.ilasm.opcode('dup')
-                self.store(link.last_exc_value)                            
-                self.ilasm.get_field(('class Object_meta', 'Object', 'meta'))
-                self.store(link.last_exception)
-            else:
-                self.store(link.last_exc_value)
-            self._setup_link(link)
-
-class LastExceptionHandler(object):
-    in_try = False
-
-    def begin_try(self):
-        self.in_try = True
-        self.ilasm.opcode('// begin_try')
-
-    def end_try(self, target_label):
-        self.ilasm.opcode('ldsfld', 'object last_exception')
-        self.ilasm.opcode('brnull', target_label)
-        self.ilasm.opcode('// end try')
-        self.in_try = False
-
-    def begin_catch(self, llexitcase):
-        self.ilasm.label(self.current_label('catch'))
-        ll_meta_exc = llexitcase
-        ll_exc = ll_meta_exc._inst.class_._INSTANCE
-        cts_exc = self.cts.lltype_to_cts(ll_exc, False)
-        self.ilasm.opcode('ldsfld', 'object last_exception')
-        self.isinstance(cts_exc)
-        self.ilasm.opcode('dup')
-        self.ilasm.opcode('brtrue.s', 6)
-        self.ilasm.opcode('pop')
-        self.ilasm.opcode('br', self.next_label('catch'))
-        # here is the target of the above brtrue.s
-        self.ilasm.opcode('ldnull')
-        self.ilasm.opcode('stsfld', 'object last_exception')
-
-    def end_catch(self, target_label):
-        self.ilasm.opcode('br', target_label)
-
-    def store_exception_and_link(self, link):
-        if self._is_raise_block(link.target):
-            # the exception value is on the stack, use it as the 2nd target arg
-            assert len(link.args) == 2
-            assert len(link.target.inputargs) == 2
-            self.store(link.target.inputargs[1])
-        else:
-            # the exception value is on the stack, store it in the proper place
-            if isinstance(link.last_exception, flowmodel.Variable):
-                self.ilasm.opcode('dup')
-                self.store(link.last_exc_value)                            
-                self.ilasm.get_field(('class Object_meta', 'Object', 'meta'))
-                self.store(link.last_exception)
-            else:
-                self.store(link.last_exc_value)
-            self._setup_link(link)
-
-    def before_last_blocks(self):
-        self.ilasm.label(self.current_label('catch'))
-        self.ilasm.opcode('nop')
-
-    def render_raise_block(self, block):
-        exc = block.inputargs[1]
-        self.load(exc)
-        self.ilasm.opcode('stsfld', 'object last_exception')
-        if not self.return_block: # must be a void function
-            TYPE = self.graph.getreturnvar().concretetype
-            default = TYPE._defl()
-            if default is not None: # concretetype is Void
-                try:
-                    self.db.constant_generator.push_primitive_constant(self, TYPE, default)
-                except AssertionError:
-                    self.ilasm.opcode('ldnull') # :-(
-            self.ilasm.opcode('ret')
-        else:
-            self.ilasm.opcode('br', self._get_block_name(self.return_block))
-
-    def _render_op(self, op):
-        OOFunction._render_op(self, op)
-        if op.opname in ('direct_call', 'oosend', 'indirect_call') and not self.in_try:
-            self._premature_return()
-
-    def _render_sub_op(self, sub_op):
-        OOFunction._render_sub_op(self, sub_op)
-        if sub_op.op.opname in ('direct_call', 'oosend', 'indirect_call') and not self.in_try:
-            self._premature_return(need_pop=sub_op.op.result is not ootype.Void)
-
-
-    def _premature_return(self, need_pop=False):
-        try:
-            return_block = self._get_block_name(self.graph.returnblock)
-        except KeyError:
-            self.ilasm.opcode('//premature return')
-            self.ilasm.opcode('ldsfld', 'object last_exception')
-            TYPE = self.graph.getreturnvar().concretetype
-            default = TYPE._defl()
-            if default is None: # concretetype is Void
-                self.ilasm.opcode('brfalse.s', 1)
-                self.ilasm.opcode('ret')
-            else:
-                self.ilasm.opcode('brfalse.s', 3) # ??
-                try:
-                    self.db.constant_generator.push_primitive_constant(self, TYPE, default)
-                except AssertionError:
-                    self.ilasm.opcode('ldnull') # :-(
-                self.ilasm.opcode('ret')
-        else:
-            self.ilasm.opcode('ldsfld', 'object last_exception')
-            self.ilasm.opcode('brtrue', return_block)
-
-
-if USE_LAST:
-    ExceptionHandler = LastExceptionHandler
-else:
-    ExceptionHandler = NativeExceptionHandler
-
-class Function(ExceptionHandler, OOFunction, Node, CLIBaseGenerator):
+    auto_propagate_exceptions = True
 
     def __init__(self, *args, **kwargs):
         OOFunction.__init__(self, *args, **kwargs)
-        self._set_args()
-        self._set_locals()
+
+        if hasattr(self.db.genoo, 'exceptiontransformer'):
+            self.auto_propagate_exceptions = False
+        
         namespace = getattr(self.graph.func, '_namespace_', None)
-        str
         if namespace:
             if '.' in namespace:
                 self.namespace, self.classname = namespace.rsplit('.', 1)
@@ -195,7 +49,25 @@
         if NATIVE_INSTANCE is None:
             OOFunction.record_ll_meta_exc(self, ll_meta_exc)
 
+    def _trace_enabled(self):
+        return getoption('trace')
+
+    def _trace(self, s, writeline=False):
+        self.ilasm.stderr(s, writeline=writeline)
+
+    def _trace_value(self, prompt, v):
+        self.ilasm.stderr('  ' + prompt + ': ', writeline=False)
+        self.ilasm.load_stderr()
+        self.load(v)
+        if v.concretetype is not ootype.String:
+            from pypy.translator.cli.test.runtest import format_object
+            format_object(v.concretetype, self.cts, self.ilasm)
+        self.ilasm.write_stderr()
+
     def begin_render(self):
+        self._set_args()
+        self._set_locals()
+        
         returntype, returnvar = self.cts.llvar_to_cts(self.graph.getreturnvar())
         if self.is_method:
             args = self.args[1:] # self is implicit
@@ -227,6 +99,49 @@
             self.load(return_var)
         self.ilasm.opcode('ret')
 
+    def begin_try(self, cond):
+        if cond:
+            self.ilasm.begin_try()
+
+    def end_try(self, target_label, cond):
+        if cond:
+            self.ilasm.leave(target_label)
+            self.ilasm.end_try()
+        else:
+            self.ilasm.branch(target_label)
+
+    def begin_catch(self, llexitcase):
+        ll_meta_exc = llexitcase
+        ll_exc = ll_meta_exc._inst.class_._INSTANCE
+        cts_exc = self.cts.lltype_to_cts(ll_exc)
+        self.ilasm.begin_catch(cts_exc.classname())
+
+    def end_catch(self, target_label):
+        self.ilasm.leave(target_label)
+        self.ilasm.end_catch()
+
+    def render_raise_block(self, block):
+        exc = block.inputargs[1]
+        self.load(exc)
+        self.ilasm.opcode('throw')
+
+    def store_exception_and_link(self, link):
+        if self._is_raise_block(link.target):
+            # the exception value is on the stack, use it as the 2nd target arg
+            assert len(link.args) == 2
+            assert len(link.target.inputargs) == 2
+            self.store(link.target.inputargs[1])
+        else:
+            # the exception value is on the stack, store it in the proper place
+            if isinstance(link.last_exception, flowmodel.Variable):
+                self.ilasm.opcode('dup')
+                self.store(link.last_exc_value)
+                self.ilasm.get_field(('class Object_meta', 'Object', 'meta'))
+                self.store(link.last_exception)
+            else:
+                self.store(link.last_exc_value)
+            self._setup_link(link)
+
     # XXX: this method should be moved into oosupport, but other
     # backends are not ready :-(
     def render_bool_switch(self, block):
@@ -239,7 +154,7 @@
 
         true_label = self.next_label('link_true')
         self.generator.load(block.exitswitch)
-        self.generator.branch_conditionally(link.exitcase, true_label)
+        self.generator.branch_conditionally(True, true_label)
         self._follow_link(link_false) # if here, the exitswitch is false
         self.set_label(true_label)
         self._follow_link(link_true)  # if here, the exitswitch is true

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/cli/gencli.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/cli/gencli.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/cli/gencli.py	Mon Aug 27 16:08:52 2007
@@ -19,7 +19,6 @@
 from pypy.translator.cli.rte import get_pypy_dll
 from pypy.translator.cli.support import Tee
 from pypy.translator.cli.prebuiltnodes import get_prebuilt_nodes
-from pypy.translator.cli.stackopt import StackOptGenerator
 from pypy.translator.cli import query
 from pypy.translator.cli import constant
 
@@ -28,10 +27,6 @@
 except NameError:
     from sets import Set as set
 
-#USE_STACKOPT = True and not getoption('nostackopt')
-USE_STACKOPT = False
-
-
 class GenCli(GenOO):
     TypeSystem = CTS
     Function = Function
@@ -49,14 +44,23 @@
     DictConst = constant.CLIDictConst
     WeakRefConst = constant.CLIWeakRefConst
 
-    def __init__(self, tmpdir, translator, entrypoint, config=None):
+    def __init__(self, tmpdir, translator, entrypoint, config=None, exctrans=False):
         GenOO.__init__(self, tmpdir, translator, entrypoint, config)
+        exctrans = exctrans or translator.config.translation.cli.exception_transformer
+        if exctrans:
+            self.db.exceptiontransformer = translator.getexceptiontransformer()
+
         for node in get_prebuilt_nodes(translator, self.db):
             self.db.pending_node(node)
         self.assembly_name = entrypoint.get_name()
         self.tmpfile = tmpdir.join(self.assembly_name + '.il')
         self.const_stat = str(tmpdir.join('const_stat'))
 
+        if exctrans:
+            etrafo = self.db.exceptiontransformer
+            for graph in translator.graphs:
+                etrafo.create_exception_handling(graph)
+
         if translator.config.translation.backendopt.stack_optimization:
             for graph in translator.graphs:
                 SSI_to_SSA(graph)
@@ -72,12 +76,8 @@
         out = self.tmpfile.open('w')
         if getoption('stdout'):
             out = Tee(sys.stdout, out)
-
-        if USE_STACKOPT:
-            return StackOptGenerator(out, self.assembly_name, self.config)
-        else:
-            isnetmodule = self.entrypoint.isnetmodule
-            return IlasmGenerator(out, self.assembly_name, self.config, isnetmodule)
+        isnetmodule = self.entrypoint.isnetmodule
+        return IlasmGenerator(out, self.assembly_name, self.config, isnetmodule)
 
     def build_exe(self):        
         if getoption('source'):

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/cli/ilgenerator.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/cli/ilgenerator.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/cli/ilgenerator.py	Mon Aug 27 16:08:52 2007
@@ -58,7 +58,6 @@
             self.code.writeline('.module %s.netmodule' % name)
         else:
             self.code.writeline('.assembly %s {}' % name)
-        self.code.writeline('.field static object last_exception') # XXX
 
     def close(self):
         self.out.close()
@@ -252,12 +251,22 @@
         self.code.write(opcode + ' ')
         self.code.writeline(' '.join(map(str, args)))
 
-    def stderr(self, msg, cond=True):
+    def stderr(self, msg, cond=True, writeline=True):
         from pypy.translator.cli.support import string_literal
         if cond:
-            self.call('class [mscorlib]System.IO.TextWriter class [mscorlib]System.Console::get_Error()')
+            self.load_stderr()
             self.opcode('ldstr', string_literal(msg))
-            self.call_method('void class [mscorlib]System.IO.TextWriter::WriteLine(string)', virtual=True)
+            self.write_stderr(writeline)
+
+    def load_stderr(self):
+        self.call('class [mscorlib]System.IO.TextWriter class [mscorlib]System.Console::get_Error()')
+
+    def write_stderr(self, writeline=True):
+        if writeline:
+            meth = 'WriteLine'
+        else:
+            meth = 'Write'
+        self.call_method('void class [mscorlib]System.IO.TextWriter::%s(string)' % meth, virtual=True)
 
     def add_comment(self, text):
         self.code.writeline('// %s' % text)
@@ -313,8 +322,8 @@
         self.ilasm.call(signature)
 
     def cast_to(self, lltype):
-        cts_type = self.cts.lltype_to_cts(lltype, False)
-        self.ilasm.opcode('castclass', cts_type)
+        cts_type = self.cts.lltype_to_cts(lltype)
+        self.ilasm.opcode('castclass', cts_type.classname())
 
     def new(self, obj):
         self.ilasm.new(self.cts.ctor_name(obj))
@@ -364,6 +373,9 @@
     def branch_if_equal(self, target_label):
         self.ilasm.opcode('beq', target_label)
 
+    def branch_if_not_equal(self, target_label):
+        self.ilasm.opcode('bne.un', target_label)
+
     def push_primitive_constant(self, TYPE, value):
         ilasm = self.ilasm
         if TYPE is ootype.Void:

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/cli/metavm.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/cli/metavm.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/cli/metavm.py	Mon Aug 27 16:08:52 2007
@@ -38,7 +38,9 @@
             self._load_arg_or_null(generator, func_arg)
         cts = generator.cts
         ret_type = cts.lltype_to_cts(funcdesc._TYPE.RESULT)
-        arg_types = [cts.lltype_to_cts(arg) for arg in funcdesc._TYPE.ARGS if arg is not ootype.Void]
+        arg_types = [cts.lltype_to_cts(arg).typename()
+                     for arg in funcdesc._TYPE.ARGS
+                     if arg is not ootype.Void]
         arg_list = ', '.join(arg_types)
         signature = '%s %s::%s(%s)' % (ret_type, funcdesc._cls._name, funcdesc._name, arg_list)
         generator.call_signature(signature)
@@ -70,8 +72,10 @@
             METH = this.concretetype._METHODS[method_name]
             cts = generator.cts
             ret_type = cts.lltype_to_cts(METH.RESULT)
-            arg_types = [cts.lltype_to_cts(arg) for arg in METH.ARGS if arg is not ootype.Void]
-            arg_types.insert(0, cts.lltype_to_cts(ootype.String))
+            arg_types = [cts.lltype_to_cts(arg).typename()
+                         for arg in METH.ARGS
+                         if arg is not ootype.Void]
+            arg_types.insert(0, cts.lltype_to_cts(ootype.String).typename())
             arg_list = ', '.join(arg_types)
             signature = '%s %s::%s(%s)' % (ret_type, STRING_HELPER_CLASS, method_name, arg_list)
             generator.call_signature(signature)
@@ -159,13 +163,6 @@
         self.mapping = mapping
 
     def render(self, generator, op):
-        from pypy.translator.cli.function import LastExceptionHandler
-        if isinstance(generator, LastExceptionHandler):
-            self.render_last(generator, op)
-        else:
-            self.render_native(generator, op)
-
-    def render_native(self, generator, op):
         ilasm = generator.ilasm
         label = '__check_block_%d' % MapException.COUNT
         MapException.COUNT += 1
@@ -181,25 +178,6 @@
         ilasm.label(label)
         ilasm.opcode('nop')
 
-    def render_last(self, generator, op):
-        ilasm = generator.ilasm
-        stdflow = '__check_block_%d' % MapException.COUNT
-        MapException.COUNT += 1
-        premature_return = '__check_block_%d' % MapException.COUNT
-        MapException.COUNT += 1
-        ilasm.begin_try()
-        self.instr.render(generator, op)
-        ilasm.leave(stdflow)
-        ilasm.end_try()
-        for cli_exc, py_exc in self.mapping:
-            ilasm.begin_catch(cli_exc)
-            ilasm.new('instance void class %s::.ctor()' % py_exc)
-            ilasm.opcode('stsfld', 'object last_exception')
-            ilasm.leave(stdflow)
-            ilasm.end_catch()
-        ilasm.label(stdflow)
-        ilasm.opcode('nop')
-
 class _Box(MicroInstruction): 
     def render(self, generator, op):
         generator.load(op.args[0])

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/cli/option.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/cli/option.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/cli/option.py	Mon Aug 27 16:08:52 2007
@@ -1,6 +1,6 @@
 from pypy.translator.cli.conftest import option
 
-_defaultopt = dict(wd = False, source = False, nostop = False, stdout = False, nostackopt = False)
+_defaultopt = dict(wd = False, source = False, nostop = False, stdout = False)
 
 def getoption(name):
     return getattr(option, name, _defaultopt.get(name))

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/cli/prebuiltnodes.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/cli/prebuiltnodes.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/cli/prebuiltnodes.py	Mon Aug 27 16:08:52 2007
@@ -50,4 +50,17 @@
     prebuilt_nodes = _build_helpers(translator, db)
     raise_OSError_graph = translator.rtyper.exceptiondata.fn_raise_OSError.graph
     prebuilt_nodes.append(Helper(db, raise_OSError_graph, 'raise_OSError'))
+
+    try:
+        etrafo = db.exceptiontransformer
+    except AttributeError:
+        pass
+    else:
+        for name in ('rpyexc_clear',
+                     'rpyexc_fetch_type',
+                     'rpyexc_fetch_value',
+                     'rpyexc_occured',
+                     'rpyexc_raise'):
+            sm = getattr(etrafo, name+'_ptr').value
+            prebuilt_nodes.append(Function(db, sm.graph, name))
     return prebuilt_nodes

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/cli/record.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/cli/record.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/cli/record.py	Mon Aug 27 16:08:52 2007
@@ -30,7 +30,7 @@
         for f_name, (FIELD_TYPE, f_default) in self.record._fields.iteritems():
             f_name = self.cts.escape_name(f_name)
             cts_type = self.cts.lltype_to_cts(FIELD_TYPE)
-            if cts_type != 'void':
+            if cts_type != CTS.types.void:
                 ilasm.field(f_name, cts_type)
         self._ctor()
         self._toString()
@@ -74,13 +74,12 @@
 
     def _equals(self):
         # field by field comparison
-        record_type = self.cts.lltype_to_cts(self.record, include_class=False)
-        class_record_type = self.cts.lltype_to_cts(self.record, include_class=True)
+        record_type = self.cts.lltype_to_cts(self.record)
         self.ilasm.begin_function('Equals', [('object', 'obj')], 'bool',
                                   False, 'virtual', 'instance', 'default')
-        self.ilasm.locals([(class_record_type, 'self')])
+        self.ilasm.locals([(record_type, 'self')])
         self.ilasm.opcode('ldarg.1')
-        self.ilasm.opcode('castclass', record_type)
+        self.ilasm.opcode('castclass', record_type.classname())
         self.ilasm.opcode('stloc.0')
 
         equal = 'bool [pypylib]pypy.runtime.Utils::Equal<%s>(!!0, !!0)'
@@ -91,9 +90,9 @@
             f_type = self.cts.lltype_to_cts(FIELD_TYPE)
             f_name = self.cts.escape_name(f_name)
             self.ilasm.opcode('ldarg.0')
-            self.ilasm.get_field((f_type, record_type, f_name))
+            self.ilasm.get_field((f_type, record_type.classname(), f_name))
             self.ilasm.opcode('ldloc.0')
-            self.ilasm.get_field((f_type, record_type, f_name))
+            self.ilasm.get_field((f_type, record_type.classname(), f_name))
             self.ilasm.call(equal % f_type)
             self.ilasm.opcode('and')
 
@@ -102,7 +101,7 @@
 
     def _getHashCode(self):
         # return the hash of the first field. XXX: it can lead to a bad distribution
-        record_type = self.cts.lltype_to_cts(self.record, include_class=False)
+        record_type = self.cts.lltype_to_cts(self.record)
         self.ilasm.begin_function('GetHashCode', [], 'int32', False, 'virtual', 'instance', 'default')
         gethash = 'int32 [pypylib]pypy.runtime.Utils::GetHashCode<%s>(!!0)'
         if self.record._fields:
@@ -113,7 +112,7 @@
                 f_name = self.cts.escape_name(f_name)
                 f_type = self.cts.lltype_to_cts(FIELD_TYPE)
                 self.ilasm.opcode('ldarg.0')
-                self.ilasm.get_field((f_type, record_type, f_name))
+                self.ilasm.get_field((f_type, record_type.classname(), f_name))
                 self.ilasm.call(gethash % f_type)
         else:
             self.ilasm.opcode('ldc.i4.0')

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/cli/src/pypylib.cs
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/cli/src/pypylib.cs	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/cli/src/pypylib.cs	Mon Aug 27 16:08:52 2007
@@ -201,7 +201,7 @@
 
         public static int ll_strcmp(string s1, string s2)
         {
-            return string.Compare(s1, s2);
+            return string.Compare(s1, s2, StringComparison.Ordinal);
         }
 
         public static bool ll_startswith(string s1, string s2)

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/runtest.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/runtest.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/runtest.py	Mon Aug 27 16:08:52 2007
@@ -53,7 +53,7 @@
 
         RETURN_TYPE = self.graph.getreturnvar().concretetype
         return_type = self.cts.lltype_to_cts(RETURN_TYPE)
-        if return_type != 'void':
+        if return_type != CTS.types.void:
             ilasm.locals([(return_type, 'res')])
 
         if self.wrap_exceptions:
@@ -70,10 +70,10 @@
 
         # call the function and convert the result to a string containing a valid python expression
         ilasm.call(self.cts.graph_to_signature(self.graph))
-        if return_type != 'void':
+        if return_type != CTS.types.void:
             ilasm.opcode('stloc', 'res')
         if self.wrap_exceptions:
-            ilasm.leave('check_last_exception')
+            ilasm.leave('check_etrafo_exception')
         else:
             ilasm.leave('print_result')
 
@@ -90,17 +90,20 @@
                     ilasm.leave('return')
                 ilasm.end_catch()
 
-            ilasm.label('check_last_exception')
-            ilasm.opcode('ldsfld', 'object last_exception')
-            ilasm.opcode('brnull', 'print_result')
-            # there is a pending exception
-            ilasm.opcode('ldsfld', 'object last_exception')
-            ilasm.call('string class [pypylib]pypy.test.Result::FormatException(object)')
-            ilasm.call('void class [mscorlib]System.Console::WriteLine(string)')
-            ilasm.opcode('br', 'return')
+            # check for exception tranformer exceptions
+            ilasm.label('check_etrafo_exception')
+            if hasattr(self.db, 'exceptiontransformer'):
+                ilasm.opcode('call', 'bool rpyexc_occured()')
+                ilasm.opcode('brfalse', 'print_result') # no exceptions
+                ilasm.opcode('call', 'Object rpyexc_fetch_value()')
+                ilasm.call('string class [pypylib]pypy.test.Result::FormatException(object)')
+                ilasm.call('void class [mscorlib]System.Console::WriteLine(string)')
+                ilasm.opcode('br', 'return')
+            else:
+                ilasm.opcode('br', 'print_result')
 
         ilasm.label('print_result')
-        if return_type != 'void':
+        if return_type != CTS.types.void:
             ilasm.opcode('ldloc', 'res')
         format_object(RETURN_TYPE, self.cts, ilasm)
         ilasm.call('void class [mscorlib]System.Console::WriteLine(string)')
@@ -112,13 +115,13 @@
 
     def __convert_method(self, arg_type):
         _conv = {
-            'int32': 'ToInt32',
-            'unsigned int32': 'ToUInt32',
-            'int64': 'ToInt64',
-            'unsigned int64': 'ToUInt64',
-            'bool': 'ToBoolean',
-            'float64': 'ToDouble',
-            'char': 'ToChar',
+            CTS.types.int32: 'ToInt32',
+            CTS.types.uint32: 'ToUInt32',
+            CTS.types.int64: 'ToInt64',
+            CTS.types.uint64: 'ToUInt64',
+            CTS.types.bool: 'ToBoolean',
+            CTS.types.float64: 'ToDouble',
+            CTS.types.char: 'ToChar',
             }
 
         try:
@@ -127,15 +130,16 @@
             assert False, 'Input type %s not supported' % arg_type
 
 
-def compile_function(func, annotation=[], graph=None, backendopt=True):
+def compile_function(func, annotation=[], graph=None, backendopt=True,
+                     auto_raise_exc=False, exctrans=False):
     olddefs = patch()
-    gen = _build_gen(func, annotation, graph, backendopt)
+    gen = _build_gen(func, annotation, graph, backendopt, exctrans)
     gen.generate_source()
     exe_name = gen.build_exe()
     unpatch(*olddefs) # restore original values
-    return CliFunctionWrapper(exe_name)
+    return CliFunctionWrapper(exe_name, func.__name__, auto_raise_exc)
 
-def _build_gen(func, annotation, graph=None, backendopt=True):
+def _build_gen(func, annotation, graph=None, backendopt=True, exctrans=False):
     try: 
         func = func.im_func
     except AttributeError: 
@@ -169,11 +173,13 @@
     else:
         tmpdir = udir
 
-    return GenCli(tmpdir, t, TestEntryPoint(main_graph, True))
+    return GenCli(tmpdir, t, TestEntryPoint(main_graph, True), exctrans=exctrans)
 
 class CliFunctionWrapper(object):
-    def __init__(self, exe_name):
+    def __init__(self, exe_name, name=None, auto_raise_exc=False):
         self._exe = exe_name
+        self.__name__ = name or exe_name
+        self.auto_raise_exc = auto_raise_exc
 
     def run(self, *args):
         if self._exe is None:
@@ -199,6 +205,13 @@
             res = StructTuple(res) # so tests can access tuple elements with .item0, .item1, etc.
         elif isinstance(res, list):
             res = OOList(res)
+        elif self.auto_raise_exc and isinstance(res, ExceptionWrapper):
+            excname = res.class_name
+            if excname.startswith('exceptions.'):
+                import exceptions
+                raise eval(excname)
+            else:
+                raise res # probably it's a .NET exception with no RPython equivalent
         return res
 
 class StructTuple(tuple):
@@ -233,13 +246,15 @@
         self._ann = None
         self._cli_func = None
 
-    def _compile(self, fn, args, ann=None, backendopt=True):
+    def _compile(self, fn, args, ann=None, backendopt=True, auto_raise_exc=False, exctrans=False):
         if ann is None:
             ann = [lltype_to_annotation(typeOf(x)) for x in args]
         if self._func is fn and self._ann == ann:
             return self._cli_func
         else:
-            self._cli_func = compile_function(fn, ann, backendopt=backendopt)
+            self._cli_func = compile_function(fn, ann, backendopt=backendopt,
+                                              auto_raise_exc=auto_raise_exc,
+                                              exctrans=exctrans)
             self._func = fn
             self._ann = ann
             return self._cli_func
@@ -252,17 +267,17 @@
         if platform.processor() == 'powerpc':
             py.test.skip('PowerPC --> %s' % reason)
 
-    def interpret(self, fn, args, annotation=None, backendopt=True):
-        f = self._compile(fn, args, annotation, backendopt)
+    def interpret(self, fn, args, annotation=None, backendopt=True, exctrans=False):
+        f = self._compile(fn, args, annotation, backendopt=backendopt, exctrans=exctrans)
         res = f(*args)
         if isinstance(res, ExceptionWrapper):
             raise res
         return res
 
-    def interpret_raises(self, exception, fn, args):
+    def interpret_raises(self, exception, fn, args, backendopt=True, exctrans=False):
         import exceptions # needed by eval
         try:
-            self.interpret(fn, args)
+            self.interpret(fn, args, backendopt=backendopt, exctrans=exctrans)
         except ExceptionWrapper, ex:
             assert issubclass(eval(ex.class_name), exception)
         else:

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_dotnet.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_dotnet.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_dotnet.py	Mon Aug 27 16:08:52 2007
@@ -174,11 +174,6 @@
     def _skip_pythonnet(self, msg):
         pass
 
-    def _skip_exception(self):
-        from pypy.translator.cli import function
-        if function.USE_LAST:
-            py.test.skip("Fixme!")
-
     def test_staticmeth_call(self):
         def fn(x):
             return Math.Abs(x)
@@ -292,7 +287,6 @@
         assert self.interpret(fn, []) is None
 
     def test_native_exception_precise(self):
-        self._skip_exception()
         ArgumentOutOfRangeException = NativeException(CLR.System.ArgumentOutOfRangeException)
         def fn():
             x = ArrayList()
@@ -304,7 +298,6 @@
         assert self.interpret(fn, []) == True
 
     def test_native_exception_superclass(self):
-        self._skip_exception()
         SystemException = NativeException(CLR.System.Exception)
         def fn():
             x = ArrayList()
@@ -316,7 +309,6 @@
         assert self.interpret(fn, []) == True
 
     def test_native_exception_object(self):
-        self._skip_exception()
         SystemException = NativeException(CLR.System.Exception)
         def fn():
             x = ArrayList()
@@ -330,7 +322,6 @@
         assert res.startswith("Index is less than 0")
 
     def test_native_exception_invoke(self):
-        self._skip_exception()
         TargetInvocationException = NativeException(CLR.System.Reflection.TargetInvocationException)
         def fn():
             x = ArrayList()

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_exception.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_exception.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_exception.py	Mon Aug 27 16:08:52 2007
@@ -3,6 +3,12 @@
 from pypy.rpython.test.test_exception import BaseTestException
 
 class TestCliException(CliTest, BaseTestException):
+    use_exception_transformer = False
+
+    def interpret(self, *args, **kwds):
+        kwds['exctrans'] = self.use_exception_transformer
+        return CliTest.interpret(self, *args, **kwds)
+
     def test_nested_try(self):
         def helper(x):
             if x == 0:
@@ -55,3 +61,21 @@
                 obj = Derived()
             return obj.foo()
         assert self.interpret(fn, [0]) == 42
+
+    def test_missing_handler(self):
+        def foo(x):
+            if x:
+                raise ValueError
+        
+        def fn(x):
+            try:
+                foo(x)
+            except ValueError:
+                raise
+            return 42
+        assert self.interpret(fn, [0], backendopt=False) == 42
+        self.interpret_raises(ValueError, fn, [1], backendopt=False)
+
+
+class TestCliExceptionTransformer(TestCliException):
+    use_exception_transformer = True

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_runtest.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_runtest.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_runtest.py	Mon Aug 27 16:08:52 2007
@@ -1,3 +1,4 @@
+import py
 from pypy.translator.cli.test.runtest import CliTest
 from pypy.translator.cli.test.runtest import FLOAT_PRECISION
 from pypy.annotation.listdef import s_list_of_strings
@@ -64,3 +65,10 @@
             else:
                 return None
         assert self.interpret(fn, [False]) is None
+
+    def test_auto_raise_exc(self):
+        def fn():
+            raise ValueError
+        f = self._compile(fn, [], auto_raise_exc=True)
+        py.test.raises(ValueError, f)
+        

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_snippet.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_snippet.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_snippet.py	Mon Aug 27 16:08:52 2007
@@ -13,3 +13,31 @@
         res = self.ll_to_list(self.interpret(fn, []))
         assert res == [52, 53, 54]
 
+    def test_mangle(self):
+        class Foo:
+            def le(self):
+                return 42
+
+        def fn():
+            f = Foo()
+            return f.le()
+        res = self.interpret(fn, [], backendopt=False)
+        
+    def test_link_vars_overlapping(self):
+        from pypy.rlib.rarithmetic import ovfcheck, ovfcheck_lshift
+        def fn(maxofs):
+            lastofs = 0
+            ofs = 1
+            while ofs < maxofs:
+                lastofs = ofs
+                try:
+                    ofs = ovfcheck_lshift(ofs, 1)
+                except OverflowError:
+                    ofs = maxofs
+                else:
+                    ofs = ofs + 1
+            return lastofs
+        res = self.interpret(fn, [64])
+        expected = fn(64)
+        assert res == expected
+        

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_string.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_string.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_string.py	Mon Aug 27 16:08:52 2007
@@ -24,3 +24,8 @@
     def test_getitem_exc(self):
         py.test.skip('fixme!')
 
+    def test_compare(self):
+        strings = ['aa', 'ZZ']
+        def fn(i, j):
+            return strings[i] < strings[j]
+        assert self.interpret(fn, [0, 1], backendopt=False) == fn(0, 1)

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/jvm/node.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/jvm/node.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/jvm/node.py	Mon Aug 27 16:08:52 2007
@@ -280,12 +280,14 @@
     def set_label(self, blocklbl):
         self.ilasm.mark(blocklbl)
 
-    def begin_try(self):
-        self.ilasm.begin_try()
+    def begin_try(self, cond):
+        if cond:
+            self.ilasm.begin_try()
 
-    def end_try(self, exit_label):
+    def end_try(self, exit_label, cond):
         self.ilasm.branch_unconditionally(exit_label)
-        self.ilasm.end_try()
+        if cond:
+            self.ilasm.end_try()
 
     def begin_catch(self, llexitcase):
         ll_meta_exc = llexitcase
@@ -337,7 +339,9 @@
             
         self.ilasm.throw()
 
-    def _trace(self, str):
+    def _trace(self, str, writeline=False):
+        if writeline:
+            str += '\n'
         jvmgen.SYSTEMERR.load(self.generator)
         self.generator.load_string(str)
         jvmgen.PRINTSTREAMPRINTSTR.invoke(self.generator)
@@ -381,19 +385,13 @@
             self.generator.emit(jvmgen.PRINTSTREAMPRINTSTR)
             self._trace("\n")
 
+    def _trace_enabled(self):
+        return getoption('trace')
+
     def _render_op(self, op):
         self.generator.add_comment(str(op))
-        
-        if getoption('trace'):
-            self._trace(str(op)+"\n")
-
-            for i, arg in enumerate(op.args):
-                self._trace_value('Arg %02d' % i, arg)
-
         OOFunction._render_op(self, op)
 
-        if getoption('trace'):
-            self._trace_value('Result', op.result)
 
 class StaticMethodInterface(Node, JvmClassType):
     """

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/oosupport/function.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/oosupport/function.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/oosupport/function.py	Mon Aug 27 16:08:52 2007
@@ -11,6 +11,8 @@
 
 
 class Function(object):
+    
+    auto_propagate_exceptions = False
 
     def __init__(self, db, graph, name = None, is_method = False, is_entrypoint = False):
         self.db = db
@@ -140,9 +142,17 @@
         for op in block.operations[:-1]:
             self._render_op(op)
 
+        anyHandler = False
+        for link in block.exits:
+            if link.exitcase is None:
+                continue
+            if not self._is_raise_block(link.target):
+                anyHandler = True
+        anyHandler = anyHandler or not self.auto_propagate_exceptions
+        
         # render the last one (if any!) and prepend a .try
         if block.operations:
-            self.begin_try()
+            self.begin_try(anyHandler)
             self._render_op(block.operations[-1])
 
         # search for the "default" block to be executed when no
@@ -150,7 +160,7 @@
         for link in block.exits:
             if link.exitcase is None:
                 self._setup_link(link)
-                self.end_try(self._get_block_name(link.target))
+                self.end_try(self._get_block_name(link.target), anyHandler)
                 break
         else:
             assert False, "No non-exceptional case from exc_handling block"
@@ -160,6 +170,8 @@
             if link.exitcase is None:
                 continue # see above
             assert issubclass(link.exitcase, py.builtin.BaseException)
+            if self._is_raise_block(link.target) and self.auto_propagate_exceptions:
+                continue # let the exception propagate
             ll_meta_exc = link.llexitcase
             self.record_ll_meta_exc(ll_meta_exc)
             self.begin_catch(link.llexitcase)
@@ -218,13 +230,17 @@
     def render_numeric_switch_naive(self, block):
         for link in block.exits:
             target_label = self._get_block_name(link.target)
-            self._setup_link(link)
             if link.exitcase == 'default':
+                self._setup_link(link)
                 self.generator.branch_unconditionally(target_label)
             else:
+                next_case = self.next_label('next_case')
                 self.generator.push_primitive_constant(block.exitswitch.concretetype, link.exitcase)
                 self.generator.load(block.exitswitch)
-                self.generator.branch_if_equal(target_label)
+                self.generator.branch_if_not_equal(next_case)
+                self._setup_link(link)
+                self.generator.branch_unconditionally(target_label)
+                self.set_label(next_case)
 
     def _follow_link(self, link):
         target_label = self._get_block_name(link.target)
@@ -233,20 +249,54 @@
 
     def _setup_link(self, link):
         target = link.target
+        linkvars = []
         for to_load, to_store in zip(link.args, target.inputargs):
             if isinstance(to_load, flowmodel.Variable) and to_load.name == to_store.name:
                 continue
             if to_load.concretetype is ootype.Void:
                 continue
-            self.generator.add_comment("%r --> %r" % (to_load, to_store))
+            linkvars.append((to_load, to_store))
+
+        # after SSI_to_SSA it can happen to have to_load = [a, b] and
+        # to_store = [b, c].  If we store each variable sequentially,
+        # 'b' would be overwritten before being read.  To solve, we
+        # first load all the values on the stack, then store in the
+        # appropriate places.
+
+        if self._trace_enabled():
+            self._trace('link', writeline=True)
+            for to_load, to_store in linkvars:
+                self._trace_value('%s <-- %s' % (to_store, to_load), to_load)
+            self._trace('', writeline=True)
+
+        for to_load, to_store in linkvars:
             self.generator.load(to_load)
+        for to_load, to_store in reversed(linkvars):
             self.generator.store(to_store)
 
+    def _trace_enabled(self):
+        return False
+
+    def _trace(self, s):
+        raise NotImplementedError
+
+    def _trace_value(self, prompt, v):
+        raise NotImplementedError
+
     def _render_op(self, op):
         instr_list = self.db.genoo.opcodes.get(op.opname, None)
         assert instr_list is not None, 'Unknown opcode: %s ' % op
         assert isinstance(instr_list, InstructionList)
+
+        if self._trace_enabled():
+            self._trace(str(op), writeline=True)
+            for i, arg in enumerate(op.args):
+                self._trace_value('Arg %02d' % i, arg)
+
         instr_list.render(self.generator, op)
+ 
+        if self._trace_enabled():
+            self._trace_value('Result', op.result)
 
     def _render_sub_op(self, sub_op):
         op = sub_op.op

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/oosupport/test_template/snippets.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/oosupport/test_template/snippets.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/oosupport/test_template/snippets.py	Mon Aug 27 16:08:52 2007
@@ -48,3 +48,16 @@
             obj.x = x + y
             return obj.x
         assert self.interpret(fn, [1,3]) == 4
+
+    def test_link(self):
+        def fn():
+            plus = False
+            for c in 'a':
+                if c == 'b':
+                    plus = True
+                elif c == 'c':
+                    binary = True
+            return plus
+        res = self.interpret(fn, [])
+        expected = fn()
+        assert res == expected



More information about the Pypy-commit mailing list