[pypy-svn] r25725 - in pypy/dist/pypy/translator/cli: . test

antocuni at codespeak.net antocuni at codespeak.net
Wed Apr 12 18:29:44 CEST 2006


Author: antocuni
Date: Wed Apr 12 18:29:32 2006
New Revision: 25725

Modified:
   pypy/dist/pypy/translator/cli/cts.py
   pypy/dist/pypy/translator/cli/database.py
   pypy/dist/pypy/translator/cli/function.py
   pypy/dist/pypy/translator/cli/metavm.py
   pypy/dist/pypy/translator/cli/opcodes.py
   pypy/dist/pypy/translator/cli/test/compile.py
Log:
Refactored exception handling: the first try was to translate Python
exception to CLI exceptions, but this would have caused some trobules
because the two inheritance hierarchies don't overlap.

Now Python exceptions has its own CLI hierarchy, generated in exactly
the same way that is for other classes. This means that we can no
longer rely on CLI '.ovf' opcodes that raises OverflowException on
error, because Python's OverflowError doesn't map to CLI's
OverfloweException. For now the tricky and inefficient solution is to
explicitly catch OverflowException and throw a fresh OverflowError
instead.



Modified: pypy/dist/pypy/translator/cli/cts.py
==============================================================================
--- pypy/dist/pypy/translator/cli/cts.py	(original)
+++ pypy/dist/pypy/translator/cli/cts.py	Wed Apr 12 18:29:32 2006
@@ -49,16 +49,21 @@
     def __init__(self, db):
         self.db = db
 
-    def lltype_to_cts(self, t):
+    def __class(self, result, include_class):
+        if include_class:
+            return 'class ' + result
+        else:
+            return result
+
+    def lltype_to_cts(self, t, include_class=True):
         if isinstance(t, Instance):
-            name = t._name
             self.db.pending_class(t)
-            return 'class %s' % name
+            return self.__class(t._name, include_class)
         elif isinstance(t, StaticMethod):
             return 'void' # TODO: is it correct to ignore StaticMethod?
         elif isinstance(t, List):
             item_type = self.lltype_to_cts(t._ITEMTYPE)
-            return 'class [pypylib]pypy.runtime.List`1<%s>' % item_type
+            return self.__class('[pypylib]pypy.runtime.List`1<%s>' % item_type, include_class)
 
         return _get_from_dict(_lltype_to_cts, t, 'Unknown type %s' % t)
 
@@ -75,7 +80,7 @@
         ret_type, ret_var = self.llvar_to_cts(graph.getreturnvar())
         func_name = func_name or graph.name
 
-        args = graph.getargs()
+        args = [arg for arg in graph.getargs() if arg.concretetype is not Void]
         if is_method:
             args = args[1:]
 
@@ -108,6 +113,3 @@
             return parts
         else:
             return None, parts[0]
-
-    def pyexception_to_cts(self, exc):
-        return _get_from_dict(_pyexception_to_cts, exc, 'Unknown exception %s' % exc)

Modified: pypy/dist/pypy/translator/cli/database.py
==============================================================================
--- pypy/dist/pypy/translator/cli/database.py	(original)
+++ pypy/dist/pypy/translator/cli/database.py	Wed Apr 12 18:29:32 2006
@@ -19,6 +19,7 @@
         self.functions = {} # graph --> function_name
         self.methods = {} # graph --> method_name
         self.consts = {}  # value --> const_name
+        self.const_names = set()
 
     def pending_function(self, graph):
         self.pending_node(Function(self, graph))
@@ -48,8 +49,11 @@
         try:
             name = self.consts[const]
         except KeyError:
-            name = const.get_name(len(self.consts))
+            name = const.get_name()
+            if name in self.const_names:
+                name += '__%d' % len(self.consts)
             self.consts[const] = name
+            self.const_names.add(name)
 
         return '%s.%s::%s' % (CONST_NAMESPACE, CONST_CLASS, name)
 
@@ -90,7 +94,7 @@
             assert False, 'Unknown constant: %s' % const
     make = staticmethod(make)
     
-    def get_name(self, n):
+    def get_name(self):
         pass
 
     def get_type(self):
@@ -115,9 +119,8 @@
     def __eq__(self, other):
         return self.obj == other.obj
 
