Author: Armin Rigo <ar...@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; } _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit