[pypy-svn] r79842 - in pypy/branch/inline-shadowstack/pypy: config jit/codewriter jit/codewriter/test tool/algo tool/algo/test translator/c translator/c/src
arigo at codespeak.net
arigo at codespeak.net
Mon Dec 6 11:38:38 CET 2010
Author: arigo
Date: Mon Dec 6 11:38:36 2010
New Revision: 79842
Added:
pypy/branch/inline-shadowstack/pypy/tool/algo/regalloc.py
- copied, changed from r79813, pypy/branch/inline-shadowstack/pypy/jit/codewriter/regalloc.py
pypy/branch/inline-shadowstack/pypy/tool/algo/test/test_regalloc.py
Removed:
pypy/branch/inline-shadowstack/pypy/jit/codewriter/regalloc.py
Modified:
pypy/branch/inline-shadowstack/pypy/config/translationoption.py
pypy/branch/inline-shadowstack/pypy/jit/codewriter/codewriter.py
pypy/branch/inline-shadowstack/pypy/jit/codewriter/test/test_regalloc.py
pypy/branch/inline-shadowstack/pypy/translator/c/funcgen.py
pypy/branch/inline-shadowstack/pypy/translator/c/gc.py
pypy/branch/inline-shadowstack/pypy/translator/c/genc.py
pypy/branch/inline-shadowstack/pypy/translator/c/src/mem.h
Log:
First implementation. The results are not great on targetgcbench.
Modified: pypy/branch/inline-shadowstack/pypy/config/translationoption.py
==============================================================================
--- pypy/branch/inline-shadowstack/pypy/config/translationoption.py (original)
+++ pypy/branch/inline-shadowstack/pypy/config/translationoption.py Mon Dec 6 11:38:36 2010
@@ -86,14 +86,16 @@
default=IS_64_BITS, cmdline="--gcremovetypeptr"),
ChoiceOption("gcrootfinder",
"Strategy for finding GC Roots (framework GCs only)",
- ["n/a", "shadowstack", "asmgcc"],
+ ["n/a", "shadowstack", "asmgcc", "inlinestack"],
"shadowstack",
cmdline="--gcrootfinder",
requires={
- "shadowstack": [("translation.gctransformer", "framework")],
- "asmgcc": [("translation.gctransformer", "framework"),
- ("translation.backend", "c")],
- }),
+ "shadowstack": [("translation.gctransformer", "framework")],
+ "asmgcc": [("translation.gctransformer", "framework"),
+ ("translation.backend", "c")],
+ "inlinestack": [("translation.gctransformer", "framework"),
+ ("translation.backend", "c")],
+ }),
# other noticeable options
BoolOption("thread", "enable use of threading primitives",
Modified: pypy/branch/inline-shadowstack/pypy/jit/codewriter/codewriter.py
==============================================================================
--- pypy/branch/inline-shadowstack/pypy/jit/codewriter/codewriter.py (original)
+++ pypy/branch/inline-shadowstack/pypy/jit/codewriter/codewriter.py Mon Dec 6 11:38:36 2010
@@ -1,5 +1,6 @@
from pypy.jit.codewriter import support, heaptracker
-from pypy.jit.codewriter.regalloc import perform_register_allocation
+from pypy.tool.algo.regalloc import perform_register_allocation
+from pypy.jit.metainterp.history import getkind
from pypy.jit.codewriter.flatten import flatten_graph, KINDS
from pypy.jit.codewriter.assembler import Assembler, JitCode
from pypy.jit.codewriter.jtransform import transform_graph
@@ -43,7 +44,8 @@
# step 2: perform register allocation on it
regallocs = {}
for kind in KINDS:
- regallocs[kind] = perform_register_allocation(graph, kind)
+ kind_filter = lambda v: getkind(v.concretetype) == kind
+ regallocs[kind] = perform_register_allocation(graph, kind_filter)
#
# step 3: flatten the graph to produce human-readable "assembler",
# which means mostly producing a linear list of operations and
Modified: pypy/branch/inline-shadowstack/pypy/jit/codewriter/test/test_regalloc.py
==============================================================================
--- pypy/branch/inline-shadowstack/pypy/jit/codewriter/test/test_regalloc.py (original)
+++ pypy/branch/inline-shadowstack/pypy/jit/codewriter/test/test_regalloc.py Mon Dec 6 11:38:36 2010
@@ -1,9 +1,9 @@
import py, sys
from pypy.jit.codewriter import support
-from pypy.jit.codewriter.regalloc import perform_register_allocation
+from pypy.tool.algo.regalloc import perform_register_allocation
from pypy.jit.codewriter.flatten import flatten_graph, ListOfKind
from pypy.jit.codewriter.format import assert_format
-from pypy.jit.metainterp.history import AbstractDescr
+from pypy.jit.metainterp.history import AbstractDescr, getkind
from pypy.objspace.flow.model import Variable, Constant, SpaceOperation
from pypy.objspace.flow.model import FunctionGraph, Block, Link
from pypy.objspace.flow.model import c_last_exception
@@ -18,6 +18,10 @@
self.rtyper = support.annotate(func, values, type_system=type_system)
return self.rtyper.annotator.translator.graphs
+ def perform_register_allocation(self, graph, kind):
+ kind_filter = lambda v: getkind(v.concretetype) == kind
+ return perform_register_allocation(graph, kind_filter)
+
def check_assembler(self, graph, expected, transform=False,
callcontrol=None):
# 'transform' can be False only for simple graphs. More complex
@@ -26,8 +30,8 @@
if transform:
from pypy.jit.codewriter.jtransform import transform_graph
transform_graph(graph, callcontrol=callcontrol)
- regalloc = perform_register_allocation(graph, 'int')
- regalloc2 = perform_register_allocation(graph, 'ref')
+ regalloc = self.perform_register_allocation(graph, 'int')
+ regalloc2 = self.perform_register_allocation(graph, 'ref')
ssarepr = flatten_graph(graph, {'int': regalloc,
'ref': regalloc2})
assert_format(ssarepr, expected)
@@ -36,7 +40,7 @@
def f(a, b):
return a + b
graph = self.make_graphs(f, [5, 6])[0]
- regalloc = perform_register_allocation(graph, 'int')
+ regalloc = self.perform_register_allocation(graph, 'int')
va, vb = graph.startblock.inputargs
vc = graph.startblock.operations[0].result
assert regalloc.getcolor(va) == 0
@@ -50,7 +54,7 @@
a -= 1
return b
graph = self.make_graphs(f, [5, 6])[0]
- regalloc = perform_register_allocation(graph, 'float')
+ regalloc = self.perform_register_allocation(graph, 'float')
# assert did not crash
def test_regalloc_loop(self):
@@ -285,18 +289,18 @@
self.check_assembler(graph, """
residual_call_r_r $<* fn bar>, <Descr>, R[%r0] -> %r1
-live-
- residual_call_ir_r $<* fn g>, <Descr>, I[%i0], R[] -> %r2
+ residual_call_ir_r $<* fn g>, <Descr>, I[%i0], R[] -> %r1
-live-
catch_exception L1
- ref_return %r2
+ ref_return %r1
---
L1:
goto_if_exception_mismatch $<* struct object_vtable>, L2
- ref_copy %r0 -> %r2
+ ref_copy %r0 -> %r1
last_exc_value -> %r0
residual_call_r_r $<* fn foo>, <Descr>, R[%r0] -> %r0
-live-
- ref_return %r2
+ ref_return %r1
---
L2:
reraise
Copied: pypy/branch/inline-shadowstack/pypy/tool/algo/regalloc.py (from r79813, pypy/branch/inline-shadowstack/pypy/jit/codewriter/regalloc.py)
==============================================================================
--- pypy/branch/inline-shadowstack/pypy/jit/codewriter/regalloc.py (original)
+++ pypy/branch/inline-shadowstack/pypy/tool/algo/regalloc.py Mon Dec 6 11:38:36 2010
@@ -2,13 +2,12 @@
from pypy.objspace.flow.model import Variable
from pypy.tool.algo.color import DependencyGraph
from pypy.tool.algo.unionfind import UnionFind
-from pypy.jit.metainterp.history import getkind
-from pypy.jit.codewriter.flatten import ListOfKind
-def perform_register_allocation(graph, kind):
- """Perform register allocation for the Variables of the given 'kind'
- in the 'graph'."""
- regalloc = RegAllocator(graph, kind)
+def perform_register_allocation(graph, kind_filter, identity_op_filter=None):
+ """Perform register allocation for the Variables of the given kind
+ in the graph.
+ """
+ regalloc = RegAllocator(graph, kind_filter, identity_op_filter)
regalloc.make_dependencies()
regalloc.coalesce_variables()
regalloc.find_node_coloring()
@@ -18,12 +17,18 @@
class RegAllocator(object):
DEBUG_REGALLOC = False
- def __init__(self, graph, kind):
+ def __init__(self, graph, kind_filter, identity_op_filter=None):
self.graph = graph
- self.kind = kind
+ self.kind_filter = kind_filter
+ if identity_op_filter is not None:
+ self.identity_op_filter = identity_op_filter
+
+ def identity_op_filter(self, op):
+ return False # default implementation
def make_dependencies(self):
dg = DependencyGraph()
+ uf = UnionFind()
for block in self.graph.iterblocks():
# Compute die_at = {Variable: index_of_operation_with_last_usage}
die_at = dict.fromkeys(block.inputargs, 0)
@@ -31,13 +36,13 @@
for v in op.args:
if isinstance(v, Variable):
die_at[v] = i
- elif isinstance(v, ListOfKind):
+ elif is_iterable(v):
for v1 in v:
if isinstance(v1, Variable):
die_at[v1] = i
if op.result is not None:
- die_at[op.result] = i
- if isinstance(block.exitswitch, tuple):
+ die_at[op.result] = i + 1
+ if is_iterable(block.exitswitch):
for x in block.exitswitch:
die_at.pop(x, None)
else:
@@ -48,10 +53,10 @@
die_at = [(value, key) for (key, value) in die_at.items()]
die_at.sort()
die_at.append((sys.maxint,))
- # Done. XXX the code above this line runs 3 times
- # (for kind in KINDS) to produce the same result...
- livevars = [v for v in block.inputargs
- if getkind(v.concretetype) == self.kind]
+ # Done. XXX if we need to perform register allocation on
+ # the same graph with various 'kinds', the code above this
+ # line runs several times to produce the same result...
+ livevars = [v for v in block.inputargs if self.kind_filter(v)]
# Add the variables of this block to the dependency graph
for i, v in enumerate(livevars):
dg.add_node(v)
@@ -66,17 +71,21 @@
except KeyError:
pass
die_index += 1
- if (op.result is not None and
- getkind(op.result.concretetype) == self.kind):
- dg.add_node(op.result)
- for v in livevars:
- if getkind(v.concretetype) == self.kind:
- dg.add_edge(v, op.result)
+ if op.result is not None and self.kind_filter(op.result):
+ if self.identity_op_filter(op):
+ rep1 = uf.find_rep(op.args[0])
+ _, rep2, _ = uf.union(rep1, op.result)
+ assert rep2 is rep1
+ else:
+ dg.add_node(op.result)
+ for v in livevars:
+ assert self.kind_filter(v)
+ dg.add_edge(uf.find_rep(v), op.result)
livevars.add(op.result)
self._depgraph = dg
+ self._unionfind = uf
def coalesce_variables(self):
- self._unionfind = UnionFind()
pendingblocks = list(self.graph.iterblocks())
while pendingblocks:
block = pendingblocks.pop()
@@ -95,7 +104,7 @@
self._try_coalesce(v, link.target.inputargs[i])
def _try_coalesce(self, v, w):
- if isinstance(v, Variable) and getkind(v.concretetype) == self.kind:
+ if isinstance(v, Variable) and self.kind_filter(v):
dg = self._depgraph
uf = self._unionfind
v0 = uf.find_rep(v)
@@ -126,3 +135,11 @@
self._coloring[key] = col2
elif value == col2:
self._coloring[key] = col1
+
+
+def is_iterable(x):
+ try:
+ iter(x)
+ return True
+ except (TypeError, AttributeError):
+ return False
Added: pypy/branch/inline-shadowstack/pypy/tool/algo/test/test_regalloc.py
==============================================================================
--- (empty file)
+++ pypy/branch/inline-shadowstack/pypy/tool/algo/test/test_regalloc.py Mon Dec 6 11:38:36 2010
@@ -0,0 +1,82 @@
+
+# XXX not enough tests, but see also jit/codewriter/test/test_regalloc.py
+
+import py
+from pypy.tool.algo.regalloc import perform_register_allocation
+from pypy.rpython.test.test_llinterp import gengraph
+from pypy.rpython.lltypesystem import lltype
+from pypy.rlib.jit import hint
+
+
+def test_simple():
+ def f(a, b, c):
+ return (b * c) + a
+ def kind_float(v):
+ return v.concretetype == lltype.Float
+
+ t, rtyper, graph = gengraph(f, [int, int, float])
+ assert [op.opname for op in graph.startblock.operations] == [
+ "cast_int_to_float", # (1) = b
+ "float_mul", # (0) = (1) * (0)
+ "cast_int_to_float", # (1) = a
+ "float_add"] # (0) = (1) + (0)
+
+ regalloc = perform_register_allocation(graph, kind_float)
+
+ py.test.raises(KeyError, regalloc.getcolor, graph.getargs()[0])
+ py.test.raises(KeyError, regalloc.getcolor, graph.getargs()[1])
+
+ ops = graph.startblock.operations
+ assert regalloc.getcolor(graph.getargs()[2]) == 0
+ assert regalloc.getcolor(ops[0].result) == 1
+ assert regalloc.getcolor(ops[1].result) == 0
+ assert regalloc.getcolor(ops[2].result) == 1
+ assert regalloc.getcolor(ops[3].result) == 0
+ assert regalloc.getcolor(graph.getreturnvar()) == 0
+
+def test_unused_result():
+ def f(x):
+ hint(x, blah=True)
+ hint(x, blah=True)
+ hint(x, blah=True)
+ return x
+ def kind_float(v):
+ return v.concretetype == lltype.Float
+
+ t, rtyper, graph = gengraph(f, [lltype.Float])
+ assert [op.opname for op in graph.startblock.operations] == [
+ "hint", # (1) = hint(0)
+ "hint", # (1) = hint(0)
+ "hint"] # (1) = hint(0)
+
+ regalloc = perform_register_allocation(graph, kind_float)
+ ops = graph.startblock.operations
+ assert regalloc.getcolor(graph.getargs()[0]) == 0
+ assert regalloc.getcolor(ops[0].result) == 1
+ assert regalloc.getcolor(ops[1].result) == 1
+ assert regalloc.getcolor(ops[2].result) == 1
+ assert regalloc.getcolor(graph.getreturnvar()) == 0
+
+def test_identity_op():
+ def f(x):
+ y = hint(x, blah=True)
+ z = hint(y, blah=True)
+ t = hint(x, blah=True)
+ return 0
+ def kind_float(v):
+ return v.concretetype == lltype.Float
+ def identity_op(op):
+ return op.opname == 'hint'
+
+ t, rtyper, graph = gengraph(f, [lltype.Float])
+ assert [op.opname for op in graph.startblock.operations] == [
+ "hint", # (0) = hint(0)
+ "hint", # (0) = hint(0)
+ "hint"] # (0) = hint(0)
+
+ regalloc = perform_register_allocation(graph, kind_float, identity_op)
+ ops = graph.startblock.operations
+ assert regalloc.getcolor(graph.getargs()[0]) == 0
+ assert regalloc.getcolor(ops[0].result) == 0
+ assert regalloc.getcolor(ops[1].result) == 0
+ assert regalloc.getcolor(ops[2].result) == 0
Modified: pypy/branch/inline-shadowstack/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/branch/inline-shadowstack/pypy/translator/c/funcgen.py (original)
+++ pypy/branch/inline-shadowstack/pypy/translator/c/funcgen.py Mon Dec 6 11:38:36 2010
@@ -176,6 +176,9 @@
if self.lltypemap(v) is Void and special_case_void:
return '/* nothing */'
else:
+ s = self.gcpolicy.special_ref_name_for_local(v)
+ if s:
+ return s
return LOCALVAR % v.name
elif isinstance(v, Constant):
value = llvalue_from_constant(v)
@@ -190,6 +193,7 @@
def cfunction_declarations(self):
# declare the local variables, excluding the function arguments
+ self.gcpolicy.prepare_declarations_in_function(self)
seen = {}
for a in self.graph.getargs():
seen[a.name] = True
@@ -199,6 +203,8 @@
name = v.name
if name not in seen:
seen[name] = True
+ if self.gcpolicy.special_ref_name_for_local(v):
+ continue
result = cdecl(self.lltypename(v), LOCALVAR % name) + ';'
if self.lltypemap(v) is Void:
continue #result = '/*%s*/' % result
@@ -209,6 +215,8 @@
# ____________________________________________________________
def cfunction_body(self):
+ for line in self.gcpolicy.extra_declarations_in_function(self):
+ yield line
graph = self.graph
yield 'goto block0;' # to avoid a warning "this label is not used"
@@ -232,6 +240,8 @@
retval = self.expr(block.inputargs[0])
if self.exception_policy != "exc_helper":
yield 'RPY_DEBUG_RETURN();'
+ for line in self.gcpolicy.extra_code_at_return(self):
+ yield line
yield 'return %s;' % retval
continue
elif block.exitswitch is None:
@@ -306,7 +316,7 @@
if a2type is Void:
continue
src = self.expr(a1)
- dest = LOCALVAR % a2.name
+ dest = self.expr(a2)
assignments.append((a2typename, dest, src))
for line in gen_assignments(assignments):
yield line
Modified: pypy/branch/inline-shadowstack/pypy/translator/c/gc.py
==============================================================================
--- pypy/branch/inline-shadowstack/pypy/translator/c/gc.py (original)
+++ pypy/branch/inline-shadowstack/pypy/translator/c/gc.py Mon Dec 6 11:38:36 2010
@@ -1,12 +1,12 @@
import sys
-from pypy.objspace.flow.model import Constant
+from pypy.objspace.flow.model import Constant, Variable
from pypy.translator.c.support import cdecl
from pypy.translator.c.node import ContainerNode
from pypy.rpython.lltypesystem.lltype import \
typeOf, Ptr, ContainerType, RttiStruct, \
RuntimeTypeInfo, getRuntimeTypeInfo, top_container
from pypy.rpython.memory.gctransform import \
- refcounting, boehm, framework, asmgcroot
+ refcounting, boehm, framework, asmgcroot, inlinestack
from pypy.rpython.lltypesystem import lltype, llmemory
from pypy.translator.tool.cbuild import ExternalCompilationInfo
@@ -70,6 +70,15 @@
def rtti_type(self):
return ''
+ def prepare_declarations_in_function(self, funcgen):
+ pass
+ def special_ref_name_for_local(self, v):
+ return False
+ def extra_declarations_in_function(self, funcgen):
+ return []
+ def extra_code_at_return(self, funcgen):
+ return []
+
def OP_GC_PUSH_ALIVE_PYOBJ(self, funcgen, op):
expr = funcgen.expr(op.args[0])
if expr == 'NULL':
@@ -384,6 +393,65 @@
def OP_GC_STACK_BOTTOM(self, funcgen, op):
return 'pypy_asm_stack_bottom();'
+class InlineStackFrameworkGcPolicy(FrameworkGcPolicy):
+ transformerclass = inlinestack.InlineStackFrameworkGCTransformer
+
+ def prepare_declarations_in_function(self, funcgen):
+ self.gcvar2index = {} # xxx should be stored on 'funcgen', ideally
+ self.all_gcvars = []
+ for block in funcgen.graph.iterblocks():
+ for op in block.operations:
+ if op.opname == 'gc_push_roots':
+ for v in op.args:
+ if not isinstance(v, Variable):
+ continue
+ assert funcgen.lltypemap(v) is not lltype.Void
+ vname = v.name
+ if vname not in self.gcvar2index:
+ self.gcvar2index[vname] = len(self.all_gcvars)
+ self.all_gcvars.append((funcgen.lltypename(v),
+ vname))
+
+ def special_ref_name_for_local(self, v):
+ if v.name in self.gcvar2index:
+ return 'ref.%s' % v.name
+ return None
+
+ def extra_declarations_in_function(self, funcgen):
+ if self.all_gcvars:
+ yield 'struct {'
+ yield '\tstruct pypy_stackref_s hdr;'
+ assert len(self.all_gcvars) < 32 # XXX fix this limitation
+ for vtype, vname in self.all_gcvars:
+ yield '\t%s;' % cdecl(vtype, vname)
+ yield '} ref;'
+ #
+ yield 'ref.hdr.prev = pypy_stackref;'
+ yield 'pypy_stackref = &ref.hdr;'
+ for argname, v in zip(funcgen.argnames(), funcgen.graph.getargs()):
+ s = self.special_ref_name_for_local(v)
+ if s:
+ yield '%s = %s;' % (s, argname)
+
+ def extra_code_at_return(self, funcgen):
+ if self.all_gcvars:
+ yield 'pypy_stackref = ref.hdr.prev;'
+
+ def OP_GC_PUSH_ROOTS(self, funcgen, op):
+ bitfield = 0
+ vars = []
+ for v in op.args:
+ if isinstance(v, Variable):
+ bitfield |= 1 << self.gcvar2index[v.name]
+ vars.append(v.name)
+ if not self.all_gcvars:
+ assert not vars
+ return ''
+ result = 'ref.hdr.bitfield = %d;' % bitfield
+ if vars:
+ result += ' /* %s */' % (' '.join(vars),)
+ return result
+
name_to_gcpolicy = {
'boehm': BoehmGcPolicy,
@@ -391,6 +459,5 @@
'none': NoneGcPolicy,
'framework': FrameworkGcPolicy,
'framework+asmgcroot': AsmGcRootFrameworkGcPolicy,
+ 'framework+inlinestack': InlineStackFrameworkGcPolicy,
}
-
-
Modified: pypy/branch/inline-shadowstack/pypy/translator/c/genc.py
==============================================================================
--- pypy/branch/inline-shadowstack/pypy/translator/c/genc.py (original)
+++ pypy/branch/inline-shadowstack/pypy/translator/c/genc.py Mon Dec 6 11:38:36 2010
@@ -205,6 +205,8 @@
name = self.config.translation.gctransformer
if self.config.translation.gcrootfinder == "asmgcc":
name = "%s+asmgcroot" % (name,)
+ elif self.config.translation.gcrootfinder == "inlinestack":
+ name = "%s+inlinestack" % (name,)
return gc.name_to_gcpolicy[name]
return self.gcpolicy
Modified: pypy/branch/inline-shadowstack/pypy/translator/c/src/mem.h
==============================================================================
--- pypy/branch/inline-shadowstack/pypy/translator/c/src/mem.h (original)
+++ pypy/branch/inline-shadowstack/pypy/translator/c/src/mem.h Mon Dec 6 11:38:36 2010
@@ -9,6 +9,18 @@
extern long pypy_asm_stackwalk(void*, void*);
#define __gcnoreorderhack __gcmapend
+struct pypy_stackref_s {
+ struct pypy_stackref_s *prev;
+ long bitfield;
+};
+extern struct pypy_stackref_s *pypy_stackref;
+extern void *get_pypy_stackref(void);
+
+#ifndef PYPY_NOT_MAIN_FILE
+struct pypy_stackref_s *pypy_stackref = NULL;
+void *get_pypy_stackref(void) { return pypy_stackref; }
+#endif
+
/* The following pseudo-instruction is used by --gcrootfinder=asmgcc
just after a call to tell gcc to put a GCROOT mark on each gc-pointer
local variable. All such local variables need to go through a "v =
More information about the Pypy-commit
mailing list