[pypy-commit] pypy default: Remove this implementation of malloc removal, which was never used

arigo pypy.commits at gmail.com
Sun Dec 18 09:17:29 EST 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r89144:b89ea292e8c6
Date: 2016-12-18 15:16 +0100
http://bitbucket.org/pypy/pypy/changeset/b89ea292e8c6/

Log:	Remove this implementation of malloc removal, which was never used

diff --git a/rpython/translator/backendopt/mallocv.py b/rpython/translator/backendopt/mallocv.py
deleted file mode 100644
--- a/rpython/translator/backendopt/mallocv.py
+++ /dev/null
@@ -1,1055 +0,0 @@
-from rpython.flowspace.model import Variable, Constant, Block, Link
-from rpython.flowspace.model import SpaceOperation, copygraph
-from rpython.flowspace.model import checkgraph
-from rpython.translator.backendopt.support import log
-from rpython.translator.simplify import join_blocks
-from rpython.translator.unsimplify import varoftype
-from rpython.rtyper.lltypesystem.lltype import getfunctionptr
-from rpython.rtyper.lltypesystem import lltype
-from rpython.rtyper.lltypesystem.lloperation import llop
-
-
-def virtualize_mallocs(translator, graphs, verbose=False):
-    newgraphs = graphs[:]
-    mallocv = MallocVirtualizer(newgraphs, translator.rtyper, verbose)
-    while mallocv.remove_mallocs_once():
-        pass
-    for graph in newgraphs:
-        checkgraph(graph)
-        join_blocks(graph)
-    assert newgraphs[:len(graphs)] == graphs
-    del newgraphs[:len(graphs)]
-    translator.graphs.extend(newgraphs)
-
-# ____________________________________________________________
-
-
-class MallocTypeDesc(object):
-
-    def __init__(self, MALLOCTYPE):
-        if not isinstance(MALLOCTYPE, lltype.GcStruct):
-            raise CannotRemoveThisType
-        self.MALLOCTYPE = MALLOCTYPE
-        self.check_no_destructor()
-        self.names_and_types = []
-        self.name2index = {}
-        self.name2subtype = {}
-        self.initialize_type(MALLOCTYPE)
-        #self.immutable_struct = MALLOCTYPE._hints.get('immutable')
-
-    def check_no_destructor(self):
-        STRUCT = self.MALLOCTYPE
-        try:
-            rttiptr = lltype.getRuntimeTypeInfo(STRUCT)
-        except ValueError:
-            return    # ok
-        destr_ptr = getattr(rttiptr._obj, 'destructor_funcptr', None)
-        if destr_ptr:
-            raise CannotRemoveThisType
-
-    def initialize_type(self, TYPE):
-        fieldnames = TYPE._names
-        firstname, FIRSTTYPE = TYPE._first_struct()
-        if FIRSTTYPE is not None:
-            self.initialize_type(FIRSTTYPE)
-            fieldnames = fieldnames[1:]
-        for name in fieldnames:
-            FIELDTYPE = TYPE._flds[name]
-            if isinstance(FIELDTYPE, lltype.ContainerType):
-                raise CannotRemoveThisType("inlined substructure")
-            self.name2index[name] = len(self.names_and_types)
-            self.names_and_types.append((name, FIELDTYPE))
-            self.name2subtype[name] = TYPE
-
-
-class SpecNode(object):
-    pass
-
-
-class RuntimeSpecNode(SpecNode):
-
-    def __init__(self, name, TYPE):
-        self.name = name
-        self.TYPE = TYPE
-
-    def newvar(self):
-        v = Variable(self.name)
-        v.concretetype = self.TYPE
-        return v
-
-    def getfrozenkey(self, memo):
-        return 'R'
-
-    def accumulate_nodes(self, rtnodes, vtnodes):
-        rtnodes.append(self)
-
-    def copy(self, memo, flagreadonly):
-        return RuntimeSpecNode(self.name, self.TYPE)
-
-    def bind_rt_nodes(self, memo, newnodes_iter):
-        return newnodes_iter.next()
-
-
-class VirtualSpecNode(SpecNode):
-
-    def __init__(self, typedesc, fields, readonly=False):
-        self.typedesc = typedesc
-        self.fields = fields     # list of SpecNodes
-        self.readonly = readonly
-
-    def getfrozenkey(self, memo):
-        if self in memo:
-            return memo[self]
-        else:
-            memo[self] = len(memo)
-            result = [self.typedesc, self.readonly]
-            for subnode in self.fields:
-                result.append(subnode.getfrozenkey(memo))
-            return tuple(result)
-
-    def accumulate_nodes(self, rtnodes, vtnodes):
-        if self in vtnodes:
-            return
-        vtnodes[self] = True
-        for subnode in self.fields:
-            subnode.accumulate_nodes(rtnodes, vtnodes)
-
-    def copy(self, memo, flagreadonly):
-        if self in memo:
-            return memo[self]
-        readonly = self.readonly or self in flagreadonly
-        newnode = VirtualSpecNode(self.typedesc, [], readonly)
-        memo[self] = newnode
-        for subnode in self.fields:
-            newnode.fields.append(subnode.copy(memo, flagreadonly))
-        return newnode
-
-    def bind_rt_nodes(self, memo, newnodes_iter):
-        if self in memo:
-            return memo[self]
-        newnode = VirtualSpecNode(self.typedesc, [], self.readonly)
-        memo[self] = newnode
-        for subnode in self.fields:
-            newnode.fields.append(subnode.bind_rt_nodes(memo, newnodes_iter))
-        return newnode
-
-
-class VirtualFrame(object):
-
-    def __init__(self, sourceblock, nextopindex,
-                 allnodes, callerframe=None, calledgraphs={}):
-        if isinstance(allnodes, dict):
-            self.varlist = vars_alive_through_op(sourceblock, nextopindex)
-            self.nodelist = [allnodes[v] for v in self.varlist]
-        else:
-            assert nextopindex == 0
-            self.varlist = sourceblock.inputargs
-            self.nodelist = allnodes[:]
-        self.sourceblock = sourceblock
-        self.nextopindex = nextopindex
-        self.callerframe = callerframe
-        self.calledgraphs = calledgraphs
-
-    def get_nodes_in_use(self):
-        return dict(zip(self.varlist, self.nodelist))
-
-    def shallowcopy(self):
-        newframe = VirtualFrame.__new__(VirtualFrame)
-        newframe.varlist = self.varlist
-        newframe.nodelist = self.nodelist
-        newframe.sourceblock = self.sourceblock
-        newframe.nextopindex = self.nextopindex
-        newframe.callerframe = self.callerframe
-        newframe.calledgraphs = self.calledgraphs
-        return newframe
-
-    def copy(self, memo, flagreadonly={}):
-        newframe = self.shallowcopy()
-        newframe.nodelist = [node.copy(memo, flagreadonly)
-                             for node in newframe.nodelist]
-        if newframe.callerframe is not None:
-            newframe.callerframe = newframe.callerframe.copy(memo,
-                                                             flagreadonly)
-        return newframe
-
-    def enum_call_stack(self):
-        frame = self
-        while frame is not None:
-            yield frame
-            frame = frame.callerframe
-
-    def getfrozenkey(self):
-        memo = {}
-        key = []
-        for frame in self.enum_call_stack():
-            key.append(frame.sourceblock)
-            key.append(frame.nextopindex)
-            for node in frame.nodelist:
-                key.append(node.getfrozenkey(memo))
-        return tuple(key)
-
-    def find_all_nodes(self):
-        rtnodes = []
-        vtnodes = {}
-        for frame in self.enum_call_stack():
-            for node in frame.nodelist:
-                node.accumulate_nodes(rtnodes, vtnodes)
-        return rtnodes, vtnodes
-
-    def find_rt_nodes(self):
-        rtnodes, vtnodes = self.find_all_nodes()
-        return rtnodes
-
-    def find_vt_nodes(self):
-        rtnodes, vtnodes = self.find_all_nodes()
-        return vtnodes
-
-
-def copynodes(nodelist, flagreadonly={}):
-    memo = {}
-    return [node.copy(memo, flagreadonly) for node in nodelist]
-
-def find_all_nodes(nodelist):
-    rtnodes = []
-    vtnodes = {}
-    for node in nodelist:
-        node.accumulate_nodes(rtnodes, vtnodes)
-    return rtnodes, vtnodes
-
-def is_trivial_nodelist(nodelist):
-    for node in nodelist:
-        if not isinstance(node, RuntimeSpecNode):
-            return False
-    return True
-
-def bind_rt_nodes(srcnodelist, newnodes_list):
-    """Return srcnodelist with all RuntimeNodes replaced by nodes
-    coming from newnodes_list.
-    """
-    memo = {}
-    newnodes_iter = iter(newnodes_list)
-    result = [node.bind_rt_nodes(memo, newnodes_iter) for node in srcnodelist]
-    rest = list(newnodes_iter)
-    assert rest == [], "too many nodes in newnodes_list"
-    return result
-
-
-class CannotVirtualize(Exception):
-    pass
-
-class ForcedInline(Exception):
-    pass
-
-class CannotRemoveThisType(Exception):
-    pass
-
-# ____________________________________________________________
-
-
-class MallocVirtualizer(object):
-
-    def __init__(self, graphs, rtyper, verbose=False):
-        self.graphs = graphs
-        self.rtyper = rtyper
-        self.excdata = rtyper.exceptiondata
-        self.graphbuilders = {}
-        self.specialized_graphs = {}
-        self.specgraphorigin = {}
-        self.inline_and_remove = {}    # {graph: op_to_remove}
-        self.inline_and_remove_seen = {}   # set of (graph, op_to_remove)
-        self.malloctypedescs = {}
-        self.count_virtualized = 0
-        self.verbose = verbose
-        self.EXCTYPE_to_vtable = self.build_obscure_mapping()
-
-    def build_obscure_mapping(self):
-        result = {}
-        for rinstance in self.rtyper.instance_reprs.values():
-            result[rinstance.lowleveltype.TO] = rinstance.rclass.getvtable()
-        return result
-
-    def report_result(self, progress):
-        if progress:
-            log.mallocv('removed %d mallocs so far' % self.count_virtualized)
-        else:
-            log.mallocv('done')
-
-    def enum_all_mallocs(self, graph):
-        for block in graph.iterblocks():
-            for op in block.operations:
-                if op.opname == 'malloc':
-                    MALLOCTYPE = op.result.concretetype.TO
-                    try:
-                        self.getmalloctypedesc(MALLOCTYPE)
-                    except CannotRemoveThisType:
-                        pass
-                    else:
-                        yield (block, op)
-                elif op.opname == 'direct_call':
-                    graph = graph_called_by(op)
-                    if graph in self.inline_and_remove:
-                        yield (block, op)
-
-    def remove_mallocs_once(self):
-        self.flush_failed_specializations()
-        prev = self.count_virtualized
-        count_inline_and_remove = len(self.inline_and_remove)
-        for graph in self.graphs:
-            seen = {}
-            while True:
-                for block, op in self.enum_all_mallocs(graph):
-                    if op.result not in seen:
-                        seen[op.result] = True
-                        if self.try_remove_malloc(graph, block, op):
-                            break   # graph mutated, restart enum_all_mallocs()
-                else:
-                    break   # enum_all_mallocs() exhausted, graph finished
-        progress1 = self.count_virtualized - prev
-        progress2 = len(self.inline_and_remove) - count_inline_and_remove
-        progress = progress1 or bool(progress2)
-        self.report_result(progress)
-        return progress
-
-    def flush_failed_specializations(self):
-        for key, (mode, specgraph) in self.specialized_graphs.items():
-            if mode == 'fail':
-                del self.specialized_graphs[key]
-
-    def fixup_except_block(self, exceptblock):
-        # hack: this block's inputargs may be missing concretetypes...
-        e1, v1 = exceptblock.inputargs
-        e1.concretetype = self.excdata.lltype_of_exception_type
-        v1.concretetype = self.excdata.lltype_of_exception_value
-
-    def getmalloctypedesc(self, MALLOCTYPE):
-        try:
-            dsc = self.malloctypedescs[MALLOCTYPE]
-        except KeyError:
-            dsc = self.malloctypedescs[MALLOCTYPE] = MallocTypeDesc(MALLOCTYPE)
-        return dsc
-
-    def try_remove_malloc(self, graph, block, op):
-        if (graph, op) in self.inline_and_remove_seen:
-            return False      # no point in trying again
-        graphbuilder = GraphBuilder(self, graph)
-        if graph in self.graphbuilders:
-            graphbuilder.initialize_from_old_builder(self.graphbuilders[graph])
-        graphbuilder.start_from_a_malloc(graph, block, op.result)
-        try:
-            graphbuilder.propagate_specializations()
-        except CannotVirtualize as e:
-            self.logresult(op, 'failed', e)
-            return False
-        except ForcedInline as e:
-            self.logresult(op, 'forces inlining', e)
-            self.inline_and_remove[graph] = op
-            self.inline_and_remove_seen[graph, op] = True
-            return False
-        else:
-            self.logresult(op, 'removed')
-            graphbuilder.finished_removing_malloc()
-            self.graphbuilders[graph] = graphbuilder
-            self.count_virtualized += 1
-            return True
-
-    def logresult(self, op, msg, exc=None):    # only for nice log outputs
-        if self.verbose:
-            if exc is None:
-                exc = ''
-            else:
-                exc = ': %s' % (exc,)
-            chain = []
-            while True:
-                chain.append(str(op.result))
-                if op.opname != 'direct_call':
-                    break
-                fobj = op.args[0].value._obj
-                op = self.inline_and_remove[fobj.graph]
-            log.mallocv('%s %s%s' % ('->'.join(chain), msg, exc))
-        elif exc is None:
-            log.dot()
-
-    def get_specialized_graph(self, graph, nodelist):
-        assert len(graph.getargs()) == len(nodelist)
-        if is_trivial_nodelist(nodelist):
-            return 'trivial', graph
-        if graph in self.specgraphorigin:
-            orggraph, orgnodelist = self.specgraphorigin[graph]
-            nodelist = bind_rt_nodes(orgnodelist, nodelist)
-            graph = orggraph
-        virtualframe = VirtualFrame(graph.startblock, 0, nodelist)
-        key = virtualframe.getfrozenkey()
-        try:
-            return self.specialized_graphs[key]
-        except KeyError:
-            self.build_specialized_graph(graph, key, nodelist)
-            return self.specialized_graphs[key]
-
-    def build_specialized_graph(self, graph, key, nodelist):
-        graph2 = copygraph(graph)
-        virtualframe = VirtualFrame(graph2.startblock, 0, nodelist)
-        graphbuilder = GraphBuilder(self, graph2)
-        specblock = graphbuilder.start_from_virtualframe(virtualframe)
-        specgraph = graph2
-        specgraph.name += '_mallocv'
-        specgraph.startblock = specblock
-        self.specialized_graphs[key] = ('call', specgraph)
-        try:
-            graphbuilder.propagate_specializations()
-        except ForcedInline as e:
-            if self.verbose:
-                log.mallocv('%s inlined: %s' % (graph.name, e))
-            self.specialized_graphs[key] = ('inline', None)
-        except CannotVirtualize as e:
-            if self.verbose:
-                log.mallocv('%s failing: %s' % (graph.name, e))
-            self.specialized_graphs[key] = ('fail', None)
-        else:
-            self.graphbuilders[specgraph] = graphbuilder
-            self.specgraphorigin[specgraph] = graph, nodelist
-            self.graphs.append(specgraph)
-
-
-class GraphBuilder(object):
-
-    def __init__(self, mallocv, graph):
-        self.mallocv = mallocv
-        self.graph = graph
-        self.specialized_blocks = {}
-        self.pending_specializations = []
-
-    def initialize_from_old_builder(self, oldbuilder):
-        self.specialized_blocks.update(oldbuilder.specialized_blocks)
-
-    def start_from_virtualframe(self, startframe):
-        spec = BlockSpecializer(self)
-        spec.initialize_renamings(startframe)
-        self.pending_specializations.append(spec)
-        return spec.specblock
-
-    def start_from_a_malloc(self, graph, block, v_result):
-        assert v_result in [op.result for op in block.operations]
-        nodelist = []
-        for v in block.inputargs:
-            nodelist.append(RuntimeSpecNode(v, v.concretetype))
-        trivialframe = VirtualFrame(block, 0, nodelist)
-        spec = BlockSpecializer(self, v_result)
-        spec.initialize_renamings(trivialframe, keep_inputargs=True)
-        self.pending_specializations.append(spec)
-        self.pending_patch = (block, spec.specblock)
-
-    def finished_removing_malloc(self):
-        (srcblock, specblock) = self.pending_patch
-        srcblock.inputargs = specblock.inputargs
-        srcblock.operations = specblock.operations
-        srcblock.exitswitch = specblock.exitswitch
-        srcblock.recloseblock(*specblock.exits)
-
-    def create_outgoing_link(self, currentframe, targetblock,
-                             nodelist, renamings, v_expand_malloc=None):
-        assert len(nodelist) == len(targetblock.inputargs)
-        #
-        if is_except(targetblock):
-            v_expand_malloc = None
-            while currentframe.callerframe is not None:
-                currentframe = currentframe.callerframe
-                newlink = self.handle_catch(currentframe, nodelist, renamings)
-                if newlink:
-                    return newlink
-            else:
-                targetblock = self.exception_escapes(nodelist, renamings)
-                assert len(nodelist) == len(targetblock.inputargs)
-
-        if (currentframe.callerframe is None and
-              is_trivial_nodelist(nodelist)):
-            # there is no more VirtualSpecNodes being passed around,
-            # so we can stop specializing
-            rtnodes = nodelist
-            specblock = targetblock
-        else:
-            if is_return(targetblock):
-                v_expand_malloc = None
-                newframe = self.return_to_caller(currentframe, nodelist[0])
-            else:
-                targetnodes = dict(zip(targetblock.inputargs, nodelist))
-                newframe = VirtualFrame(targetblock, 0, targetnodes,
-                                        callerframe=currentframe.callerframe,
-                                        calledgraphs=currentframe.calledgraphs)
-            rtnodes = newframe.find_rt_nodes()
-            specblock = self.get_specialized_block(newframe, v_expand_malloc)
-
-        linkargs = [renamings[rtnode] for rtnode in rtnodes]
-        return Link(linkargs, specblock)
-
-    def return_to_caller(self, currentframe, retnode):
-        callerframe = currentframe.callerframe
-        if callerframe is None:
-            raise ForcedInline("return block")
-        nodelist = callerframe.nodelist
-        callerframe = callerframe.shallowcopy()
-        callerframe.nodelist = []
-        for node in nodelist:
-            if isinstance(node, FutureReturnValue):
-                node = retnode
-            callerframe.nodelist.append(node)
-        return callerframe
-
-    def handle_catch(self, catchingframe, nodelist, renamings):
-        if not self.has_exception_catching(catchingframe):
-            return None
-        [exc_node, exc_value_node] = nodelist
-        v_exc_type = renamings.get(exc_node)
-        if isinstance(v_exc_type, Constant):
-            exc_type = v_exc_type.value
-        elif isinstance(exc_value_node, VirtualSpecNode):
-            EXCTYPE = exc_value_node.typedesc.MALLOCTYPE
-            exc_type = self.mallocv.EXCTYPE_to_vtable[EXCTYPE]
-        else:
-            raise CannotVirtualize("raising non-constant exc type")
-        excdata = self.mallocv.excdata
-        assert catchingframe.sourceblock.exits[0].exitcase is None
-        for catchlink in catchingframe.sourceblock.exits[1:]:
-            if excdata.fn_exception_match(exc_type, catchlink.llexitcase):
-                # Match found.  Follow this link.
-                mynodes = catchingframe.get_nodes_in_use()
-                for node, attr in zip(nodelist,
-                                      ['last_exception', 'last_exc_value']):
-                    v = getattr(catchlink, attr)
-                    if isinstance(v, Variable):
-                        mynodes[v] = node
-                #
-                nodelist = []
-                for v in catchlink.args:
-                    if isinstance(v, Variable):
-                        node = mynodes[v]
-                    else:
-                        node = getconstnode(v, renamings)
-                    nodelist.append(node)
-                return self.create_outgoing_link(catchingframe,
-                                                 catchlink.target,
-                                                 nodelist, renamings)
-        else:
-            # No match at all, propagate the exception to the caller
-            return None
-
-    def has_exception_catching(self, catchingframe):
-        if not catchingframe.sourceblock.canraise:
-            return False
-        else:
-            operations = catchingframe.sourceblock.operations
-            assert 1 <= catchingframe.nextopindex <= len(operations)
-            return catchingframe.nextopindex == len(operations)
-
-    def exception_escapes(self, nodelist, renamings):
-        # the exception escapes
-        if not is_trivial_nodelist(nodelist):
-            # start of hacks to help handle_catch()
-            [exc_node, exc_value_node] = nodelist
-            v_exc_type = renamings.get(exc_node)
-            if isinstance(v_exc_type, Constant):
-                # cannot improve: handle_catch() would already be happy
-                # by seeing the exc_type as a constant
-                pass
-            elif isinstance(exc_value_node, VirtualSpecNode):
-                # can improve with a strange hack: we pretend that
-                # the source code jumps to a block that itself allocates
-                # the exception, sets all fields, and raises it by
-                # passing a constant type.
-                typedesc = exc_value_node.typedesc
-                return self.get_exc_reconstruction_block(typedesc)
-            else:
-                # cannot improve: handle_catch() will have no clue about
-                # the exception type
-                pass
-            raise CannotVirtualize("except block")
-        targetblock = self.graph.exceptblock
-        self.mallocv.fixup_except_block(targetblock)
-        return targetblock
-
-    def get_exc_reconstruction_block(self, typedesc):
-        exceptblock = self.graph.exceptblock
-        self.mallocv.fixup_except_block(exceptblock)
-        TEXC = exceptblock.inputargs[0].concretetype
-        TVAL = exceptblock.inputargs[1].concretetype
-        #
-        v_ignored_type = varoftype(TEXC)
-        v_incoming_value = varoftype(TVAL)
-        block = Block([v_ignored_type, v_incoming_value])
-        #
-        c_EXCTYPE = Constant(typedesc.MALLOCTYPE, lltype.Void)
-        v = varoftype(lltype.Ptr(typedesc.MALLOCTYPE))
-        c_flavor = Constant({'flavor': 'gc'}, lltype.Void)
-        op = SpaceOperation('malloc', [c_EXCTYPE, c_flavor], v)
-        block.operations.append(op)
-        #
-        for name, FIELDTYPE in typedesc.names_and_types:
-            EXACTPTR = lltype.Ptr(typedesc.name2subtype[name])
-            c_name = Constant(name)
-            c_name.concretetype = lltype.Void
-            #
-            v_in = varoftype(EXACTPTR)
-            op = SpaceOperation('cast_pointer', [v_incoming_value], v_in)
-            block.operations.append(op)
-            #
-            v_field = varoftype(FIELDTYPE)
-            op = SpaceOperation('getfield', [v_in, c_name], v_field)
-            block.operations.append(op)
-            #
-            v_out = varoftype(EXACTPTR)
-            op = SpaceOperation('cast_pointer', [v], v_out)
-            block.operations.append(op)
-            #
-            v0 = varoftype(lltype.Void)
-            op = SpaceOperation('setfield', [v_out, c_name, v_field], v0)
-            block.operations.append(op)
-        #
-        v_exc_value = varoftype(TVAL)
-        op = SpaceOperation('cast_pointer', [v], v_exc_value)
-        block.operations.append(op)
-        #
-        exc_type = self.mallocv.EXCTYPE_to_vtable[typedesc.MALLOCTYPE]
-        c_exc_type = Constant(exc_type, TEXC)
-        block.closeblock(Link([c_exc_type, v_exc_value], exceptblock))
-        return block
-
-    def get_specialized_block(self, virtualframe, v_expand_malloc=None):
-        key = virtualframe.getfrozenkey()
-        specblock = self.specialized_blocks.get(key)
-        if specblock is None:
-            orgblock = virtualframe.sourceblock
-            assert len(orgblock.exits) != 0
-            spec = BlockSpecializer(self, v_expand_malloc)
-            spec.initialize_renamings(virtualframe)
-            self.pending_specializations.append(spec)
-            specblock = spec.specblock
-            self.specialized_blocks[key] = specblock
-        return specblock
-
-    def propagate_specializations(self):
-        while self.pending_specializations:
-            spec = self.pending_specializations.pop()
-            spec.specialize_operations()
-            spec.follow_exits()
-
-
-class BlockSpecializer(object):
-
-    def __init__(self, graphbuilder, v_expand_malloc=None):
-        self.graphbuilder = graphbuilder
-        self.v_expand_malloc = v_expand_malloc
-        self.specblock = Block([])
-
-    def initialize_renamings(self, virtualframe, keep_inputargs=False):
-        # we make a copy of the original 'virtualframe' because the
-        # specialize_operations() will mutate some of its content.
-        virtualframe = virtualframe.copy({})
-        self.virtualframe = virtualframe
-        self.nodes = virtualframe.get_nodes_in_use()
-        self.renamings = {}    # {RuntimeSpecNode(): Variable()}
-        if keep_inputargs:
-            assert virtualframe.varlist == virtualframe.sourceblock.inputargs
-        specinputargs = []
-        for i, rtnode in enumerate(virtualframe.find_rt_nodes()):
-            if keep_inputargs:
-                v = virtualframe.varlist[i]
-                assert v.concretetype == rtnode.TYPE
-            else:
-                v = rtnode.newvar()
-            self.renamings[rtnode] = v
-            specinputargs.append(v)
-        self.specblock.inputargs = specinputargs
-
-    def setnode(self, v, node):
-        assert v not in self.nodes
-        self.nodes[v] = node
-
-    def getnode(self, v):
-        if isinstance(v, Variable):
-            return self.nodes[v]
-        else:
-            return getconstnode(v, self.renamings)
-
-    def rename_nonvirtual(self, v, where=None):
-        if not isinstance(v, Variable):
-            return v
-        node = self.nodes[v]
-        if not isinstance(node, RuntimeSpecNode):
-            raise CannotVirtualize(where)
-        return self.renamings[node]
-
-    def expand_nodes(self, nodelist):
-        rtnodes, vtnodes = find_all_nodes(nodelist)
-        return [self.renamings[rtnode] for rtnode in rtnodes]
-
-    def specialize_operations(self):
-        newoperations = []
-        self.ops_produced_by_last_op = 0
-        # note that 'self.virtualframe' can be changed during the loop!
-        while True:
-            operations = self.virtualframe.sourceblock.operations
-            try:
-                op = operations[self.virtualframe.nextopindex]
-                self.virtualframe.nextopindex += 1
-            except IndexError:
-                break
-
-            meth = getattr(self, 'handle_op_' + op.opname,
-                           self.handle_default)
-            newops_for_this_op = meth(op)
-            newoperations += newops_for_this_op
-            self.ops_produced_by_last_op = len(newops_for_this_op)
-        for op in newoperations:
-            if op.opname == 'direct_call':
-                graph = graph_called_by(op)
-                if graph in self.virtualframe.calledgraphs:
-                    raise CannotVirtualize("recursion in residual call")
-        self.specblock.operations = newoperations
-
-    def follow_exits(self):
-        block = self.virtualframe.sourceblock
-        self.specblock.exitswitch = self.rename_nonvirtual(block.exitswitch,
-                                                           'exitswitch')
-        links = block.exits
-        catch_exc = self.specblock.canraise
-
-        if not catch_exc and isinstance(self.specblock.exitswitch, Constant):
-            # constant-fold the switch
-            for link in links:
-                if link.exitcase == 'default':
-                    break
-                if link.llexitcase == self.specblock.exitswitch.value:
-                    break
-            else:
-                raise Exception("exit case not found?")
-            links = (link,)
-            self.specblock.exitswitch = None
-
-        if catch_exc and self.ops_produced_by_last_op == 0:
-            # the last op of the sourceblock did not produce any
-            # operation in specblock, so we need to discard the
-            # exception-catching.
-            catch_exc = False
-            links = links[:1]
-            assert links[0].exitcase is None  # the non-exception-catching case
-            self.specblock.exitswitch = None
-
-        newlinks = []
-        for link in links:
-            is_catch_link = catch_exc and link.exitcase is not None
-            if is_catch_link:
-                extravars = []
-                for attr in ['last_exception', 'last_exc_value']:
-                    v = getattr(link, attr)
-                    if isinstance(v, Variable):
-                        rtnode = RuntimeSpecNode(v, v.concretetype)
-                        self.setnode(v, rtnode)
-                        self.renamings[rtnode] = v = rtnode.newvar()
-                    extravars.append(v)
-
-            linkargsnodes = [self.getnode(v1) for v1 in link.args]
-            #
-            newlink = self.graphbuilder.create_outgoing_link(
-                self.virtualframe, link.target, linkargsnodes,
-                self.renamings, self.v_expand_malloc)
-            #
-            if self.specblock.exitswitch is not None:
-                newlink.exitcase = link.exitcase
-                if hasattr(link, 'llexitcase'):
-                    newlink.llexitcase = link.llexitcase
-                if is_catch_link:
-                    newlink.extravars(*extravars)
-            newlinks.append(newlink)
-
-        self.specblock.closeblock(*newlinks)
-
-    def make_rt_result(self, v_result):
-        newrtnode = RuntimeSpecNode(v_result, v_result.concretetype)
-        self.setnode(v_result, newrtnode)
-        v_new = newrtnode.newvar()
-        self.renamings[newrtnode] = v_new
-        return v_new
-
-    def make_const_rt_result(self, v_result, value):
-        newrtnode = RuntimeSpecNode(v_result, v_result.concretetype)
-        self.setnode(v_result, newrtnode)
-        if v_result.concretetype is not lltype.Void:
-            assert v_result.concretetype == lltype.typeOf(value)
-        c_value = Constant(value)
-        c_value.concretetype = v_result.concretetype
-        self.renamings[newrtnode] = c_value
-
-    def handle_default(self, op):
-        newargs = [self.rename_nonvirtual(v, op) for v in op.args]
-        constresult = try_fold_operation(op.opname, newargs,
-                                         op.result.concretetype)
-        if constresult:
-            self.make_const_rt_result(op.result, constresult[0])
-            return []
-        else:
-            newresult = self.make_rt_result(op.result)
-            return [SpaceOperation(op.opname, newargs, newresult)]
-
-    def handle_unreachable(self, op):
-        from rpython.rtyper.lltypesystem.rstr import string_repr
-        msg = 'unreachable: %s' % (op,)
-        ll_msg = string_repr.convert_const(msg)
-        c_msg = Constant(ll_msg, lltype.typeOf(ll_msg))
-        newresult = self.make_rt_result(op.result)
-        return [SpaceOperation('debug_fatalerror', [c_msg], newresult)]
-
-    def handle_op_getfield(self, op):
-        node = self.getnode(op.args[0])
-        if isinstance(node, VirtualSpecNode):
-            fieldname = op.args[1].value
-            index = node.typedesc.name2index[fieldname]
-            self.setnode(op.result, node.fields[index])
-            return []
-        else:
-            return self.handle_default(op)
-
-    def handle_op_setfield(self, op):
-        node = self.getnode(op.args[0])
-        if isinstance(node, VirtualSpecNode):
-            if node.readonly:
-                raise ForcedInline(op)
-            fieldname = op.args[1].value
-            index = node.typedesc.name2index[fieldname]
-            node.fields[index] = self.getnode(op.args[2])
-            return []
-        else:
-            return self.handle_default(op)
-
-    def handle_op_same_as(self, op):
-        node = self.getnode(op.args[0])
-        if isinstance(node, VirtualSpecNode):
-            node = self.getnode(op.args[0])
-            self.setnode(op.result, node)
-            return []
-        else:
-            return self.handle_default(op)
-
-    def handle_op_cast_pointer(self, op):
-        node = self.getnode(op.args[0])
-        if isinstance(node, VirtualSpecNode):
-            node = self.getnode(op.args[0])
-            SOURCEPTR = lltype.Ptr(node.typedesc.MALLOCTYPE)
-            TARGETPTR = op.result.concretetype
-            try:
-                if lltype.castable(TARGETPTR, SOURCEPTR) < 0:
-                    raise lltype.InvalidCast
-            except lltype.InvalidCast:
-                return self.handle_unreachable(op)
-            self.setnode(op.result, node)
-            return []
-        else:
-            return self.handle_default(op)
-
-    def handle_op_ptr_nonzero(self, op):
-        node = self.getnode(op.args[0])
-        if isinstance(node, VirtualSpecNode):
-            self.make_const_rt_result(op.result, True)
-            return []
-        else:
-            return self.handle_default(op)
-
-    def handle_op_ptr_iszero(self, op):
-        node = self.getnode(op.args[0])
-        if isinstance(node, VirtualSpecNode):
-            self.make_const_rt_result(op.result, False)
-            return []
-        else:
-            return self.handle_default(op)
-
-    def handle_op_ptr_eq(self, op):
-        node0 = self.getnode(op.args[0])
-        node1 = self.getnode(op.args[1])
-        if (isinstance(node0, VirtualSpecNode) or
-            isinstance(node1, VirtualSpecNode)):
-            self.make_const_rt_result(op.result, node0 is node1)
-            return []
-        else:
-            return self.handle_default(op)
-
-    def handle_op_ptr_ne(self, op):
-        node0 = self.getnode(op.args[0])
-        node1 = self.getnode(op.args[1])
-        if (isinstance(node0, VirtualSpecNode) or
-            isinstance(node1, VirtualSpecNode)):
-            self.make_const_rt_result(op.result, node0 is not node1)
-            return []
-        else:
-            return self.handle_default(op)
-
-    def handle_op_malloc(self, op):
-        if op.result is self.v_expand_malloc:
-            MALLOCTYPE = op.result.concretetype.TO
-            typedesc = self.graphbuilder.mallocv.getmalloctypedesc(MALLOCTYPE)
-            virtualnode = VirtualSpecNode(typedesc, [])
-            self.setnode(op.result, virtualnode)
-            for name, FIELDTYPE in typedesc.names_and_types:
-                fieldnode = RuntimeSpecNode(name, FIELDTYPE)
-                virtualnode.fields.append(fieldnode)
-                c = Constant(FIELDTYPE._defl())
-                c.concretetype = FIELDTYPE
-                self.renamings[fieldnode] = c
-            self.v_expand_malloc = None      # done
-            return []
-        else:
-            return self.handle_default(op)
-
-    def handle_op_direct_call(self, op):
-        graph = graph_called_by(op)
-        if graph is None:
-            return self.handle_default(op)
-        nb_args = len(op.args) - 1
-        assert nb_args == len(graph.getargs())
-        newnodes = [self.getnode(v) for v in op.args[1:]]
-        myframe = self.get_updated_frame(op)
-        mallocv = self.graphbuilder.mallocv
-
-        if op.result is self.v_expand_malloc:
-            # move to inlining the callee, and continue looking for the
-            # malloc to expand in the callee's graph
-            op_to_remove = mallocv.inline_and_remove[graph]
-            self.v_expand_malloc = op_to_remove.result
-            return self.handle_inlined_call(myframe, graph, newnodes)
-
-        argnodes = copynodes(newnodes, flagreadonly=myframe.find_vt_nodes())
-        kind, newgraph = mallocv.get_specialized_graph(graph, argnodes)
-        if kind == 'trivial':
-            return self.handle_default(op)
-        elif kind == 'inline':
-            return self.handle_inlined_call(myframe, graph, newnodes)
-        elif kind == 'call':
-            return self.handle_residual_call(op, newgraph, newnodes)
-        elif kind == 'fail':
-            raise CannotVirtualize(op)
-        else:
-            raise ValueError(kind)
-
-    def get_updated_frame(self, op):
-        sourceblock = self.virtualframe.sourceblock
-        nextopindex = self.virtualframe.nextopindex
-        self.nodes[op.result] = FutureReturnValue(op)
-        myframe = VirtualFrame(sourceblock, nextopindex, self.nodes,
-                               self.virtualframe.callerframe,
-                               self.virtualframe.calledgraphs)
-        del self.nodes[op.result]
-        return myframe
-
-    def handle_residual_call(self, op, newgraph, newnodes):
-        fspecptr = getfunctionptr(newgraph)
-        newargs = [Constant(fspecptr,
-                            concretetype=lltype.typeOf(fspecptr))]
-        newargs += self.expand_nodes(newnodes)
-        newresult = self.make_rt_result(op.result)
-        newop = SpaceOperation('direct_call', newargs, newresult)
-        return [newop]
-
-    def handle_inlined_call(self, myframe, graph, newnodes):
-        assert len(graph.getargs()) == len(newnodes)
-        targetnodes = dict(zip(graph.getargs(), newnodes))
-        calledgraphs = myframe.calledgraphs.copy()
-        if graph in calledgraphs:
-            raise CannotVirtualize("recursion during inlining")
-        calledgraphs[graph] = True
-        calleeframe = VirtualFrame(graph.startblock, 0,
-                                   targetnodes, myframe, calledgraphs)
-        self.virtualframe = calleeframe
-        self.nodes = calleeframe.get_nodes_in_use()
-        return []
-
-    def handle_op_indirect_call(self, op):
-        v_func = self.rename_nonvirtual(op.args[0], op)
-        if isinstance(v_func, Constant):
-            op = SpaceOperation('direct_call', [v_func] + op.args[1:-1],
-                                op.result)
-            return self.handle_op_direct_call(op)
-        else:
-            return self.handle_default(op)
-
-
-class FutureReturnValue(object):
-    def __init__(self, op):
-        self.op = op    # for debugging
-    def getfrozenkey(self, memo):
-        return None
-    def accumulate_nodes(self, rtnodes, vtnodes):
-        pass
-    def copy(self, memo, flagreadonly):
-        return self
-
-# ____________________________________________________________
-# helpers
-
-def vars_alive_through_op(block, index):
-    # NB. make sure this always returns the variables in the same order
-    if len(block.exits) == 0:
-        return block.inputargs   # return or except block
-    result = []
-    seen = {}
-    def see(v):
-        if isinstance(v, Variable) and v not in seen:
-            result.append(v)
-            seen[v] = True
-    # don't include the variables produced by the current or future operations
-    for op in block.operations[index:]:
-        seen[op.result] = True
-    # don't include the extra vars produced by exception-catching links
-    for link in block.exits:
-        for v in link.getextravars():
-            seen[v] = True
-    # but include the variables consumed by the current or any future operation
-    for op in block.operations[index:]:
-        for v in op.args:
-            see(v)
-    see(block.exitswitch)
-    for link in block.exits:
-        for v in link.args:
-            see(v)
-    return result
-
-def is_return(block):
-    return len(block.exits) == 0 and len(block.inputargs) == 1
-
-def is_except(block):
-    return len(block.exits) == 0 and len(block.inputargs) == 2
-
-class CannotConstFold(Exception):
-    pass
-
-def try_fold_operation(opname, args_v, RESTYPE):
-    args = []
-    for c in args_v:
-        if not isinstance(c, Constant):
-            return
-        args.append(c.value)
-    try:
-        op = getattr(llop, opname)
-    except AttributeError:
-        return
-    if not op.is_pure(args_v):
-        return
-    try:
-        result = op(RESTYPE, *args)
-    except TypeError:
-        pass
-    except (KeyboardInterrupt, SystemExit):
-        raise
-    except Exception as e:
-        pass
-        #log.WARNING('constant-folding %s%r:' % (opname, args_v))
-        #log.WARNING('  %s: %s' % (e.__class__.__name__, e))
-    else:
-        return (result,)
-
-def getconstnode(v, renamings):
-    rtnode = RuntimeSpecNode(None, v.concretetype)
-    renamings[rtnode] = v
-    return rtnode
-
-def graph_called_by(op):
-    assert op.opname == 'direct_call'
-    fobj = op.args[0].value._obj
-    graph = getattr(fobj, 'graph', None)
-    return graph
diff --git a/rpython/translator/backendopt/test/test_mallocv.py b/rpython/translator/backendopt/test/test_mallocv.py
deleted file mode 100644
--- a/rpython/translator/backendopt/test/test_mallocv.py
+++ /dev/null
@@ -1,786 +0,0 @@
-import py
-import sys
-from rpython.translator.backendopt.mallocv import MallocVirtualizer
-from rpython.translator.translator import TranslationContext, graphof
-from rpython.flowspace.model import summary
-from rpython.rtyper.llinterp import LLInterpreter, LLException
-from rpython.rtyper.lltypesystem import lltype, lloperation
-from rpython.rtyper.annlowlevel import llhelper
-from rpython.rlib.rarithmetic import ovfcheck
-from rpython.conftest import option
-
-DONT_CHECK_RESULT = object()
-class CHECK_RAISES:
-    def __init__(self, excname):
-        assert isinstance(excname, str)
-        self.excname = excname
-
-
-class TestMallocRemoval(object):
-    def check_malloc_removed(cls, graph, expected_mallocs, expected_calls):
-        count_mallocs = 0
-        count_calls = 0
-        for node in graph.iterblocks():
-                for op in node.operations:
-                    if op.opname == 'malloc':
-                        count_mallocs += 1
-                    if op.opname == 'direct_call':
-                        count_calls += 1
-        assert count_mallocs == expected_mallocs
-        assert count_calls == expected_calls
-    check_malloc_removed = classmethod(check_malloc_removed)
-
-    def check(self, fn, signature, args, expected_result,
-              expected_mallocs=0, expected_calls=0):
-        t = TranslationContext()
-        self.translator = t
-        t.buildannotator().build_types(fn, signature)
-        t.buildrtyper().specialize()
-        graph = graphof(t, fn)
-        if option.view:
-            t.view()
-        self.original_graph_count = len(t.graphs)
-        # to detect broken intermediate graphs,
-        # we do the loop ourselves instead of calling remove_simple_mallocs()
-        maxiter = 100
-        mallocv = MallocVirtualizer(t.graphs, t.rtyper, verbose=True)
-        while True:
-            progress = mallocv.remove_mallocs_once()
-            if progress and option.view:
-                t.view()
-            t.checkgraphs()
-            if expected_result is not DONT_CHECK_RESULT:
-                interp = LLInterpreter(t.rtyper)
-                if not isinstance(expected_result, CHECK_RAISES):
-                    res = interp.eval_graph(graph, args)
-                    assert res == expected_result
-                else:
-                    excinfo = py.test.raises(LLException,
-                                             interp.eval_graph, graph, args)
-                    assert expected_result.excname in str(excinfo.value)
-            if not progress:
-                break
-            maxiter -= 1
-            assert maxiter > 0, "infinite loop?"
-        self.check_malloc_removed(graph, expected_mallocs, expected_calls)
-        return graph
-
-    def test_fn1(self):
-        def fn1(x, y):
-            if x > 0:
-                t = x+y, x-y
-            else:
-                t = x-y, x+y
-            s, d = t
-            return s*d
-        graph = self.check(fn1, [int, int], [15, 10], 125)
-        insns = summary(graph)
-        assert insns['int_mul'] == 1
-
-    def test_aliasing1(self):
-        A = lltype.GcStruct('A', ('x', lltype.Signed))
-        def fn1(x):
-            a1 = lltype.malloc(A)
-            a1.x = 123
-            if x > 0:
-                a2 = a1
-            else:
-                a2 = lltype.malloc(A)
-                a2.x = 456
-            a1.x += 1
-            return a2.x
-        self.check(fn1, [int], [3], 124)
-        self.check(fn1, [int], [-3], 456)
-
-    def test_direct_call(self):
-        def g(t):
-            a, b = t
-            return a * b
-        def f(x):
-            return g((x+1, x-1))
-        graph = self.check(f, [int], [10], 99,
-                           expected_calls=1)     # not inlined
-
-    def test_direct_call_mutable_simple(self):
-        A = lltype.GcStruct('A', ('x', lltype.Signed))
-        def g(a):
-            a.x += 1
-        def f(x):
-            a = lltype.malloc(A)
-            a.x = x
-            g(a)
-            return a.x
-        graph = self.check(f, [int], [41], 42,
-                           expected_calls=0)     # no more call, inlined
-
-    def test_direct_call_mutable_retval(self):
-        A = lltype.GcStruct('A', ('x', lltype.Signed))
-        def g(a):
-            a.x += 1
-            return a.x * 100
-        def f(x):
-            a = lltype.malloc(A)
-            a.x = x
-            y = g(a)
-            return a.x + y
-        graph = self.check(f, [int], [41], 4242,
-                           expected_calls=0)     # no more call, inlined
-
-    def test_direct_call_mutable_ret_virtual(self):
-        A = lltype.GcStruct('A', ('x', lltype.Signed))
-        def g(a):
-            a.x += 1
-            return a
-        def f(x):
-            a = lltype.malloc(A)
-            a.x = x
-            b = g(a)
-            return a.x + b.x
-        graph = self.check(f, [int], [41], 84,
-                           expected_calls=0)     # no more call, inlined
-
-    def test_direct_call_mutable_lastref(self):
-        A = lltype.GcStruct('A', ('x', lltype.Signed))
-        def g(a):
-            a.x *= 10
-            return a.x
-        def f(x):
-            a = lltype.malloc(A)
-            a.x = x
-            y = g(a)
-            return x - y
-        graph = self.check(f, [int], [5], -45,
-                           expected_calls=1)     # not inlined
-
-    def test_direct_call_ret_virtual(self):
-        A = lltype.GcStruct('A', ('x', lltype.Signed))
-        prebuilt_a = lltype.malloc(A)
-        def g(a):
-            prebuilt_a.x += a.x
-            return a
-        def f(n):
-            prebuilt_a.x = n
-            a = lltype.malloc(A)
-            a.x = 2
-            a = g(a)
-            return prebuilt_a.x * a.x
-        graph = self.check(f, [int], [19], 42,
-                           expected_calls=0)     # inlined
-
-    def test_direct_call_unused_arg(self):
-        A = lltype.GcStruct('A', ('x', lltype.Signed))
-        prebuilt_a = lltype.malloc(A)
-        def g(a, unused):
-            return a.x
-        def f(n):
-            a = lltype.malloc(A)
-            a.x = 15
-            return g(a, n)
-        graph = self.check(f, [int], [42], 15,
-                           expected_calls=1)     # not inlined
-
-    def test_raises_simple(self):
-        class MyExc(Exception):
-            pass
-        def f(n):
-            if n < 3:
-                e = MyExc()
-                e.n = n
-                raise e
-            return n
-        self.check(f, [int], [5], 5, expected_mallocs=1)
-        self.check(f, [int], [-5], CHECK_RAISES("MyExc"), expected_mallocs=1)
-
-    def test_catch_simple(self):
-        class A:
-            pass
-        class E(Exception):
-            def __init__(self, n):
-                self.n = n
-        def g(n):
-            if n < 0:
-                raise E(n)
-        def f(n):
-            a = A()
-            a.n = 10
-            try:
-                g(n)       # this call should not be inlined
-            except E as e:
-                a.n = e.n
-            return a.n
-        self.check(f, [int], [15], 10, expected_calls=1)
-        self.check(f, [int], [-15], -15, expected_calls=1)
-
-    def test_raise_catch(self):
-        class A:
-            pass
-        class E(Exception):
-            def __init__(self, n):
-                self.n = n
-        def f(n):
-            a = A()
-            e1 = E(n)
-            try:
-                raise e1
-            except E as e:
-                a.n = e.n
-            return a.n
-        self.check(f, [int], [15], 15)
-
-    def test_raising_op(self):
-        class A:
-            pass
-        def f(n):
-            a = A()
-            a.n = n
-            try:
-                a.n = ovfcheck(a.n + 1)
-            except OverflowError:
-                return -42
-            return a.n
-        self.check(f, [int], [19], 20)
-        self.check(f, [int], [sys.maxint], -42)
-
-    def test_raises_through_spec_graph(self):
-        class A:
-            pass
-        def g(a):
-            if a.n < 0:
-                raise ValueError
-        def f(n):
-            a = A()
-            a.n = n
-            g(a)
-            return a.n
-        self.check(f, [int], [19], 19,
-                   expected_calls=1)
-        self.check(f, [int], [-19], CHECK_RAISES("ValueError"),
-                   expected_calls=1)
-
-    def test_raises_through_inlining(self):
-        class A:
-            pass
-        def g(a):
-            a.n -= 1
-            if a.n < 0:
-                raise ValueError
-        def f(n):
-            a = A()
-            a.n = n
-            g(a)
-            return a.n
-        self.check(f, [int], [19], 18)
-        self.check(f, [int], [-19], CHECK_RAISES("ValueError"))
-
-    def test_call_raise_catch(self):
-        class A:
-            pass
-        def g(a):
-            a.n -= 1
-            if a.n <= 0:
-                raise StopIteration
-            return a.n * 10
-        def f(n):
-            a = A()
-            a.n = n
-            total = 0
-            try:
-                while True:
-                    total += g(a)
-            except StopIteration:
-                pass
-            return total
-        graph = self.check(f, [int], [11], 550,
-                           expected_calls=0)     # inlined
-
-    def test_call_raise_catch_inspect(self):
-        class A:
-            pass
-        class E(Exception):
-            def __init__(self, n):
-                self.n = n
-        def g(a):
-            a.n -= 1
-            if a.n < 0:
-                raise E(a.n * 10)
-        def f(n):
-            a = A()
-            a.n = n
-            try:
-                g(a)       # this call should be inlined
-            except E as e:
-                a.n = e.n
-            return a.n
-        self.check(f, [int], [15], 14, expected_calls=0)
-        self.check(f, [int], [-15], -160, expected_calls=0)
-
-    def test_fn2(self):
-        class T:
-            pass
-        def fn2(x, y):
-            t = T()
-            t.x = x
-            t.y = y
-            if x > 0:
-                return t.x + t.y
-            else:
-                return t.x - t.y
-        self.check(fn2, [int, int], [-6, 7], -13)
-
-    def test_fn3(self):
-        def fn3(x):
-            a, ((b, c), d, e) = x+1, ((x+2, x+3), x+4, x+5)
-            return a+b+c+d+e
-        self.check(fn3, [int], [10], 65)
-
-    def test_fn4(self):
-        class A:
-            pass
-        class B(A):
-            pass
-        def fn4(i):
-            a = A()
-            b = B()
-            a.b = b
-            b.i = i
-            return a.b.i
-        self.check(fn4, [int], [42], 42)
-
-    def test_fn5(self):
-        class A:
-            attr = 666
-        class B(A):
-            attr = 42
-        def fn5():
-            b = B()
-            return b.attr
-        self.check(fn5, [], [], 42)
-
-    def test_aliasing(self):
-        class A:
-            pass
-        def fn6(n):
-            a1 = A()
-            a1.x = 5
-            a2 = A()
-            a2.x = 6
-            if n > 0:
-                a = a1
-            else:
-                a = a2
-            a.x = 12
-            return a1.x
-        self.check(fn6, [int], [1], 12)
-
-    def test_with__del__(self):
-        class A(object):
-            def __del__(self):
-                pass
-        def fn7():
-            A()
-        self.check(fn7, [], [], None, expected_mallocs=1)  # don't remove
-
-    def test_call_to_allocating(self):
-        class A:
-            pass
-        def g(n):
-            a = A()
-            a.x = n
-            a.y = n + 1
-            return a
-        def fn8(n):
-            a = g(n)
-            return a.x * a.y
-        self.check(fn8, [int], [6], 42, expected_calls=0)  # inlined
-
-    def test_many_calls_to_allocating(self):
-        class A:
-            pass
-        def g(n):
-            a = A()
-            a.x = n
-            return a
-        def h(n):
-            a = g(n)
-            a.y = n
-            return a
-        def i(n):
-            a = h(n)
-            a.y += 1
-            return a
-        def fn9(n):
-            a = i(n)
-            return a.x * a.y
-        self.check(fn9, [int], [6], 42, expected_calls=0)  # inlined
-
-    def test_remove_for_in_range(self):
-        def fn10(n):
-            total = 0
-            for i in range(n):
-                total += i
-            return total
-        self.check(fn10, [int], [10], 45)
-
-    def test_recursion_spec(self):
-        class A:
-            pass
-        def make_chain(n):
-            a = A()
-            if n >= 0:
-                a.next = make_chain(n-1)
-                a.value = a.next.value + n
-            else:
-                a.value = 0
-            return a
-        def fn11(n):
-            return make_chain(n).value
-        self.check(fn11, [int], [10], 55,
-                   expected_calls=1)
-
-    def test_recursion_inlining(self):
-        class A:
-            pass
-        def make_chain(a, n):
-            if n >= 0:
-                a.next = A()
-                make_chain(a.next, n-1)
-                a.value = a.next.value + n
-            else:
-                a.value = 0
-        def fn12(n):
-            a = A()
-            make_chain(a, n)
-            return a.value
-        self.check(fn12, [int], [10], 55,
-                   expected_mallocs=1, expected_calls=1)
-
-    def test_constfold_exitswitch(self):
-        class A:
-            pass
-        def fn13(n):
-            a = A()
-            if lloperation.llop.same_as(lltype.Bool, True):
-                a.n = 4
-            else:
-                a.n = -13
-            return a.n
-        self.check(fn13, [int], [10], 4)
-
-    def test_constfold_indirect_call(self):
-        F = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed))
-        class A:
-            pass
-        def h1(n):
-            return n - 1
-        def fn16(n):
-            a = A()
-            a.n = n
-            h = llhelper(F, h1)
-            h2 = lloperation.llop.same_as(F, h)
-            return h2(a.n)
-        self.check(fn16, [int], [10], 9, expected_calls=1)
-
-    def test_bug_on_links_to_return(self):
-        class A:
-            pass
-        def h1(n):
-            return n - 1
-        def h2(n):
-            return n - 2
-        def g(a):
-            a.n += 1
-            if a.n > 5:
-                return h1
-            else:
-                return h2
-        def fn15(n):
-            a = A()
-            a.n = n
-            m = g(a)(n)
-            return a.n * m
-        assert fn15(10) == 99
-        self.check(fn15, [int], [10], 99)
-
-    def test_preserve_annotations_on_graph(self):
-        class A:
-            pass
-        def fn14(n):
-            a = A()
-            a.n = n + 1
-            return a.n
-        graph = self.check(fn14, [int], [10], 11)
-        annotator = self.translator.annotator
-        assert annotator.binding(graph.getargs()[0]).knowntype is int
-        assert annotator.binding(graph.getreturnvar()).knowntype is int
-
-    def test_double_spec_order(self):
-        class A:
-            pass
-        def g(a1, a2):
-            return a1.x - a2.y
-        #
-        def fn17():
-            a1 = A(); a2 = A()
-            a1.x = 5; a1.y = 6; a2.x = 7; a2.y = 8
-            n1 = g(a1, a2)
-            #
-            a1 = A(); a2 = A()
-            a1.x = 50; a1.y = 60; a2.x = 70; a2.y = 80
-            n2 = g(a2, a1)
-            #
-            return n1 * n2
-        #
-        assert fn17() == -30
-        self.check(fn17, [], [], -30, expected_calls=2)
-        extra_graphs = len(self.translator.graphs) - self.original_graph_count
-        assert extra_graphs <= 3     # g(Virtual, Runtime)
-                                     # g(Runtime, Virtual)
-                                     # g(Virtual, Virtual)
-
-
-    def test_getsubstruct(self):
-        SMALL = lltype.Struct('SMALL', ('x', lltype.Signed))
-        BIG = lltype.GcStruct('BIG', ('z', lltype.Signed), ('s', SMALL))
-
-        def fn(n1, n2):
-            b = lltype.malloc(BIG)
-            b.z = n1
-            b.s.x = n2
-            return b.z - b.s.x
-
-        self.check(fn, [int, int], [100, 58], 42,
-                   expected_mallocs=1)   # no support for interior structs
-
-    def test_fixedsizearray(self):
-        A = lltype.FixedSizeArray(lltype.Signed, 3)
-        S = lltype.GcStruct('S', ('a', A))
-
-        def fn(n1, n2):
-            s = lltype.malloc(S)
-            a = s.a
-            a[0] = n1
-            a[2] = n2
-            return a[0]-a[2]
-
-        self.check(fn, [int, int], [100, 42], 58,
-                   expected_mallocs=1)   # no support for interior arrays
-
-    def test_wrapper_cannot_be_removed(self):
-        SMALL = lltype.OpaqueType('SMALL')
-        BIG = lltype.GcStruct('BIG', ('z', lltype.Signed), ('s', SMALL))
-
-        def g(small):
-            return -1
-        def fn():
-            b = lltype.malloc(BIG)
-            g(b.s)
-
-        self.check(fn, [], [], None,
-                   expected_mallocs=1,   # no support for interior opaques
-                   expected_calls=1)
-
-    def test_direct_fieldptr(self):
-        py.test.skip("llptr support not really useful any more")
-        S = lltype.GcStruct('S', ('x', lltype.Signed))
-
-        def fn():
-            s = lltype.malloc(S)
-            s.x = 11
-            p = lltype.direct_fieldptr(s, 'x')
-            return p[0]
-
-        self.check(fn, [], [], 11)
-
-    def test_direct_fieldptr_2(self):
-        py.test.skip("llptr support not really useful any more")
-        T = lltype.GcStruct('T', ('z', lltype.Signed))
-        S = lltype.GcStruct('S', ('t', T),
-                                 ('x', lltype.Signed),
-                                 ('y', lltype.Signed))
-        def fn():
-            s = lltype.malloc(S)
-            s.x = 10
-            s.t.z = 1
-            px = lltype.direct_fieldptr(s, 'x')
-            py = lltype.direct_fieldptr(s, 'y')
-            pz = lltype.direct_fieldptr(s.t, 'z')
-            py[0] = 31
-            return px[0] + s.y + pz[0]
-
-        self.check(fn, [], [], 42)
-
-    def test_getarraysubstruct(self):
-        py.test.skip("llptr support not really useful any more")
-        U = lltype.Struct('U', ('n', lltype.Signed))
-        for length in [1, 2]:
-            S = lltype.GcStruct('S', ('a', lltype.FixedSizeArray(U, length)))
-            for index in range(length):
-
-                def fn():
-                    s = lltype.malloc(S)
-                    s.a[index].n = 12
-                    return s.a[index].n
-                self.check(fn, [], [], 12)
-
-    def test_ptr_nonzero(self):
-        S = lltype.GcStruct('S')
-        def fn():
-            s = lltype.malloc(S)
-            return lloperation.llop.ptr_nonzero(lltype.Bool, s)
-        self.check(fn, [], [], True, expected_mallocs=0)
-
-    def test_ptr_iszero(self):
-        S = lltype.GcStruct('S')
-        def fn():
-            s = lltype.malloc(S)
-            return lloperation.llop.ptr_iszero(lltype.Bool, s)
-        self.check(fn, [], [], False, expected_mallocs=0)
-
-    def test_ptr_eq_null_left(self):
-        S = lltype.GcStruct('S')
-        def fn():
-            s = lltype.malloc(S)
-            null = lltype.nullptr(S)
-            return lloperation.llop.ptr_eq(lltype.Bool, s, null)
-        self.check(fn, [], [], False, expected_mallocs=0)
-
-    def test_ptr_ne_null_left(self):
-        S = lltype.GcStruct('S')
-        def fn():
-            s = lltype.malloc(S)
-            null = lltype.nullptr(S)
-            return lloperation.llop.ptr_ne(lltype.Bool, s, null)
-        self.check(fn, [], [], True, expected_mallocs=0)
-
-    def test_ptr_eq_null_right(self):
-        S = lltype.GcStruct('S')
-        def fn():
-            s = lltype.malloc(S)
-            null = lltype.nullptr(S)
-            return lloperation.llop.ptr_eq(lltype.Bool, null, s)
-        self.check(fn, [], [], False, expected_mallocs=0)
-
-    def test_ptr_ne_null_right(self):
-        S = lltype.GcStruct('S')
-        def fn():
-            s = lltype.malloc(S)
-            null = lltype.nullptr(S)
-            return lloperation.llop.ptr_ne(lltype.Bool, null, s)
-        self.check(fn, [], [], True, expected_mallocs=0)
-
-    def test_ptr_eq_same_struct(self):
-        S = lltype.GcStruct('S')
-        def fn():
-            s1 = lltype.malloc(S)
-            return lloperation.llop.ptr_eq(lltype.Bool, s1, s1)
-        self.check(fn, [], [], True, expected_mallocs=0)
-
-    def test_ptr_ne_same_struct(self):
-        S = lltype.GcStruct('S')
-        def fn():
-            s1 = lltype.malloc(S)
-            return lloperation.llop.ptr_ne(lltype.Bool, s1, s1)
-        self.check(fn, [], [], False, expected_mallocs=0)
-
-    def test_ptr_eq_diff_struct(self):
-        S = lltype.GcStruct('S')
-        def fn():
-            s1 = lltype.malloc(S)
-            s2 = lltype.malloc(S)
-            return lloperation.llop.ptr_eq(lltype.Bool, s1, s2)
-        self.check(fn, [], [], False, expected_mallocs=0)
-
-    def test_ptr_ne_diff_struct(self):
-        S = lltype.GcStruct('S')
-        def fn():
-            s1 = lltype.malloc(S)
-            s2 = lltype.malloc(S)
-            return lloperation.llop.ptr_ne(lltype.Bool, s1, s2)
-        self.check(fn, [], [], True, expected_mallocs=0)
-
-    def test_substruct_not_accessed(self):
-        py.test.skip("llptr support not really useful any more")
-        SMALL = lltype.Struct('SMALL', ('x', lltype.Signed))
-        BIG = lltype.GcStruct('BIG', ('z', lltype.Signed), ('s', SMALL))
-        def fn():
-            x = lltype.malloc(BIG)
-            while x.z < 10:    # makes several blocks
-                x.z += 3
-            return x.z
-        self.check(fn, [], [], 12)
-
-    def test_union(self):
-        py.test.skip("llptr support not really useful any more")
-        UNION = lltype.Struct('UNION', ('a', lltype.Signed), ('b', lltype.Signed),
-                              hints = {'union': True})
-        BIG = lltype.GcStruct('BIG', ('u1', UNION), ('u2', UNION))
-        def fn():
-            x = lltype.malloc(BIG)
-            x.u1.a = 3
-            x.u2.b = 6
-            return x.u1.b * x.u2.a
-        self.check(fn, [], [], DONT_CHECK_RESULT)
-
-    def test_nested_struct(self):
-        S = lltype.GcStruct("S", ('x', lltype.Signed))
-        T = lltype.GcStruct("T", ('s', S))
-        def f(x):
-            t = lltype.malloc(T)
-            s = t.s
-            if x:
-                s.x = x
-            return t.s.x + s.x
-        graph = self.check(f, [int], [42], 2 * 42)
-
-    def test_interior_ptr(self):
-        py.test.skip("llptr support not really useful any more")
-        S = lltype.Struct("S", ('x', lltype.Signed))
-        T = lltype.GcStruct("T", ('s', S))
-        def f(x):
-            t = lltype.malloc(T)
-            t.s.x = x
-            return t.s.x
-        graph = self.check(f, [int], [42], 42)
-
-    def test_interior_ptr_with_index(self):
-        py.test.skip("llptr support not really useful any more")
-        S = lltype.Struct("S", ('x', lltype.Signed))
-        T = lltype.GcArray(S)
-        def f(x):
-            t = lltype.malloc(T, 1)
-            t[0].x = x
-            return t[0].x
-        graph = self.check(f, [int], [42], 42)
-
-    def test_interior_ptr_with_field_and_index(self):
-        py.test.skip("llptr support not really useful any more")
-        S = lltype.Struct("S", ('x', lltype.Signed))
-        T = lltype.GcStruct("T", ('items', lltype.Array(S)))
-        def f(x):
-            t = lltype.malloc(T, 1)
-            t.items[0].x = x
-            return t.items[0].x
-        graph = self.check(f, [int], [42], 42)
-
-    def test_interior_ptr_with_index_and_field(self):
-        py.test.skip("llptr support not really useful any more")
-        S = lltype.Struct("S", ('x', lltype.Signed))
-        T = lltype.Struct("T", ('s', S))
-        U = lltype.GcArray(T)
-        def f(x):
-            u = lltype.malloc(U, 1)
-            u[0].s.x = x
-            return u[0].s.x
-        graph = self.check(f, [int], [42], 42)
-
-    def test_bogus_cast_pointer(self):
-        S = lltype.GcStruct("S", ('x', lltype.Signed))
-        T = lltype.GcStruct("T", ('s', S), ('y', lltype.Signed))
-        def f(x):
-            s = lltype.malloc(S)
-            s.x = 123
-            if x < 0:
-                t = lltype.cast_pointer(lltype.Ptr(T), s)
-                t.y += 1
-            return s.x
-        graph = self.check(f, [int], [5], 123)


More information about the pypy-commit mailing list