Esempio n. 1
0
def call_final_function(translator, final_func, annhelper=None):
    """When the program finishes normally, call 'final_func()'."""
    from pypy.annotation import model as annmodel
    from pypy.rpython.lltypesystem import lltype
    from pypy.rpython.annlowlevel import MixLevelHelperAnnotator

    own_annhelper = (annhelper is None)
    if own_annhelper:
        annhelper = MixLevelHelperAnnotator(translator.rtyper)
    c_final_func = annhelper.constfunc(final_func, [], annmodel.s_None)
    if own_annhelper:
        annhelper.finish()

    entry_point = translator.graphs[0]
    v = copyvar(translator.annotator, entry_point.getreturnvar())
    extrablock = Block([v])
    v_none = varoftype(lltype.Void)
    newop = SpaceOperation('direct_call', [c_final_func], v_none)
    extrablock.operations = [newop]
    extrablock.closeblock(Link([v], entry_point.returnblock))
    for block in entry_point.iterblocks():
        if block is not extrablock:
            for link in block.exits:
                if link.target is entry_point.returnblock:
                    link.target = extrablock
    checkgraph(entry_point)
Esempio n. 2
0
def call_final_function(translator, final_func, annhelper=None):
    """When the program finishes normally, call 'final_func()'."""
    from pypy.annotation import model as annmodel
    from pypy.rpython.lltypesystem import lltype
    from pypy.rpython.annlowlevel import MixLevelHelperAnnotator

    own_annhelper = (annhelper is None)
    if own_annhelper:
        annhelper = MixLevelHelperAnnotator(translator.rtyper)
    c_final_func = annhelper.constfunc(final_func, [], annmodel.s_None)
    if own_annhelper:
        annhelper.finish()

    entry_point = translator.entry_point_graph
    v = copyvar(translator.annotator, entry_point.getreturnvar())
    extrablock = Block([v])
    v_none = varoftype(lltype.Void)
    newop = SpaceOperation('direct_call', [c_final_func], v_none)
    extrablock.operations = [newop]
    extrablock.closeblock(Link([v], entry_point.returnblock))
    for block in entry_point.iterblocks():
        if block is not extrablock:
            for link in block.exits:
                if link.target is entry_point.returnblock:
                    link.target = extrablock
    checkgraph(entry_point)
Esempio n. 3
0
def builtin_func_for_spec(rtyper, oopspec_name, ll_args, ll_res):
    key = (oopspec_name, tuple(ll_args), ll_res)
    try:
        return rtyper._builtin_func_for_spec_cache[key]
    except (KeyError, AttributeError):
        pass
    args_s = [annmodel.lltype_to_annotation(v) for v in ll_args]
    if '.' not in oopspec_name:    # 'newxxx' operations
        LIST_OR_DICT = ll_res
    else:
        LIST_OR_DICT = ll_args[0]
    s_result = annmodel.lltype_to_annotation(ll_res)
    impl = setup_extra_builtin(rtyper, oopspec_name, len(args_s))
    if getattr(impl, 'need_result_type', False):
        bk = rtyper.annotator.bookkeeper
        args_s.insert(0, annmodel.SomePBC([bk.getdesc(deref(ll_res))]))
    #
    mixlevelann = MixLevelHelperAnnotator(rtyper)
    c_func = mixlevelann.constfunc(impl, args_s, s_result)
    mixlevelann.finish()
    #
    if not hasattr(rtyper, '_builtin_func_for_spec_cache'):
        rtyper._builtin_func_for_spec_cache = {}
    rtyper._builtin_func_for_spec_cache[key] = (c_func, LIST_OR_DICT)
    #
    return c_func, LIST_OR_DICT
Esempio n. 4
0
 def make_driverhook_graphs(self):
     from pypy.rlib.jit import BaseJitCell
     bk = self.rtyper.annotator.bookkeeper
     classdef = bk.getuniqueclassdef(BaseJitCell)
     s_BaseJitCell_or_None = annmodel.SomeInstance(classdef,
                                                   can_be_None=True)
     s_BaseJitCell_not_None = annmodel.SomeInstance(classdef)
     s_Str = annmodel.SomeString()
     #
     annhelper = MixLevelHelperAnnotator(self.translator.rtyper)
     for jd in self.jitdrivers_sd:
         jd._set_jitcell_at_ptr = self._make_hook_graph(jd,
             annhelper, jd.jitdriver.set_jitcell_at, annmodel.s_None,
             s_BaseJitCell_not_None)
         jd._get_jitcell_at_ptr = self._make_hook_graph(jd,
             annhelper, jd.jitdriver.get_jitcell_at, s_BaseJitCell_or_None)
         jd._get_printable_location_ptr = self._make_hook_graph(jd,
             annhelper, jd.jitdriver.get_printable_location, s_Str)
         jd._confirm_enter_jit_ptr = self._make_hook_graph(jd,
             annhelper, jd.jitdriver.confirm_enter_jit, annmodel.s_Bool,
             onlygreens=False)
         jd._can_never_inline_ptr = self._make_hook_graph(jd,
             annhelper, jd.jitdriver.can_never_inline, annmodel.s_Bool)
         jd._should_unroll_one_iteration_ptr = self._make_hook_graph(jd,
             annhelper, jd.jitdriver.should_unroll_one_iteration,
             annmodel.s_Bool)
     annhelper.finish()
Esempio n. 5
0
def builtin_func_for_spec(rtyper, oopspec_name, ll_args, ll_res):
    key = (oopspec_name, tuple(ll_args), ll_res)
    try:
        return rtyper._builtin_func_for_spec_cache[key]
    except (KeyError, AttributeError):
        pass
    args_s = [annmodel.lltype_to_annotation(v) for v in ll_args]
    if "." not in oopspec_name:  # 'newxxx' operations
        LIST_OR_DICT = ll_res
    else:
        LIST_OR_DICT = ll_args[0]
    s_result = annmodel.lltype_to_annotation(ll_res)
    impl = setup_extra_builtin(rtyper, oopspec_name, len(args_s))
    if getattr(impl, "need_result_type", False):
        bk = rtyper.annotator.bookkeeper
        args_s.insert(0, annmodel.SomePBC([bk.getdesc(deref(ll_res))]))
    #
    mixlevelann = MixLevelHelperAnnotator(rtyper)
    c_func = mixlevelann.constfunc(impl, args_s, s_result)
    mixlevelann.finish()
    #
    if not hasattr(rtyper, "_builtin_func_for_spec_cache"):
        rtyper._builtin_func_for_spec_cache = {}
    rtyper._builtin_func_for_spec_cache[key] = (c_func, LIST_OR_DICT)
    #
    return c_func, LIST_OR_DICT
Esempio n. 6
0
 def make_driverhook_graphs(self):
     from pypy.rlib.jit import BaseJitCell
     bk = self.rtyper.annotator.bookkeeper
     classdef = bk.getuniqueclassdef(BaseJitCell)
     s_BaseJitCell_or_None = annmodel.SomeInstance(classdef,
                                                   can_be_None=True)
     s_BaseJitCell_not_None = annmodel.SomeInstance(classdef)
     s_Str = annmodel.SomeString()
     #
     annhelper = MixLevelHelperAnnotator(self.translator.rtyper)
     for jd in self.jitdrivers_sd:
         jd._set_jitcell_at_ptr = self._make_hook_graph(jd,
             annhelper, jd.jitdriver.set_jitcell_at, annmodel.s_None,
             s_BaseJitCell_not_None)
         jd._get_jitcell_at_ptr = self._make_hook_graph(jd,
             annhelper, jd.jitdriver.get_jitcell_at, s_BaseJitCell_or_None)
         jd._get_printable_location_ptr = self._make_hook_graph(jd,
             annhelper, jd.jitdriver.get_printable_location, s_Str)
         jd._confirm_enter_jit_ptr = self._make_hook_graph(jd,
             annhelper, jd.jitdriver.confirm_enter_jit, annmodel.s_Bool,
             onlygreens=False)
         jd._can_never_inline_ptr = self._make_hook_graph(jd,
             annhelper, jd.jitdriver.can_never_inline, annmodel.s_Bool)
         jd._should_unroll_one_iteration_ptr = self._make_hook_graph(jd,
             annhelper, jd.jitdriver.should_unroll_one_iteration,
             annmodel.s_Bool)
     annhelper.finish()
Esempio n. 7
0
def builtin_func_for_spec(rtyper, oopspec_name, ll_args, ll_res,
                          extra=None, extrakey=None):
    assert (extra is None) == (extrakey is None)
    key = (oopspec_name, tuple(ll_args), ll_res, extrakey)
    try:
        return rtyper._builtin_func_for_spec_cache[key]
    except (KeyError, AttributeError):
        pass
    args_s = [annmodel.lltype_to_annotation(v) for v in ll_args]
    if '.' not in oopspec_name:    # 'newxxx' operations
        LIST_OR_DICT = ll_res
    else:
        LIST_OR_DICT = ll_args[0]
    s_result = annmodel.lltype_to_annotation(ll_res)
    impl = setup_extra_builtin(rtyper, oopspec_name, len(args_s), extra)
    if getattr(impl, 'need_result_type', False):
        bk = rtyper.annotator.bookkeeper
        args_s.insert(0, annmodel.SomePBC([bk.getdesc(deref(ll_res))]))
    #
    if hasattr(rtyper, 'annotator'):  # regular case
        mixlevelann = MixLevelHelperAnnotator(rtyper)
        c_func = mixlevelann.constfunc(impl, args_s, s_result)
        mixlevelann.finish()
    else:
        # for testing only
        c_func = Constant(oopspec_name,
                          lltype.Ptr(lltype.FuncType(ll_args, ll_res)))
    #
    if not hasattr(rtyper, '_builtin_func_for_spec_cache'):
        rtyper._builtin_func_for_spec_cache = {}
    rtyper._builtin_func_for_spec_cache[key] = (c_func, LIST_OR_DICT)
    #
    return c_func, LIST_OR_DICT
Esempio n. 8
0
 def make_leave_jit_graph(self):
     self.leave_graph = None
     if self.jitdriver.leave:
         args_s = self.portal_args_s
         from pypy.annotation import model as annmodel
         annhelper = MixLevelHelperAnnotator(self.translator.rtyper)
         s_result = annmodel.s_None
         self.leave_graph = annhelper.getgraph(self.jitdriver.leave,
                                               args_s, s_result)
         annhelper.finish()
Esempio n. 9
0
def test_enforced_args():
    from pypy.annotation.model import s_None
    from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
    from pypy.translator.interactive import Translation
    def f1():
        str2charp("hello")
    def f2():
        str2charp("world")
    t = Translation(f1, [])
    t.rtype()
    mixann = MixLevelHelperAnnotator(t.context.rtyper)
    mixann.getgraph(f2, [], s_None)
    mixann.finish()
Esempio n. 10
0
 def build_meta_interp(self,
                       CPUClass,
                       translate_support_code=False,
                       view="auto",
                       no_stats=False,
                       ProfilerClass=EmptyProfiler,
                       **kwds):
     assert CPUClass is not None
     opt = history.Options(**kwds)
     if no_stats:
         stats = history.NoStats()
     else:
         stats = history.Stats()
     self.stats = stats
     if translate_support_code:
         self.annhelper = MixLevelHelperAnnotator(self.translator.rtyper)
         annhelper = self.annhelper
     else:
         annhelper = None
     cpu = CPUClass(self.translator.rtyper,
                    self.stats,
                    translate_support_code,
                    gcdescr=self.gcdescr)
     self.cpu = cpu
     self.metainterp_sd = MetaInterpStaticData(
         self.portal_graph,  # xxx
         cpu,
         self.stats,
         opt,
         ProfilerClass=ProfilerClass,
         warmrunnerdesc=self)
Esempio n. 11
0
 def build_cpu(self,
               CPUClass,
               translate_support_code=False,
               no_stats=False,
               supports_floats=True,
               supports_longlong=True,
               supports_singlefloats=True,
               **kwds):
     assert CPUClass is not None
     self.opt = history.Options(**kwds)
     if no_stats:
         stats = history.NoStats()
     else:
         stats = history.Stats()
     self.stats = stats
     if translate_support_code:
         self.annhelper = MixLevelHelperAnnotator(self.translator.rtyper)
     cpu = CPUClass(self.translator.rtyper,
                    self.stats,
                    self.opt,
                    translate_support_code,
                    gcdescr=self.gcdescr)
     if not supports_floats: cpu.supports_floats = False
     if not supports_longlong: cpu.supports_longlong = False
     if not supports_singlefloats: cpu.supports_singlefloats = False
     self.cpu = cpu
Esempio n. 12
0
def test_pseudohighlevelcallable():
    t = TranslationContext()
    t.buildannotator()
    rtyper = t.buildrtyper()
    rtyper.specialize()
    a = MixLevelHelperAnnotator(rtyper)

    class A:
        value = 5

        def double(self):
            return self.value * 2

    def fn1(a):
        a2 = A()
        a2.value = a.double()
        return a2

    s_A, r_A = a.s_r_instanceof(A)
    fn1ptr = a.delayedfunction(fn1, [s_A], s_A)
    pseudo = PseudoHighLevelCallable(fn1ptr, [s_A], s_A)

    def fn2(n):
        a = A()
        a.value = n
        a2 = pseudo(a)
        return a2.value

    graph = a.getgraph(fn2, [annmodel.SomeInteger()], annmodel.SomeInteger())
    a.finish()

    llinterp = LLInterpreter(rtyper)
    res = llinterp.eval_graph(graph, [21])
    assert res == 42
Esempio n. 13
0
 def make_driverhook_graphs(self):
     from pypy.rlib.jit import BaseJitCell
     bk = self.rtyper.annotator.bookkeeper
     classdef = bk.getuniqueclassdef(BaseJitCell)
     s_BaseJitCell_or_None = annmodel.SomeInstance(classdef,
                                                   can_be_None=True)
     s_BaseJitCell_not_None = annmodel.SomeInstance(classdef)
     s_Str = annmodel.SomeString()
     #
     annhelper = MixLevelHelperAnnotator(self.translator.rtyper)
     self.set_jitcell_at_ptr = self._make_hook_graph(
         annhelper, self.jitdriver.set_jitcell_at, annmodel.s_None,
         s_BaseJitCell_not_None)
     self.get_jitcell_at_ptr = self._make_hook_graph(
         annhelper, self.jitdriver.get_jitcell_at, s_BaseJitCell_or_None)
     self.can_inline_ptr = self._make_hook_graph(
         annhelper, self.jitdriver.can_inline, annmodel.s_Bool)
     self.get_printable_location_ptr = self._make_hook_graph(
         annhelper, self.jitdriver.get_printable_location, s_Str)
     annhelper.finish()
Esempio n. 14
0
 def make_driverhook_graphs(self):
     from pypy.rlib.jit import BaseJitCell
     bk = self.rtyper.annotator.bookkeeper
     classdef = bk.getuniqueclassdef(BaseJitCell)
     s_BaseJitCell_or_None = annmodel.SomeInstance(classdef,
                                                   can_be_None=True)
     s_BaseJitCell_not_None = annmodel.SomeInstance(classdef)
     s_Str = annmodel.SomeString()
     #
     annhelper = MixLevelHelperAnnotator(self.translator.rtyper)
     self.set_jitcell_at_ptr = self._make_hook_graph(
         annhelper, self.jitdriver.set_jitcell_at, annmodel.s_None,
         s_BaseJitCell_not_None)
     self.get_jitcell_at_ptr = self._make_hook_graph(
         annhelper, self.jitdriver.get_jitcell_at, s_BaseJitCell_or_None)
     self.can_inline_ptr = self._make_hook_graph(annhelper,
                                                 self.jitdriver.can_inline,
                                                 annmodel.s_Bool)
     self.get_printable_location_ptr = self._make_hook_graph(
         annhelper, self.jitdriver.get_printable_location, s_Str)
     annhelper.finish()
Esempio n. 15
0
def test_pseudohighlevelcallable():
    t = TranslationContext()
    t.buildannotator()
    rtyper = t.buildrtyper()
    rtyper.specialize()
    a = MixLevelHelperAnnotator(rtyper)

    class A:
        value = 5
        def double(self):
            return self.value * 2

    def fn1(a):
        a2 = A()
        a2.value = a.double()
        return a2

    s_A, r_A = a.s_r_instanceof(A)
    fn1ptr = a.delayedfunction(fn1, [s_A], s_A)
    pseudo = PseudoHighLevelCallable(fn1ptr, [s_A], s_A)

    def fn2(n):
        a = A()
        a.value = n
        a2 = pseudo(a)
        return a2.value

    graph = a.getgraph(fn2, [annmodel.SomeInteger()], annmodel.SomeInteger())
    a.finish()

    llinterp = LLInterpreter(rtyper)
    res = llinterp.eval_graph(graph, [21])
    assert res == 42
Esempio n. 16
0
def call_initial_function(translator, initial_func, annhelper=None):
    """Before the program starts, call 'initial_func()'."""
    from pypy.annotation import model as annmodel
    from pypy.rpython.lltypesystem import lltype
    from pypy.rpython.annlowlevel import MixLevelHelperAnnotator

    own_annhelper = (annhelper is None)
    if own_annhelper:
        annhelper = MixLevelHelperAnnotator(translator.rtyper)
    c_initial_func = annhelper.constfunc(initial_func, [], annmodel.s_None)
    if own_annhelper:
        annhelper.finish()

    entry_point = translator.entry_point_graph
    args = [copyvar(translator.annotator, v) for v in entry_point.getargs()]
    extrablock = Block(args)
    v_none = varoftype(lltype.Void)
    newop = SpaceOperation('direct_call', [c_initial_func], v_none)
    extrablock.operations = [newop]
    extrablock.closeblock(Link(args, entry_point.startblock))
    entry_point.startblock = extrablock
    checkgraph(entry_point)
Esempio n. 17
0
    def replace_force_virtualizable(self, rtyper, graphs):
        from pypy.annotation import model as annmodel
        from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
        graph = graphs[0]

        for block, op in graph.iterblockops():
            if op.opname == 'jit_force_virtualizable':
                v_inst_ll_type = op.args[0].concretetype
                break
            
        def mycall(vinst_ll):
            if vinst_ll.vable_token:
                raise ValueError
        annhelper = MixLevelHelperAnnotator(rtyper)
        if self.type_system == 'lltype':
            s_vinst = annmodel.SomePtr(v_inst_ll_type)
        else:
            s_vinst = annmodel.SomeOOInstance(v_inst_ll_type)
        funcptr = annhelper.delayedfunction(mycall, [s_vinst], annmodel.s_None)
        annhelper.finish()
        replace_force_virtualizable_with_call(graphs, v_inst_ll_type, funcptr)
        return funcptr
Esempio n. 18
0
def call_initial_function(translator, initial_func, annhelper=None):
    """Before the program starts, call 'initial_func()'."""
    from pypy.annotation import model as annmodel
    from pypy.rpython.lltypesystem import lltype
    from pypy.rpython.annlowlevel import MixLevelHelperAnnotator

    own_annhelper = (annhelper is None)
    if own_annhelper:
        annhelper = MixLevelHelperAnnotator(translator.rtyper)
    c_initial_func = annhelper.constfunc(initial_func, [], annmodel.s_None)
    if own_annhelper:
        annhelper.finish()

    entry_point = translator.entry_point_graph
    args = [copyvar(translator.annotator, v) for v in entry_point.getargs()]
    extrablock = Block(args)
    v_none = varoftype(lltype.Void)
    newop = SpaceOperation('direct_call', [c_initial_func], v_none)
    extrablock.operations = [newop]
    extrablock.closeblock(Link(args, entry_point.startblock))
    entry_point.startblock = extrablock
    checkgraph(entry_point)
Esempio n. 19
0
    def replace_promote_virtualizable(self, rtyper, graphs):
        from pypy.annotation import model as annmodel
        from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
        graph = graphs[0]

        for block, op in graph.iterblockops():
            if op.opname == 'promote_virtualizable':
                v_inst_ll_type = op.args[0].concretetype
                break

        def mycall(vinst_ll):
            pass

        annhelper = MixLevelHelperAnnotator(rtyper)
        if self.type_system == 'lltype':
            s_vinst = annmodel.SomePtr(v_inst_ll_type)
        else:
            s_vinst = annmodel.SomeOOInstance(v_inst_ll_type)
        funcptr = annhelper.delayedfunction(mycall, [s_vinst], annmodel.s_None)
        annhelper.finish()
        replace_promote_virtualizable_with_call(graphs, v_inst_ll_type,
                                                funcptr)
        return funcptr
Esempio n. 20
0
    def test_secondary_backendopt(self):
        # checks an issue with a newly added graph that calls an
        # already-exception-transformed graph.  This can occur e.g.
        # from a late-seen destructor added by the GC transformer
        # which ends up calling existing code.
        def common(n):
            if n > 5:
                raise ValueError

        def main(n):
            common(n)

        def later(n):
            try:
                common(n)
                return 0
            except ValueError:
                return 1

        t = TranslationContext()
        t.buildannotator().build_types(main, [int])
        t.buildrtyper(type_system='lltype').specialize()
        exctransformer = t.getexceptiontransformer()
        exctransformer.create_exception_handling(graphof(t, common))
        from pypy.annotation import model as annmodel
        from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
        annhelper = MixLevelHelperAnnotator(t.rtyper)
        later_graph = annhelper.getgraph(later, [annmodel.SomeInteger()],
                                         annmodel.SomeInteger())
        annhelper.finish()
        annhelper.backend_optimize()
        # ^^^ as the inliner can't handle exception-transformed graphs,
        # this should *not* inline common() into later().
        if conftest.option.view:
            later_graph.show()
        common_graph = graphof(t, common)
        found = False
        for block in later_graph.iterblocks():
            for op in block.operations:
                if (op.opname == 'direct_call'
                        and op.args[0].value._obj.graph is common_graph):
                    found = True
        assert found, "cannot find the call (buggily inlined?)"
        from pypy.rpython.llinterp import LLInterpreter
        llinterp = LLInterpreter(t.rtyper)
        res = llinterp.eval_graph(later_graph, [10])
        assert res == 1
Esempio n. 21
0
 def __init__(self, translator, inline=False):
     self.translator = translator
     self.seen_graphs = {}
     self.prepared = False
     self.minimal_transform = {}
     if translator:
         self.mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper)
     else:
         self.mixlevelannotator = None
     self.inline = inline
     if translator and inline:
         self.lltype_to_classdef = translator.rtyper.lltype_to_classdef_mapping()
     self.graphs_to_inline = {}
     self.graph_dependencies = {}
     self.ll_finalizers_ptrs = []
     if self.MinimalGCTransformer:
         self.minimalgctransformer = self.MinimalGCTransformer(self)
     else:
         self.minimalgctransformer = None
Esempio n. 22
0
def test_enforced_args():
    from pypy.annotation.model import s_None
    from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
    from pypy.translator.interactive import Translation

    def f1():
        str2charp("hello")

    def f2():
        str2charp("world")

    t = Translation(f1, [])
    t.rtype()
    mixann = MixLevelHelperAnnotator(t.context.rtyper)
    mixann.getgraph(f2, [], s_None)
    mixann.finish()
Esempio n. 23
0
    def test_secondary_backendopt(self):
        # checks an issue with a newly added graph that calls an
        # already-exception-transformed graph.  This can occur e.g.
        # from a late-seen destructor added by the GC transformer
        # which ends up calling existing code.
        def common(n):
            if n > 5:
                raise ValueError

        def main(n):
            common(n)

        def later(n):
            try:
                common(n)
                return 0
            except ValueError:
                return 1

        t = TranslationContext()
        t.buildannotator().build_types(main, [int])
        t.buildrtyper(type_system="lltype").specialize()
        exctransformer = t.getexceptiontransformer()
        exctransformer.create_exception_handling(graphof(t, common))
        from pypy.annotation import model as annmodel
        from pypy.rpython.annlowlevel import MixLevelHelperAnnotator

        annhelper = MixLevelHelperAnnotator(t.rtyper)
        later_graph = annhelper.getgraph(later, [annmodel.SomeInteger()], annmodel.SomeInteger())
        annhelper.finish()
        annhelper.backend_optimize()
        # ^^^ as the inliner can't handle exception-transformed graphs,
        # this should *not* inline common() into later().
        if conftest.option.view:
            later_graph.show()
        common_graph = graphof(t, common)
        found = False
        for block in later_graph.iterblocks():
            for op in block.operations:
                if op.opname == "direct_call" and op.args[0].value._obj.graph is common_graph:
                    found = True
        assert found, "cannot find the call (buggily inlined?)"
        from pypy.rpython.llinterp import LLInterpreter

        llinterp = LLInterpreter(t.rtyper)
        res = llinterp.eval_graph(later_graph, [10])
        assert res == 1
