Beispiel #1
0
    def rewrite_can_enter_jit(self, jd, can_enter_jits):
        FUNCPTR = jd._PTR_JIT_ENTER_FUNCTYPE
        jit_enter_fnptr = self.helper_func(FUNCPTR, jd._maybe_enter_jit_fn)

        if len(can_enter_jits) == 0:
            # see test_warmspot.test_no_loop_at_all
            operations = jd.portal_graph.startblock.operations
            op1 = operations[0]
            assert (op1.opname == 'jit_marker' and
                    op1.args[0].value == 'jit_merge_point')
            op0 = SpaceOperation(
                'jit_marker',
                [Constant('can_enter_jit', lltype.Void)] + op1.args[1:],
                None)
            operations.insert(0, op0)
            can_enter_jits = [(jd.portal_graph, jd.portal_graph.startblock, 0)]

        for graph, block, index in can_enter_jits:
            if graph is jd._jit_merge_point_in:
                continue

            op = block.operations[index]
            greens_v, reds_v = support.decode_hp_hint_args(op)
            args_v = greens_v + reds_v

            vlist = [Constant(jit_enter_fnptr, FUNCPTR)] + args_v

            v_result = Variable()
            v_result.concretetype = lltype.Void
            newop = SpaceOperation('direct_call', vlist, v_result)
            block.operations[index] = newop
Beispiel #2
0
    def rewrite_can_enter_jit(self, jd, can_enter_jits):
        FUNCPTR = jd._PTR_JIT_ENTER_FUNCTYPE
        jit_enter_fnptr = self.helper_func(FUNCPTR, jd._maybe_enter_jit_fn)

        if len(can_enter_jits) == 0:
            # see test_warmspot.test_no_loop_at_all
            operations = jd.portal_graph.startblock.operations
            op1 = operations[0]
            assert (op1.opname == 'jit_marker'
                    and op1.args[0].value == 'jit_merge_point')
            op0 = SpaceOperation('jit_marker',
                                 [Constant('can_enter_jit', lltype.Void)] +
                                 op1.args[1:], None)
            operations.insert(0, op0)
            can_enter_jits = [(jd.portal_graph, jd.portal_graph.startblock, 0)]

        for graph, block, index in can_enter_jits:
            if graph is jd._jit_merge_point_in:
                continue

            op = block.operations[index]
            greens_v, reds_v = support.decode_hp_hint_args(op)
            args_v = greens_v + reds_v

            vlist = [Constant(jit_enter_fnptr, FUNCPTR)] + args_v

            v_result = Variable()
            v_result.concretetype = lltype.Void
            newop = SpaceOperation('direct_call', vlist, v_result)
            block.operations[index] = newop
Beispiel #3
0
 def make_args_specification(self, jd):
     graph = jd._jit_merge_point_in
     _, _, op = locate_jit_merge_point(graph)
     greens_v, reds_v = support.decode_hp_hint_args(op)
     ALLARGS = [v.concretetype for v in (greens_v + reds_v)]
     jd._green_args_spec = [v.concretetype for v in greens_v]
     jd.red_args_types = [history.getkind(v.concretetype) for v in reds_v]
     jd.num_green_args = len(jd._green_args_spec)
     jd.num_red_args = len(jd.red_args_types)
     RESTYPE = graph.getreturnvar().concretetype
     (jd._JIT_ENTER_FUNCTYPE,
      jd._PTR_JIT_ENTER_FUNCTYPE) = self.cpu.ts.get_FuncType(ALLARGS, lltype.Void)
     (jd._PORTAL_FUNCTYPE,
      jd._PTR_PORTAL_FUNCTYPE) = self.cpu.ts.get_FuncType(ALLARGS, RESTYPE)
     #
     if jd.result_type == 'v':
         ASMRESTYPE = lltype.Void
     elif jd.result_type == history.INT:
         ASMRESTYPE = lltype.Signed
     elif jd.result_type == history.REF:
         ASMRESTYPE = llmemory.GCREF
     elif jd.result_type == history.FLOAT:
         ASMRESTYPE = lltype.Float
     else:
         assert False
     (_, jd._PTR_ASSEMBLER_HELPER_FUNCTYPE) = self.cpu.ts.get_FuncType(
         [llmemory.GCREF, llmemory.GCREF], ASMRESTYPE)
Beispiel #4
0
 def make_args_specification(self, jd):
     graph = jd._jit_merge_point_in
     _, _, op = locate_jit_merge_point(graph)
     greens_v, reds_v = support.decode_hp_hint_args(op)
     ALLARGS = [v.concretetype for v in (greens_v + reds_v)]
     jd._green_args_spec = [v.concretetype for v in greens_v]
     jd.red_args_types = [history.getkind(v.concretetype) for v in reds_v]
     jd.num_green_args = len(jd._green_args_spec)
     jd.num_red_args = len(jd.red_args_types)
     RESTYPE = graph.getreturnvar().concretetype
     (jd._JIT_ENTER_FUNCTYPE,
      jd._PTR_JIT_ENTER_FUNCTYPE) = self.cpu.ts.get_FuncType(
          ALLARGS, lltype.Void)
     (jd._PORTAL_FUNCTYPE,
      jd._PTR_PORTAL_FUNCTYPE) = self.cpu.ts.get_FuncType(ALLARGS, RESTYPE)
     #
     if jd.result_type == 'v':
         ASMRESTYPE = lltype.Void
     elif jd.result_type == history.INT:
         ASMRESTYPE = lltype.Signed
     elif jd.result_type == history.REF:
         ASMRESTYPE = llmemory.GCREF
     elif jd.result_type == history.FLOAT:
         ASMRESTYPE = lltype.Float
     else:
         assert False
     (_, jd._PTR_ASSEMBLER_HELPER_FUNCTYPE) = self.cpu.ts.get_FuncType(
         [llmemory.GCREF, llmemory.GCREF], ASMRESTYPE)
Beispiel #5
0
                bhcaller._setup_return_value_i(result)
            elif result_kind == 'ref':
                bhcaller._setup_return_value_r(result)
            elif result_kind == 'float':
                bhcaller._setup_return_value_f(result)
            else:
                assert False
        jd.handle_jitexc_from_bh = handle_jitexception_from_blackhole

        # ____________________________________________________________
        # Now mutate origportalgraph to end with a call to portal_runner_ptr
        #
        origblock, origindex, op = locate_jit_merge_point(origportalgraph)
        assert op.opname == 'jit_marker'
        assert op.args[0].value == 'jit_merge_point'
        greens_v, reds_v = support.decode_hp_hint_args(op)
        vlist = [Constant(jd.portal_runner_ptr, jd._PTR_PORTAL_FUNCTYPE)]
        vlist += greens_v
        vlist += reds_v
        v_result = Variable()
        v_result.concretetype = PORTALFUNC.RESULT
        newop = SpaceOperation('direct_call', vlist, v_result)
        del origblock.operations[origindex:]
        origblock.operations.append(newop)
        origblock.exitswitch = None
        origblock.recloseblock(Link([v_result], origportalgraph.returnblock))
        # the origportal now can raise (even if it did not raise before),
        # which means that we cannot inline it anywhere any more, but that's
        # fine since any forced inlining has been done before
        #
        checkgraph(origportalgraph)
Beispiel #6
0
            elif result_kind == 'ref':
                bhcaller._setup_return_value_r(result)
            elif result_kind == 'float':
                bhcaller._setup_return_value_f(result)
            else:
                assert False

        jd.handle_jitexc_from_bh = handle_jitexception_from_blackhole

        # ____________________________________________________________
        # Now mutate origportalgraph to end with a call to portal_runner_ptr
        #
        origblock, origindex, op = locate_jit_merge_point(origportalgraph)
        assert op.opname == 'jit_marker'
        assert op.args[0].value == 'jit_merge_point'
        greens_v, reds_v = support.decode_hp_hint_args(op)
        vlist = [Constant(jd.portal_runner_ptr, jd._PTR_PORTAL_FUNCTYPE)]
        vlist += greens_v
        vlist += reds_v
        v_result = Variable()
        v_result.concretetype = PORTALFUNC.RESULT
        newop = SpaceOperation('direct_call', vlist, v_result)
        del origblock.operations[origindex:]
        origblock.operations.append(newop)
        origblock.exitswitch = None
        origblock.recloseblock(Link([v_result], origportalgraph.returnblock))
        # the origportal now can raise (even if it did not raise before),
        # which means that we cannot inline it anywhere any more, but that's
        # fine since any forced inlining has been done before
        #
        checkgraph(origportalgraph)
Beispiel #7
0
    def rewrite_jit_merge_point(self, jd, policy):
        #
        # Mutate the original portal graph from this:
        #
        #       def original_portal(..):
        #           stuff
        #           while 1:
        #               jit_merge_point(*args)
        #               more stuff
        #
        # to that:
        #
        #       def original_portal(..):
        #           stuff
        #           return portal_runner(*args)
        #
        #       def portal_runner(*args):
        #           while 1:
        #               try:
        #                   return portal(*args)
        #               except JitException, e:
        #                   return handle_jitexception(e)
        #
        #       def portal(*args):
        #           while 1:
        #               more stuff
        #
        origportalgraph = jd._jit_merge_point_in
        portalgraph = jd.portal_graph
        PORTALFUNC = jd._PORTAL_FUNCTYPE

        # ____________________________________________________________
        # Prepare the portal_runner() helper
        #
        from rpython.jit.metainterp.warmstate import specialize_value
        from rpython.jit.metainterp.warmstate import unspecialize_value
        portal_ptr = self.cpu.ts.functionptr(PORTALFUNC,
                                             'portal',
                                             graph=portalgraph)
        jd._portal_ptr = portal_ptr
        #
        portalfunc_ARGS = []
        nums = {}
        for i, ARG in enumerate(PORTALFUNC.ARGS):
            kind = history.getkind(ARG)
            assert kind != 'void'
            if i < len(jd.jitdriver.greens):
                color = 'green'
            else:
                color = 'red'
            attrname = '%s_%s' % (color, kind)
            count = nums.get(attrname, 0)
            nums[attrname] = count + 1
            portalfunc_ARGS.append((ARG, attrname, count))
        portalfunc_ARGS = unrolling_iterable(portalfunc_ARGS)
        #
        rtyper = self.translator.rtyper
        RESULT = PORTALFUNC.RESULT
        result_kind = history.getkind(RESULT)
        assert result_kind.startswith(jd.result_type)
        ts = self.cpu.ts
        state = jd.warmstate
        maybe_compile_and_run = jd._maybe_compile_and_run_fn
        EnterJitAssembler = jd._EnterJitAssembler

        def ll_portal_runner(*args):
            try:
                # maybe enter from the function's start.
                maybe_compile_and_run(state.increment_function_threshold,
                                      *args)
                #
                # then run the normal portal function, i.e. the
                # interpreter's main loop.  It might enter the jit
                # via maybe_enter_jit(), which typically ends with
                # handle_fail() being called, which raises on the
                # following exceptions --- catched here, because we
                # want to interrupt the whole interpreter loop.
                return support.maybe_on_top_of_llinterp(rtyper,
                                                        portal_ptr)(*args)
            except jitexc.JitException as e:
                result = handle_jitexception(e)
                if result_kind != 'void':
                    result = specialize_value(RESULT, result)
                return result

        def handle_jitexception(e):
            # XXX there are too many exceptions all around...
            while True:
                if isinstance(e, EnterJitAssembler):
                    try:
                        return e.execute()
                    except jitexc.JitException as e:
                        continue
                #
                if isinstance(e, jitexc.ContinueRunningNormally):
                    args = ()
                    for ARGTYPE, attrname, count in portalfunc_ARGS:
                        x = getattr(e, attrname)[count]
                        x = specialize_value(ARGTYPE, x)
                        args = args + (x, )
                    try:
                        result = support.maybe_on_top_of_llinterp(
                            rtyper, portal_ptr)(*args)
                    except jitexc.JitException as e:
                        continue
                    if result_kind != 'void':
                        result = unspecialize_value(result)
                    return result
                #
                if result_kind == 'void':
                    if isinstance(e, jitexc.DoneWithThisFrameVoid):
                        return None
                if result_kind == 'int':
                    if isinstance(e, jitexc.DoneWithThisFrameInt):
                        return e.result
                if result_kind == 'ref':
                    if isinstance(e, jitexc.DoneWithThisFrameRef):
                        return e.result
                if result_kind == 'float':
                    if isinstance(e, jitexc.DoneWithThisFrameFloat):
                        return e.result
                #
                if isinstance(e, jitexc.ExitFrameWithExceptionRef):
                    value = ts.cast_to_baseclass(e.value)
                    if not we_are_translated():
                        raise LLException(ts.get_typeptr(value), value)
                    else:
                        value = cast_base_ptr_to_instance(Exception, value)
                        assert value is not None
                        raise value
                #
                raise AssertionError("all cases should have been handled")

        jd._ll_portal_runner = ll_portal_runner  # for debugging
        jd.portal_runner_ptr = self.helper_func(jd._PTR_PORTAL_FUNCTYPE,
                                                ll_portal_runner)
        jd.portal_runner_adr = llmemory.cast_ptr_to_adr(jd.portal_runner_ptr)
        jd.portal_calldescr = self.cpu.calldescrof(
            jd._PTR_PORTAL_FUNCTYPE.TO, jd._PTR_PORTAL_FUNCTYPE.TO.ARGS,
            jd._PTR_PORTAL_FUNCTYPE.TO.RESULT, EffectInfo.MOST_GENERAL)

        vinfo = jd.virtualizable_info

        def assembler_call_helper(deadframe, virtualizableref):
            fail_descr = self.cpu.get_latest_descr(deadframe)
            try:
                fail_descr.handle_fail(deadframe, self.metainterp_sd, jd)
            except jitexc.JitException as e:
                return handle_jitexception(e)
            else:
                assert 0, "should have raised"

        jd._assembler_call_helper = assembler_call_helper  # for debugging
        jd._assembler_helper_ptr = self.helper_func(
            jd._PTR_ASSEMBLER_HELPER_FUNCTYPE, assembler_call_helper)
        jd.assembler_helper_adr = llmemory.cast_ptr_to_adr(
            jd._assembler_helper_ptr)
        if vinfo is not None:
            jd.vable_token_descr = vinfo.vable_token_descr

        def handle_jitexception_from_blackhole(bhcaller, e):
            result = handle_jitexception(e)
            if result_kind == 'void':
                pass
            elif result_kind == 'int':
                bhcaller._setup_return_value_i(result)
            elif result_kind == 'ref':
                bhcaller._setup_return_value_r(result)
            elif result_kind == 'float':
                bhcaller._setup_return_value_f(result)
            else:
                assert False

        jd.handle_jitexc_from_bh = handle_jitexception_from_blackhole

        # ____________________________________________________________
        # Now mutate origportalgraph to end with a call to portal_runner_ptr
        #
        origblock, origindex, op = locate_jit_merge_point(origportalgraph)
        assert op.opname == 'jit_marker'
        assert op.args[0].value == 'jit_merge_point'
        greens_v, reds_v = support.decode_hp_hint_args(op)
        vlist = [Constant(jd.portal_runner_ptr, jd._PTR_PORTAL_FUNCTYPE)]
        vlist += greens_v
        vlist += reds_v
        v_result = Variable()
        v_result.concretetype = PORTALFUNC.RESULT
        newop = SpaceOperation('direct_call', vlist, v_result)
        del origblock.operations[origindex:]
        origblock.operations.append(newop)
        origblock.exitswitch = None
        origblock.recloseblock(Link([v_result], origportalgraph.returnblock))
        # the origportal now can raise (even if it did not raise before),
        # which means that we cannot inline it anywhere any more, but that's
        # fine since any forced inlining has been done before
        #
        checkgraph(origportalgraph)
