Beispiel #1
0
def test_graphs_from_no_target():
    cc = CallControl()
    F = lltype.FuncType([], lltype.Signed)
    v = varoftype(lltype.Signed)
    op = SpaceOperation("indirect_call", [varoftype(lltype.Ptr(F)), Constant(None, lltype.Void)], v)
    lst = cc.graphs_from(op, {}.__contains__)
    assert lst is None
Beispiel #2
0
def test_get_jitcode():
    from pypy.jit.codewriter.test.test_flatten import FakeCPU

    class FakeRTyper:
        class annotator:
            translator = None

        class type_system:
            name = "lltypesystem"

            @staticmethod
            def getcallable(graph):
                F = lltype.FuncType([], lltype.Signed)
                return lltype.functionptr(F, "bar")

    #
    cc = CallControl(FakeCPU(FakeRTyper()))

    class somegraph:
        name = "foo"

    jitcode = cc.get_jitcode(somegraph)
    assert jitcode is cc.get_jitcode(somegraph)  # caching
    assert jitcode.name == "foo"
    pending = list(cc.enum_pending_graphs())
    assert pending == [(somegraph, jitcode)]
Beispiel #3
0
def test_find_all_graphs():
    def g(x):
        return x + 2
    def f(x):
        return g(x) + 1
    rtyper = support.annotate(f, [7])
    jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0])
    cc = CallControl(jitdrivers_sd=[jitdriver_sd])
    res = cc.find_all_graphs(FakePolicy())
    funcs = set([graph.func for graph in res])
    assert funcs == set([f, g])
Beispiel #4
0
def test_graphs_from_direct_call():
    cc = CallControl()
    F = lltype.FuncType([], lltype.Signed)
    f = lltype.functionptr(F, 'f', graph='fgraph')
    v = varoftype(lltype.Signed)
    op = SpaceOperation('direct_call', [Constant(f, lltype.Ptr(F))], v)
    #
    lst = cc.graphs_from(op, {}.__contains__)
    assert lst is None     # residual call
    #
    lst = cc.graphs_from(op, {'fgraph': True}.__contains__)
    assert lst == ['fgraph']     # normal call
Beispiel #5
0
def test_find_all_graphs_without_g():
    def g(x):
        return x + 2
    def f(x):
        return g(x) + 1
    rtyper = support.annotate(f, [7])
    jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0])
    cc = CallControl(jitdrivers_sd=[jitdriver_sd])
    class CustomFakePolicy:
        def look_inside_graph(self, graph):
            assert graph.name == 'g'
            return False
    res = cc.find_all_graphs(CustomFakePolicy())
    funcs = [graph.func for graph in res]
    assert funcs == [f]
Beispiel #6
0
def test_graphs_from_indirect_call():
    cc = CallControl()
    F = lltype.FuncType([], lltype.Signed)
    v = varoftype(lltype.Signed)
    graphlst = ["f1graph", "f2graph"]
    op = SpaceOperation("indirect_call", [varoftype(lltype.Ptr(F)), Constant(graphlst, lltype.Void)], v)
    #
    lst = cc.graphs_from(op, {"f1graph": True, "f2graph": True}.__contains__)
    assert lst == ["f1graph", "f2graph"]  # normal indirect call
    #
    lst = cc.graphs_from(op, {"f1graph": True}.__contains__)
    assert lst == ["f1graph"]  # indirect call, look only inside some graphs
    #
    lst = cc.graphs_from(op, {}.__contains__)
    assert lst is None  # indirect call, don't look inside any graph