Esempio n. 24
0
class BaseExceptionTransformer(object):
    def __init__(self, translator):
        self.translator = translator
        self.raise_analyzer = canraise.RaiseAnalyzer(translator)
        edata = translator.rtyper.getexceptiondata()
        self.lltype_of_exception_value = edata.lltype_of_exception_value
        self.lltype_of_exception_type = edata.lltype_of_exception_type
        self.mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper)
        exc_data, null_type, null_value = self.setup_excdata()

        rclass = translator.rtyper.type_system.rclass
        (assertion_error_ll_exc_type,
         assertion_error_ll_exc) = self.get_builtin_exception(AssertionError)
        (n_i_error_ll_exc_type,
         n_i_error_ll_exc) = self.get_builtin_exception(NotImplementedError)

        self.c_assertion_error_ll_exc_type = constant_value(
            assertion_error_ll_exc_type)
        self.c_n_i_error_ll_exc_type = constant_value(n_i_error_ll_exc_type)

        def rpyexc_occured():
            exc_type = exc_data.exc_type
            return bool(exc_type)

        def rpyexc_fetch_type():
            return exc_data.exc_type

        def rpyexc_fetch_value():
            return exc_data.exc_value

        def rpyexc_clear():
            exc_data.exc_type = null_type
            exc_data.exc_value = null_value

        def rpyexc_raise(etype, evalue):
            # When compiling in debug mode, the following ll_asserts will
            # crash the program as soon as it raises AssertionError or
            # NotImplementedError.  Useful when you are in a debugger.
            # When compiling in release mode, AssertionErrors and
            # NotImplementedErrors are raised normally, and only later
            # caught by debug_catch_exception and printed, which allows
            # us to see at least part of the traceback for them.
            ll_assert(etype != assertion_error_ll_exc_type, "AssertionError")
            ll_assert(etype != n_i_error_ll_exc_type, "NotImplementedError")
            exc_data.exc_type = etype
            exc_data.exc_value = evalue
            lloperation.llop.debug_start_traceback(lltype.Void, etype)

        def rpyexc_reraise(etype, evalue):
            exc_data.exc_type = etype
            exc_data.exc_value = evalue
            lloperation.llop.debug_reraise_traceback(lltype.Void, etype)

        def rpyexc_fetch_exception():
            evalue = rpyexc_fetch_value()
            rpyexc_clear()
            return evalue

        def rpyexc_restore_exception(evalue):
            if evalue:
                exc_data.exc_type = rclass.ll_inst_type(evalue)
                exc_data.exc_value = evalue

        self.rpyexc_occured_ptr = self.build_func("RPyExceptionOccurred",
                                                  rpyexc_occured, [],
                                                  lltype.Bool)

        self.rpyexc_fetch_type_ptr = self.build_func(
            "RPyFetchExceptionType", rpyexc_fetch_type, [],
            self.lltype_of_exception_type)

        self.rpyexc_fetch_value_ptr = self.build_func(
            "RPyFetchExceptionValue", rpyexc_fetch_value, [],
            self.lltype_of_exception_value)

        self.rpyexc_clear_ptr = self.build_func("RPyClearException",
                                                rpyexc_clear, [], lltype.Void)

        self.rpyexc_raise_ptr = self.build_func(
            "RPyRaiseException",
            self.noinline(rpyexc_raise),
            [self.lltype_of_exception_type, self.lltype_of_exception_value],
            lltype.Void,
            jitcallkind='rpyexc_raise')  # for the JIT

        self.rpyexc_reraise_ptr = self.build_func(
            "RPyReRaiseException",
            rpyexc_reraise,
            [self.lltype_of_exception_type, self.lltype_of_exception_value],
            lltype.Void,
            jitcallkind='rpyexc_raise')  # for the JIT

        self.rpyexc_fetch_exception_ptr = self.build_func(
            "RPyFetchException", rpyexc_fetch_exception, [],
            self.lltype_of_exception_value)

        self.rpyexc_restore_exception_ptr = self.build_func(
            "RPyRestoreException", self.noinline(rpyexc_restore_exception),
            [self.lltype_of_exception_value], lltype.Void)

        self.build_extra_funcs()

        self.mixlevelannotator.finish()
        self.lltype_to_classdef = translator.rtyper.lltype_to_classdef_mapping(
        )

    def noinline(self, fn):
        fn = func_with_new_name(fn, fn.__name__)
        fn._dont_inline_ = True
        return fn

    def build_func(self, name, fn, inputtypes, rettype, **kwds):
        l2a = annmodel.lltype_to_annotation
        graph = self.mixlevelannotator.getgraph(fn, map(l2a, inputtypes),
                                                l2a(rettype))
        return self.constant_func(name,
                                  inputtypes,
                                  rettype,
                                  graph,
                                  exception_policy="exc_helper",
                                  **kwds)

    def get_builtin_exception(self, Class):
        edata = self.translator.rtyper.getexceptiondata()
        rclass = self.translator.rtyper.type_system.rclass
        bk = self.translator.annotator.bookkeeper
        error_def = bk.getuniqueclassdef(Class)
        error_ll_exc = edata.get_standard_ll_exc_instance(
            self.translator.rtyper, error_def)
        error_ll_exc_type = rclass.ll_inst_type(error_ll_exc)
        return error_ll_exc_type, error_ll_exc

    def transform_completely(self):
        for graph in self.translator.graphs:
            self.create_exception_handling(graph)

    def create_exception_handling(self, graph):
        """After an exception in a direct_call (or indirect_call), that is not caught
        by an explicit
        except statement, we need to reraise the exception. So after this
        direct_call we need to test if an exception had occurred. If so, we return
        from the current graph with a special value (False/-1/-1.0/null).
        Because of the added exitswitch we need an additional block.
        """
        if hasattr(graph, 'exceptiontransformed'):
            assert self.same_obj(self.exc_data_ptr, graph.exceptiontransformed)
            return
        else:
            self.raise_analyzer.analyze_direct_call(graph)
            graph.exceptiontransformed = self.exc_data_ptr

        join_blocks(graph)
        # collect the blocks before changing them
        n_need_exc_matching_blocks = 0
        n_gen_exc_checks = 0
        #
        entrymap = mkentrymap(graph)
        if graph.exceptblock in entrymap:
            for link in entrymap[graph.exceptblock]:
                self.transform_jump_to_except_block(graph, entrymap, link)
        #
        for block in list(graph.iterblocks()):
            self.replace_fetch_restore_operations(block)
            need_exc_matching, gen_exc_checks = self.transform_block(
                graph, block)
            n_need_exc_matching_blocks += need_exc_matching
            n_gen_exc_checks += gen_exc_checks
        cleanup_graph(graph)
        return n_need_exc_matching_blocks, n_gen_exc_checks

    def replace_fetch_restore_operations(self, block):
        # the gctransformer will create these operations.  It looks as if the
        # order of transformations is important - but the gctransformer will
        # put them in a new graph, so all transformations will run again.
        for i in range(len(block.operations)):
            opname = block.operations[i].opname
            if opname == 'gc_fetch_exception':
                block.operations[i].opname = "direct_call"
                block.operations[i].args = [self.rpyexc_fetch_exception_ptr]

            elif opname == 'gc_restore_exception':
                block.operations[i].opname = "direct_call"
                block.operations[i].args.insert(
                    0, self.rpyexc_restore_exception_ptr)
            elif opname == 'get_exception_addr':  # only for lltype
                block.operations[i].opname = "direct_call"
                block.operations[i].args.insert(
                    0, self.rpyexc_get_exception_addr_ptr)
            elif opname == 'get_exc_value_addr':  # only for lltype
                block.operations[i].opname = "direct_call"
                block.operations[i].args.insert(
                    0, self.rpyexc_get_exc_value_addr_ptr)

    def transform_block(self, graph, block):
        need_exc_matching = False
        n_gen_exc_checks = 0
        if block is graph.exceptblock:
            return need_exc_matching, n_gen_exc_checks
        elif block is graph.returnblock:
            return need_exc_matching, n_gen_exc_checks
        last_operation = len(block.operations) - 1
        if block.exitswitch == c_last_exception:
            need_exc_matching = True
            last_operation -= 1
        elif (len(block.exits) == 1
              and block.exits[0].target is graph.returnblock
              and len(block.operations)
              and (block.exits[0].args[0].concretetype is lltype.Void
                   or block.exits[0].args[0] is block.operations[-1].result)
              and block.operations[-1].opname not in (
                  'malloc',  # special cases
                  'malloc_nonmovable')):
            last_operation -= 1
        lastblock = block
        for i in range(last_operation, -1, -1):
            op = block.operations[i]
            if not self.raise_analyzer.can_raise(op):
                continue

            splitlink = split_block(None, block, i + 1)
            afterblock = splitlink.target
            if lastblock is block:
                lastblock = afterblock

            self.gen_exc_check(block, graph.returnblock, afterblock)
            n_gen_exc_checks += 1
        if need_exc_matching:
            assert lastblock.exitswitch == c_last_exception
            if not self.raise_analyzer.can_raise(lastblock.operations[-1]):
                #print ("operation %s cannot raise, but has exception"
                #       " guarding in graph %s" % (lastblock.operations[-1],
                #                                  graph))
                lastblock.exitswitch = None
                lastblock.recloseblock(lastblock.exits[0])
                lastblock.exits[0].exitcase = None
            else:
                self.insert_matching(lastblock, graph)
        return need_exc_matching, n_gen_exc_checks

    def comes_from_last_exception(self, entrymap, link):
        seen = {}
        pending = [(link, link.args[1])]
        while pending:
            link, v = pending.pop()
            if (link, v) in seen:
                continue
            seen[link, v] = True
            if link.last_exc_value is not None and v is link.last_exc_value:
                return True
            block = link.prevblock
            if block is None:
                continue
            for op in block.operations[::-1]:
                if v is op.result:
                    if op.opname == 'cast_pointer':
                        v = op.args[0]
                    else:
                        break
            for link in entrymap.get(block, ()):
                for v1, v2 in zip(link.args, block.inputargs):
                    if v2 is v:
                        pending.append((link, v1))
        return False

    def transform_jump_to_except_block(self, graph, entrymap, link):
        reraise = self.comes_from_last_exception(entrymap, link)
        result = Variable()
        result.concretetype = lltype.Void
        block = Block([copyvar(None, v) for v in graph.exceptblock.inputargs])
        if reraise:
            block.operations = [
                SpaceOperation("direct_call",
                               [self.rpyexc_reraise_ptr] + block.inputargs,
                               result),
            ]
        else:
            block.operations = [
                SpaceOperation("direct_call",
                               [self.rpyexc_raise_ptr] + block.inputargs,
                               result),
                SpaceOperation('debug_record_traceback', [],
                               varoftype(lltype.Void)),
            ]
        link.target = block
        RETTYPE = graph.returnblock.inputargs[0].concretetype
        l = Link([error_constant(RETTYPE)], graph.returnblock)
        block.recloseblock(l)

    def insert_matching(self, block, graph):
        proxygraph, op = self.create_proxy_graph(block.operations[-1])
        block.operations[-1] = op
        #non-exception case
        block.exits[0].exitcase = block.exits[0].llexitcase = None
        # use the dangerous second True flag :-)
        inliner = inline.OneShotInliner(
            self.translator,
            graph,
            self.lltype_to_classdef,
            inline_guarded_calls=True,
            inline_guarded_calls_no_matter_what=True,
            raise_analyzer=self.raise_analyzer)
        inliner.inline_once(block, len(block.operations) - 1)
        #block.exits[0].exitcase = block.exits[0].llexitcase = False

    def create_proxy_graph(self, op):
        """ creates a graph which calls the original function, checks for
        raised exceptions, fetches and then raises them again. If this graph is
        inlined, the correct exception matching blocks are produced."""
        # XXX slightly annoying: construct a graph by hand
        # but better than the alternative
        result = copyvar(None, op.result)
        opargs = []
        inputargs = []
        callargs = []
        ARGTYPES = []
        for var in op.args:
            if isinstance(var, Variable):
                v = Variable()
                v.concretetype = var.concretetype
                inputargs.append(v)
                opargs.append(v)
                callargs.append(var)
                ARGTYPES.append(var.concretetype)
            else:
                opargs.append(var)
        newop = SpaceOperation(op.opname, opargs, result)
        startblock = Block(inputargs)
        startblock.operations.append(newop)
        newgraph = FunctionGraph("dummy_exc1", startblock)
        startblock.closeblock(Link([result], newgraph.returnblock))
        newgraph.returnblock.inputargs[0].concretetype = op.result.concretetype
        self.gen_exc_check(startblock, newgraph.returnblock)
        excblock = Block([])

        llops = rtyper.LowLevelOpList(None)
        var_value = self.gen_getfield('exc_value', llops)
        var_type = self.gen_getfield('exc_type', llops)
        #
        c_check1 = self.c_assertion_error_ll_exc_type
        c_check2 = self.c_n_i_error_ll_exc_type
        llops.genop('debug_catch_exception', [var_type, c_check1, c_check2])
        #
        self.gen_setfield('exc_value', self.c_null_evalue, llops)
        self.gen_setfield('exc_type', self.c_null_etype, llops)
        excblock.operations[:] = llops
        newgraph.exceptblock.inputargs[
            0].concretetype = self.lltype_of_exception_type
        newgraph.exceptblock.inputargs[
            1].concretetype = self.lltype_of_exception_value
        excblock.closeblock(Link([var_type, var_value], newgraph.exceptblock))
        startblock.exits[True].target = excblock
        startblock.exits[True].args = []
        fptr = self.constant_func("dummy_exc1", ARGTYPES,
                                  op.result.concretetype, newgraph)
        return newgraph, SpaceOperation("direct_call", [fptr] + callargs,
                                        op.result)

    def gen_exc_check(self, block, returnblock, normalafterblock=None):
        #var_exc_occured = Variable()
        #var_exc_occured.concretetype = lltype.Bool
        #block.operations.append(SpaceOperation("safe_call", [self.rpyexc_occured_ptr], var_exc_occured))

        llops = rtyper.LowLevelOpList(None)

        spaceop = block.operations[-1]
        alloc_shortcut = self.check_for_alloc_shortcut(spaceop)

        # XXX: does alloc_shortcut make sense also for ootype?
        if alloc_shortcut:
            T = spaceop.result.concretetype
            var_no_exc = self.gen_nonnull(spaceop.result, llops)
        else:
            v_exc_type = self.gen_getfield('exc_type', llops)
            var_no_exc = self.gen_isnull(v_exc_type, llops)

        block.operations.extend(llops)

        block.exitswitch = var_no_exc
        #exception occurred case
        b = Block([])
        b.operations = [
            SpaceOperation('debug_record_traceback', [],
                           varoftype(lltype.Void))
        ]
        l = Link([error_constant(returnblock.inputargs[0].concretetype)],
                 returnblock)
        b.closeblock(l)
        l = Link([], b)
        l.exitcase = l.llexitcase = False

        #non-exception case
        l0 = block.exits[0]
        l0.exitcase = l0.llexitcase = True

        block.recloseblock(l0, l)

        insert_zeroing_op = False
        if spaceop.opname == 'malloc':
            flavor = spaceop.args[1].value['flavor']
            if flavor == 'gc':
                insert_zeroing_op = True
        elif spaceop.opname == 'malloc_nonmovable':
            # xxx we cannot insert zero_gc_pointers_inside after
            # malloc_nonmovable, because it can return null.  For now
            # we simply always force the zero=True flag on
            # malloc_nonmovable.
            c_flags = spaceop.args[1]
            c_flags.value = c_flags.value.copy()
            spaceop.args[1].value['zero'] = True
        # NB. when inserting more special-cases here, keep in mind that
        # you also need to list the opnames in transform_block()
        # (see "special cases")

        if insert_zeroing_op:
            if normalafterblock is None:
                normalafterblock = insert_empty_block(None, l0)
            v_result = spaceop.result
            if v_result in l0.args:
                result_i = l0.args.index(v_result)
                v_result_after = normalafterblock.inputargs[result_i]
            else:
                v_result_after = copyvar(None, v_result)
                l0.args.append(v_result)
                normalafterblock.inputargs.append(v_result_after)
            normalafterblock.operations.insert(
                0,
                SpaceOperation('zero_gc_pointers_inside', [v_result_after],
                               varoftype(lltype.Void)))
Esempio n. 25
0
 def getannmixlevel(self):
     if self.annmixlevel is not None:
         return self.annmixlevel
     from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
     self.annmixlevel = MixLevelHelperAnnotator(self)
     return self.annmixlevel
Esempio n. 26
0
class BaseExceptionTransformer(object):

    def __init__(self, translator):
        self.translator = translator
        self.raise_analyzer = canraise.RaiseAnalyzer(translator)
        edata = translator.rtyper.getexceptiondata()
        self.lltype_of_exception_value = edata.lltype_of_exception_value
        self.lltype_of_exception_type = edata.lltype_of_exception_type
        self.mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper)
        exc_data, null_type, null_value = self.setup_excdata()

        rclass = translator.rtyper.type_system.rclass
        (runtime_error_ll_exc_type,
         runtime_error_ll_exc) = self.get_builtin_exception(RuntimeError)
        (assertion_error_ll_exc_type,
         assertion_error_ll_exc) = self.get_builtin_exception(AssertionError)
        (n_i_error_ll_exc_type,
         n_i_error_ll_exc) = self.get_builtin_exception(NotImplementedError)

        self.c_assertion_error_ll_exc_type = constant_value(
            assertion_error_ll_exc_type)
        self.c_n_i_error_ll_exc_type = constant_value(n_i_error_ll_exc_type)

        def rpyexc_occured():
            exc_type = exc_data.exc_type
            return bool(exc_type)

        def rpyexc_fetch_type():
            return exc_data.exc_type

        def rpyexc_fetch_value():
            return exc_data.exc_value

        def rpyexc_clear():
            exc_data.exc_type = null_type
            exc_data.exc_value = null_value

        def rpyexc_raise(etype, evalue):
            # When compiling in debug mode, the following ll_asserts will
            # crash the program as soon as it raises AssertionError or
            # NotImplementedError.  Useful when you are in a debugger.
            # When compiling in release mode, AssertionErrors and
            # NotImplementedErrors are raised normally, and only later
            # caught by debug_catch_exception and printed, which allows
            # us to see at least part of the traceback for them.
            ll_assert(etype != assertion_error_ll_exc_type, "AssertionError")
            ll_assert(etype != n_i_error_ll_exc_type, "NotImplementedError")
            exc_data.exc_type = etype
            exc_data.exc_value = evalue
            lloperation.llop.debug_start_traceback(lltype.Void, etype)

        def rpyexc_reraise(etype, evalue):
            exc_data.exc_type = etype
            exc_data.exc_value = evalue
            lloperation.llop.debug_reraise_traceback(lltype.Void, etype)

        def rpyexc_fetch_exception():
            evalue = rpyexc_fetch_value()
            rpyexc_clear()
            return evalue
        
        def rpyexc_restore_exception(evalue):
            if evalue:
                exc_data.exc_type = rclass.ll_inst_type(evalue)
                exc_data.exc_value = evalue

        def rpyexc_raise_runtime_error():
            rpyexc_raise(runtime_error_ll_exc_type, runtime_error_ll_exc)

        self.rpyexc_occured_ptr = self.build_func(
            "RPyExceptionOccurred",
            rpyexc_occured,
            [], lltype.Bool)

        self.rpyexc_fetch_type_ptr = self.build_func(
            "RPyFetchExceptionType",
            rpyexc_fetch_type,
            [], self.lltype_of_exception_type)

        self.rpyexc_fetch_value_ptr = self.build_func(
            "RPyFetchExceptionValue",
            rpyexc_fetch_value,
            [], self.lltype_of_exception_value)

        self.rpyexc_clear_ptr = self.build_func(
            "RPyClearException",
            rpyexc_clear,
            [], lltype.Void)

        self.rpyexc_raise_ptr = self.build_func(
            "RPyRaiseException",
            self.noinline(rpyexc_raise),
            [self.lltype_of_exception_type, self.lltype_of_exception_value],
            lltype.Void,
            jitcallkind='rpyexc_raise') # for the JIT

        self.rpyexc_reraise_ptr = self.build_func(
            "RPyReRaiseException",
            rpyexc_reraise,
            [self.lltype_of_exception_type, self.lltype_of_exception_value],
            lltype.Void,
            jitcallkind='rpyexc_raise') # for the JIT

        self.rpyexc_raise_runtime_error_ptr = self.build_func(
            "RPyRaiseRuntimeError",
            self.noinline(rpyexc_raise_runtime_error),
            [], lltype.Void)

        self.rpyexc_fetch_exception_ptr = self.build_func(
            "RPyFetchException",
            rpyexc_fetch_exception,
            [], self.lltype_of_exception_value)

        self.rpyexc_restore_exception_ptr = self.build_func(
            "RPyRestoreException",
            self.noinline(rpyexc_restore_exception),
            [self.lltype_of_exception_value], lltype.Void)

        self.build_extra_funcs()

        self.mixlevelannotator.finish()
        self.lltype_to_classdef = translator.rtyper.lltype_to_classdef_mapping()

    def noinline(self, fn):
        fn = func_with_new_name(fn, fn.__name__)
        fn._dont_inline_ = True
        return fn

    def build_func(self, name, fn, inputtypes, rettype, **kwds):
        l2a = annmodel.lltype_to_annotation
        graph = self.mixlevelannotator.getgraph(fn, map(l2a, inputtypes), l2a(rettype))
        return self.constant_func(name, inputtypes, rettype, graph, 
                                  exception_policy="exc_helper", **kwds)

    def get_builtin_exception(self, Class):
        edata = self.translator.rtyper.getexceptiondata()
        rclass = self.translator.rtyper.type_system.rclass
        bk = self.translator.annotator.bookkeeper
        error_def = bk.getuniqueclassdef(Class)
        error_ll_exc = edata.get_standard_ll_exc_instance(
            self.translator.rtyper, error_def)
        error_ll_exc_type = rclass.ll_inst_type(error_ll_exc)
        return error_ll_exc_type, error_ll_exc

    def transform_completely(self):
        for graph in self.translator.graphs:
            self.create_exception_handling(graph)

    def create_exception_handling(self, graph, always_exc_clear=False):
        """After an exception in a direct_call (or indirect_call), that is not caught
        by an explicit
        except statement, we need to reraise the exception. So after this
        direct_call we need to test if an exception had occurred. If so, we return
        from the current graph with a special value (False/-1/-1.0/null).
        Because of the added exitswitch we need an additional block.
        """
        if hasattr(graph, 'exceptiontransformed'):
            assert self.same_obj(self.exc_data_ptr, graph.exceptiontransformed)
            return
        else:
            self.raise_analyzer.analyze_direct_call(graph)
            graph.exceptiontransformed = self.exc_data_ptr

        self.always_exc_clear = always_exc_clear
        join_blocks(graph)
        # collect the blocks before changing them
        n_need_exc_matching_blocks = 0
        n_gen_exc_checks           = 0
        #
        entrymap = mkentrymap(graph)
        if graph.exceptblock in entrymap:
            for link in entrymap[graph.exceptblock]:
                self.transform_jump_to_except_block(graph, entrymap, link)
        #
        for block in list(graph.iterblocks()):
            self.replace_stack_unwind(block)
            self.replace_fetch_restore_operations(block)
            need_exc_matching, gen_exc_checks = self.transform_block(graph, block)
            n_need_exc_matching_blocks += need_exc_matching
            n_gen_exc_checks           += gen_exc_checks
        cleanup_graph(graph)
        removenoops.remove_superfluous_keep_alive(graph)
        return n_need_exc_matching_blocks, n_gen_exc_checks

    def replace_stack_unwind(self, block):
        for i in range(len(block.operations)):
            if block.operations[i].opname == 'stack_unwind':
                # if there are stack_unwind ops left,
                # the graph was not stackless-transformed
                # so we need to raise a RuntimeError in any
                # case
                block.operations[i].opname = "direct_call"
                block.operations[i].args = [self.rpyexc_raise_runtime_error_ptr]

    def replace_fetch_restore_operations(self, block):
        # the gctransformer will create these operations.  It looks as if the
        # order of transformations is important - but the gctransformer will
        # put them in a new graph, so all transformations will run again.
        for i in range(len(block.operations)):
            opname = block.operations[i].opname
            if opname == 'gc_fetch_exception':
                block.operations[i].opname = "direct_call"
                block.operations[i].args = [self.rpyexc_fetch_exception_ptr]

            elif opname == 'gc_restore_exception':
                block.operations[i].opname = "direct_call"
                block.operations[i].args.insert(0, self.rpyexc_restore_exception_ptr)
            elif opname == 'get_exception_addr':    # only for lltype
                block.operations[i].opname = "direct_call"
                block.operations[i].args.insert(0, self.rpyexc_get_exception_addr_ptr)
            elif opname == 'get_exc_value_addr':    # only for lltype
                block.operations[i].opname = "direct_call"
                block.operations[i].args.insert(0, self.rpyexc_get_exc_value_addr_ptr)

    def transform_block(self, graph, block):
        need_exc_matching = False
        n_gen_exc_checks = 0
        if block is graph.exceptblock:
            return need_exc_matching, n_gen_exc_checks
        elif block is graph.returnblock:
            return need_exc_matching, n_gen_exc_checks
        last_operation = len(block.operations) - 1
        if block.exitswitch == c_last_exception:
            need_exc_matching = True
            last_operation -= 1
        elif (len(block.exits) == 1 and 
              block.exits[0].target is graph.returnblock and
              len(block.operations) and
              (block.exits[0].args[0].concretetype is lltype.Void or
               block.exits[0].args[0] is block.operations[-1].result)):
            last_operation -= 1
        lastblock = block
        for i in range(last_operation, -1, -1):
            op = block.operations[i]
            if not self.raise_analyzer.can_raise(op):
                continue

            splitlink = split_block(None, block, i+1)
            afterblock = splitlink.target
            if lastblock is block:
                lastblock = afterblock

            self.gen_exc_check(block, graph.returnblock, afterblock)
            n_gen_exc_checks += 1
        if need_exc_matching:
            assert lastblock.exitswitch == c_last_exception
            if not self.raise_analyzer.can_raise(lastblock.operations[-1]):
                #print ("operation %s cannot raise, but has exception"
                #       " guarding in graph %s" % (lastblock.operations[-1],
                #                                  graph))
                lastblock.exitswitch = None
                lastblock.recloseblock(lastblock.exits[0])
                lastblock.exits[0].exitcase = None
            else:
                self.insert_matching(lastblock, graph)
        return need_exc_matching, n_gen_exc_checks

    def comes_from_last_exception(self, entrymap, link):
        seen = {}
        pending = [(link, link.args[1])]
        while pending:
            link, v = pending.pop()
            if (link, v) in seen:
                continue
            seen[link, v] = True
            if link.last_exc_value is not None and v is link.last_exc_value:
                return True
            block = link.prevblock
            if block is None:
                continue
            for op in block.operations[::-1]:
                if v is op.result:
                    if op.opname == 'cast_pointer':
                        v = op.args[0]
                    else:
                        break
            for link in entrymap.get(block, ()):
                for v1, v2 in zip(link.args, block.inputargs):
                    if v2 is v:
                        pending.append((link, v1))
        return False

    def transform_jump_to_except_block(self, graph, entrymap, link):
        reraise = self.comes_from_last_exception(entrymap, link)
        result = Variable()
        result.concretetype = lltype.Void
        block = Block([copyvar(None, v)
                       for v in graph.exceptblock.inputargs])
        if reraise:
            block.operations = [
                SpaceOperation("direct_call",
                               [self.rpyexc_reraise_ptr] + block.inputargs,
                               result),
                ]
        else:
            block.operations = [
                SpaceOperation("direct_call",
                               [self.rpyexc_raise_ptr] + block.inputargs,
                               result),
                SpaceOperation('debug_record_traceback', [],
                               varoftype(lltype.Void)),
                ]
        link.target = block
        RETTYPE = graph.returnblock.inputargs[0].concretetype
        l = Link([error_constant(RETTYPE)], graph.returnblock)
        block.recloseblock(l)

    def insert_matching(self, block, graph):
        proxygraph, op = self.create_proxy_graph(block.operations[-1])
        block.operations[-1] = op
        #non-exception case
        block.exits[0].exitcase = block.exits[0].llexitcase = None
        # use the dangerous second True flag :-)
        inliner = inline.OneShotInliner(
            self.translator, graph, self.lltype_to_classdef,
            inline_guarded_calls=True, inline_guarded_calls_no_matter_what=True,
            raise_analyzer=self.raise_analyzer)
        inliner.inline_once(block, len(block.operations)-1)
        #block.exits[0].exitcase = block.exits[0].llexitcase = False

    def create_proxy_graph(self, op):
        """ creates a graph which calls the original function, checks for
        raised exceptions, fetches and then raises them again. If this graph is
        inlined, the correct exception matching blocks are produced."""
        # XXX slightly annoying: construct a graph by hand
        # but better than the alternative
        result = copyvar(None, op.result)
        opargs = []
        inputargs = []
        callargs = []
        ARGTYPES = []
        for var in op.args:
            if isinstance(var, Variable):
                v = Variable()
                v.concretetype = var.concretetype
                inputargs.append(v)
                opargs.append(v)
                callargs.append(var)
                ARGTYPES.append(var.concretetype)
            else:
                opargs.append(var)
        newop = SpaceOperation(op.opname, opargs, result)
        startblock = Block(inputargs)
        startblock.operations.append(newop) 
        newgraph = FunctionGraph("dummy_exc1", startblock)
        startblock.closeblock(Link([result], newgraph.returnblock))
        newgraph.returnblock.inputargs[0].concretetype = op.result.concretetype
        self.gen_exc_check(startblock, newgraph.returnblock)
        excblock = Block([])

        llops = rtyper.LowLevelOpList(None)
        var_value = self.gen_getfield('exc_value', llops)
        var_type  = self.gen_getfield('exc_type' , llops)
        #
        c_check1 = self.c_assertion_error_ll_exc_type
        c_check2 = self.c_n_i_error_ll_exc_type
        llops.genop('debug_catch_exception', [var_type, c_check1, c_check2])
        #
        self.gen_setfield('exc_value', self.c_null_evalue, llops)
        self.gen_setfield('exc_type',  self.c_null_etype,  llops)
        excblock.operations[:] = llops
        newgraph.exceptblock.inputargs[0].concretetype = self.lltype_of_exception_type
        newgraph.exceptblock.inputargs[1].concretetype = self.lltype_of_exception_value
        excblock.closeblock(Link([var_type, var_value], newgraph.exceptblock))
        startblock.exits[True].target = excblock
        startblock.exits[True].args = []
        fptr = self.constant_func("dummy_exc1", ARGTYPES, op.result.concretetype, newgraph)
        return newgraph, SpaceOperation("direct_call", [fptr] + callargs, op.result) 

    def gen_exc_check(self, block, returnblock, normalafterblock=None):
        #var_exc_occured = Variable()
        #var_exc_occured.concretetype = lltype.Bool
        #block.operations.append(SpaceOperation("safe_call", [self.rpyexc_occured_ptr], var_exc_occured))

        llops = rtyper.LowLevelOpList(None)

        spaceop = block.operations[-1]
        alloc_shortcut = self.check_for_alloc_shortcut(spaceop)

        # XXX: does alloc_shortcut make sense also for ootype?
        if alloc_shortcut:
            T = spaceop.result.concretetype
            var_no_exc = self.gen_nonnull(spaceop.result, llops)
        else:
            v_exc_type = self.gen_getfield('exc_type', llops)
            var_no_exc = self.gen_isnull(v_exc_type, llops)

        block.operations.extend(llops)
        
        block.exitswitch = var_no_exc
        #exception occurred case
        b = Block([])
        b.operations = [SpaceOperation('debug_record_traceback', [],
                                       varoftype(lltype.Void))]
        l = Link([error_constant(returnblock.inputargs[0].concretetype)], returnblock)
        b.closeblock(l)
        l = Link([], b)
        l.exitcase = l.llexitcase = False

        #non-exception case
        l0 = block.exits[0]
        l0.exitcase = l0.llexitcase = True

        block.recloseblock(l0, l)

        insert_zeroing_op = False
        # XXX this is not right. it also inserts zero_gc_pointers_inside
        # XXX on a path that malloc_nonmovable returns null, but does not raise
        # XXX which might end up with a segfault. But we don't have such gc now
        if spaceop.opname == 'malloc' or spaceop.opname == 'malloc_nonmovable':
            flavor = spaceop.args[1].value['flavor']
            if flavor == 'gc':
                insert_zeroing_op = True

        if insert_zeroing_op:
            if normalafterblock is None:
                normalafterblock = insert_empty_block(None, l0)
            v_result = spaceop.result
            if v_result in l0.args:
                result_i = l0.args.index(v_result)
                v_result_after = normalafterblock.inputargs[result_i]
            else:
                v_result_after = copyvar(None, v_result)
                l0.args.append(v_result)
                normalafterblock.inputargs.append(v_result_after)
            normalafterblock.operations.insert(
                0, SpaceOperation('zero_gc_pointers_inside',
                                  [v_result_after],
                                  varoftype(lltype.Void)))

        if self.always_exc_clear:
            # insert code that clears the exception even in the non-exceptional
            # case...  this is a hint for the JIT, but pointless otherwise
            if normalafterblock is None:
                normalafterblock = insert_empty_block(None, l0)
            llops = rtyper.LowLevelOpList(None)
            self.gen_setfield('exc_value', self.c_null_evalue, llops)
            self.gen_setfield('exc_type',  self.c_null_etype,  llops)
            normalafterblock.operations[:0] = llops
