[pypy-svn] r32577 - in pypy/branch/kill-keepalives/pypy: objspace/flow rpython rpython/lltypesystem rpython/memory translator/backendopt translator/c
mwh at codespeak.net
mwh at codespeak.net
Fri Sep 22 15:00:30 CEST 2006
Author: mwh
Date: Fri Sep 22 15:00:25 2006
New Revision: 32577
Modified:
pypy/branch/kill-keepalives/pypy/objspace/flow/model.py
pypy/branch/kill-keepalives/pypy/rpython/llinterp.py
pypy/branch/kill-keepalives/pypy/rpython/lltypesystem/lloperation.py
pypy/branch/kill-keepalives/pypy/rpython/memory/gctransform.py
pypy/branch/kill-keepalives/pypy/translator/backendopt/malloc.py
pypy/branch/kill-keepalives/pypy/translator/c/funcgen.py
Log:
yet another and apparently working go at malloc removal of things with
autofree_fields.
this took an obscenely long time to get right.
Modified: pypy/branch/kill-keepalives/pypy/objspace/flow/model.py
==============================================================================
--- pypy/branch/kill-keepalives/pypy/objspace/flow/model.py (original)
+++ pypy/branch/kill-keepalives/pypy/objspace/flow/model.py Fri Sep 22 15:00:25 2006
@@ -42,7 +42,7 @@
class FunctionGraph(object):
- __slots__ = ['startblock', 'returnblock', 'exceptblock', '__dict__']
+ __slots__ = ['startblock', 'returnblock', 'exceptblock', '__dict__', 'needs_more_malloc_removal']
def __init__(self, name, startblock, return_var=None):
self.name = name # function name (possibly mangled already)
@@ -57,6 +57,7 @@
Variable('evalue')]) # exception value
self.exceptblock.operations = ()
self.exceptblock.exits = ()
+ self.needs_more_malloc_removal = False
def getargs(self):
return self.startblock.inputargs
Modified: pypy/branch/kill-keepalives/pypy/rpython/llinterp.py
==============================================================================
--- pypy/branch/kill-keepalives/pypy/rpython/llinterp.py (original)
+++ pypy/branch/kill-keepalives/pypy/rpython/llinterp.py Fri Sep 22 15:00:25 2006
@@ -171,7 +171,6 @@
self.curr_block = None
self.curr_operation_index = 0
self.alloca_objects = []
- self.local_mallocs = []
# _______________________________________________________
# variable setters/getters helpers
@@ -245,8 +244,6 @@
for obj in self.alloca_objects:
#XXX slighly unclean
obj._setobj(None)
- for adr in self.local_mallocs:
- self.heap.raw_free(adr)
return args
finally:
if tracer:
@@ -511,6 +508,7 @@
setattr(obj, finalfield, fieldvalue)
else:
obj[finalfield] = fieldvalue
+ op_bare_setinteriorfield = op_setinteriorfield
def op_getarrayitem(self, array, index):
return array[index]
@@ -526,7 +524,7 @@
args = gc.get_arg_write_barrier(array, index, item)
write_barrier = gc.get_funcptr_write_barrier()
self.op_direct_call(write_barrier, *args)
-
+ op_bare_setarrayitem = op_setarrayitem
def perform_call(self, f, ARGS, args):
fobj = self.llinterpreter.typer.type_system.deref(f)
@@ -751,11 +749,6 @@
assert lltype.typeOf(value) == typ
getattr(addr, str(typ).lower())[offset] = value
- def op_local_raw_malloc(self, size):
- r = self.heap.raw_malloc(size)
- self.local_mallocs.append(r)
- return r
-
# ____________________________________________________________
# Overflow-detecting variants
Modified: pypy/branch/kill-keepalives/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/branch/kill-keepalives/pypy/rpython/lltypesystem/lloperation.py (original)
+++ pypy/branch/kill-keepalives/pypy/rpython/lltypesystem/lloperation.py Fri Sep 22 15:00:25 2006
@@ -329,7 +329,6 @@
# __________ address operations __________
'raw_malloc': LLOp(canraise=(MemoryError,)),
- 'local_raw_malloc': LLOp(canraise=(MemoryError,)),
'raw_malloc_usage': LLOp(sideeffects=False),
'raw_free': LLOp(),
'raw_memclear': LLOp(),
Modified: pypy/branch/kill-keepalives/pypy/rpython/memory/gctransform.py
==============================================================================
--- pypy/branch/kill-keepalives/pypy/rpython/memory/gctransform.py (original)
+++ pypy/branch/kill-keepalives/pypy/rpython/memory/gctransform.py Fri Sep 22 15:00:25 2006
@@ -81,7 +81,6 @@
return
self.seen_graphs[graph] = True
self.links_to_split = {} # link -> vars to pop_alive across the link
- self.seen_local_raw_malloc = False
# for sanity, we need an empty block at the start of the graph
if not starts_with_empty_block(graph):
@@ -108,68 +107,12 @@
if starts_with_empty_block(graph):
remove_empty_startblock(graph)
- if self.seen_local_raw_malloc:
- self.remove_local_mallocs(graph)
-
self.links_to_split = None
v = Variable('vanishing_exc_value')
v.concretetype = self.get_lltype_of_exception_value()
graph.exc_cleanup = (v, self.pop_alive(v))
return is_borrowed # xxx for tests only
- def remove_local_mallocs(self, graph):
- from pypy.translator.backendopt.malloc import compute_lifetimes
- lifetimes = compute_lifetimes(graph)
- for info in lifetimes:
- cand = True
- # XXX do checking
- for cp in info.creationpoints:
- if cp[0] != "op":
- cand = False
- break
- op = cp[2]
- if op.opname != 'local_raw_malloc':
- cand = False
- break
- op.opname = 'raw_malloc'
- if cand:
- for cp in info.creationpoints:
- cp[2].opname = 'raw_malloc'
-
- variables_by_block = {}
- for block, var in info.variables:
- vars = variables_by_block.setdefault(block, set())
- vars.add(var)
- for block, vars in variables_by_block.iteritems():
- links_with_a_var = []
- links_without_a_var = []
- for link in block.exits:
- if vars & set(link.args):
- links_with_a_var.append(link)
- else:
- links_without_a_var.append(link)
- #if not links_without_a_var:
- # continue
- for link in links_without_a_var:
- vv = iter(vars).next()
- for v in vars:
- assert v not in link.args
- if v.concretetype == llmemory.Address:
- vv = v
- newblock = insert_empty_block(None, link)
- link.args.append(vv)
- newblock.inputargs.append(copyvar(None, vv))
- if vv.concretetype != llmemory.Address:
- newv = varoftype(llmemory.Address)
- newblock.operations.append(SpaceOperation(
- "cast_ptr_to_adr", [newblock.inputargs[-1]], newv))
- vv = newv
- else:
- vv = newblock.inputargs[-1]
- newblock.operations.append(SpaceOperation(
- "raw_free", [vv], varoftype(lltype.Void)))
- checkgraph(graph)
-
def compute_borrowed_vars(self, graph):
# the input args are borrowed, and stay borrowed for as long as they
# are not merged with other values.
@@ -328,10 +271,6 @@
replace_setinteriorfield = replace_setfield
replace_setarrayitem = replace_setfield
- def replace_local_raw_malloc(self, op, livevars, block):
- self.seen_local_raw_malloc = True
- return [op]
-
def replace_safe_call(self, op, livevars, block):
return [SpaceOperation("direct_call", op.args, op.result)]
Modified: pypy/branch/kill-keepalives/pypy/translator/backendopt/malloc.py
==============================================================================
--- pypy/branch/kill-keepalives/pypy/translator/backendopt/malloc.py (original)
+++ pypy/branch/kill-keepalives/pypy/translator/backendopt/malloc.py Fri Sep 22 15:00:25 2006
@@ -1,9 +1,9 @@
from pypy.objspace.flow.model import Variable, Constant, Block, Link
-from pypy.objspace.flow.model import SpaceOperation, traverse
+from pypy.objspace.flow.model import SpaceOperation, traverse, checkgraph
from pypy.tool.algo.unionfind import UnionFind
from pypy.rpython.lltypesystem import lltype
-from pypy.translator.simplify import remove_identical_vars
-from pypy.translator.unsimplify import varoftype
+from pypy.translator.simplify import remove_identical_vars, join_blocks
+from pypy.translator.unsimplify import varoftype, insert_empty_block, copyvar
from pypy.translator.backendopt.support import log
from pypy.translator.backendopt.constfold import constant_fold_graph
@@ -87,7 +87,7 @@
def visit(node):
if isinstance(node, Block):
for op in node.operations:
- if op.opname in ("same_as", "cast_pointer", "cast_adr_to_ptr"):
+ if op.opname in ("same_as", "cast_pointer"):
# special-case these operations to identify their input
# and output variables
union(node, op.args[0], node, op.result)
@@ -128,7 +128,7 @@
traverse(visit, graph)
return lifetimes.infos()
-def _try_inline_malloc(info):
+def _try_inline_malloc(graph, info, links_to_split, remove_autofrees=False):
"""Try to inline the mallocs creation and manipulation of the Variables
in the given LifeTime."""
# the values must be only ever created by a "malloc"
@@ -220,18 +220,29 @@
try:
destr_ptr = lltype.getRuntimeTypeInfo(STRUCT)._obj.destructor_funcptr
- if destr_ptr and 'autofree_fields' not in STRUCT._hints:
- return False
- fields_to_raw_free = STRUCT._hints['autofree_fields']
+ if destr_ptr:
+ if 'autofree_fields' in STRUCT._hints:
+ if remove_autofrees:
+ fields_to_raw_free = STRUCT._hints['autofree_fields']
+ assert len(info.creationpoints) == 1
+ else:
+ graph.needs_more_malloc_removal = True
+ return False
+ else:
+ return False
except (ValueError, AttributeError), e:
pass
+ assert not fields_to_raw_free or remove_autofrees
+
# must not remove unions inlined as the only field of a GcStruct
if union_wrapper(STRUCT):
return False
# success: replace each variable with a family of variables (one per field)
+ # print 'removing malloc of', STRUCT, fields_to_raw_free
+
# 'flatnames' is a list of (STRUCTTYPE, fieldname_in_that_struct) that
# describes the list of variables that should replace the single
# malloc'ed pointer variable that we are about to remove. For primitive
@@ -306,6 +317,16 @@
for block, vars in variables_by_block.items():
+ links_without_vars = []
+
+ if fields_to_raw_free:
+ for link in block.exits:
+ if not set(link.args) & set(vars):
+ links_without_vars.append(link)
+## print "link hasn't var", link, 'args:', link.args, 'vars', vars
+## print [(c, c.concretetype) for c in link.args]
+## print [(c, c.concretetype) for c in vars]
+
def flowin(var, newvarsmap, insert_keepalive=False):
# in this 'block', follow where the 'var' goes to and replace
# it by a flattened-out family of variables. This family is given
@@ -341,15 +362,6 @@
S = op.args[0].concretetype.TO
fldnames = [a.value for a in op.args[1:-1]]
key = key_for_field_access(S, *fldnames)
- if len(fldnames) == 1 and fldnames[0] in fields_to_raw_free and not isinstance(op.args[2], Constant):
- # find the raw malloc and replace it with a local_raw_malloc
- # XXX delicate in the extreme!
- i = -1
- while newops[i].opname != 'raw_malloc':
- i -= 1
- newops[i] = SpaceOperation("local_raw_malloc",
- newops[i].args,
- newops[i].result)
assert key in newvarsmap
if key in accessed_substructs:
c_name = Constant('data', lltype.Void)
@@ -423,28 +435,22 @@
count[0] += progress
else:
newops.append(op)
+## if newops[-1:] != [op] and remove_autofrees:
+## newops.append(SpaceOperation("debug_print", [Constant(str(op), lltype.Void)], varoftype(lltype.Void)))
assert block.exitswitch not in vars
- var_exits = False
for link in block.exits:
newargs = []
+ oldargs = link.args[:]
for arg in link.args:
if arg in vars:
newargs += list_newvars()
insert_keepalive = False # kept alive by the link
- var_exits = True
else:
newargs.append(arg)
link.args[:] = newargs
-## if not var_exits:
-## for field in fields_to_raw_free:
-## newops.append(SpaceOperation("flavored_free",
-## [Constant("raw", lltype.Void),
-## newvarsmap[key_for_field_access(STRUCT, field)]],
-## varoftype(lltype.Void)))
-
if insert_keepalive and last_removed_access is not None:
keepalives = []
for v in list_newvars():
@@ -458,6 +464,10 @@
block.operations[:] = newops
+ return newvarsmap
+
+ for_field_freeing_varmap = None
+
# look for variables arriving from outside the block
for var in vars:
if var in block.inputargs:
@@ -465,14 +475,14 @@
newinputargs = block.inputargs[:i]
newvarsmap = {}
for key in flatnames:
- newvar = Variable()
+ newvar = Variable(key[0]._name + ''.join(map(str, key[1:])))
newvar.concretetype = newvarstype[key]
newvarsmap[key] = newvar
newinputargs.append(newvar)
newinputargs += block.inputargs[i+1:]
block.inputargs[:] = newinputargs
assert var not in block.inputargs
- flowin(var, newvarsmap, insert_keepalive=True)
+ for_field_freeing_varmap = flowin(var, newvarsmap, insert_keepalive=True)
# look for variables created inside the block by a malloc
vars_created_here = []
@@ -480,24 +490,50 @@
if op.opname in ("malloc", "zero_malloc") and op.result in vars:
vars_created_here.append(op.result)
for var in vars_created_here:
- flowin(var, newvarsmap=None)
+ newmap = flowin(var, newvarsmap=None)
+ if for_field_freeing_varmap is None:
+ for_field_freeing_varmap = newmap
+
+ if fields_to_raw_free and links:
+ for link in links_without_vars:
+ varstofree = [for_field_freeing_varmap[key_for_field_access(STRUCT, field)] for field in fields_to_raw_free]
+ varstofree = [v for v in varstofree if isinstance(v, Variable)]
+ if varstofree:
+ links_to_split.setdefault(link, []).extend(varstofree)
return count[0]
-def remove_mallocs_once(graph):
+def remove_mallocs_once(graph, remove_autofrees=False):
"""Perform one iteration of malloc removal."""
remove_identical_vars(graph)
lifetimes = compute_lifetimes(graph)
progress = 0
+ links_to_split = {}
for info in lifetimes:
- progress += _try_inline_malloc(info)
+ progress += _try_inline_malloc(graph, info, links_to_split, remove_autofrees)
+ checkgraph(graph)
+ join_blocks(graph)
+ for link, vars_to_free in links_to_split.iteritems():
+ newblock = None
+ for v in vars_to_free:
+ if isinstance(v, Variable):
+ if not newblock:
+ newblock = insert_empty_block(None, link)
+ link.args.append(v)
+ newblock.inputargs.append(copyvar(None, v))
+ newblock.operations.append(SpaceOperation("flavored_free",
+ [Constant("raw", lltype.Void),
+ newblock.inputargs[-1]],
+ varoftype(lltype.Void)))
+## if graph.name == "func" and remove_autofrees and progress:
+## graph.show()
return progress
-def remove_simple_mallocs(graph, callback=None):
+def remove_simple_mallocs(graph, callback=None, remove_autofrees=False):
"""Iteratively remove (inline) the mallocs that can be simplified away."""
tot = 0
while True:
- count = remove_mallocs_once(graph)
+ count = remove_mallocs_once(graph, remove_autofrees)
if count:
log.malloc('%d simple mallocs removed in %r' % (count, graph.name))
constant_fold_graph(graph)
Modified: pypy/branch/kill-keepalives/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/branch/kill-keepalives/pypy/translator/c/funcgen.py (original)
+++ pypy/branch/kill-keepalives/pypy/translator/c/funcgen.py Fri Sep 22 15:00:25 2006
@@ -48,6 +48,9 @@
# apply the exception transformation
if self.db.exctransformer:
self.db.exctransformer.create_exception_handling(self.graph)
+ if graph.needs_more_malloc_removal:
+ from pypy.translator.backendopt.malloc import remove_simple_mallocs
+ remove_simple_mallocs(graph, remove_autofrees=True)
# apply the gc transformation
if self.db.gctransformer:
self.db.gctransformer.transform_graph(self.graph)
@@ -753,6 +756,9 @@
format.append(arg.value.replace('%', '%%'))
continue
format.append('%c')
+ elif T == Void and isinstance(arg, Constant) and isinstance(arg.value, str):
+ format.append(arg.value.replace('%', '%%'))
+ continue
else:
raise Exception("don't know how to debug_print %r" % (T,))
argv.append(self.expr(arg))
More information about the Pypy-commit
mailing list