Author: Armin Rigo <[email protected]>
Branch: shadowstack-perf-2
Changeset: r84512:54426da3ccd4
Date: 2016-05-18 10:32 +0200
http://bitbucket.org/pypy/pypy/changeset/54426da3ccd4/
Log: Implement the shortcut in walking roots during minor collections by
abusing the bitmask
diff --git a/rpython/memory/gctransform/shadowcolor.py
b/rpython/memory/gctransform/shadowcolor.py
--- a/rpython/memory/gctransform/shadowcolor.py
+++ b/rpython/memory/gctransform/shadowcolor.py
@@ -6,6 +6,7 @@
from rpython.translator.unsimplify import varoftype, insert_empty_block
from rpython.translator.unsimplify import insert_empty_startblock, split_block
from rpython.translator.simplify import join_blocks
+from rpython.rlib.rarithmetic import intmask
from collections import defaultdict
@@ -113,6 +114,7 @@
if not interesting_vars:
return None
regalloc = perform_register_allocation(graph,
interesting_vars.__contains__)
+ assert regalloc.graph is graph
regalloc.find_num_colors()
return regalloc
@@ -127,12 +129,10 @@
return SpaceOperation('gc_restore_root', [c_index, var],
varoftype(lltype.Void))
-def make_bitmask(filled):
+def make_bitmask(filled, graph='?'):
n = filled.count(False)
if n == 0:
return (None, None)
- if n == 1:
- return (filled.index(False), 0)
bitmask = 0
last_index = 0
for i in range(len(filled)):
@@ -141,6 +141,18 @@
last_index = i
bitmask |= 1
assert bitmask & 1
+ if bitmask != intmask(bitmask):
+ raise GCBitmaskTooLong("the graph %r is too complex: cannot create "
+ "a bitmask telling than more than 31/63 "
+ "shadowstack entries are unused" % (graph,))
+ # the mask is always a positive value, but it is replaced by a
+ # negative value during a minor collection root walking. Then,
+ # if the next minor collection finds an already-negative value,
+ # we know we can stop. So that's why we don't include here an
+ # optimization to not re-write a same-valued mask: it is important
+ # to re-write the value, to turn it from potentially negative back
+ # to positive, in order to mark this shadow frame as modified.
+ assert bitmask > 0
return (last_index, bitmask)
@@ -154,7 +166,7 @@
assert not filled[index]
filled[index] = True
yield _gc_save_root(index, v)
- bitmask_index, bitmask = make_bitmask(filled)
+ bitmask_index, bitmask = make_bitmask(filled, regalloc.graph)
if bitmask_index is not None:
# xxx we might in some cases avoid this gc_save_root
# entirely, if we know we're after another gc_push/gc_pop
@@ -504,8 +516,6 @@
# gc_save_root() that writes the bitmask meaning "everything is
# free". Remove such gc_save_root().
bitmask_all_free = (1 << regalloc.numcolors) - 1
- if bitmask_all_free == 1:
- bitmask_all_free = 0
for block in graph.iterblocks():
if block in flagged_blocks:
continue
@@ -533,6 +543,9 @@
# new blocks made by insert_empty_block() earlier
+class GCBitmaskTooLong(Exception):
+ pass
+
class PostProcessCheckError(Exception):
pass
@@ -594,11 +607,11 @@
locsaved[v] = locsaved.get(v, frozenset()).union([num])
continue
bitmask = v.value
- if bitmask != 0:
+ if bitmask != 1:
# cancel any variable that would be saved in any
# position shown by the bitmask, not just 'num'
assert bitmask & 1
- assert bitmask < (2<<num)
+ assert 1 < bitmask < (2<<num)
nummask = [i for i in range(num+1)
if bitmask & (1<<(num-i))]
assert nummask[-1] == num
diff --git a/rpython/memory/gctransform/shadowstack.py
b/rpython/memory/gctransform/shadowstack.py
--- a/rpython/memory/gctransform/shadowstack.py
+++ b/rpython/memory/gctransform/shadowstack.py
@@ -57,27 +57,6 @@
return top
self.decr_stack = decr_stack
- def walk_stack_root(callback, start, end):
- gc = self.gc
- addr = end
- skip = 0
- while addr != start:
- addr -= sizeofaddr
- #XXX reintroduce support for tagged values?
- #if gc.points_to_valid_gc_object(addr):
- # callback(gc, addr)
-
- if skip & 1 == 0:
- content = addr.address[0]
- if content:
- n = llmemory.cast_adr_to_int(content)
- if n & 1 == 0:
- callback(gc, addr) # non-0, non-odd: a regular ptr
- else:
- skip = n # odd number: a skip bitmask
- skip >>= 1
- self.rootstackhook = walk_stack_root
-
self.shadow_stack_pool = ShadowStackPool(gcdata)
rsd = gctransformer.root_stack_depth
if rsd is not None:
@@ -96,9 +75,36 @@
BaseRootWalker.setup_root_walker(self)
def walk_stack_roots(self, collect_stack_root, is_minor=False):
+ gc = self.gc
gcdata = self.gcdata
- self.rootstackhook(collect_stack_root,
- gcdata.root_stack_base, gcdata.root_stack_top)
+ start = gcdata.root_stack_base
+ addr = gcdata.root_stack_top
+ skip = 0
+ while addr != start:
+ addr -= sizeofaddr
+ #XXX reintroduce support for tagged values?
+ #if gc.points_to_valid_gc_object(addr):
+ # callback(gc, addr)
+
+ if skip & 1 == 0:
+ content = addr.address[0]
+ n = llmemory.cast_adr_to_int(content)
+ if n & 1 == 0:
+ if content: # non-0, non-odd: a regular ptr
+ collect_stack_root(gc, addr)
+ else:
+ # odd number: a skip bitmask
+ if n > 0: # initially, an unmarked value
+ if is_minor:
+ newcontent = llmemory.cast_int_to_adr(-n)
+ addr.address[0] = newcontent # mark
+ skip = n
+ else:
+ # a marked value
+ if is_minor:
+ return
+ skip = -n
+ skip >>= 1
def need_thread_support(self, gctransformer, getfn):
from rpython.rlib import rthread # xxx fish
diff --git a/rpython/memory/gctransform/test/test_shadowcolor.py
b/rpython/memory/gctransform/test/test_shadowcolor.py
--- a/rpython/memory/gctransform/test/test_shadowcolor.py
+++ b/rpython/memory/gctransform/test/test_shadowcolor.py
@@ -254,8 +254,7 @@
else:
assert 0 <= index < len(boollist)
assert boollist[index] == False
- if bitmask == 0:
- bitmask = 1
+ assert bitmask >= 1
while bitmask:
if bitmask & 1:
assert index >= 0
@@ -267,6 +266,8 @@
class FakeRegAlloc:
+ graph = '?'
+
def __init__(self, expected_op, **colors):
self.expected_op = expected_op
self.numcolors = len(colors)
@@ -280,14 +281,12 @@
result.append((spaceop.args[0].value, spaceop.args[1]))
return result
-c_NULL = Constant(0, lltype.Signed)
-
def test_expand_one_push_roots():
regalloc = FakeRegAlloc('gc_save_root', a=0, b=1, c=2)
assert regalloc.check(expand_one_push_roots(regalloc, ['a', 'b', 'c'])) ==
[
(0, 'a'), (1, 'b'), (2, 'c')]
assert regalloc.check(expand_one_push_roots(regalloc, ['a', 'c'])) == [
- (0, 'a'), (2, 'c'), (1, c_NULL)]
+ (0, 'a'), (2, 'c'), (1, Constant(0x1, lltype.Signed))]
assert regalloc.check(expand_one_push_roots(regalloc, ['b'])) == [
(1, 'b'), (2, Constant(0x5, lltype.Signed))]
assert regalloc.check(expand_one_push_roots(regalloc, ['a'])) == [
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit