[pypy-commit] pypy shadowstack-no-move-2: Kill and simplify a lot of code

arigo noreply at buildbot.pypy.org
Fri Sep 25 16:38:02 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: shadowstack-no-move-2
Changeset: r79826:3bf64dd0bbef
Date: 2015-09-25 16:38 +0200
http://bitbucket.org/pypy/pypy/changeset/3bf64dd0bbef/

Log:	Kill and simplify a lot of code

diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -902,39 +902,6 @@
                    op.args[0]],
                   resultvar=op.result)
 
-    def gct_gc_shadowstackref_new(self, hop):
-        op = hop.spaceop
-        livevars = self.push_roots(hop)
-        hop.genop("direct_call", [self.root_walker.gc_shadowstackref_new_ptr],
-                  resultvar=op.result)
-        self.pop_roots(hop, livevars)
-
-    def gct_gc_shadowstackref_context(self, hop):
-        op = hop.spaceop
-        hop.genop("direct_call",
-                  [self.root_walker.gc_shadowstackref_context_ptr, op.args[0]],
-                  resultvar=op.result)
-
-    def gct_gc_save_current_state_away(self, hop):
-        op = hop.spaceop
-        hop.genop("direct_call",
-                  [self.root_walker.gc_save_current_state_away_ptr,
-                   op.args[0], op.args[1]])
-
-    def gct_gc_forget_current_state(self, hop):
-        hop.genop("direct_call",
-                  [self.root_walker.gc_forget_current_state_ptr])
-
-    def gct_gc_restore_state_from(self, hop):
-        op = hop.spaceop
-        hop.genop("direct_call",
-                  [self.root_walker.gc_restore_state_from_ptr,
-                   op.args[0]])
-
-    def gct_gc_start_fresh_new_state(self, hop):
-        hop.genop("direct_call",
-                  [self.root_walker.gc_start_fresh_new_state_ptr])
-
     def gct_do_malloc_fixedsize(self, hop):
         # used by the JIT (see rpython.jit.backend.llsupport.gc)
         op = hop.spaceop
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
@@ -219,52 +219,8 @@
                                            minimal_transform=False)
 
     def need_stacklet_support(self, gctransformer, getfn):
-        shadow_stack_pool = self.shadow_stack_pool
-        SHADOWSTACKREF = get_shadowstackref(self, gctransformer)
-
-        def gc_shadowstackref_new():
-            ssref = shadow_stack_pool.allocate(SHADOWSTACKREF)
-            return lltype.cast_opaque_ptr(llmemory.GCREF, ssref)
-
-        def gc_shadowstackref_context(gcref):
-            ssref = lltype.cast_opaque_ptr(lltype.Ptr(SHADOWSTACKREF), gcref)
-            return ssref.context
-
-        def gc_save_current_state_away(gcref, ncontext):
-            ssref = lltype.cast_opaque_ptr(lltype.Ptr(SHADOWSTACKREF), gcref)
-            shadow_stack_pool.save_current_state_away(ssref, ncontext)
-
-        def gc_forget_current_state():
-            shadow_stack_pool.forget_current_state()
-
-        def gc_restore_state_from(gcref):
-            ssref = lltype.cast_opaque_ptr(lltype.Ptr(SHADOWSTACKREF), gcref)
-            shadow_stack_pool.restore_state_from(ssref)
-
-        def gc_start_fresh_new_state():
-            shadow_stack_pool.start_fresh_new_state()
-
-        s_gcref = SomePtr(llmemory.GCREF)
-        s_addr = SomeAddress()
-        self.gc_shadowstackref_new_ptr = getfn(gc_shadowstackref_new,
-                                               [], s_gcref,
-                                               minimal_transform=False)
-        self.gc_shadowstackref_context_ptr = getfn(gc_shadowstackref_context,
-                                                   [s_gcref], s_addr,
-                                                   inline=True)
-        self.gc_save_current_state_away_ptr = getfn(gc_save_current_state_away,
-                                                    [s_gcref, s_addr],
-                                                    annmodel.s_None,
-                                                    inline=True)
-        self.gc_forget_current_state_ptr = getfn(gc_forget_current_state,
-                                                 [], annmodel.s_None,
-                                                 inline=True)
-        self.gc_restore_state_from_ptr = getfn(gc_restore_state_from,
-                                               [s_gcref], annmodel.s_None,
-                                               inline=True)
-        self.gc_start_fresh_new_state_ptr = getfn(gc_start_fresh_new_state,
-                                                  [], annmodel.s_None,
-                                                  inline=True)
+        from rpython.rlib import _stacklet_shadowstack
+        _stacklet_shadowstack.complete_destrptr(gctransformer)
 
 # ____________________________________________________________
 
diff --git a/rpython/rlib/_stacklet_shadowstack.py b/rpython/rlib/_stacklet_shadowstack.py
--- a/rpython/rlib/_stacklet_shadowstack.py
+++ b/rpython/rlib/_stacklet_shadowstack.py
@@ -1,104 +1,176 @@
 from rpython.rlib import _rffi_stacklet as _c
 from rpython.rlib.debug import ll_assert
-from rpython.rtyper.annlowlevel import llhelper
-from rpython.rtyper.lltypesystem import lltype, llmemory
+from rpython.rlib import rgc
+from rpython.rtyper.annlowlevel import llhelper, MixLevelHelperAnnotator
+from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
 from rpython.rtyper.lltypesystem.lloperation import llop
+from rpython.annotator import model as annmodel
+from rpython.rtyper.llannotation import lltype_to_annotation
 
 
-NULL_SUSPSTACK = lltype.nullptr(llmemory.GCREF.TO)
+#
+# A GC wrapper around the C stacklet handles, with additionally a
+# copy of the shadowstack (for all stacklets different than the main)
+#
+STACKLET = lltype.GcStruct('Stacklet',
+                           ('s_handle', _c.handle),
+                           ('s_sscopy', llmemory.Address),
+                           rtti=True)
+STACKLET_PTR = lltype.Ptr(STACKLET)
+NULL_STACKLET = lltype.nullptr(STACKLET)
 
 
+def complete_destrptr(gctransformer):
+    translator = gctransformer.translator
+    mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper)
+    args_s = [lltype_to_annotation(STACKLET_PTR)]
+    s_result = annmodel.s_None
+    destrptr = mixlevelannotator.delayedfunction(stacklet_destructor,
+                                                 args_s, s_result)
+    mixlevelannotator.finish()
+    lltype.attachRuntimeTypeInfo(STACKLET, destrptr=destrptr)
+
+def stacklet_destructor(stacklet):
+    sscopy = stacklet.s_sscopy
+    if sscopy:
+        llmemory.raw_free(sscopy)
+    h = stacklet.s_handle
+    if h:
+        _c.destroy(h)
+
+
+SIZEADDR = llmemory.sizeof(llmemory.Address)
+
+def customtrace(gc, obj, callback, arg):
+    stacklet = llmemory.cast_adr_to_ptr(obj, STACKLET_PTR)
+    sscopy = stacklet.s_sscopy
+    if sscopy:
+        length_bytes = sscopy.signed[0]
+        while length_bytes > 0:
+            addr = sscopy + length_bytes
+            gc._trace_callback(callback, arg, addr)
+            length_bytes -= SIZEADDR
+lambda_customtrace = lambda: customtrace
+
+def sscopy_detach_shadow_stack():
+    base = llop.gc_adr_of_root_stack_base(llmemory.Address).address[0]
+    top = llop.gc_adr_of_root_stack_top(llmemory.Address).address[0]
+    length_bytes = top - base
+    result = llmemory.raw_malloc(SIZEADDR + length_bytes)
+    if result:
+        result.signed[0] = length_bytes
+        llmemory.raw_memcopy(base, result + SIZEADDR, length_bytes)
+        llop.gc_adr_of_root_stack_top(llmemory.Address).address[0] = base
+    return result
+
+def sscopy_attach_shadow_stack(sscopy):
+    base = llop.gc_adr_of_root_stack_base(llmemory.Address).address[0]
+    ll_assert(llop.gc_adr_of_root_stack_top(llmemory.Address).address[0]==base,
+              "attach_shadow_stack: ss is not empty?")
+    length_bytes = sscopy.signed[0]
+    llmemory.raw_memcopy(sscopy + SIZEADDR, base, length_bytes)
+    llop.gc_adr_of_root_stack_top(llmemory.Address).address[0] = (
+        base + length_bytes)
+    llmemory.raw_free(sscopy)
+
+def alloc_stacklet():
+    new_stacklet = lltype.malloc(STACKLET)
+    new_stacklet.s_handle = _c.null_handle
+    return new_stacklet
+
+def attach_handle_on_stacklet(stacklet, h):
+    if not h:
+        raise MemoryError
+    elif _c.is_empty_handle(h):
+        ll_assert(gcrootfinder.sscopy == llmemory.NULL,
+                  "empty_handle but sscopy != NULL")
+        return NULL_STACKLET
+    else:
+        # This is a return that gave us a real handle.  Store it.
+        stacklet.s_handle = h
+        stacklet.s_sscopy = gcrootfinder.sscopy
+        ll_assert(gcrootfinder.sscopy != llmemory.NULL,
+                  "!empty_handle but sscopy == NULL")
+        gcrootfinder.sscopy = llmemory.NULL
+        llop.gc_writebarrier(lltype.Void, llmemory.cast_ptr_to_adr(stacklet))
+        return stacklet
+
+def consume_stacklet(stacklet):
+    h = stacklet.s_handle
+    ll_assert(bool(h), "consume_stacklet: null handle")
+    stacklet.s_handle = _c.null_handle
+    stacklet.s_sscopy = llmemory.NULL
+    return h
+
 def _new_callback(h, arg):
-    # We still have the old shadowstack active at this point; save it
-    # away, and start a fresh new one
-    oldsuspstack = gcrootfinder.oldsuspstack
-    h = llmemory.cast_ptr_to_adr(h)
-    llop.gc_save_current_state_away(lltype.Void,
-                                    oldsuspstack, h)
-    llop.gc_start_fresh_new_state(lltype.Void)
-    gcrootfinder.oldsuspstack = NULL_SUSPSTACK
+    # There is a fresh stacklet object waiting on the gcrootfinder,
+    # so populate it with data that represents the parent suspended
+    # stacklet and detach the stacklet object from gcrootfinder.
+    stacklet = gcrootfinder.fresh_stacklet
+    gcrootfinder.fresh_stacklet = NULL_STACKLET
+    ll_assert(stacklet != NULL_STACKLET, "_new_callback: NULL #1")
+    stacklet = attach_handle_on_stacklet(stacklet, h)
+    ll_assert(stacklet != NULL_STACKLET, "_new_callback: NULL #2")
     #
-    newsuspstack = gcrootfinder.callback(oldsuspstack, arg)
+    # Call the main function provided by the (RPython) user.
+    stacklet = gcrootfinder.runfn(stacklet, arg)
     #
-    # Finishing this stacklet.
-    gcrootfinder.oldsuspstack = NULL_SUSPSTACK
-    gcrootfinder.newsuspstack = newsuspstack
-    h = llop.gc_shadowstackref_context(llmemory.Address, newsuspstack)
-    return llmemory.cast_adr_to_ptr(h, _c.handle)
+    # Here, 'stacklet' points to the target stacklet to which we want
+    # to jump to next.  Read the 'handle' and forget about the
+    # stacklet object.
+    gcrootfinder.sscopy = llmemory.NULL
+    return consume_stacklet(stacklet)
 
-def prepare_old_suspstack():
-    if not gcrootfinder.oldsuspstack:   # else reuse the one still there
-        _allocate_old_suspstack()
+def _new(thread_handle, arg):
+    # No shadowstack manipulation here (no usage of gc references)
+    sscopy = sscopy_detach_shadow_stack()
+    gcrootfinder.sscopy = sscopy
+    if not sscopy:
+        return _c.null_handle
+    h = _c.new(thread_handle, llhelper(_c.run_fn, _new_callback), arg)
+    sscopy_attach_shadow_stack(sscopy)
+    return h
+_new._dont_inline_ = True
 
-def _allocate_old_suspstack():
-    suspstack = llop.gc_shadowstackref_new(llmemory.GCREF)
-    gcrootfinder.oldsuspstack = suspstack
-_allocate_old_suspstack._dont_inline_ = True
-
-def get_result_suspstack(h):
-    # Now we are in the target, after the switch() or the new().
-    # Note that this whole module was carefully written in such a way as
-    # not to invoke pushing/popping things off the shadowstack at
-    # unexpected moments...
-    oldsuspstack = gcrootfinder.oldsuspstack
-    newsuspstack = gcrootfinder.newsuspstack
-    gcrootfinder.oldsuspstack = NULL_SUSPSTACK
-    gcrootfinder.newsuspstack = NULL_SUSPSTACK
-    if not h:
-        raise MemoryError
-    # We still have the old shadowstack active at this point; save it
-    # away, and restore the new one
-    if oldsuspstack:
-        ll_assert(not _c.is_empty_handle(h),"unexpected empty stacklet handle")
-        h = llmemory.cast_ptr_to_adr(h)
-        llop.gc_save_current_state_away(lltype.Void, oldsuspstack, h)
-    else:
-        ll_assert(_c.is_empty_handle(h),"unexpected non-empty stacklet handle")
-        llop.gc_forget_current_state(lltype.Void)
-    #
-    llop.gc_restore_state_from(lltype.Void, newsuspstack)
-    #
-    # From this point on, 'newsuspstack' is consumed and done, its
-    # shadow stack installed as the current one.  It should not be
-    # used any more.  For performance, we avoid it being deallocated
-    # by letting it be reused on the next switch.
-    gcrootfinder.oldsuspstack = newsuspstack
-    # Return.
-    return oldsuspstack
+def _switch(h):
+    # No shadowstack manipulation here (no usage of gc references)
+    sscopy = sscopy_detach_shadow_stack()
+    gcrootfinder.sscopy = sscopy
+    if not sscopy:
+        return _c.null_handle
+    h = _c.switch(h)
+    sscopy_attach_shadow_stack(sscopy)
+    return h
+_switch._dont_inline_ = True
 
 
 class StackletGcRootFinder(object):
-    def new(thrd, callback, arg):
-        gcrootfinder.callback = callback
-        thread_handle = thrd._thrd
-        prepare_old_suspstack()
-        h = _c.new(thread_handle, llhelper(_c.run_fn, _new_callback), arg)
-        return get_result_suspstack(h)
-    new._dont_inline_ = True
-    new = staticmethod(new)
-
-    def switch(suspstack):
-        # suspstack has a handle to target, i.e. where to switch to
-        ll_assert(suspstack != gcrootfinder.oldsuspstack,
-                  "stacklet: invalid use")
-        gcrootfinder.newsuspstack = suspstack
-        h = llop.gc_shadowstackref_context(llmemory.Address, suspstack)
-        h = llmemory.cast_adr_to_ptr(h, _c.handle)
-        prepare_old_suspstack()
-        h = _c.switch(h)
-        return get_result_suspstack(h)
-    switch._dont_inline_ = True
-    switch = staticmethod(switch)
+    fresh_stacklet = NULL_STACKLET
 
     @staticmethod
-    def is_empty_handle(suspstack):
-        return not suspstack
+    def new(thrd, callback, arg):
+        rgc.register_custom_trace_hook(STACKLET, lambda_customtrace)
+        result_stacklet = alloc_stacklet()
+        gcrootfinder.fresh_stacklet = alloc_stacklet()
+        gcrootfinder.runfn = callback
+        thread_handle = thrd._thrd
+        h = _new(thread_handle, arg)
+        return attach_handle_on_stacklet(result_stacklet, h)
+
+    @staticmethod
+    def switch(stacklet):
+        # 'stacklet' has a handle to target, i.e. where to switch to
+        h = consume_stacklet(stacklet)
+        h = _switch(h)
+        return attach_handle_on_stacklet(stacklet, h)
+
+    @staticmethod
+    def is_empty_handle(stacklet):
+        return not stacklet
 
     @staticmethod
     def get_null_handle():
-        return NULL_SUSPSTACK
+        return NULL_STACKLET
 
 
 gcrootfinder = StackletGcRootFinder()
-gcrootfinder.oldsuspstack = NULL_SUSPSTACK
-gcrootfinder.newsuspstack = NULL_SUSPSTACK
diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py
--- a/rpython/rtyper/llinterp.py
+++ b/rpython/rtyper/llinterp.py
@@ -890,19 +890,6 @@
     def op_gc_reattach_callback_pieces(self):
         raise NotImplementedError("gc_reattach_callback_pieces")
 
-    def op_gc_shadowstackref_new(self):   # stacklet+shadowstack
-        raise NotImplementedError("gc_shadowstackref_new")
-    def op_gc_shadowstackref_context(self):
-        raise NotImplementedError("gc_shadowstackref_context")
-    def op_gc_save_current_state_away(self):
-        raise NotImplementedError("gc_save_current_state_away")
-    def op_gc_forget_current_state(self):
-        raise NotImplementedError("gc_forget_current_state")
-    def op_gc_restore_state_from(self):
-        raise NotImplementedError("gc_restore_state_from")
-    def op_gc_start_fresh_new_state(self):
-        raise NotImplementedError("gc_start_fresh_new_state")
-
     def op_gc_get_type_info_group(self):
         raise NotImplementedError("gc_get_type_info_group")
 
diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -521,14 +521,6 @@
     'gc_detach_callback_pieces': LLOp(),
     'gc_reattach_callback_pieces': LLOp(),
 
-    # for stacklet+shadowstack support
-    'gc_shadowstackref_new':      LLOp(canmallocgc=True),
-    'gc_shadowstackref_context':  LLOp(),
-    'gc_save_current_state_away': LLOp(),
-    'gc_forget_current_state':    LLOp(),
-    'gc_restore_state_from':      LLOp(),
-    'gc_start_fresh_new_state':   LLOp(),
-
     # NOTE NOTE NOTE! don't forget *** canmallocgc=True *** for anything that
     # can malloc a GC object.
 


More information about the pypy-commit mailing list