Author: Armin Rigo <[email protected]>
Branch: r15-for-shadowstack
Changeset: r65976:7262c0519909
Date: 2013-08-06 16:47 +0200
http://bitbucket.org/pypy/pypy/changeset/7262c0519909/
Log: in-progress, targetgcbench works
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
@@ -784,6 +784,7 @@
self._gc_adr_of_gc_attr(hop, 'nursery_top')
def _gc_adr_of_gcdata_attr(self, hop, attrname):
+ xxxxxxxxxxxxxx
op = hop.spaceop
ofs = llmemory.offsetof(self.c_const_gcdata.concretetype.TO,
'inst_' + attrname)
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
@@ -4,7 +4,8 @@
from rpython.rlib import rgc
from rpython.rtyper import rmodel
from rpython.rtyper.annlowlevel import llhelper
-from rpython.rtyper.lltypesystem import lltype, llmemory
+from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
+from rpython.rtyper.lltypesystem.lloperation import llop
from rpython.memory.gctransform.framework import (
BaseFrameworkGCTransformer, BaseRootWalker, sizeofaddr)
from rpython.rtyper.rbuiltin import gen_cast
@@ -12,14 +13,7 @@
class ShadowStackFrameworkGCTransformer(BaseFrameworkGCTransformer):
def annotate_walker_functions(self, getfn):
- self.incr_stack_ptr = getfn(self.root_walker.incr_stack,
- [annmodel.SomeInteger()],
- annmodel.SomeAddress(),
- inline = True)
- self.decr_stack_ptr = getfn(self.root_walker.decr_stack,
- [annmodel.SomeInteger()],
- annmodel.SomeAddress(),
- inline = True)
+ pass
def build_root_walker(self):
return ShadowStackRootWalker(self)
@@ -27,30 +21,13 @@
def push_roots(self, hop, keep_current_args=False):
livevars = self.get_livevars_for_roots(hop, keep_current_args)
self.num_pushs += len(livevars)
- if not livevars:
- return []
- c_len = rmodel.inputconst(lltype.Signed, len(livevars) )
- base_addr = hop.genop("direct_call", [self.incr_stack_ptr, c_len ],
- resulttype=llmemory.Address)
- for k,var in enumerate(livevars):
- c_k = rmodel.inputconst(lltype.Signed, k * sizeofaddr)
- v_adr = gen_cast(hop.llops, llmemory.Address, var)
- hop.genop("raw_store", [base_addr, c_k, v_adr])
+ hop.genop("shadowstack_push", list(livevars)) # may be 0
return livevars
def pop_roots(self, hop, livevars):
if not livevars:
return
- c_len = rmodel.inputconst(lltype.Signed, len(livevars) )
- base_addr = hop.genop("direct_call", [self.decr_stack_ptr, c_len ],
- resulttype=llmemory.Address)
- if self.gcdata.gc.moving_gc:
- # for moving collectors, reload the roots into the local variables
- for k,var in enumerate(livevars):
- c_k = rmodel.inputconst(lltype.Signed, k * sizeofaddr)
- v_newaddr = hop.genop("raw_load", [base_addr, c_k],
- resulttype=llmemory.Address)
- hop.genop("gc_reload_possibly_moved", [v_newaddr, var])
+ hop.genop("shadowstack_pop", list(livevars))
class ShadowStackRootWalker(BaseRootWalker):
@@ -59,53 +36,21 @@
# NB. 'self' is frozen, but we can use self.gcdata to store state
gcdata = self.gcdata
- def incr_stack(n):
- top = gcdata.root_stack_top
- gcdata.root_stack_top = top + n*sizeofaddr
- return top
- self.incr_stack = incr_stack
-
- def decr_stack(n):
- top = gcdata.root_stack_top - n*sizeofaddr
- gcdata.root_stack_top = top
- return top
- self.decr_stack = decr_stack
-
- root_iterator = get_root_iterator(gctransformer)
- def walk_stack_root(callback, start, end):
- root_iterator.setcontext(NonConstant(llmemory.NULL))
- gc = self.gc
- addr = end
- while True:
- addr = root_iterator.nextleft(gc, start, addr)
- if addr == llmemory.NULL:
- return
- callback(gc, addr)
- self.rootstackhook = walk_stack_root
-
- self.shadow_stack_pool = ShadowStackPool(gcdata)
- rsd = gctransformer.root_stack_depth
- if rsd is not None:
- self.shadow_stack_pool.root_stack_depth = rsd
-
- def push_stack(self, addr):
- top = self.incr_stack(1)
- top.address[0] = addr
-
- def pop_stack(self):
- top = self.decr_stack(1)
- return top.address[0]
-
- def setup_root_walker(self):
- self.shadow_stack_pool.initial_setup()
- BaseRootWalker.setup_root_walker(self)
-
def walk_stack_roots(self, collect_stack_root):
- gcdata = self.gcdata
- self.rootstackhook(collect_stack_root,
- gcdata.root_stack_base, gcdata.root_stack_top)
+ WORD = llmemory.sizeof(llmemory.Address)
+ r15 = llop.shadowstack_r15(lltype.Signed)
+ gc = self.gc
+ while r15 != -1:
+ n = (r15 & 7) + 1
+ r15 &= ~7
+ while n > 0:
+ addr = rffi.cast(llmemory.Address, r15 + n * WORD)
+ collect_stack_root(gc, addr)
+ n -= 1
+ r15 = rffi.cast(llmemory.Address, r15).signed[0]
def need_thread_support(self, gctransformer, getfn):
+ xxxxxxxxx
from rpython.rlib import rthread # xxx fish
gcdata = self.gcdata
# the interfacing between the threads and the GC is done via
@@ -216,6 +161,7 @@
minimal_transform=False)
def need_stacklet_support(self, gctransformer, getfn):
+ xxxxxxxxxxxxx
shadow_stack_pool = self.shadow_stack_pool
SHADOWSTACKREF = get_shadowstackref(self, gctransformer)
@@ -264,156 +210,3 @@
inline=True)
# ____________________________________________________________
-
-class ShadowStackPool(object):
- """Manages a pool of shadowstacks. The MAX most recently used
- 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. XXX NOT IMPLEMENTED SO FAR!
- """
- _alloc_flavor_ = "raw"
- root_stack_depth = 163840
-
- #MAX = 20 not implemented yet
-
- def __init__(self, gcdata):
- self.unused_full_stack = llmemory.NULL
- self.gcdata = gcdata
-
- def initial_setup(self):
- self._prepare_unused_stack()
- self.start_fresh_new_state()
-
- def allocate(self, SHADOWSTACKREF):
- """Allocate an empty SHADOWSTACKREF object."""
- return lltype.malloc(SHADOWSTACKREF, zero=True)
-
- 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
- forget_current_state(), and then call restore_state_from()
- or start_fresh_new_state().
- """
- 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
- #
- # cannot use llop.gc_assume_young_pointers() here, because
- # we are in a minimally-transformed GC helper :-/
- gc = self.gcdata.gc
- if hasattr(gc.__class__, 'assume_young_pointers'):
- shadowstackadr = llmemory.cast_ptr_to_adr(shadowstackref)
- gc.assume_young_pointers(shadowstackadr)
- #
- self.gcdata.root_stack_top = llmemory.NULL # to detect missing restore
-
- def forget_current_state(self):
- ll_assert(self.gcdata.root_stack_base == self.gcdata.root_stack_top,
- "forget_current_state: shadowstack not empty!")
- if self.unused_full_stack:
- llmemory.raw_free(self.unused_full_stack)
- self.unused_full_stack = self.gcdata.root_stack_base
- self.gcdata.root_stack_top = llmemory.NULL # to detect missing restore
-
- def restore_state_from(self, shadowstackref):
- ll_assert(bool(shadowstackref.base), "empty shadowstackref!")
- ll_assert(shadowstackref.base <= shadowstackref.top,
- "restore_state_from: broken shadowstack")
- self.gcdata.root_stack_base = shadowstackref.base
- self.gcdata.root_stack_top = shadowstackref.top
- self._cleanup(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 _cleanup(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:
- root_stack_size = sizeofaddr * self.root_stack_depth
- self.unused_full_stack = llmemory.raw_malloc(root_stack_size)
- if self.unused_full_stack == llmemory.NULL:
- raise MemoryError
-
-
-def get_root_iterator(gctransformer):
- if hasattr(gctransformer, '_root_iterator'):
- return gctransformer._root_iterator # if already built
- class RootIterator(object):
- def _freeze_(self):
- return True
- def setcontext(self, context):
- pass
- def nextleft(self, gc, start, addr):
- while addr != start:
- addr -= sizeofaddr
- if gc.points_to_valid_gc_object(addr):
- return addr
- return llmemory.NULL
- result = RootIterator()
- gctransformer._root_iterator = result
- return result
-
-
-def get_shadowstackref(root_walker, gctransformer):
- if hasattr(gctransformer, '_SHADOWSTACKREF'):
- return gctransformer._SHADOWSTACKREF
-
- SHADOWSTACKREFPTR = lltype.Ptr(lltype.GcForwardReference())
- SHADOWSTACKREF = lltype.GcStruct('ShadowStackRef',
- ('base', llmemory.Address),
- ('top', llmemory.Address),
- ('context', llmemory.Address),
- #('fullstack', lltype.Bool),
- rtti=True)
- SHADOWSTACKREFPTR.TO.become(SHADOWSTACKREF)
-
- gc = gctransformer.gcdata.gc
- root_iterator = get_root_iterator(gctransformer)
-
- def customtrace(obj, prev):
- obj = llmemory.cast_adr_to_ptr(obj, SHADOWSTACKREFPTR)
- if not prev:
- root_iterator.setcontext(obj.context)
- prev = obj.top
- return root_iterator.nextleft(gc, obj.base, prev)
-
- CUSTOMTRACEFUNC = lltype.FuncType([llmemory.Address, llmemory.Address],
- llmemory.Address)
- customtraceptr = llhelper(lltype.Ptr(CUSTOMTRACEFUNC), customtrace)
-
- def shadowstack_destructor(shadowstackref):
- if root_walker.stacklet_support:
- from rpython.rlib import _rffi_stacklet as _c
- h = shadowstackref.context
- h = llmemory.cast_adr_to_ptr(h, _c.handle)
- shadowstackref.context = llmemory.NULL
- #
- base = shadowstackref.base
- shadowstackref.base = llmemory.NULL
- shadowstackref.top = llmemory.NULL
- llmemory.raw_free(base)
- #
- if root_walker.stacklet_support:
- if h:
- _c.destroy(h)
-
- destrptr = gctransformer.annotate_helper(shadowstack_destructor,
- [SHADOWSTACKREFPTR], lltype.Void)
-
- lltype.attachRuntimeTypeInfo(SHADOWSTACKREF, customtraceptr=customtraceptr,
- destrptr=destrptr)
-
- gctransformer._SHADOWSTACKREF = SHADOWSTACKREF
- return SHADOWSTACKREF
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
@@ -561,6 +561,10 @@
'debug_print_traceback': LLOp(),
'debug_nonnull_pointer': LLOp(canrun=True),
+ 'shadowstack_push': LLOp(),
+ 'shadowstack_pop': LLOp(),
+ 'shadowstack_r15': LLOp(),
+
# __________ instrumentation _________
'instrument_count': LLOp(),
}
diff --git a/rpython/translator/c/funcgen.py b/rpython/translator/c/funcgen.py
--- a/rpython/translator/c/funcgen.py
+++ b/rpython/translator/c/funcgen.py
@@ -204,6 +204,8 @@
def cfunction_body(self):
graph = self.graph
+ yield 'char *shadowstack[9]; /* xxx reduce */'
+ yield 'shadowstack[0] = pypy_r15;'
yield 'goto block0;' # to avoid a warning "this label is not used"
# generate the body of each block
@@ -899,4 +901,34 @@
else:
return None # use the default
+ def OP_SHADOWSTACK_PUSH(self, op):
+ numvars = len(op.args)
+ if numvars == 0:
+ return 'pypy_r15 = shadowstack[0];'
+ else:
+ assert numvars <= 8
+ exprs = []
+ for i in range(numvars):
+ exprs.append('shadowstack[%d] = (char *)%s;' % (
+ i + 1, self.expr(op.args[i])))
+ exprs.append('pypy_r15 = ((char *)shadowstack) + %d;' % (
+ numvars - 1,))
+ return '\n'.join(exprs)
+
+ def OP_SHADOWSTACK_POP(self, op):
+ numvars = len(op.args)
+ assert 1 <= numvars <= 8
+ exprs = []
+ for i in range(numvars-1, -1, -1):
+ v = op.args[i]
+ exprs.append('%s = (%s)shadowstack[%d];' % (
+ self.expr(v), cdecl(self.lltypename(v), ''), i + 1))
+ return '\n'.join(exprs)
+
+ def OP_SHADOWSTACK_R15(self, op):
+ v = op.result
+ return '%s = (%s)pypy_r15;' % (self.expr(v),
+ cdecl(self.lltypename(v), ''))
+
+
assert not USESLOTS or '__dict__' not in dir(FunctionCodeGenerator)
diff --git a/rpython/translator/c/src/entrypoint.c
b/rpython/translator/c/src/entrypoint.c
--- a/rpython/translator/c/src/entrypoint.c
+++ b/rpython/translator/c/src/entrypoint.c
@@ -30,14 +30,18 @@
char *errmsg;
int i, exitcode;
RPyListOfString *list;
+ char *saved_r15;
#ifdef PYPY_USE_ASMGCC
pypy_g_rpython_rtyper_lltypesystem_rffi_StackCounter.sc_inst_stacks_counter++;
#endif
- pypy_asm_stack_bottom();
+ saved_r15 = pypy_r15;
+ //pypy_asm_stack_bottom();
#ifdef PYPY_X86_CHECK_SSE2_DEFINED
+ pypy_r15 = (char *)-1;
pypy_x86_check_sse2();
#endif
+ pypy_r15 = (char *)-1;
instrument_setup();
#ifndef MS_WINDOWS
@@ -49,28 +53,37 @@
}
#endif
+ pypy_r15 = (char *)-1;
errmsg = RPython_StartupCode();
if (errmsg) goto error;
+ pypy_r15 = (char *)-1;
list = _RPyListOfString_New(argc);
if (RPyExceptionOccurred()) goto memory_out;
for (i=0; i<argc; i++) {
+ pypy_r15 = (char *)-1;
RPyString *s = RPyString_FromString(argv[i]);
if (RPyExceptionOccurred()) goto memory_out;
+ pypy_r15 = (char *)-1;
_RPyListOfString_SetItem(list, i, s);
}
+ pypy_r15 = (char *)-1;
exitcode = STANDALONE_ENTRY_POINT(list);
+ pypy_r15 = (char *)-1;
pypy_debug_alloc_results();
+ pypy_r15 = (char *)-1;
if (RPyExceptionOccurred()) {
/* print the RPython traceback */
pypy_debug_catch_fatal_exception();
}
+ pypy_r15 = (char *)-1;
pypy_malloc_counters_results();
+ pypy_r15 = saved_r15;
return exitcode;
memory_out:
@@ -78,7 +91,7 @@
error:
fprintf(stderr, "Fatal error during initialization: %s\n", errmsg);
abort();
- return 1;
+ return 1; /* not actually reachable */
}
int PYPY_MAIN_FUNCTION(int argc, char *argv[])
diff --git a/rpython/translator/c/src/g_prerequisite.h
b/rpython/translator/c/src/g_prerequisite.h
--- a/rpython/translator/c/src/g_prerequisite.h
+++ b/rpython/translator/c/src/g_prerequisite.h
@@ -26,3 +26,6 @@
#include "src/align.h"
+
+
+register char *pypy_r15 asm("r15");
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit