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

Reply via email to