Esempio n. 27
0
        dump_arguments = rmarshal.get_marshaller(tuple(args_s))
        load_result = rmarshal.get_loader(s_result)

    except (NotImplementedError,
            rmarshal.CannotMarshal,
            rmarshal.CannotUnmarshall), e:
        msg = 'Not Implemented: %s' % (e,)
        log.WARNING(msg)
        def execute(*args):
            not_implemented_stub(msg)

    else:
        def execute(*args):
            # marshal the function name and input arguments
            buf = []
            dump_string(buf, fnname)
            dump_arguments(buf, args)
            # send the buffer and wait for the answer
            loader = sandboxed_io(buf)
            # decode the answer
            result = load_result(loader)
            loader.check_finished()
            return result
    execute = func_with_new_name(execute, 'sandboxed_' + fnname)

    ann = MixLevelHelperAnnotator(db.translator.rtyper)
    graph = ann.getgraph(execute, args_s, s_result)
    ann.finish()
    return graph
Esempio n. 28
0
    def __init__(self, translator):
        self.translator = translator
        self.raise_analyzer = canraise.RaiseAnalyzer(translator)
        edata = translator.rtyper.getexceptiondata()
        self.lltype_of_exception_value = edata.lltype_of_exception_value
        self.lltype_of_exception_type = edata.lltype_of_exception_type
        self.mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper)
        exc_data, null_type, null_value = self.setup_excdata()

        rclass = translator.rtyper.type_system.rclass
        (runtime_error_ll_exc_type,
         runtime_error_ll_exc) = self.get_builtin_exception(RuntimeError)
        (assertion_error_ll_exc_type,
         assertion_error_ll_exc) = self.get_builtin_exception(AssertionError)
        (n_i_error_ll_exc_type,
         n_i_error_ll_exc) = self.get_builtin_exception(NotImplementedError)

        self.c_assertion_error_ll_exc_type = constant_value(
            assertion_error_ll_exc_type)
        self.c_n_i_error_ll_exc_type = constant_value(n_i_error_ll_exc_type)

        def rpyexc_occured():
            exc_type = exc_data.exc_type
            return bool(exc_type)

        def rpyexc_fetch_type():
            return exc_data.exc_type

        def rpyexc_fetch_value():
            return exc_data.exc_value

        def rpyexc_clear():
            exc_data.exc_type = null_type
            exc_data.exc_value = null_value

        def rpyexc_raise(etype, evalue):
            # When compiling in debug mode, the following ll_asserts will
            # crash the program as soon as it raises AssertionError or
            # NotImplementedError.  Useful when you are in a debugger.
            # When compiling in release mode, AssertionErrors and
            # NotImplementedErrors are raised normally, and only later
            # caught by debug_catch_exception and printed, which allows
            # us to see at least part of the traceback for them.
            ll_assert(etype != assertion_error_ll_exc_type, "AssertionError")
            ll_assert(etype != n_i_error_ll_exc_type, "NotImplementedError")
            exc_data.exc_type = etype
            exc_data.exc_value = evalue
            lloperation.llop.debug_start_traceback(lltype.Void, etype)

        def rpyexc_reraise(etype, evalue):
            exc_data.exc_type = etype
            exc_data.exc_value = evalue
            lloperation.llop.debug_reraise_traceback(lltype.Void, etype)

        def rpyexc_fetch_exception():
            evalue = rpyexc_fetch_value()
            rpyexc_clear()
            return evalue
        
        def rpyexc_restore_exception(evalue):
            if evalue:
                exc_data.exc_type = rclass.ll_inst_type(evalue)
                exc_data.exc_value = evalue

        def rpyexc_raise_runtime_error():
            rpyexc_raise(runtime_error_ll_exc_type, runtime_error_ll_exc)

        self.rpyexc_occured_ptr = self.build_func(
            "RPyExceptionOccurred",
            rpyexc_occured,
            [], lltype.Bool)

        self.rpyexc_fetch_type_ptr = self.build_func(
            "RPyFetchExceptionType",
            rpyexc_fetch_type,
            [], self.lltype_of_exception_type)

        self.rpyexc_fetch_value_ptr = self.build_func(
            "RPyFetchExceptionValue",
            rpyexc_fetch_value,
            [], self.lltype_of_exception_value)

        self.rpyexc_clear_ptr = self.build_func(
            "RPyClearException",
            rpyexc_clear,
            [], lltype.Void)

        self.rpyexc_raise_ptr = self.build_func(
            "RPyRaiseException",
            self.noinline(rpyexc_raise),
            [self.lltype_of_exception_type, self.lltype_of_exception_value],
            lltype.Void,
            jitcallkind='rpyexc_raise') # for the JIT

        self.rpyexc_reraise_ptr = self.build_func(
            "RPyReRaiseException",
            rpyexc_reraise,
            [self.lltype_of_exception_type, self.lltype_of_exception_value],
            lltype.Void,
            jitcallkind='rpyexc_raise') # for the JIT

        self.rpyexc_raise_runtime_error_ptr = self.build_func(
            "RPyRaiseRuntimeError",
            self.noinline(rpyexc_raise_runtime_error),
            [], lltype.Void)

        self.rpyexc_fetch_exception_ptr = self.build_func(
            "RPyFetchException",
            rpyexc_fetch_exception,
            [], self.lltype_of_exception_value)

        self.rpyexc_restore_exception_ptr = self.build_func(
            "RPyRestoreException",
            self.noinline(rpyexc_restore_exception),
            [self.lltype_of_exception_value], lltype.Void)

        self.build_extra_funcs()

        self.mixlevelannotator.finish()
        self.lltype_to_classdef = translator.rtyper.lltype_to_classdef_mapping()
Esempio n. 29
0
class BaseExceptionTransformer(object):

    def __init__(self, translator):
        self.translator = translator
        self.raise_analyzer = canraise.RaiseAnalyzer(translator)
        edata = translator.rtyper.getexceptiondata()
        self.lltype_of_exception_value = edata.lltype_of_exception_value
        self.lltype_of_exception_type = edata.lltype_of_exception_type
        self.mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper)
        exc_data, null_type, null_value = self.setup_excdata()

        rclass = translator.rtyper.type_system.rclass
        runtime_error_def = translator.annotator.bookkeeper.getuniqueclassdef(RuntimeError)
        runtime_error_ll_exc = edata.get_standard_ll_exc_instance(translator.rtyper, runtime_error_def)
        runtime_error_ll_exc_type = rclass.ll_inst_type(runtime_error_ll_exc)

        def rpyexc_occured():
            exc_type = exc_data.exc_type
            return bool(exc_type)

        def rpyexc_fetch_type():
            return exc_data.exc_type

        def rpyexc_fetch_value():
            return exc_data.exc_value

        def rpyexc_clear():
            exc_data.exc_type = null_type
            exc_data.exc_value = null_value

        def rpyexc_raise(etype, evalue):
            # assert(!RPyExceptionOccurred());
            exc_data.exc_type = etype
            exc_data.exc_value = evalue

        def rpyexc_fetch_exception():
            evalue = rpyexc_fetch_value()
            rpyexc_clear()
            return evalue
        
        def rpyexc_restore_exception(evalue):
            if evalue:
                rpyexc_raise(rclass.ll_inst_type(evalue), evalue)

        def rpyexc_raise_runtime_error():
            rpyexc_raise(runtime_error_ll_exc_type, runtime_error_ll_exc)

        self.rpyexc_occured_ptr = self.build_func(
            "RPyExceptionOccurred",
            rpyexc_occured,
            [], lltype.Bool)

        self.rpyexc_fetch_type_ptr = self.build_func(
            "RPyFetchExceptionType",
            rpyexc_fetch_type,
            [], self.lltype_of_exception_type)

        self.rpyexc_fetch_value_ptr = self.build_func(
            "RPyFetchExceptionValue",
            rpyexc_fetch_value,
            [], self.lltype_of_exception_value)

        self.rpyexc_clear_ptr = self.build_func(
            "RPyClearException",
            rpyexc_clear,
            [], lltype.Void)

        self.rpyexc_raise_ptr = self.build_func(
            "RPyRaiseException",
            rpyexc_raise,
            [self.lltype_of_exception_type, self.lltype_of_exception_value],
            lltype.Void,
            jitcallkind='rpyexc_raise') # for the JIT

        self.rpyexc_raise_runtime_error_ptr = self.build_func(
            "RPyRaiseRuntimeError",
            rpyexc_raise_runtime_error,
            [], lltype.Void)

        self.rpyexc_fetch_exception_ptr = self.build_func(
            "RPyFetchException",
            rpyexc_fetch_exception,
            [], self.lltype_of_exception_value)

        self.rpyexc_restore_exception_ptr = self.build_func(
            "RPyRestoreException",
            rpyexc_restore_exception,
            [self.lltype_of_exception_value], lltype.Void)

        self.mixlevelannotator.finish()
        self.lltype_to_classdef = translator.rtyper.lltype_to_classdef_mapping()

    def build_func(self, name, fn, inputtypes, rettype, **kwds):
        l2a = annmodel.lltype_to_annotation
        graph = self.mixlevelannotator.getgraph(fn, map(l2a, inputtypes), l2a(rettype))
        return self.constant_func(name, inputtypes, rettype, graph, 
                                  exception_policy="exc_helper", **kwds)

    def transform_completely(self):
        for graph in self.translator.graphs:
            self.create_exception_handling(graph)

    def create_exception_handling(self, graph, always_exc_clear=False):
        """After an exception in a direct_call (or indirect_call), that is not caught
        by an explicit
        except statement, we need to reraise the exception. So after this
        direct_call we need to test if an exception had occurred. If so, we return
        from the current graph with a special value (False/-1/-1.0/null).
        Because of the added exitswitch we need an additional block.
        """
        if hasattr(graph, 'exceptiontransformed'):
            assert self.same_obj(self.exc_data_ptr, graph.exceptiontransformed)
            return
        else:
            self.raise_analyzer.analyze_direct_call(graph)
            graph.exceptiontransformed = self.exc_data_ptr

        self.always_exc_clear = always_exc_clear
        join_blocks(graph)
        # collect the blocks before changing them
        n_need_exc_matching_blocks = 0
        n_gen_exc_checks           = 0
        for block in list(graph.iterblocks()):
            self.replace_stack_unwind(block)
            self.replace_fetch_restore_operations(block)
            need_exc_matching, gen_exc_checks = self.transform_block(graph, block)
            n_need_exc_matching_blocks += need_exc_matching
            n_gen_exc_checks           += gen_exc_checks
        self.transform_except_block(graph, graph.exceptblock)
        cleanup_graph(graph)
        removenoops.remove_superfluous_keep_alive(graph)
        return n_need_exc_matching_blocks, n_gen_exc_checks

    def replace_stack_unwind(self, block):
        for i in range(len(block.operations)):
            if block.operations[i].opname == 'stack_unwind':
                # if there are stack_unwind ops left,
                # the graph was not stackless-transformed
                # so we need to raise a RuntimeError in any
                # case
                block.operations[i].opname = "direct_call"
                block.operations[i].args = [self.rpyexc_raise_runtime_error_ptr]

    def replace_fetch_restore_operations(self, block):
        # the gctransformer will create these operations.  It looks as if the
        # order of transformations is important - but the gctransformer will
        # put them in a new graph, so all transformations will run again.
        for i in range(len(block.operations)):
            if block.operations[i].opname == 'gc_fetch_exception':
                block.operations[i].opname = "direct_call"
                block.operations[i].args = [self.rpyexc_fetch_exception_ptr]

            if block.operations[i].opname == 'gc_restore_exception':
                block.operations[i].opname = "direct_call"
                block.operations[i].args.insert(0, self.rpyexc_restore_exception_ptr)

    def transform_block(self, graph, block):
        need_exc_matching = False
        n_gen_exc_checks = 0
        if block is graph.exceptblock:
            return need_exc_matching, n_gen_exc_checks
        elif block is graph.returnblock:
            return need_exc_matching, n_gen_exc_checks
        last_operation = len(block.operations) - 1
        if block.exitswitch == c_last_exception:
            need_exc_matching = True
            last_operation -= 1
        elif (len(block.exits) == 1 and 
              block.exits[0].target is graph.returnblock and
              len(block.operations) and
              (block.exits[0].args[0].concretetype is lltype.Void or
               block.exits[0].args[0] is block.operations[-1].result)):
            last_operation -= 1
        lastblock = block
        for i in range(last_operation, -1, -1):
            op = block.operations[i]
            if not self.raise_analyzer.can_raise(op):
                continue

            splitlink = split_block(None, block, i+1)
            afterblock = splitlink.target
            if lastblock is block:
                lastblock = afterblock

            self.gen_exc_check(block, graph.returnblock, afterblock)
            n_gen_exc_checks += 1
        if need_exc_matching:
            assert lastblock.exitswitch == c_last_exception
            if not self.raise_analyzer.can_raise(lastblock.operations[-1]):
                #print ("operation %s cannot raise, but has exception"
                #       " guarding in graph %s" % (lastblock.operations[-1],
                #                                  graph))
                lastblock.exitswitch = None
                lastblock.recloseblock(lastblock.exits[0])
                lastblock.exits[0].exitcase = None
            else:
                self.insert_matching(lastblock, graph)
        return need_exc_matching, n_gen_exc_checks

    def transform_except_block(self, graph, block):
        # attach an except block -- let's hope that nobody uses it
        graph.exceptblock = Block([Variable('etype'),   # exception class
                                   Variable('evalue')])  # exception value
        graph.exceptblock.operations = ()
        graph.exceptblock.closeblock()
        
        result = Variable()
        result.concretetype = lltype.Void
        block.operations = [SpaceOperation(
           "direct_call", [self.rpyexc_raise_ptr] + block.inputargs, result)]
        l = Link([error_constant(graph.returnblock.inputargs[0].concretetype)], graph.returnblock)
        block.recloseblock(l)

    def insert_matching(self, block, graph):
        proxygraph, op = self.create_proxy_graph(block.operations[-1])
        block.operations[-1] = op
        #non-exception case
        block.exits[0].exitcase = block.exits[0].llexitcase = None
        # use the dangerous second True flag :-)
        inliner = inline.OneShotInliner(
            self.translator, graph, self.lltype_to_classdef,
            inline_guarded_calls=True, inline_guarded_calls_no_matter_what=True,
            raise_analyzer=self.raise_analyzer)
        inliner.inline_once(block, len(block.operations)-1)
        #block.exits[0].exitcase = block.exits[0].llexitcase = False

    def create_proxy_graph(self, op):
        """ creates a graph which calls the original function, checks for
        raised exceptions, fetches and then raises them again. If this graph is
        inlined, the correct exception matching blocks are produced."""
        # XXX slightly annoying: construct a graph by hand
        # but better than the alternative
        result = copyvar(None, op.result)
        opargs = []
        inputargs = []
        callargs = []
        ARGTYPES = []
        for var in op.args:
            if isinstance(var, Variable):
                v = Variable()
                v.concretetype = var.concretetype
                inputargs.append(v)
                opargs.append(v)
                callargs.append(var)
                ARGTYPES.append(var.concretetype)
            else:
                opargs.append(var)
        newop = SpaceOperation(op.opname, opargs, result)
        startblock = Block(inputargs)
        startblock.operations.append(newop) 
        newgraph = FunctionGraph("dummy_exc1", startblock)
        startblock.closeblock(Link([result], newgraph.returnblock))
        newgraph.returnblock.inputargs[0].concretetype = op.result.concretetype
        self.gen_exc_check(startblock, newgraph.returnblock)
        excblock = Block([])

        llops = rtyper.LowLevelOpList(None)
        var_value = self.gen_getfield('exc_value', llops)
        var_type  = self.gen_getfield('exc_type' , llops)
        self.gen_setfield('exc_value', self.c_null_evalue, llops)
        self.gen_setfield('exc_type',  self.c_null_etype,  llops)
        excblock.operations[:] = llops
        newgraph.exceptblock.inputargs[0].concretetype = self.lltype_of_exception_type
        newgraph.exceptblock.inputargs[1].concretetype = self.lltype_of_exception_value
        excblock.closeblock(Link([var_type, var_value], newgraph.exceptblock))
        startblock.exits[True].target = excblock
        startblock.exits[True].args = []
        fptr = self.constant_func("dummy_exc1", ARGTYPES, op.result.concretetype, newgraph)
        return newgraph, SpaceOperation("direct_call", [fptr] + callargs, op.result) 

    def gen_exc_check(self, block, returnblock, normalafterblock=None):
        #var_exc_occured = Variable()
        #var_exc_occured.concretetype = lltype.Bool
        #block.operations.append(SpaceOperation("safe_call", [self.rpyexc_occured_ptr], var_exc_occured))

        llops = rtyper.LowLevelOpList(None)

        spaceop = block.operations[-1]
        alloc_shortcut = self.check_for_alloc_shortcut(spaceop)

        # XXX: does alloc_shortcut make sense also for ootype?
        if alloc_shortcut:
            T = spaceop.result.concretetype
            var_no_exc = self.gen_nonnull(spaceop.result, llops)
        else:
            v_exc_type = self.gen_getfield('exc_type', llops)
            var_no_exc = self.gen_isnull(v_exc_type, llops)

        block.operations.extend(llops)
        
        block.exitswitch = var_no_exc
        #exception occurred case
        l = Link([error_constant(returnblock.inputargs[0].concretetype)], returnblock)
        l.exitcase = l.llexitcase = False

        #non-exception case
        l0 = block.exits[0]
        l0.exitcase = l0.llexitcase = True

        block.recloseblock(l0, l)

        insert_zeroing_op = False
        if spaceop.opname == 'malloc':
            flavor = spaceop.args[1].value['flavor']
            if flavor == 'gc':
                insert_zeroing_op = True

        if insert_zeroing_op:
            if normalafterblock is None:
                normalafterblock = insert_empty_block(None, l0)
            v_result = spaceop.result
            if v_result in l0.args:
                result_i = l0.args.index(v_result)
                v_result_after = normalafterblock.inputargs[result_i]
            else:
                v_result_after = copyvar(None, v_result)
                l0.args.append(v_result)
                normalafterblock.inputargs.append(v_result_after)
            normalafterblock.operations.insert(
                0, SpaceOperation('zero_gc_pointers_inside',
                                  [v_result_after],
                                  varoftype(lltype.Void)))

        if self.always_exc_clear:
            # insert code that clears the exception even in the non-exceptional
            # case...  this is a hint for the JIT, but pointless otherwise
            if normalafterblock is None:
                normalafterblock = insert_empty_block(None, l0)
            llops = rtyper.LowLevelOpList(None)
            self.gen_setfield('exc_value', self.c_null_evalue, llops)
            self.gen_setfield('exc_type',  self.c_null_etype,  llops)
            normalafterblock.operations[:0] = llops
Esempio n. 30
0
    def __init__(self, translator):
        self.translator = translator
        self.raise_analyzer = canraise.RaiseAnalyzer(translator)
        edata = translator.rtyper.getexceptiondata()
        self.lltype_of_exception_value = edata.lltype_of_exception_value
        self.lltype_of_exception_type = edata.lltype_of_exception_type
        self.mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper)
        exc_data, null_type, null_value = self.setup_excdata()

        rclass = translator.rtyper.type_system.rclass
        runtime_error_def = translator.annotator.bookkeeper.getuniqueclassdef(RuntimeError)
        runtime_error_ll_exc = edata.get_standard_ll_exc_instance(translator.rtyper, runtime_error_def)
        runtime_error_ll_exc_type = rclass.ll_inst_type(runtime_error_ll_exc)

        def rpyexc_occured():
            exc_type = exc_data.exc_type
            return bool(exc_type)

        def rpyexc_fetch_type():
            return exc_data.exc_type

        def rpyexc_fetch_value():
            return exc_data.exc_value

        def rpyexc_clear():
            exc_data.exc_type = null_type
            exc_data.exc_value = null_value

        def rpyexc_raise(etype, evalue):
            # assert(!RPyExceptionOccurred());
            exc_data.exc_type = etype
            exc_data.exc_value = evalue

        def rpyexc_fetch_exception():
            evalue = rpyexc_fetch_value()
            rpyexc_clear()
            return evalue
        
        def rpyexc_restore_exception(evalue):
            if evalue:
                rpyexc_raise(rclass.ll_inst_type(evalue), evalue)

        def rpyexc_raise_runtime_error():
            rpyexc_raise(runtime_error_ll_exc_type, runtime_error_ll_exc)

        self.rpyexc_occured_ptr = self.build_func(
            "RPyExceptionOccurred",
            rpyexc_occured,
            [], lltype.Bool)

        self.rpyexc_fetch_type_ptr = self.build_func(
            "RPyFetchExceptionType",
            rpyexc_fetch_type,
            [], self.lltype_of_exception_type)

        self.rpyexc_fetch_value_ptr = self.build_func(
            "RPyFetchExceptionValue",
            rpyexc_fetch_value,
            [], self.lltype_of_exception_value)

        self.rpyexc_clear_ptr = self.build_func(
            "RPyClearException",
            rpyexc_clear,
            [], lltype.Void)

        self.rpyexc_raise_ptr = self.build_func(
            "RPyRaiseException",
            rpyexc_raise,
            [self.lltype_of_exception_type, self.lltype_of_exception_value],
            lltype.Void,
            jitcallkind='rpyexc_raise') # for the JIT

        self.rpyexc_raise_runtime_error_ptr = self.build_func(
            "RPyRaiseRuntimeError",
            rpyexc_raise_runtime_error,
            [], lltype.Void)

        self.rpyexc_fetch_exception_ptr = self.build_func(
            "RPyFetchException",
            rpyexc_fetch_exception,
            [], self.lltype_of_exception_value)

        self.rpyexc_restore_exception_ptr = self.build_func(
            "RPyRestoreException",
            rpyexc_restore_exception,
            [self.lltype_of_exception_value], lltype.Void)

        self.mixlevelannotator.finish()
        self.lltype_to_classdef = translator.rtyper.lltype_to_classdef_mapping()