-    def get_name(self, n):
-        name = self.obj._TYPE._name.replace('.', '_')
-        return '%s_%d' % (name, n)
+    def get_name(self):
+        return self.obj._TYPE._name.replace('.', '_')
 
     def get_type(self):
         return self.cts.lltype_to_cts(self.static_type)

Modified: pypy/dist/pypy/translator/cli/function.py
==============================================================================
--- pypy/dist/pypy/translator/cli/function.py	(original)
+++ pypy/dist/pypy/translator/cli/function.py	Wed Apr 12 18:29:32 2006
@@ -56,7 +56,7 @@
 
         if self.is_method:
             args = self.args[1:] # self is implicit
-            meth_type = 'virtual'
+            meth_type = 'virtual' # TODO: mark as virtual only when strictly necessary
         else:
             args = self.args
             meth_type = 'static'
@@ -100,7 +100,12 @@
                         continue # see above
 
                     assert issubclass(link.exitcase, Exception)
-                    cts_exc = self.cts.pyexception_to_cts(link.exitcase)
+                    #cts_exc = self.cts.pyexception_to_cts(link.exitcase)
+                    #cts_exc = str(link.exitcase) # TODO: is it a bit hackish?
+                    ll_meta_exc = link.llexitcase
+                    self.db.record_const(ll_meta_exc)
+                    ll_exc = ll_meta_exc._inst.class_._INSTANCE
+                    cts_exc = self.cts.lltype_to_cts(ll_exc, False)
                     self.ilasm.begin_catch(cts_exc)
 
                     target = link.target
@@ -198,7 +203,8 @@
         self.locals = locals
 
     def _set_args(self):
-        self.args = map(self.cts.llvar_to_cts, self.graph.getargs())
+        args = [arg for arg in self.graph.getargs() if arg.concretetype is not Void]
+        self.args = map(self.cts.llvar_to_cts, args)
         self.argset = set([argname for argtype, argname in self.args])
 
     def _get_block_name(self, block):
@@ -257,9 +263,7 @@
         self.ilasm.call(signature)
 
     def cast_to(self, lltype):
-        cts_type = self.cts.lltype_to_cts(lltype)
-        if cts_type.startswith('class '):
-            cts_type = cts_type[len('class '):]
+        cts_type = self.cts.lltype_to_cts(lltype, False)
         self.ilasm.opcode('castclass', cts_type)
 
     def new(self, obj):

Modified: pypy/dist/pypy/translator/cli/metavm.py
==============================================================================
--- pypy/dist/pypy/translator/cli/metavm.py	(original)
+++ pypy/dist/pypy/translator/cli/metavm.py	Wed Apr 12 18:29:32 2006
@@ -28,6 +28,9 @@
     def render(self, generator, op):
         pass
 
+    def __str__(self):
+        return self.__class__.__name__
+
 
 class PushArg(MicroInstruction):
     def __init__(self, n):

Modified: pypy/dist/pypy/translator/cli/opcodes.py
==============================================================================
--- pypy/dist/pypy/translator/cli/opcodes.py	(original)
+++ pypy/dist/pypy/translator/cli/opcodes.py	Wed Apr 12 18:29:32 2006
@@ -11,6 +11,29 @@
 def _abs(type_):
     return [PushAllArgs, 'call %s class [mscorlib]System.Math::Abs(%s)' % (type_, type_)]
 