Beispiel #7
0
def test_random_effects_on_stacklet_switch():
    from pypy.jit.backend.llgraph.runner import LLtypeCPU
    from pypy.rlib._rffi_stacklet import switch, thread_handle, handle
    @jit.dont_look_inside
    def f():
        switch(rffi.cast(thread_handle, 0), rffi.cast(handle, 0))

    rtyper = support.annotate(f, [])
    jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0])
    cc = CallControl(LLtypeCPU(rtyper), jitdrivers_sd=[jitdriver_sd])
    res = cc.find_all_graphs(FakePolicy())

    [f_graph] = [x for x in res if x.func is f]
    [block, _] = list(f_graph.iterblocks())
    op = block.operations[-1]
    call_descr = cc.getcalldescr(op)
    assert call_descr.extrainfo.has_random_effects()
Beispiel #8
0
def test_releases_gil_analyzer():
    from pypy.jit.backend.llgraph.runner import LLtypeCPU

    T = rffi.CArrayPtr(rffi.TIME_T)
    external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True)

    @jit.dont_look_inside
    def f():
        return external(lltype.nullptr(T.TO))

    rtyper = support.annotate(f, [])
    jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0])
    cc = CallControl(LLtypeCPU(rtyper), jitdrivers_sd=[jitdriver_sd])
    res = cc.find_all_graphs(FakePolicy())

    [f_graph] = [x for x in res if x.func is f]
    [block, _] = list(f_graph.iterblocks())
    [op] = block.operations
    call_descr = cc.getcalldescr(op)
    assert call_descr.extrainfo.has_random_effects()
Beispiel #9
0
def test_guess_call_kind_and_calls_from_graphs():
    class portal_runner_obj:
        graph = object()
    class FakeJitDriverSD:
        portal_runner_ptr = portal_runner_obj
    g = object()
    g1 = object()
    cc = CallControl(jitdrivers_sd=[FakeJitDriverSD()])
    cc.candidate_graphs = [g, g1]

    op = SpaceOperation('direct_call', [Constant(portal_runner_obj)],
                        Variable())
    assert cc.guess_call_kind(op) == 'recursive'

    op = SpaceOperation('direct_call', [Constant(object())],
                        Variable())
    assert cc.guess_call_kind(op) == 'residual'        

    class funcptr:
        class graph:
            class func:
                oopspec = "spec"
    op = SpaceOperation('direct_call', [Constant(funcptr)],
                        Variable())
    assert cc.guess_call_kind(op) == 'builtin'

    class funcptr:
        graph = g
    op = SpaceOperation('direct_call', [Constant(funcptr)],
                        Variable())
    res = cc.graphs_from(op)
    assert res == [g]        
    assert cc.guess_call_kind(op) == 'regular'

    class funcptr:
        graph = object()
    op = SpaceOperation('direct_call', [Constant(funcptr)],
                        Variable())
    res = cc.graphs_from(op)
    assert res is None        
    assert cc.guess_call_kind(op) == 'residual'

    h = object()
    op = SpaceOperation('indirect_call', [Variable(),
                                          Constant([g, g1, h])],
                        Variable())
    res = cc.graphs_from(op)
    assert res == [g, g1]
    assert cc.guess_call_kind(op) == 'regular'

    op = SpaceOperation('indirect_call', [Variable(),
                                          Constant([h])],
                        Variable())
    res = cc.graphs_from(op)
    assert res is None
    assert cc.guess_call_kind(op) == 'residual'        
Beispiel #10
0
 def __init__(self, cpu=None, jitdrivers_sd=[]):
     self.cpu = cpu
     self.assembler = Assembler()
     self.callcontrol = CallControl(cpu, jitdrivers_sd)
     self._seen_files = set()