Esempio n. 31
0
class BaseExceptionTransformer(object):
    def __init__(self, translator):
        self.translator = translator
        self.raise_analyzer = canraise.RaiseAnalyzer(translator)
        edata = translator.rtyper.getexceptiondata()
        self.lltype_of_exception_value = edata.lltype_of_exception_value
        self.lltype_of_exception_type = edata.lltype_of_exception_type
        self.mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper)
        exc_data, null_type, null_value = self.setup_excdata()

        rclass = translator.rtyper.type_system.rclass
        (runtime_error_ll_exc_type,
         runtime_error_ll_exc) = self.get_builtin_exception(RuntimeError)
        (assertion_error_ll_exc_type,
         assertion_error_ll_exc) = self.get_builtin_exception(AssertionError)
        (n_i_error_ll_exc_type,
         n_i_error_ll_exc) = self.get_builtin_exception(NotImplementedError)

        def rpyexc_occured():
            exc_type = exc_data.exc_type
            return bool(exc_type)

        def rpyexc_fetch_type():
            return exc_data.exc_type

        def rpyexc_fetch_value():
            return exc_data.exc_value

        def rpyexc_clear():
            exc_data.exc_type = null_type
            exc_data.exc_value = null_value

        def rpyexc_raise(etype, evalue):
            # assert(!RPyExceptionOccurred());
            ll_assert(etype != assertion_error_ll_exc_type, "AssertionError!")
            ll_assert(etype != n_i_error_ll_exc_type, "NotImplementedError!")
            exc_data.exc_type = etype
            exc_data.exc_value = evalue

        def rpyexc_fetch_exception():
            evalue = rpyexc_fetch_value()
            rpyexc_clear()
            return evalue

        def rpyexc_restore_exception(evalue):
            if evalue:
                rpyexc_raise(rclass.ll_inst_type(evalue), evalue)

        def rpyexc_raise_runtime_error():
            rpyexc_raise(runtime_error_ll_exc_type, runtime_error_ll_exc)

        self.rpyexc_occured_ptr = self.build_func("RPyExceptionOccurred",
                                                  rpyexc_occured, [],
                                                  lltype.Bool)

        self.rpyexc_fetch_type_ptr = self.build_func(
            "RPyFetchExceptionType", rpyexc_fetch_type, [],
            self.lltype_of_exception_type)

        self.rpyexc_fetch_value_ptr = self.build_func(
            "RPyFetchExceptionValue", rpyexc_fetch_value, [],
            self.lltype_of_exception_value)

        self.rpyexc_clear_ptr = self.build_func("RPyClearException",
                                                rpyexc_clear, [], lltype.Void)

        self.rpyexc_raise_ptr = self.build_func(
            "RPyRaiseException",
            rpyexc_raise,
            [self.lltype_of_exception_type, self.lltype_of_exception_value],
            lltype.Void,
            jitcallkind='rpyexc_raise')  # for the JIT

        self.rpyexc_raise_runtime_error_ptr = self.build_func(
            "RPyRaiseRuntimeError", rpyexc_raise_runtime_error, [],
            lltype.Void)

        self.rpyexc_fetch_exception_ptr = self.build_func(
            "RPyFetchException", rpyexc_fetch_exception, [],
            self.lltype_of_exception_value)

        self.rpyexc_restore_exception_ptr = self.build_func(
            "RPyRestoreException", rpyexc_restore_exception,
            [self.lltype_of_exception_value], lltype.Void)

        self.build_extra_funcs()

        self.mixlevelannotator.finish()
        self.lltype_to_classdef = translator.rtyper.lltype_to_classdef_mapping(
        )

    def build_func(self, name, fn, inputtypes, rettype, **kwds):
        l2a = annmodel.lltype_to_annotation
        graph = self.mixlevelannotator.getgraph(fn, map(l2a, inputtypes),
                                                l2a(rettype))
        return self.constant_func(name,
                                  inputtypes,
                                  rettype,
                                  graph,
                                  exception_policy="exc_helper",
                                  **kwds)

    def get_builtin_exception(self, Class):
        edata = self.translator.rtyper.getexceptiondata()
        rclass = self.translator.rtyper.type_system.rclass
        bk = self.translator.annotator.bookkeeper
        error_def = bk.getuniqueclassdef(Class)
        error_ll_exc = edata.get_standard_ll_exc_instance(
            self.translator.rtyper, error_def)
        error_ll_exc_type = rclass.ll_inst_type(error_ll_exc)
        return error_ll_exc_type, error_ll_exc

    def transform_completely(self):
        for graph in self.translator.graphs:
            self.create_exception_handling(graph)

    def create_exception_handling(self, graph, always_exc_clear=False):
        """After an exception in a direct_call (or indirect_call), that is not caught
        by an explicit
        except statement, we need to reraise the exception. So after this
        direct_call we need to test if an exception had occurred. If so, we return
        from the current graph with a special value (False/-1/-1.0/null).
        Because of the added exitswitch we need an additional block.
        """
        if hasattr(graph, 'exceptiontransformed'):
            assert self.same_obj(self.exc_data_ptr, graph.exceptiontransformed)
            return
        else:
            self.raise_analyzer.analyze_direct_call(graph)
            graph.exceptiontransformed = self.exc_data_ptr

        self.always_exc_clear = always_exc_clear
        join_blocks(graph)
        # collect the blocks before changing them
        n_need_exc_matching_blocks = 0
        n_gen_exc_checks = 0
        for block in list(graph.iterblocks()):
            self.replace_stack_unwind(block)
            self.replace_fetch_restore_operations(block)
            need_exc_matching, gen_exc_checks = self.transform_block(
                graph, block)
            n_need_exc_matching_blocks += need_exc_matching
            n_gen_exc_checks += gen_exc_checks
        self.transform_except_block(graph, graph.exceptblock)
        cleanup_graph(graph)
        removenoops.remove_superfluous_keep_alive(graph)
        return n_need_exc_matching_blocks, n_gen_exc_checks

    def replace_stack_unwind(self, block):
        for i in range(len(block.operations)):
            if block.operations[i].opname == 'stack_unwind':
                # if there are stack_unwind ops left,
                # the graph was not stackless-transformed
                # so we need to raise a RuntimeError in any
                # case
                block.operations[i].opname = "direct_call"
                block.operations[i].args = [
                    self.rpyexc_raise_runtime_error_ptr
                ]

    def replace_fetch_restore_operations(self, block):
        # the gctransformer will create these operations.  It looks as if the
        # order of transformations is important - but the gctransformer will
        # put them in a new graph, so all transformations will run again.
        for i in range(len(block.operations)):
            opname = block.operations[i].opname
            if opname == 'gc_fetch_exception':
                block.operations[i].opname = "direct_call"
                block.operations[i].args = [self.rpyexc_fetch_exception_ptr]

            elif opname == 'gc_restore_exception':
                block.operations[i].opname = "direct_call"
                block.operations[i].args.insert(
                    0, self.rpyexc_restore_exception_ptr)
            elif opname == 'get_exception_addr':  # only for lltype
                block.operations[i].opname = "direct_call"
                block.operations[i].args.insert(
                    0, self.rpyexc_get_exception_addr_ptr)
            elif opname == 'get_exc_value_addr':  # only for lltype
                block.operations[i].opname = "direct_call"
                block.operations[i].args.insert(
                    0, self.rpyexc_get_exc_value_addr_ptr)

    def transform_block(self, graph, block):
        need_exc_matching = False
        n_gen_exc_checks = 0
        if block is graph.exceptblock:
            return need_exc_matching, n_gen_exc_checks
        elif block is graph.returnblock:
            return need_exc_matching, n_gen_exc_checks
        last_operation = len(block.operations) - 1
        if block.exitswitch == c_last_exception:
            need_exc_matching = True
            last_operation -= 1
        elif (len(block.exits) == 1
              and block.exits[0].target is graph.returnblock
              and len(block.operations)
              and (block.exits[0].args[0].concretetype is lltype.Void
                   or block.exits[0].args[0] is block.operations[-1].result)):
            last_operation -= 1
        lastblock = block
        for i in range(last_operation, -1, -1):
            op = block.operations[i]
            if not self.raise_analyzer.can_raise(op):
                continue

            splitlink = split_block(None, block, i + 1)
            afterblock = splitlink.target
            if lastblock is block:
                lastblock = afterblock

            self.gen_exc_check(block, graph.returnblock, afterblock)
            n_gen_exc_checks += 1
        if need_exc_matching:
            assert lastblock.exitswitch == c_last_exception
            if not self.raise_analyzer.can_raise(lastblock.operations[-1]):
                #print ("operation %s cannot raise, but has exception"
                #       " guarding in graph %s" % (lastblock.operations[-1],
                #                                  graph))
                lastblock.exitswitch = None
                lastblock.recloseblock(lastblock.exits[0])
                lastblock.exits[0].exitcase = None
            else:
                self.insert_matching(lastblock, graph)
        return need_exc_matching, n_gen_exc_checks

    def transform_except_block(self, graph, block):
        # attach an except block -- let's hope that nobody uses it
        graph.exceptblock = Block([
            Variable('etype'),  # exception class
            Variable('evalue')
        ])  # exception value
        graph.exceptblock.operations = ()
        graph.exceptblock.closeblock()

        result = Variable()
        result.concretetype = lltype.Void
        block.operations = [
            SpaceOperation("direct_call",
                           [self.rpyexc_raise_ptr] + block.inputargs, result)
        ]
        l = Link([error_constant(graph.returnblock.inputargs[0].concretetype)],
                 graph.returnblock)
        block.recloseblock(l)

    def insert_matching(self, block, graph):
        proxygraph, op = self.create_proxy_graph(block.operations[-1])
        block.operations[-1] = op
        #non-exception case
        block.exits[0].exitcase = block.exits[0].llexitcase = None
        # use the dangerous second True flag :-)
        inliner = inline.OneShotInliner(
            self.translator,
            graph,
            self.lltype_to_classdef,
            inline_guarded_calls=True,
            inline_guarded_calls_no_matter_what=True,
            raise_analyzer=self.raise_analyzer)
        inliner.inline_once(block, len(block.operations) - 1)
        #block.exits[0].exitcase = block.exits[0].llexitcase = False

    def create_proxy_graph(self, op):
        """ creates a graph which calls the original function, checks for
        raised exceptions, fetches and then raises them again. If this graph is
        inlined, the correct exception matching blocks are produced."""
        # XXX slightly annoying: construct a graph by hand
        # but better than the alternative
        result = copyvar(None, op.result)
        opargs = []
        inputargs = []
        callargs = []
        ARGTYPES = []
        for var in op.args:
            if isinstance(var, Variable):
                v = Variable()
                v.concretetype = var.concretetype
                inputargs.append(v)
                opargs.append(v)
                callargs.append(var)
                ARGTYPES.append(var.concretetype)
            else:
                opargs.append(var)
        newop = SpaceOperation(op.opname, opargs, result)
        startblock = Block(inputargs)
        startblock.operations.append(newop)
        newgraph = FunctionGraph("dummy_exc1", startblock)
        startblock.closeblock(Link([result], newgraph.returnblock))
        newgraph.returnblock.inputargs[0].concretetype = op.result.concretetype
        self.gen_exc_check(startblock, newgraph.returnblock)
        excblock = Block([])

        llops = rtyper.LowLevelOpList(None)
        var_value = self.gen_getfield('exc_value', llops)
        var_type = self.gen_getfield('exc_type', llops)
        self.gen_setfield('exc_value', self.c_null_evalue, llops)
        self.gen_setfield('exc_type', self.c_null_etype, llops)
        excblock.operations[:] = llops
        newgraph.exceptblock.inputargs[
            0].concretetype = self.lltype_of_exception_type
        newgraph.exceptblock.inputargs[
            1].concretetype = self.lltype_of_exception_value
        excblock.closeblock(Link([var_type, var_value], newgraph.exceptblock))
        startblock.exits[True].target = excblock
        startblock.exits[True].args = []
        fptr = self.constant_func("dummy_exc1", ARGTYPES,
                                  op.result.concretetype, newgraph)
        return newgraph, SpaceOperation("direct_call", [fptr] + callargs,
                                        op.result)

    def gen_exc_check(self, block, returnblock, normalafterblock=None):
        #var_exc_occured = Variable()
        #var_exc_occured.concretetype = lltype.Bool
        #block.operations.append(SpaceOperation("safe_call", [self.rpyexc_occured_ptr], var_exc_occured))

        llops = rtyper.LowLevelOpList(None)

        spaceop = block.operations[-1]
        alloc_shortcut = self.check_for_alloc_shortcut(spaceop)

        # XXX: does alloc_shortcut make sense also for ootype?
        if alloc_shortcut:
            T = spaceop.result.concretetype
            var_no_exc = self.gen_nonnull(spaceop.result, llops)
        else:
            v_exc_type = self.gen_getfield('exc_type', llops)
            var_no_exc = self.gen_isnull(v_exc_type, llops)

        block.operations.extend(llops)

        block.exitswitch = var_no_exc
        #exception occurred case
        l = Link([error_constant(returnblock.inputargs[0].concretetype)],
                 returnblock)
        l.exitcase = l.llexitcase = False

        #non-exception case
        l0 = block.exits[0]
        l0.exitcase = l0.llexitcase = True

        block.recloseblock(l0, l)

        insert_zeroing_op = False
        # XXX this is not right. it also inserts zero_gc_pointers_inside
        # XXX on a path that malloc_nonmovable returns null, but does not raise
        # XXX which might end up with a segfault. But we don't have such gc now
        if spaceop.opname == 'malloc' or spaceop.opname == 'malloc_nonmovable':
            flavor = spaceop.args[1].value['flavor']
            if flavor == 'gc':
                insert_zeroing_op = True

        if insert_zeroing_op:
            if normalafterblock is None:
                normalafterblock = insert_empty_block(None, l0)
            v_result = spaceop.result
            if v_result in l0.args:
                result_i = l0.args.index(v_result)
                v_result_after = normalafterblock.inputargs[result_i]
            else:
                v_result_after = copyvar(None, v_result)
                l0.args.append(v_result)
                normalafterblock.inputargs.append(v_result_after)
            normalafterblock.operations.insert(
                0,
                SpaceOperation('zero_gc_pointers_inside', [v_result_after],
                               varoftype(lltype.Void)))

        if self.always_exc_clear:
            # insert code that clears the exception even in the non-exceptional
            # case...  this is a hint for the JIT, but pointless otherwise
            if normalafterblock is None:
                normalafterblock = insert_empty_block(None, l0)
            llops = rtyper.LowLevelOpList(None)
            self.gen_setfield('exc_value', self.c_null_evalue, llops)
            self.gen_setfield('exc_type', self.c_null_etype, llops)
            normalafterblock.operations[:0] = llops