+def _check(op):
+    if isinstance(op, str):
+        op = [PushAllArgs, op, StoreResult]
+
+    label = '__check_block_%d' % _check.count
+    _check.count += 1
+
+    return [
+        '.try {'
+        ] + op + [             # do the real operations
+        'leave %s }' % label,  # continue normal execution
+
+        # if overflow, raise a pypy's OverflowError
+        'catch [mscorlib]System.OverflowException {',
+        'newobj instance void class exceptions.OverflowError::.ctor()',
+        'dup',
+        'ldsfld class Object_meta pypy.runtime.Constants::exceptions_OverflowError_meta',
+        'stfld class Object_meta Object::meta',
+        'throw }',
+
+        '%s: nop' % label      # continue normal execution
+        ]
+_check.count = 0
 
 opcodes = {
     # __________ object oriented operations __________
@@ -21,6 +44,7 @@
     'oosend':                   [CallMethod],
     'ooupcast':                 DoNothing,
     'oodowncast':               DoNothing, # TODO: is it really safe?
+    'oois':                     'ceq',
 
     
     'same_as':                  DoNothing, # TODO: does same_as really do nothing else than renaming?    
@@ -43,9 +67,9 @@
 
     'int_is_true':              DoNothing,
     'int_neg':                  'neg',
-    'int_neg_ovf':              ['ldc.i4.0', PushAllArgs, 'sub.ovf'],
+    'int_neg_ovf':              _check(['ldc.i4.0', PushAllArgs, 'sub.ovf', StoreResult]),
     'int_abs':                  _abs('int32'),
-    'int_abs_ovf':              _abs('int32'),
+    'int_abs_ovf':              _check(_abs('int32')),
     'int_invert':               'not',
 
     'int_add':                  'add',
@@ -64,9 +88,9 @@
     'int_lshift':               'shl',
     'int_rshift':               'shr',
     'int_xor':                  'xor',
-    'int_add_ovf':              'add.ovf',
-    'int_sub_ovf':              'sub.ovf',
-    'int_mul_ovf':              'mul.ovf',
+    'int_add_ovf':              _check('add.ovf'),
+    'int_sub_ovf':              _check('sub.ovf'),
+    'int_mul_ovf':              _check('mul.ovf'),
     'int_floordiv_ovf':         'div', # these can't overflow!
     'int_mod_ovf':              'rem',
     'int_lt_ovf':               'clt',
@@ -79,8 +103,8 @@
     'int_or_ovf':               'or',
 
     # are they the same?
-    'int_lshift_ovf':           [PushArg(0), 'conv.i8', PushArg(1), 'shl', 'conv.ovf.i4'],
-    'int_lshift_ovf_val':       [PushArg(0), 'conv.i8', PushArg(1), 'shl', 'conv.ovf.i4'],
+    'int_lshift_ovf':           _check([PushArg(0),'conv.i8',PushArg(1), 'shl', 'conv.ovf.i4', StoreResult]),
+    'int_lshift_ovf_val':       _check([PushArg(0),'conv.i8',PushArg(1), 'shl', 'conv.ovf.i4', StoreResult]),
 
     'int_rshift_ovf':           'shr', # these can't overflow!
     'int_xor_ovf':              'xor',
@@ -191,7 +215,10 @@
     if type(value) is str:
         value = InstructionList([PushAllArgs, value, StoreResult])
     elif value is not None:
-        value = InstructionList(value + [StoreResult])
-        
+        if StoreResult not in value:
+            value.append(StoreResult)
+        value = InstructionList(value)
+
     opcodes[key] = value
 
+

Modified: pypy/dist/pypy/translator/cli/test/compile.py
==============================================================================
--- pypy/dist/pypy/translator/cli/test/compile.py	(original)
+++ pypy/dist/pypy/translator/cli/test/compile.py	Wed Apr 12 18:29:32 2006
@@ -24,53 +24,16 @@
         print 'OK'
 
 
-class MyClass:
-    INCREMENT = 1
-
-    def __init__(self, x, y):
-        self.x = x
-        self.y = y
-
-    def compute(self):
-        return self.x + self.y
-
-    def compute_and_multiply(self, factor):
-        return self.compute() * factor
-
-    def static_meth(x, y):
-        return x*y
-    static_meth = staticmethod(static_meth)
-
-##    def class_meth(cls, x, y):
-##        return x*y + cls.INCREMENT
-##    class_meth = classmethod(class_meth)
-
-    def class_attribute(self):
-        return self.x + self.INCREMENT
-
-class MyDerivedClass(MyClass):
-    INCREMENT = 2
-
-    def __init__(self, x, y):
-        MyClass.__init__(self, x+12, y+34)
-
-    def compute(self):
-        return self.x - self.y
-
-
-
-def init_and_compute(cls, x, y):
-    return cls(x, y).compute()
-
-
 def bar(x, y):
-    return init_and_compute(MyClass, x, y) + init_and_compute(MyDerivedClass, x, y)
-
+    try:
+        return ovfcheck(x+y)
+    except OverflowError:
+        return 0
 
 f = compile_function(bar, [int, int])
 
 try:
-    check(bar, f, 42, 13)
+    check(bar, f, sys.maxint, 13)
 except py.test.Item.Skipped:
     print 'Test skipped'
 



More information about the Pypy-commit mailing list