[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