Beispiel #11
0
class CodeWriter(object):
    callcontrol = None    # for tests
    debug = False

    def __init__(self, cpu=None, jitdrivers_sd=[]):
        self.cpu = cpu
        self.assembler = Assembler()
        self.callcontrol = CallControl(cpu, jitdrivers_sd)
        self._seen_files = set()

    def transform_func_to_jitcode(self, func, values, type_system='lltype'):
        """For testing."""
        rtyper = support.annotate(func, values, type_system=type_system)
        graph = rtyper.annotator.translator.graphs[0]
        jitcode = JitCode("test")
        self.transform_graph_to_jitcode(graph, jitcode, True)
        return jitcode

    def transform_graph_to_jitcode(self, graph, jitcode, verbose):
        """Transform a graph into a JitCode containing the same bytecode
        in a different format.
        """
        portal_jd = self.callcontrol.jitdriver_sd_from_portal_graph(graph)
        graph = copygraph(graph, shallowvars=True)
        #
        # step 1: mangle the graph so that it contains the final instructions
        # that we want in the JitCode, but still as a control flow graph
        transform_graph(graph, self.cpu, self.callcontrol, portal_jd)
        #
        # step 2: perform register allocation on it
        regallocs = {}
        for kind in KINDS:
            regallocs[kind] = perform_register_allocation(graph, kind)
        #
        # step 3: flatten the graph to produce human-readable "assembler",
        # which means mostly producing a linear list of operations and
        # inserting jumps or conditional jumps.  This is a list of tuples
        # of the shape ("opname", arg1, ..., argN) or (Label(...),).
        ssarepr = flatten_graph(graph, regallocs)
        #
        # step 3b: compute the liveness around certain operations
        compute_liveness(ssarepr)
        #
        # step 4: "assemble" it into a JitCode, which contains a sequence
        # of bytes and lists of constants.  It's during this step that
        # constants are cast to their normalized type (Signed, GCREF or
        # Float).
        self.assembler.assemble(ssarepr, jitcode)
        #
        # print the resulting assembler
        if self.debug:
            self.print_ssa_repr(ssarepr, portal_jd, verbose)

    def make_jitcodes(self, verbose=False):
        log.info("making JitCodes...")
        self.callcontrol.grab_initial_jitcodes()
        count = 0
        for graph, jitcode in self.callcontrol.enum_pending_graphs():
            self.transform_graph_to_jitcode(graph, jitcode, verbose)
            count += 1
            if not count % 500:
                log.info("Produced %d jitcodes" % count)
        self.assembler.finished(self.callcontrol.callinfocollection)
        heaptracker.finish_registering(self.cpu)
        log.info("there are %d JitCode instances." % count)

    def setup_vrefinfo(self, vrefinfo):
        # must be called at most once
        assert self.callcontrol.virtualref_info is None
        self.callcontrol.virtualref_info = vrefinfo

    def setup_jitdriver(self, jitdriver_sd):
        # Must be called once per jitdriver.  Usually jitdriver_sd is an
        # instance of pypy.jit.metainterp.jitdriver.JitDriverStaticData.
        self.callcontrol.jitdrivers_sd.append(jitdriver_sd)

    def find_all_graphs(self, policy):
        return self.callcontrol.find_all_graphs(policy)

    def print_ssa_repr(self, ssarepr, portal_jitdriver, verbose):
        if verbose:
            print '%s:' % (ssarepr.name,)
            print format_assembler(ssarepr)
        else:
            log.dot()
        dir = udir.ensure("jitcodes", dir=1)
        if portal_jitdriver:
            name = "%02d_portal_runner" % (portal_jitdriver.index,)
        elif ssarepr.name and ssarepr.name != '?':
            name = ssarepr.name
        else:
            name = 'unnamed' % id(ssarepr)
        i = 1
        extra = ''
        while name+extra in self._seen_files:
            i += 1
            extra = '.%d' % i
        self._seen_files.add(name+extra)
        dir.join(name+extra).write(format_assembler(ssarepr))
Beispiel #12
0
 def __init__(self, cpu=None, jitdrivers_sd=[]):
     self.cpu = cpu
     self.assembler = Assembler()
     self.callcontrol = CallControl(cpu, jitdrivers_sd)
     self._seen_files = set()
