[pypy-svn] r25086 - in pypy/dist/pypy/translator/cli: . test
antocuni at codespeak.net
antocuni at codespeak.net
Tue Mar 28 17:37:42 CEST 2006
Author: antocuni
Date: Tue Mar 28 17:37:30 2006
New Revision: 25086
Added:
pypy/dist/pypy/translator/cli/test/test_overflow.py (contents, props changed)
Modified:
pypy/dist/pypy/translator/cli/cts.py
pypy/dist/pypy/translator/cli/function.py
pypy/dist/pypy/translator/cli/ilgenerator.py
pypy/dist/pypy/translator/cli/opcodes.py
pypy/dist/pypy/translator/cli/test/compile.py
Log:
Added support for exception handling in generated code.
Added initial support for overflow checking
Modified: pypy/dist/pypy/translator/cli/cts.py
==============================================================================
--- pypy/dist/pypy/translator/cli/cts.py (original)
+++ pypy/dist/pypy/translator/cli/cts.py Tue Mar 28 17:37:30 2006
@@ -2,8 +2,11 @@
Translate between PyPy ootypesystem and .NET Common Type System
"""
+import exceptions
+
from pypy.rpython.lltypesystem.lltype import Signed, Unsigned, Void, Bool, Float
from pypy.rpython.lltypesystem.lltype import SignedLongLong, UnsignedLongLong
+from pypy.rpython.ootypesystem.ootype import Instance
from pypy.translator.cli.option import getoption
from pypy.tool.ansi_print import ansi_log
@@ -31,29 +34,29 @@
'float64': 'r8',
}
-def lltype_to_cts(t):
+def _get_from_dict(d, key, error):
try:
- return _lltype_to_cts[t]
+ return d[key]
except KeyError:
if getoption('nostop'):
- log.WARNING('Unknown type %s' % t)
- return t
+ log.WARNING(error)
+ return key
else:
- assert False, 'Unknown type %s' % t
+ assert False, error
+
+
+def lltype_to_cts(t):
+ # TODO: handle instances more accurately
+ if isinstance(t, Instance):
+ return 'object'
+
+ return _get_from_dict(_lltype_to_cts, t, 'Unknown type %s' % t)
def lltype_to_ilasm(t):
return ctstype_to_ilasm(lltype_to_cts(t))
def ctstype_to_ilasm(t):
- try:
- return _cts_to_ilasm[t]
- except KeyError:
- if getoption('nostop'):
- log.WARNING('Unknown ilasm type %s' % t)
- return t
- else:
- assert False, 'Unknown ilasm type %s' % t
-
+ return _get_from_dict(_cts_to_ilasm, t, 'Unknown ilasm type %s' % t)
def llvar_to_cts(var):
return lltype_to_cts(var.concretetype), var.name
@@ -80,3 +83,11 @@
arg_list = ', '.join(arg_types)
return '%s %s(%s)' % (ret_type, func_name, arg_list)
+
+_pyexception_to_cts = {
+ exceptions.Exception: '[mscorlib]System.Exception',
+ exceptions.OverflowError: '[mscorlib]System.OverflowException'
+ }
+
+def pyexception_to_cts(exc):
+ return _get_from_dict(_pyexception_to_cts, exc, 'Unknown exception %s' % exc)
Modified: pypy/dist/pypy/translator/cli/function.py
==============================================================================
--- pypy/dist/pypy/translator/cli/function.py (original)
+++ pypy/dist/pypy/translator/cli/function.py Tue Mar 28 17:37:30 2006
@@ -23,50 +23,93 @@
self.graph = graph
self.is_entrypoint = is_entrypoint
self.blocknum = {}
-
self._set_args()
self._set_locals()
def get_name(self):
return self.graph.name
+ def _is_return_block(self, block):
+ return (not block.exits) and len(block.inputargs) == 1
+
+ def _is_raise_block(self, block):
+ return (not block.exits) and len(block.inputargs) == 2
+
def render(self, ilasm):
self.ilasm = ilasm
graph = self.graph
returntype, returnvar = cts.llvar_to_cts(graph.getreturnvar())
- ilasm.begin_function(graph.name, self.args, returntype, self.is_entrypoint)
- ilasm.locals(self.locals)
+ self.ilasm.begin_function(graph.name, self.args, returntype, self.is_entrypoint)
+ self.ilasm.locals(self.locals)
for block in graph.iterblocks():
- ilasm.label(self._get_block_name(block))
+ self.ilasm.label(self._get_block_name(block))
+
+ handle_exc = (block.exitswitch == flowmodel.c_last_exception)
+ if handle_exc:
+ self.ilasm.begin_try()
for op in block.operations:
self._render_op(op)
- # if it is the last block, return the result
- if not block.exits:
- assert len(block.inputargs) == 1
+ # check for codeless blocks
+ if self._is_return_block(block):
return_var = block.inputargs[0]
if return_var.concretetype is not Void:
self._push(return_var)
- ilasm.opcode('ret')
+ self.ilasm.opcode('ret')
+ elif self._is_raise_block(block):
+ exc = block.inputargs[1]
+ self._push(exc)
+ self.ilasm.opcode('throw')
+
+ if handle_exc:
+ # search for the "default" block to be executed when no exception is raised
+ for link in block.exits:
+ if link.exitcase is None:
+ self._setup_link(link)
+ target_label = self._get_block_name(link.target)
+ self.ilasm.leave(target_label)
+ self.ilasm.end_try()
+
+ # catch the exception and dispatch to the appropriate block
+ for link in block.exits:
+ if link.exitcase is None:
+ continue # see above
+
+ assert issubclass(link.exitcase, Exception)
+ cts_exc = cts.pyexception_to_cts(link.exitcase)
+ self.ilasm.begin_catch(cts_exc)
+
+ target = link.target
+ if self._is_raise_block(target):
+ # the exception value is on the stack, use it as the 2nd target arg
+ assert len(link.args) == 2
+ assert len(target.inputargs) == 2
+ self._store(link.target.inputargs[1])
+ else:
+ # pop the unused exception value
+ self.ilasm.opcode('pop')
+ self._setup_link(link)
+
+ target_label = self._get_block_name(target)
+ self.ilasm.leave(target_label)
+ self.ilasm.end_catch()
+
+ else:
+ # no exception handling, follow block links
+ for link in block.exits:
+ self._setup_link(link)
+ target_label = self._get_block_name(link.target)
+ if link.exitcase is None:
+ self.ilasm.branch(target_label)
+ else:
+ assert type(link.exitcase is bool)
+ assert block.exitswitch is not None
+ self._push(block.exitswitch)
+ self.ilasm.branch_if(link.exitcase, target_label)
- # follow block links
- for link in block.exits:
- target = link.target
- for to_load, to_store in zip(link.args, target.inputargs):
- if to_load.concretetype is not Void:
- self._push(to_load)
- self._store(to_store)
-
- target_label = self._get_block_name(target)
- if link.exitcase is None:
- self.ilasm.branch(target_label)
- else:
- assert type(link.exitcase is bool)
- self._push(block.exitswitch)
- self.ilasm.branch_if(link.exitcase, target_label)
# add a block that will never be executed, just to please the
# .NET runtime that seems to need a return statement at the
@@ -76,8 +119,15 @@
self.ilasm.opcode('ldc.%s 0' % ilasm_type)
self.ilasm.opcode('ret')
-
- ilasm.end_function()
+ self.ilasm.end_function()
+
+ def _setup_link(self, link):
+ target = link.target
+ for to_load, to_store in zip(link.args, target.inputargs):
+ if to_load.concretetype is not Void:
+ self._push(to_load)
+ self._store(to_store)
+
def _set_locals(self):
# this code is partly borrowed from pypy.translator.c.funcgen.FunctionCodeGenerator
@@ -187,6 +237,7 @@
def _store(self, v):
if isinstance(v, flowmodel.Variable):
- self.ilasm.opcode('stloc', repr(v.name))
+ if v.concretetype is not Void:
+ self.ilasm.opcode('stloc', repr(v.name))
else:
assert False
Modified: pypy/dist/pypy/translator/cli/ilgenerator.py
==============================================================================
--- pypy/dist/pypy/translator/cli/ilgenerator.py (original)
+++ pypy/dist/pypy/translator/cli/ilgenerator.py Tue Mar 28 17:37:30 2006
@@ -56,6 +56,20 @@
def end_function(self):
self.code.closeblock()
+ def begin_try(self):
+ self.code.writeline('.try')
+ self.code.openblock()
+
+ def end_try(self):
+ self.code.closeblock()
+
+ def begin_catch(self, type_):
+ self.code.writeline('catch ' + type_)
+ self.code.openblock()
+
+ def end_catch(self):
+ self.code.closeblock()
+
def locals(self, vars):
varlist = ', '.join(['%s %s' % var for var in vars])
self.code.write('.locals init (')
@@ -67,6 +81,9 @@
self.code.write(lbl + ':', indent=0)
self.code.writeline()
+ def leave(self, lbl):
+ self.code.writeline('leave ' + lbl)
+
def branch(self, lbl):
self.code.writeline('br ' + lbl)
Modified: pypy/dist/pypy/translator/cli/opcodes.py
==============================================================================
--- pypy/dist/pypy/translator/cli/opcodes.py (original)
+++ pypy/dist/pypy/translator/cli/opcodes.py Tue Mar 28 17:37:30 2006
@@ -51,11 +51,10 @@
'int_lshift': 'shl',
'int_rshift': 'shr',
'int_xor': 'xor',
- 'int_add_ovf': None,
- 'int_sub_ovf': None,
- 'int_mul_ovf': None,
- 'int_div_ovf': None,
- 'int_truediv_ovf': None,
+ 'int_add_ovf': 'add.ovf',
+ 'int_sub_ovf': 'sub.ovf',
+ 'int_mul_ovf': 'mul.ovf',
+# 'int_div_ovf': None,
'int_floordiv_ovf': None,
'int_mod_ovf': None,
'int_lt_ovf': None,
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 Tue Mar 28 17:37:30 2006
@@ -24,37 +24,23 @@
print 'OK'
-def foo(x):
- pass
-
-def xxx():
+def foo():
pass
def bar(x, y):
try:
- foo(x)
- z = ovfcheck(x+y)
- xxx()
- return z
+ foo()
+ z = x
except OverflowError:
- while x:
- x = x-1
- return x
- except IndexError:
- return 52
-
+ z = x+y
+
+ return z
-def bar(x, y):
- foo(x)
- foo(None)
f = compile_function(bar, [int, int])
try:
- check(f, bar, r_uint(sys.maxint+1), r_uint(42))
- check(f, bar, 4, 5)
+ pass
except py.test.Item.Skipped:
print 'Test skipped'
-
-#compile_function(s.is_perfect_number, [int])
Added: pypy/dist/pypy/translator/cli/test/test_overflow.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/cli/test/test_overflow.py Tue Mar 28 17:37:30 2006
@@ -0,0 +1,27 @@
+from pypy.translator.cli.test.runtest import check
+from pypy.rpython.rarithmetic import ovfcheck
+
+import sys
+
+def op_add(x, y):
+ try:
+ return ovfcheck(x+y)
+ except OverflowError:
+ return 42
+
+def op_sub(x, y):
+ try:
+ return ovfcheck(x-y)
+ except OverflowError:
+ return 42
+
+def op_mul(x, y):
+ try:
+ return ovfcheck(x*y)
+ except OverflowError:
+ return 42
+
+def test_overflow():
+ yield check, op_add, [int, int], (sys.maxint, 1)
+ yield check, op_sub, [int, int], (-sys.maxint, 1)
+ yield check, op_mul, [int, int], (sys.maxint/2 + 1, 2)
More information about the Pypy-commit
mailing list