Source

pypy / pypy / translator / cli / function.py

Full commit
Antonio Cuni 52bbfe7 
Antonio Cuni 9b5adc8 
Antonio Cuni 52bbfe7 







































Antonio Cuni b74ab46 
Antonio Cuni 52bbfe7 


































































Antonio Cuni b74ab46 
Antonio Cuni 52bbfe7 






















Antonio Cuni b74ab46 


Antonio Cuni 52bbfe7 




Antonio Cuni ee13bef 








Antonio Cuni 9b5adc8 
Antonio Cuni ee13bef 




Antonio Cuni 52bbfe7 


























































Antonio Cuni 1670501 



Antonio Cuni 52bbfe7 
from pypy.objspace.flow import model as flowmodel
from pypy.rlib.objectmodel import CDefinedIntSymbolic
from pypy.rpython.lltypesystem.lltype import Void
from pypy.rpython.ootypesystem import ootype
from pypy.translator.oosupport.treebuilder import SubOperation
from pypy.translator.oosupport.function import Function as OOFunction, render_sub_op
from pypy.translator.oosupport.constant import push_constant
from pypy.translator.cli.option import getoption
from pypy.translator.cli.cts import CTS
from pypy.translator.cli.opcodes import opcodes
from pypy.translator.cli.metavm import InstructionList, Generator
from pypy.translator.cli.node import Node
from pypy.translator.cli.class_ import Class
from pypy.translator.cli.support import log
from pypy.translator.cli.ilgenerator import CLIBaseGenerator

class Function(OOFunction, Node, CLIBaseGenerator):

    auto_propagate_exceptions = True

    def __init__(self, *args, **kwargs):
        OOFunction.__init__(self, *args, **kwargs)

        if hasattr(self.db.genoo, 'exceptiontransformer'):
            self.auto_propagate_exceptions = False
        
        namespace = getattr(self.graph.func, '_namespace_', None)
        if namespace:
            if '.' in namespace:
                self.namespace, self.classname = namespace.rsplit('.', 1)
            else:
                self.namespace = None
                self.classname = namespace
        else:
            self.namespace = None
            self.classname = None

    def _create_generator(self, ilasm):
        return self # Function implements the Generator interface

    def record_ll_meta_exc(self, ll_meta_exc):
        # record the type only if it doesn't belong to a native_class
        ll_exc = ll_meta_exc._INSTANCE
        NATIVE_INSTANCE = ll_exc._hints.get('NATIVE_INSTANCE', None)
        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
            meth_type = 'virtual' # TODO: mark as virtual only when strictly necessary
        else:
            args = self.args
            meth_type = 'static'

        if self.namespace:
            self.ilasm.begin_namespace(self.namespace)
        if self.classname:
            self.ilasm.begin_class(self.classname)
        self.ilasm.begin_function(self.name, args, returntype, self.is_entrypoint, meth_type)
        self.ilasm.locals(self.locals)

    def end_render(self):
        self.ilasm.end_function()
        if self.classname:
            self.ilasm.end_class()
        if self.namespace:
            self.ilasm.end_namespace()

    def set_label(self, label):
        self.ilasm.label(label)

    def render_return_block(self, block):
        return_var = block.inputargs[0]
        if return_var.concretetype is not Void:
            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._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.call_method(
                    'class [mscorlib]System.Type object::GetType()',
                    virtual=True)
                self.store(link.last_exception)
            else:
                self.store(link.last_exc_value)
            self._setup_link(link)

    def _dont_store(self, to_load, to_store):
        # ugly workaround to make the exceptiontransformer work with
        # valuetypes: when exceptiontransforming a function whose result is a
        # .NET valuetype, it tries to store a null into the return variable.
        # Since it is not possible to store a null into a valuetype, and that
        # in that case the value is not used anyway, we simply ignore it.
        from pypy.translator.cli.dotnet import NativeInstance
        if isinstance(to_load, flowmodel.Constant):
            value = to_load.value
            is_null = (not isinstance(value, CDefinedIntSymbolic)) and (not value)
            T = ootype.typeOf(to_load.value)
            if isinstance(T, NativeInstance) and T._is_value_type and is_null:
                return True
        return OOFunction._dont_store(self, to_load, to_store)

    def render_numeric_switch(self, block):
        if block.exitswitch.concretetype in (ootype.SignedLongLong, ootype.UnsignedLongLong):
            # TODO: it could be faster to check is the values fit in
            # 32bit, and perform a cast in that case
            self.render_numeric_switch_naive(block)
            return

        cases, min_case, max_case, default = self._collect_switch_cases(block)
        is_sparse = self._is_sparse_switch(cases, min_case, max_case)

        naive = (min_case < 0) or is_sparse
        if naive:
            self.render_numeric_switch_naive(block)
            return

        targets = []
        for i in xrange(max_case+1):
            link, lbl = cases.get(i, default)
            targets.append(lbl)
        self.generator.load(block.exitswitch)
        self.ilasm.switch(targets)
        self.render_switch_case(*default)
        for link, lbl in cases.itervalues():
            self.render_switch_case(link, lbl)

    def call_oostring(self, ARGTYPE):
        if isinstance(ARGTYPE, ootype.Instance):
            argtype = self.cts.types.object
        else:
            argtype = self.cts.lltype_to_cts(ARGTYPE)
        self.call_signature('string [pypylib]pypy.runtime.Utils::OOString(%s, int32)' % argtype)

    def call_oounicode(self, ARGTYPE):
        argtype = self.cts.lltype_to_cts(ARGTYPE)
        self.call_signature('string [pypylib]pypy.runtime.Utils::OOUnicode(%s)' % argtype)

    # Those parts of the generator interface that are function
    # specific

    def load(self, v):
        if isinstance(v, flowmodel.Variable):
            if v.concretetype is ootype.Void:
                return # ignore it
            if v.name in self.argset:
                selftype, selfname = self.args[0]
                if self.is_method and v.name == selfname:
                    self.ilasm.load_self() # special case for 'self'
                else:
                    self.ilasm.load_arg(v)
            else:
                self.ilasm.load_local(v)
        elif isinstance(v, SubOperation):
            render_sub_op(v, self.db, self.generator)
        else:
            super(Function, self).load(v)

    def store(self, v):
        if isinstance(v, flowmodel.Variable):
            if v.concretetype is not Void:
                if v.name in self.argset:
                    self.ilasm.store_arg(v)
                else:
                    self.ilasm.store_local(v)
        else:
            assert False