Beispiel #13
0
class CodeWriter(object):
    callcontrol = None  # for tests
    debug = False

    def __init__(self, cpu=None, jitdrivers_sd=[]):
        self.cpu = cpu
        self.assembler = Assembler()
        self.callcontrol = CallControl(cpu, jitdrivers_sd)
        self._seen_files = set()

    def transform_func_to_jitcode(self, func, values, type_system='lltype'):
        """For testing."""
        rtyper = support.annotate(func, values, type_system=type_system)
        graph = rtyper.annotator.translator.graphs[0]
        jitcode = JitCode("test")
        self.transform_graph_to_jitcode(graph, jitcode, True)
        return jitcode

    def transform_graph_to_jitcode(self, graph, jitcode, verbose):
        """Transform a graph into a JitCode containing the same bytecode
        in a different format.
        """
        portal_jd = self.callcontrol.jitdriver_sd_from_portal_graph(graph)
        graph = copygraph(graph, shallowvars=True)
        #
        # step 1: mangle the graph so that it contains the final instructions
        # that we want in the JitCode, but still as a control flow graph
        transform_graph(graph, self.cpu, self.callcontrol, portal_jd)
        #
        # step 2: perform register allocation on it
        regallocs = {}
        for kind in KINDS:
            regallocs[kind] = perform_register_allocation(graph, kind)
        #
        # step 3: flatten the graph to produce human-readable "assembler",
        # which means mostly producing a linear list of operations and
        # inserting jumps or conditional jumps.  This is a list of tuples
        # of the shape ("opname", arg1, ..., argN) or (Label(...),).
        ssarepr = flatten_graph(graph, regallocs)
        #
        # step 3b: compute the liveness around certain operations
        compute_liveness(ssarepr)
        #
        # step 4: "assemble" it into a JitCode, which contains a sequence
        # of bytes and lists of constants.  It's during this step that
        # constants are cast to their normalized type (Signed, GCREF or
        # Float).
        self.assembler.assemble(ssarepr, jitcode)
        #
        # print the resulting assembler
        if self.debug:
            self.print_ssa_repr(ssarepr, portal_jd, verbose)

    def make_jitcodes(self, verbose=False):
        log.info("making JitCodes...")
        self.callcontrol.grab_initial_jitcodes()
        count = 0
        for graph, jitcode in self.callcontrol.enum_pending_graphs():
            self.transform_graph_to_jitcode(graph, jitcode, verbose)
            count += 1
            if not count % 500:
                log.info("Produced %d jitcodes" % count)
        self.assembler.finished(self.callcontrol.callinfocollection)
        heaptracker.finish_registering(self.cpu)
        log.info("there are %d JitCode instances." % count)

    def setup_vrefinfo(self, vrefinfo):
        # must be called at most once
        assert self.callcontrol.virtualref_info is None
        self.callcontrol.virtualref_info = vrefinfo

    def setup_jitdriver(self, jitdriver_sd):
        # Must be called once per jitdriver.  Usually jitdriver_sd is an
        # instance of pypy.jit.metainterp.jitdriver.JitDriverStaticData.
        self.callcontrol.jitdrivers_sd.append(jitdriver_sd)

    def find_all_graphs(self, policy):
        return self.callcontrol.find_all_graphs(policy)

    def print_ssa_repr(self, ssarepr, portal_jitdriver, verbose):
        if verbose:
            print '%s:' % (ssarepr.name, )
            print format_assembler(ssarepr)
        else:
            log.dot()
        dir = udir.ensure("jitcodes", dir=1)
        if portal_jitdriver:
            name = "%02d_portal_runner" % (portal_jitdriver.index, )
        elif ssarepr.name and ssarepr.name != '?':
            name = ssarepr.name
        else:
            name = 'unnamed' % id(ssarepr)
        i = 1
        # escape <lambda> names for windows
        name = name.replace('<lambda>', '_(lambda)_')
        extra = ''
        while name + extra in self._seen_files:
            i += 1
            extra = '.%d' % i
        self._seen_files.add(name + extra)
        dir.join(name + extra).write(format_assembler(ssarepr))