[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