[pypy-commit] pypy stacklet: Stacklet+jit+shadowstack. Not well tested.

arigo noreply at buildbot.pypy.org
Tue Aug 23 13:01:43 CEST 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: stacklet
Changeset: r46722:c93c270db99b
Date: 2011-08-23 09:48 +0200
http://bitbucket.org/pypy/pypy/changeset/c93c270db99b/

Log:	Stacklet+jit+shadowstack. Not well tested.

diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py
--- a/pypy/jit/backend/llsupport/gc.py
+++ b/pypy/jit/backend/llsupport/gc.py
@@ -375,7 +375,6 @@
         #
         class RootIterator:
             _alloc_flavor_ = "raw"
-            frame_addr = 0
 
             def next(iself, gc, prev, range_lowest):
                 # Return the "next" valid GC object' address.  We enumerating
@@ -402,7 +401,9 @@
                         # important part here is that points_to_valid_gc_object
                         # above returns True even for a pointer to a MARKER
                         # (which is word-aligned).
-                        if prev.address[0].signed[0] != self.MARKER:
+                        addr = prev.address[0]
+                        addr = iself.translateptr(iself.context, addr)
+                        if addr.signed[0] != self.MARKER:
                             return prev
                         #
                         # It's a JIT frame.  Save away 'prev' for later, and
@@ -412,6 +413,7 @@
                         iself.frame_addr = frame_addr
                         addr = llmemory.cast_int_to_adr(frame_addr +
                                                         self.force_index_ofs)
+                        addr = iself.translateptr(iself.context, addr)
                         force_index = addr.signed[0]
                         if force_index < 0:
                             force_index = ~force_index
@@ -435,6 +437,7 @@
                         callshape = lltype.direct_ptradd(callshape, 1)
                         addr = llmemory.cast_int_to_adr(iself.frame_addr +
                                                         offset)
+                        addr = iself.translateptr(iself.context, addr)
                         if gc.points_to_valid_gc_object(addr):
                             #
                             # The JIT frame contains a valid GC pointer at
@@ -450,8 +453,12 @@
 
         # ---------------
         #
+        root_iterator = RootIterator()
+        root_iterator.frame_addr = 0
+        root_iterator.context = llmemory.NULL
+        root_iterator.translateptr = lambda context, addr: addr
         jit2gc.update({
-            'root_iterator': RootIterator(),
+            'root_iterator': root_iterator,
             })
 
     def initialize(self):
diff --git a/pypy/rlib/_stacklet_shadowstack.py b/pypy/rlib/_stacklet_shadowstack.py
--- a/pypy/rlib/_stacklet_shadowstack.py
+++ b/pypy/rlib/_stacklet_shadowstack.py
@@ -6,20 +6,15 @@
 from pypy.tool.staticmethods import StaticMethods
 
 
-SUSPSTACK = lltype.GcStruct('SuspStack',
-                            ('handle', _c.handle),
-                            ('shadowstackref', llmemory.GCREF))
-NULL_SUSPSTACK = lltype.nullptr(SUSPSTACK)
-NULL_GCREF = lltype.nullptr(llmemory.GCREF.TO)
+NULL_SUSPSTACK = lltype.nullptr(llmemory.GCREF.TO)
 
 
 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
-    oldsuspstack.handle = h
     llop.gc_save_current_state_away(lltype.Void,
-                                    oldsuspstack.shadowstackref)
+                                    oldsuspstack, h)
     llop.gc_start_fresh_new_state(lltype.Void)
     gcrootfinder.oldsuspstack = NULL_SUSPSTACK
     #
@@ -28,15 +23,15 @@
     # Finishing this stacklet.
     gcrootfinder.oldsuspstack = NULL_SUSPSTACK
     gcrootfinder.newsuspstack = newsuspstack
-    return newsuspstack.handle
+    h = llop.gc_shadowstackref_context(llmemory.Address, newsuspstack)
+    return llmemory.cast_adr_to_ptr(h, _c.handle)
 
 def prepare_old_suspstack():
     if not gcrootfinder.oldsuspstack:   # else reuse the one still there
         _allocate_old_suspstack()
 
 def _allocate_old_suspstack():
-    suspstack = lltype.malloc(SUSPSTACK)
-    suspstack.shadowstackref = llop.gc_new_shadowstackref(llmemory.GCREF)
+    suspstack = llop.gc_shadowstackref_new(llmemory.GCREF)
     gcrootfinder.oldsuspstack = suspstack
 _allocate_old_suspstack._dont_inline_ = True
 
@@ -55,14 +50,12 @@
     # away, and restore the new one
     if oldsuspstack:
         ll_assert(not _c.is_empty_handle(h),"unexpected empty stacklet handle")
-        oldsuspstack.handle = h
-        llop.gc_save_current_state_away(lltype.Void,
-                                        oldsuspstack.shadowstackref)
+        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.shadowstackref)
+    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
@@ -90,16 +83,17 @@
                   "stacklet: invalid use")
         gcrootfinder.newsuspstack = suspstack
         thread_handle = thrd._thrd
-        h = suspstack.handle
+        h = llop.gc_shadowstackref_context(llmemory.Address, suspstack)
+        h = llmemory.cast_adr_to_ptr(h, _c.handle)
         prepare_old_suspstack()
         h = _c.switch(thread_handle, h)
         return get_result_suspstack(h)
     switch._dont_inline_ = True
 
     def destroy(thrd, suspstack):
-        h = suspstack.handle
-        suspstack.handle = _c.null_handle
-        suspstack.shadowstackref = NULL_GCREF
+        h = llop.gc_shadowstackref_context(llmemory.Address, suspstack)
+        h = llmemory.cast_adr_to_ptr(h, _c.handle)
+        llop.gc_shadowstackref_destroy(lltype.Void, suspstack)
         _c.destroy(thrd._thrd, h)
 
     def is_empty_handle(suspstack):
diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py
--- a/pypy/rpython/llinterp.py
+++ b/pypy/rpython/llinterp.py
@@ -880,8 +880,12 @@
     def op_gc_stack_bottom(self):
         pass       # marker for trackgcroot.py
 
-    def op_gc_new_shadowstackref(self):   # stacklet+shadowstack
-        raise NotImplementedError("gc_new_shadowstackref")
+    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_shadowstackref_destroy(self):
+        raise NotImplementedError("gc_shadowstackref_destroy")
     def op_gc_save_current_state_away(self):
         raise NotImplementedError("gc_save_current_state_away")
     def op_gc_forget_current_state(self):
diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py
--- a/pypy/rpython/lltypesystem/lloperation.py
+++ b/pypy/rpython/lltypesystem/lloperation.py
@@ -489,7 +489,9 @@
     'gc_stack_bottom':      LLOp(canrun=True),
 
     # for stacklet+shadowstack support
-    'gc_new_shadowstackref':      LLOp(canmallocgc=True),
+    'gc_shadowstackref_new':      LLOp(canmallocgc=True),
+    'gc_shadowstackref_context':  LLOp(),
+    'gc_shadowstackref_destroy':  LLOp(),
     'gc_save_current_state_away': LLOp(),
     'gc_forget_current_state':    LLOp(),
     'gc_restore_state_from':      LLOp(),
diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py
--- a/pypy/rpython/memory/gctransform/framework.py
+++ b/pypy/rpython/memory/gctransform/framework.py
@@ -797,18 +797,28 @@
     def gct_gc_adr_of_root_stack_top(self, hop):
         self._gc_adr_of_gcdata_attr(hop, 'root_stack_top')
 
-    def gct_gc_new_shadowstackref(self, hop):
+    def gct_gc_shadowstackref_new(self, hop):
         op = hop.spaceop
         livevars = self.push_roots(hop)