Esempio n. 32
0
    def __init__(self, translator):
        self.translator = translator
        self.raise_analyzer = canraise.RaiseAnalyzer(translator)
        edata = translator.rtyper.getexceptiondata()
        self.lltype_of_exception_value = edata.lltype_of_exception_value
        self.lltype_of_exception_type = edata.lltype_of_exception_type
        self.mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper)
        exc_data, null_type, null_value = self.setup_excdata()

        rclass = translator.rtyper.type_system.rclass
        (runtime_error_ll_exc_type,
         runtime_error_ll_exc) = self.get_builtin_exception(RuntimeError)
        (assertion_error_ll_exc_type,
         assertion_error_ll_exc) = self.get_builtin_exception(AssertionError)
        (n_i_error_ll_exc_type,
         n_i_error_ll_exc) = self.get_builtin_exception(NotImplementedError)

        def rpyexc_occured():
            exc_type = exc_data.exc_type
            return bool(exc_type)

        def rpyexc_fetch_type():
            return exc_data.exc_type

        def rpyexc_fetch_value():
            return exc_data.exc_value

        def rpyexc_clear():
            exc_data.exc_type = null_type
            exc_data.exc_value = null_value

        def rpyexc_raise(etype, evalue):
            # assert(!RPyExceptionOccurred());
            ll_assert(etype != assertion_error_ll_exc_type, "AssertionError!")
            ll_assert(etype != n_i_error_ll_exc_type, "NotImplementedError!")
            exc_data.exc_type = etype
            exc_data.exc_value = evalue

        def rpyexc_fetch_exception():
            evalue = rpyexc_fetch_value()
            rpyexc_clear()
            return evalue

        def rpyexc_restore_exception(evalue):
            if evalue:
                rpyexc_raise(rclass.ll_inst_type(evalue), evalue)

        def rpyexc_raise_runtime_error():
            rpyexc_raise(runtime_error_ll_exc_type, runtime_error_ll_exc)

        self.rpyexc_occured_ptr = self.build_func("RPyExceptionOccurred",
                                                  rpyexc_occured, [],
                                                  lltype.Bool)

        self.rpyexc_fetch_type_ptr = self.build_func(
            "RPyFetchExceptionType", rpyexc_fetch_type, [],
            self.lltype_of_exception_type)

        self.rpyexc_fetch_value_ptr = self.build_func(
            "RPyFetchExceptionValue", rpyexc_fetch_value, [],
            self.lltype_of_exception_value)

        self.rpyexc_clear_ptr = self.build_func("RPyClearException",
                                                rpyexc_clear, [], lltype.Void)

        self.rpyexc_raise_ptr = self.build_func(
            "RPyRaiseException",
            rpyexc_raise,
            [self.lltype_of_exception_type, self.lltype_of_exception_value],
            lltype.Void,
            jitcallkind='rpyexc_raise')  # for the JIT

        self.rpyexc_raise_runtime_error_ptr = self.build_func(
            "RPyRaiseRuntimeError", rpyexc_raise_runtime_error, [],
            lltype.Void)

        self.rpyexc_fetch_exception_ptr = self.build_func(
            "RPyFetchException", rpyexc_fetch_exception, [],
            self.lltype_of_exception_value)

        self.rpyexc_restore_exception_ptr = self.build_func(
            "RPyRestoreException", rpyexc_restore_exception,
            [self.lltype_of_exception_value], lltype.Void)

        self.build_extra_funcs()

        self.mixlevelannotator.finish()
        self.lltype_to_classdef = translator.rtyper.lltype_to_classdef_mapping(
        )
Esempio n. 33
0
    def __init__(self, translator):
        self.translator = translator
        self.raise_analyzer = canraise.RaiseAnalyzer(translator)
        edata = translator.rtyper.getexceptiondata()
        self.lltype_of_exception_value = edata.lltype_of_exception_value
        self.lltype_of_exception_type = edata.lltype_of_exception_type
        mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper)
        l2a = annmodel.lltype_to_annotation

        EXCDATA = lltype.Struct('ExcData',
            ('exc_type',  self.lltype_of_exception_type),
            ('exc_value', self.lltype_of_exception_value))
        self.EXCDATA = EXCDATA

        exc_data = lltype.malloc(EXCDATA, immortal=True)
        null_type = lltype.nullptr(self.lltype_of_exception_type.TO)
        null_value = lltype.nullptr(self.lltype_of_exception_value.TO)
        
        def rpyexc_occured():
            exc_type = exc_data.exc_type
            return bool(exc_type)

        # XXX tmp HACK for genllvm
        # llvm is strongly typed between bools and ints, which means we have no way of
        # calling rpyexc_occured() from c code with lltype.Bool
        def _rpyexc_occured():
            exc_type = exc_data.exc_type
            return bool(exc_type)

        def rpyexc_fetch_type():
            return exc_data.exc_type

        def rpyexc_fetch_value():
            return exc_data.exc_value

        def rpyexc_clear():
            exc_data.exc_type = null_type
            exc_data.exc_value = null_value

        def rpyexc_raise(etype, evalue):
            # assert(!RPyExceptionOccurred());
            exc_data.exc_type = etype
            exc_data.exc_value = evalue
        
        RPYEXC_OCCURED_TYPE = lltype.FuncType([], lltype.Bool)
        rpyexc_occured_graph = mixlevelannotator.getgraph(
            rpyexc_occured, [], l2a(lltype.Bool))
        self.rpyexc_occured_ptr = Constant(lltype.functionptr(
            RPYEXC_OCCURED_TYPE, "RPyExceptionOccurred",
            graph=rpyexc_occured_graph,
            exception_policy="exc_helper"),
            lltype.Ptr(RPYEXC_OCCURED_TYPE))

        # XXX tmp HACK for genllvm
        _RPYEXC_OCCURED_TYPE = lltype.FuncType([], lltype.Signed)
        _rpyexc_occured_graph = mixlevelannotator.getgraph(
            _rpyexc_occured, [], l2a(lltype.Signed))
        self._rpyexc_occured_ptr = Constant(lltype.functionptr(
            _RPYEXC_OCCURED_TYPE, "_RPyExceptionOccurred",
            graph=_rpyexc_occured_graph,
            exception_policy="exc_helper"),
            lltype.Ptr(_RPYEXC_OCCURED_TYPE))
        
        RPYEXC_FETCH_TYPE_TYPE = lltype.FuncType([], self.lltype_of_exception_type)
        rpyexc_fetch_type_graph = mixlevelannotator.getgraph(
            rpyexc_fetch_type, [],
            l2a(self.lltype_of_exception_type))
        self.rpyexc_fetch_type_ptr = Constant(lltype.functionptr(
            RPYEXC_FETCH_TYPE_TYPE, "RPyFetchExceptionType",
            graph=rpyexc_fetch_type_graph,
            exception_policy="exc_helper"),
            lltype.Ptr(RPYEXC_FETCH_TYPE_TYPE))
        
        RPYEXC_FETCH_VALUE_TYPE = lltype.FuncType([], self.lltype_of_exception_value)
        rpyexc_fetch_value_graph = mixlevelannotator.getgraph(
            rpyexc_fetch_value, [],
            l2a(self.lltype_of_exception_value))
        self.rpyexc_fetch_value_ptr = Constant(lltype.functionptr(
            RPYEXC_FETCH_VALUE_TYPE, "RPyFetchExceptionValue",
            graph=rpyexc_fetch_value_graph,
            exception_policy="exc_helper"),
            lltype.Ptr(RPYEXC_FETCH_VALUE_TYPE))

        RPYEXC_CLEAR = lltype.FuncType([], lltype.Void)
        rpyexc_clear_graph = mixlevelannotator.getgraph(
            rpyexc_clear, [], l2a(lltype.Void))
        self.rpyexc_clear_ptr = Constant(lltype.functionptr(
            RPYEXC_CLEAR, "RPyClearException",
            graph=rpyexc_clear_graph,
            exception_policy="exc_helper"),
            lltype.Ptr(RPYEXC_CLEAR))

        RPYEXC_RAISE = lltype.FuncType([self.lltype_of_exception_type,
                                        self.lltype_of_exception_value],
                                        lltype.Void)
        rpyexc_raise_graph = mixlevelannotator.getgraph(
            rpyexc_raise, [l2a(self.lltype_of_exception_type),
                           l2a(self.lltype_of_exception_value)],
            l2a(lltype.Void))
        self.rpyexc_raise_ptr = Constant(lltype.functionptr(
            RPYEXC_RAISE, "RPyRaiseException",
            graph=rpyexc_raise_graph,
            exception_policy="exc_helper",
            jitcallkind='rpyexc_raise',   # for the JIT
            ),
            lltype.Ptr(RPYEXC_RAISE))

        mixlevelannotator.finish()

        self.exc_data_ptr = exc_data
        self.cexcdata = Constant(exc_data, lltype.Ptr(EXCDATA))
        
        self.lltype_to_classdef = translator.rtyper.lltype_to_classdef_mapping()
        p = lltype.nullptr(self.lltype_of_exception_type.TO)
        self.c_null_etype = Constant(p, self.lltype_of_exception_type)
        p = lltype.nullptr(self.lltype_of_exception_value.TO)
        self.c_null_evalue = Constant(p, self.lltype_of_exception_value)
Esempio n. 34
0
        argc = get_argc()
        argv = get_argv()
        args = [rffi.charp2str(argv[i]) for i in range(argc)]

        result = 1
        try:
            result = entrypoint(args)
        except Exception, exc:
            os.write(
                2, 'DEBUG: An uncaught exception was raised in entrypoint: ' +
                str(exc) + '\n')

        return result

    entrypoint._annenforceargs_ = [s_list_of_strings]
    mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper)
    res = annmodel.lltype_to_annotation(lltype.Signed)
    graph = mixlevelannotator.getgraph(new_entrypoint, [], res)
    mixlevelannotator.finish()
    mixlevelannotator.backend_optimize()

    return new_entrypoint


class GenLLVM(object):
    # see create_codewriter() below
    function_count = {}

    def __init__(self, translator, standalone):

        # reset counters
Esempio n. 35
0
    def __init__(self, translator):
        self.translator = translator
        self.raise_analyzer = canraise.RaiseAnalyzer(translator)
        edata = translator.rtyper.getexceptiondata()
        self.lltype_of_exception_value = edata.lltype_of_exception_value
        self.lltype_of_exception_type = edata.lltype_of_exception_type
        self.mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper)
        exc_data, null_type, null_value = self.setup_excdata()

        rclass = translator.rtyper.type_system.rclass
        (assertion_error_ll_exc_type,
         assertion_error_ll_exc) = self.get_builtin_exception(AssertionError)
        (n_i_error_ll_exc_type,
         n_i_error_ll_exc) = self.get_builtin_exception(NotImplementedError)

        self.c_assertion_error_ll_exc_type = constant_value(
            assertion_error_ll_exc_type)
        self.c_n_i_error_ll_exc_type = constant_value(n_i_error_ll_exc_type)

        def rpyexc_occured():
            exc_type = exc_data.exc_type
            return bool(exc_type)

        def rpyexc_fetch_type():
            return exc_data.exc_type

        def rpyexc_fetch_value():
            return exc_data.exc_value

        def rpyexc_clear():
            exc_data.exc_type = null_type
            exc_data.exc_value = null_value

        def rpyexc_raise(etype, evalue):
            # When compiling in debug mode, the following ll_asserts will
            # crash the program as soon as it raises AssertionError or
            # NotImplementedError.  Useful when you are in a debugger.
            # When compiling in release mode, AssertionErrors and
            # NotImplementedErrors are raised normally, and only later
            # caught by debug_catch_exception and printed, which allows
            # us to see at least part of the traceback for them.
            ll_assert(etype != assertion_error_ll_exc_type, "AssertionError")
            ll_assert(etype != n_i_error_ll_exc_type, "NotImplementedError")
            exc_data.exc_type = etype
            exc_data.exc_value = evalue
            lloperation.llop.debug_start_traceback(lltype.Void, etype)

        def rpyexc_reraise(etype, evalue):
            exc_data.exc_type = etype
            exc_data.exc_value = evalue
            lloperation.llop.debug_reraise_traceback(lltype.Void, etype)

        def rpyexc_fetch_exception():
            evalue = rpyexc_fetch_value()
            rpyexc_clear()
            return evalue

        def rpyexc_restore_exception(evalue):
            if evalue:
                exc_data.exc_type = rclass.ll_inst_type(evalue)
                exc_data.exc_value = evalue

        self.rpyexc_occured_ptr = self.build_func("RPyExceptionOccurred",
                                                  rpyexc_occured, [],
                                                  lltype.Bool)

        self.rpyexc_fetch_type_ptr = self.build_func(
            "RPyFetchExceptionType", rpyexc_fetch_type, [],
            self.lltype_of_exception_type)

        self.rpyexc_fetch_value_ptr = self.build_func(
            "RPyFetchExceptionValue", rpyexc_fetch_value, [],
            self.lltype_of_exception_value)

        self.rpyexc_clear_ptr = self.build_func("RPyClearException",
                                                rpyexc_clear, [], lltype.Void)

        self.rpyexc_raise_ptr = self.build_func(
            "RPyRaiseException",
            self.noinline(rpyexc_raise),
            [self.lltype_of_exception_type, self.lltype_of_exception_value],
            lltype.Void,
            jitcallkind='rpyexc_raise')  # for the JIT

        self.rpyexc_reraise_ptr = self.build_func(
            "RPyReRaiseException",
            rpyexc_reraise,
            [self.lltype_of_exception_type, self.lltype_of_exception_value],
            lltype.Void,
            jitcallkind='rpyexc_raise')  # for the JIT

        self.rpyexc_fetch_exception_ptr = self.build_func(
            "RPyFetchException", rpyexc_fetch_exception, [],
            self.lltype_of_exception_value)

        self.rpyexc_restore_exception_ptr = self.build_func(
            "RPyRestoreException", self.noinline(rpyexc_restore_exception),
            [self.lltype_of_exception_value], lltype.Void)

        self.build_extra_funcs()

        self.mixlevelannotator.finish()
        self.lltype_to_classdef = translator.rtyper.lltype_to_classdef_mapping(
        )