Beispiel #8
0
    def rewrite_jit_merge_point(self, jd, policy):
        #
        # Mutate the original portal graph from this:
        #
        #       def original_portal(..):
        #           stuff
        #           while 1:
        #               jit_merge_point(*args)
        #               more stuff
        #
        # to that:
        #
        #       def original_portal(..):
        #           stuff
        #           return portal_runner(*args)
        #
        #       def portal_runner(*args):
        #           while 1:
        #               try:
        #                   return portal(*args)
        #               except JitException, e:
        #                   return handle_jitexception(e)
        #
        #       def portal(*args):
        #           while 1:
        #               more stuff
        #
        origportalgraph = jd._jit_merge_point_in
        portalgraph = jd.portal_graph
        PORTALFUNC = jd._PORTAL_FUNCTYPE

        # ____________________________________________________________
        # Prepare the portal_runner() helper
        #
        from rpython.jit.metainterp.warmstate import specialize_value
        from rpython.jit.metainterp.warmstate import unspecialize_value
        portal_ptr = self.cpu.ts.functionptr(PORTALFUNC, 'portal',
                                         graph=portalgraph)
        jd._portal_ptr = portal_ptr
        #
        portalfunc_ARGS = []
        nums = {}
        for i, ARG in enumerate(PORTALFUNC.ARGS):
            kind = history.getkind(ARG)
            assert kind != 'void'
            if i < len(jd.jitdriver.greens):
                color = 'green'
            else:
                color = 'red'
            attrname = '%s_%s' % (color, kind)
            count = nums.get(attrname, 0)
            nums[attrname] = count + 1
            portalfunc_ARGS.append((ARG, attrname, count))
        portalfunc_ARGS = unrolling_iterable(portalfunc_ARGS)
        #
        rtyper = self.translator.rtyper
        RESULT = PORTALFUNC.RESULT
        result_kind = history.getkind(RESULT)
        assert result_kind.startswith(jd.result_type)
        ts = self.cpu.ts
        state = jd.warmstate
        maybe_compile_and_run = jd._maybe_compile_and_run_fn
        EnterJitAssembler = jd._EnterJitAssembler

        def ll_portal_runner(*args):
            try:
                # maybe enter from the function's start.
                maybe_compile_and_run(
                    state.increment_function_threshold, *args)
                #
                # then run the normal portal function, i.e. the
                # interpreter's main loop.  It might enter the jit
                # via maybe_enter_jit(), which typically ends with
                # handle_fail() being called, which raises on the
                # following exceptions --- catched here, because we
                # want to interrupt the whole interpreter loop.
                return support.maybe_on_top_of_llinterp(rtyper,
                                                  portal_ptr)(*args)
            except jitexc.JitException as e:
                result = handle_jitexception(e)
                if result_kind != 'void':
                    result = specialize_value(RESULT, result)
                return result

        def handle_jitexception(e):
            # XXX there are too many exceptions all around...
            while True:
                if isinstance(e, EnterJitAssembler):
                    try:
                        return e.execute()
                    except jitexc.JitException as e:
                        continue
                #
                if isinstance(e, jitexc.ContinueRunningNormally):
                    args = ()
                    for ARGTYPE, attrname, count in portalfunc_ARGS:
                        x = getattr(e, attrname)[count]
                        x = specialize_value(ARGTYPE, x)
                        args = args + (x,)
                    try:
                        result = support.maybe_on_top_of_llinterp(rtyper,
                                                            portal_ptr)(*args)
                    except jitexc.JitException as e:
                        continue
                    if result_kind != 'void':
                        result = unspecialize_value(result)
                    return result
                #
                if result_kind == 'void':
                    if isinstance(e, jitexc.DoneWithThisFrameVoid):
                        return None
                if result_kind == 'int':
                    if isinstance(e, jitexc.DoneWithThisFrameInt):
                        return e.result
                if result_kind == 'ref':
                    if isinstance(e, jitexc.DoneWithThisFrameRef):
                        return e.result
                if result_kind == 'float':
                    if isinstance(e, jitexc.DoneWithThisFrameFloat):
                        return e.result
                #
                if isinstance(e, jitexc.ExitFrameWithExceptionRef):
                    value = ts.cast_to_baseclass(e.value)
                    if not we_are_translated():
                        raise LLException(ts.get_typeptr(value), value)
                    else:
                        value = cast_base_ptr_to_instance(Exception, value)
                        assert value is not None
                        raise value
                #
                raise AssertionError("all cases should have been handled")

        jd._ll_portal_runner = ll_portal_runner # for debugging
        jd.portal_runner_ptr = self.helper_func(jd._PTR_PORTAL_FUNCTYPE,
                                                ll_portal_runner)
        jd.portal_runner_adr = llmemory.cast_ptr_to_adr(jd.portal_runner_ptr)
        jd.portal_calldescr = self.cpu.calldescrof(
            jd._PTR_PORTAL_FUNCTYPE.TO,
            jd._PTR_PORTAL_FUNCTYPE.TO.ARGS,
            jd._PTR_PORTAL_FUNCTYPE.TO.RESULT,
            EffectInfo.MOST_GENERAL)

        vinfo = jd.virtualizable_info

        def assembler_call_helper(deadframe, virtualizableref):
            fail_descr = self.cpu.get_latest_descr(deadframe)
            try:
                fail_descr.handle_fail(deadframe, self.metainterp_sd, jd)
            except jitexc.JitException as e:
                return handle_jitexception(e)
            else:
                assert 0, "should have raised"

        jd._assembler_call_helper = assembler_call_helper # for debugging
        jd._assembler_helper_ptr = self.helper_func(
            jd._PTR_ASSEMBLER_HELPER_FUNCTYPE,
            assembler_call_helper)
        jd.assembler_helper_adr = llmemory.cast_ptr_to_adr(
            jd._assembler_helper_ptr)
        if vinfo is not None:
            jd.vable_token_descr = vinfo.vable_token_descr

        def handle_jitexception_from_blackhole(bhcaller, e):
            result = handle_jitexception(e)
            if result_kind == 'void':
                pass
            elif result_kind == 'int':
                bhcaller._setup_return_value_i(result)
            elif result_kind == 'ref':
                bhcaller._setup_return_value_r(result)
            elif result_kind == 'float':
                bhcaller._setup_return_value_f(result)
            else:
                assert False
        jd.handle_jitexc_from_bh = handle_jitexception_from_blackhole

        # ____________________________________________________________
        # Now mutate origportalgraph to end with a call to portal_runner_ptr
        #
        origblock, origindex, op = locate_jit_merge_point(origportalgraph)
        assert op.opname == 'jit_marker'
        assert op.args[0].value == 'jit_merge_point'
        greens_v, reds_v = support.decode_hp_hint_args(op)
        vlist = [Constant(jd.portal_runner_ptr, jd._PTR_PORTAL_FUNCTYPE)]
        vlist += greens_v
        vlist += reds_v
        v_result = Variable()
        v_result.concretetype = PORTALFUNC.RESULT
        newop = SpaceOperation('direct_call', vlist, v_result)
        del origblock.operations[origindex:]
        origblock.operations.append(newop)
        origblock.exitswitch = None
        origblock.recloseblock(Link([v_result], origportalgraph.returnblock))
        # the origportal now can raise (even if it did not raise before),
        # which means that we cannot inline it anywhere any more, but that's
        # fine since any forced inlining has been done before
        #
        checkgraph(origportalgraph)