-        hop.genop("direct_call", [self.root_walker.gc_new_shadowstackref_ptr],
+        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_shadowstackref_destroy(self, hop):
+        hop.genop("direct_call",
+                  [self.root_walker.gc_shadowstackref_destroy_ptr, op.args[0]])
+
     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[0], op.args[1]])
 
     def gct_gc_forget_current_state(self, hop):
         hop.genop("direct_call",
diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py
--- a/pypy/rpython/memory/gctransform/shadowstack.py
+++ b/pypy/rpython/memory/gctransform/shadowstack.py
@@ -30,6 +30,7 @@
         if hasattr(translator, '_jit2gc'):
             root_iterator = translator._jit2gc['root_iterator']
             def jit_walk_stack_root(callback, addr, end):
+                root_iterator.context = llmemory.NULL
                 gc = self.gc
                 while True:
                     end = root_iterator.next(gc, end, addr)
@@ -139,7 +140,7 @@
                 thread_stacks[gcdata.active_tid] = old_ref
             #
             # no GC operation from here -- switching shadowstack!
-            shadow_stack_pool.save_current_state_away(old_ref)
+            shadow_stack_pool.save_current_state_away(old_ref, llmemory.NULL)
             if new_ref:
                 shadow_stack_pool.restore_state_from(new_ref)
             else:
@@ -181,13 +182,21 @@
         shadow_stack_pool = self.shadow_stack_pool
         SHADOWSTACKREF = get_shadowstackref(gctransformer)
 
-        def gc_new_shadowstackref():
+        def gc_shadowstackref_new():
             ssref = shadow_stack_pool.allocate(SHADOWSTACKREF)
             return lltype.cast_opaque_ptr(llmemory.GCREF, ssref)
 
-        def gc_save_current_state_away(gcref):
+        def gc_shadowstackref_context(gcref):
             ssref = lltype.cast_opaque_ptr(lltype.Ptr(SHADOWSTACKREF), gcref)
-            shadow_stack_pool.save_current_state_away(ssref)
+            return ssref.context
+
+        def gc_shadowstackref_destroy(gcref):
+            ssref = lltype.cast_opaque_ptr(lltype.Ptr(SHADOWSTACKREF), gcref)
+            shadow_stack_pool.destroy(ssref)
+
+        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()
@@ -200,17 +209,35 @@
             shadow_stack_pool.start_fresh_new_state()
 
         s_gcref = annmodel.SomePtr(llmemory.GCREF)
-        self.gc_new_shadowstackref_ptr = getfn(gc_new_shadowstackref,
+        s_addr = annmodel.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_shadowstackref_destroy_ptr = getfn(gc_shadowstackref_destroy,
+                                                   [s_gcref], annmodel.s_None,
+                                                   inline=True)
         self.gc_save_current_state_away_ptr = getfn(gc_save_current_state_away,
-                                                    [s_gcref], annmodel.s_None)
+                                                    [s_gcref, s_addr],
+                                                    annmodel.s_None,
+                                                    inline=True)
         self.gc_forget_current_state_ptr = getfn(gc_forget_current_state,
-                                                 [], annmodel.s_None)
+                                                 [], annmodel.s_None,
+                                                 inline=True)
         self.gc_restore_state_from_ptr = getfn(gc_restore_state_from,
-                                               [s_gcref], annmodel.s_None)
+                                               [s_gcref], annmodel.s_None,
+                                               inline=True)
         self.gc_start_fresh_new_state_ptr = getfn(gc_start_fresh_new_state,
-                                                  [], annmodel.s_None)
+                                                  [], annmodel.s_None,
+                                                  inline=True)
+        # fish...
+        translator = gctransformer.translator
+        if hasattr(translator, '_jit2gc'):
+            from pypy.rlib._rffi_stacklet import _translate_pointer
+            root_iterator = translator._jit2gc['root_iterator']
+            root_iterator.translateptr = _translate_pointer
 
 # ____________________________________________________________
 
@@ -219,7 +246,7 @@
     shadowstacks are fully allocated and can be directly jumped into.
     The rest are stored in a more virtual-memory-friendly way, i.e.
     with just the right amount malloced.  Before they can run, they
-    must be copied into a full shadowstack.
+    must be copied into a full shadowstack.  XXX NOT IMPLEMENTED SO FAR!
     """
     _alloc_flavor_ = "raw"
     root_stack_depth = 163840
@@ -239,7 +266,7 @@
         """Allocate an empty SHADOWSTACKREF object."""
         return lltype.malloc(SHADOWSTACKREF, zero=True)
 
-    def save_current_state_away(self, shadowstackref):
+    def save_current_state_away(self, shadowstackref, ncontext):
         """Save the current state away into 'shadowstackref'.
         This either works, or raise MemoryError and nothing is done.
         To do a switch, first call save_current_state_away() or
@@ -249,6 +276,7 @@
         self._prepare_unused_stack()
         shadowstackref.base = self.gcdata.root_stack_base
         shadowstackref.top  = self.gcdata.root_stack_top
+        shadowstackref.context = ncontext
         ll_assert(shadowstackref.base <= shadowstackref.top,
                   "save_current_state_away: broken shadowstack")
         #shadowstackref.fullstack = True
@@ -274,14 +302,18 @@
                   "restore_state_from: broken shadowstack")
         self.gcdata.root_stack_base = shadowstackref.base
         self.gcdata.root_stack_top  = shadowstackref.top
-        shadowstackref.base = llmemory.NULL
-        shadowstackref.top  = llmemory.NULL
+        self.destroy(shadowstackref)
 
     def start_fresh_new_state(self):
         self.gcdata.root_stack_base = self.unused_full_stack
         self.gcdata.root_stack_top  = self.unused_full_stack
         self.unused_full_stack = llmemory.NULL
 
+    def destroy(self, shadowstackref):
+        shadowstackref.base = llmemory.NULL
+        shadowstackref.top = llmemory.NULL
+        shadowstackref.context = llmemory.NULL
+
     def _prepare_unused_stack(self):
         if self.unused_full_stack == llmemory.NULL:
             self.unused_full_stack = llmemory.raw_malloc(self.root_stack_size)
@@ -297,6 +329,7 @@
     SHADOWSTACKREF = lltype.GcStruct('ShadowStackRef',
                                      ('base', llmemory.Address),
                                      ('top', llmemory.Address),
+                                     ('context', llmemory.Address),
                                      #('fullstack', lltype.Bool),
                                      rtti=True)
     SHADOWSTACKREFPTR.TO.become(SHADOWSTACKREF)
@@ -306,10 +339,11 @@
         gc = gctransformer.gcdata.gc
         root_iterator = translator._jit2gc['root_iterator']
         def customtrace(obj, prev):
+            obj = llmemory.cast_adr_to_ptr(obj, SHADOWSTACKREFPTR)
             if not prev:
-                prev = llmemory.cast_adr_to_ptr(obj, SHADOWSTACKREFPTR).top
-            base = llmemory.cast_adr_to_ptr(obj, SHADOWSTACKREFPTR).base
-            return root_iterator.next(gc, prev, base)
+                prev = obj.top
+                root_iterator.context = obj.context
+            return root_iterator.next(gc, prev, obj.base)
     else:
         def customtrace(obj, prev):
             # a simple but not JIT-ready version
diff --git a/pypy/translator/c/src/stacklet/stacklet.c b/pypy/translator/c/src/stacklet/stacklet.c
--- a/pypy/translator/c/src/stacklet/stacklet.c
+++ b/pypy/translator/c/src/stacklet/stacklet.c
@@ -319,6 +319,8 @@
 
 char **_stacklet_translate_pointer(stacklet_handle context, char **ptr)
 {
+  if (context == NULL)
+    return ptr;
   char *p = (char *)ptr;
   long delta = p - context->stack_start;
   if (((unsigned long)delta) < ((unsigned long)context->stack_saved)) {
@@ -326,6 +328,7 @@
       char *c = (char *)(context + 1);
       return (char **)(c + delta);
   }
+#if 0
   if (((unsigned long)delta) >=
       (unsigned long)(context->stack_stop - context->stack_start)) {
       /* out-of-stack pointer!  it's only ok if we are the main stacklet
@@ -334,5 +337,6 @@
       assert(delta >= 0);
       assert(((long)context->stack_stop) & 1);
   }
+#endif
   return ptr;
 }


More information about the pypy-commit mailing list