[pypy-commit] pypy tealet: hg merge custom-trace
arigo
noreply at buildbot.pypy.org
Fri Jul 22 13:42:31 CEST 2011
Author: Armin Rigo <arigo at tunes.org>
Branch: tealet
Changeset: r45879:9b46053cc47d
Date: 2011-07-22 13:41 +0200
http://bitbucket.org/pypy/pypy/changeset/9b46053cc47d/
Log: hg merge custom-trace
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
@@ -522,7 +522,8 @@
self.c_vtinfo_skip_offset = rmodel.inputconst(lltype.typeOf(sko), sko)
def build_root_walker(self):
- return ShadowStackRootWalker(self)
+ from pypy.rpython.memory.gctransform import shadowstack
+ return shadowstack.ShadowStackRootWalker(self)
def consider_constant(self, TYPE, value):
self.layoutbuilder.consider_constant(TYPE, value, self.gcdata.gc)
@@ -1354,269 +1355,3 @@
def need_thread_support(self, gctransformer, getfn):
raise Exception("%s does not support threads" % (
self.__class__.__name__,))
-
- def need_tealet_support(self, gctransformer, getfn):
- raise Exception("%s does not support tealets" % (
- self.__class__.__name__,))
-
-
-class ShadowStackRootWalker(BaseRootWalker):
- need_root_stack = True
- collect_stacks_from_other_threads = None
-
- def __init__(self, gctransformer):
- BaseRootWalker.__init__(self, gctransformer)
- self.rootstacksize = sizeofaddr * gctransformer.root_stack_depth
- # 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
-
- self.jit2gc = getattr(gctransformer.translator, '_jit2gc', {})
- try:
- self.rootstackhook = self.jit2gc['rootstackhook']
- except KeyError:
- def collect_stack_root(callback, gc, addr):
- if gc.points_to_valid_gc_object(addr):
- callback(gc, addr)
- return sizeofaddr
- self.rootstackhook = collect_stack_root
-
- 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 allocate_stack(self):
- return llmemory.raw_malloc(self.rootstacksize)
-
- def setup_root_walker(self):
- stackbase = self.allocate_stack()
- ll_assert(bool(stackbase), "could not allocate root stack")
- self.gcdata.root_stack_top = stackbase
- self.gcdata.root_stack_base = stackbase
- BaseRootWalker.setup_root_walker(self)
-
- def walk_stack_roots(self, collect_stack_root):
- gcdata = self.gcdata
- gc = self.gc
- rootstackhook = self.rootstackhook
- addr = gcdata.root_stack_base
- end = gcdata.root_stack_top
- while addr != end:
- addr += rootstackhook(collect_stack_root, gc, addr)
- if self.collect_stacks_from_other_threads is not None:
- self.collect_stacks_from_other_threads(collect_stack_root)
-
- def need_tealet_support(self, gctransformer, getfn):
- GCPTR_ARRAY = lltype.Ptr(lltype.GcArray(llmemory.GCREF))
- SIGNED_ARRAY = lltype.Ptr(lltype.GcArray(lltype.Signed))
- WALKER_PTR = lltype.Ptr(lltype.Struct('walker',
- ('gcptr_array', GCPTR_ARRAY),
- ('signed_array', SIGNED_ARRAY)))
- gcdata = self.gcdata
- jit_save_stack_roots = self.jit2gc.get('savestackhook')
- jit_restore_stack_roots = self.jit2gc.get('restorestackhook')
- #
- def ll_save_stack_roots(walker):
- if jit_save_stack_roots is not None:
- jit_save_stack_roots(walker, gcdata)
- else:
- addr = gcdata.root_stack_base
- end = gcdata.root_stack_top
- count = (end - addr) // sizeofaddr
- walker.gcptr_array = array = lltype.malloc(GCPTR_ARRAY.TO,count)
- n = 0
- while n < len(array):
- array[n] = llmemory.cast_adr_to_ptr(addr.address[n],
- llmemory.GCREF)
- n += 1
- gcdata.root_stack_top = gcdata.root_stack_base # make it empty
- #
- def ll_restore_stack_roots(walker):
- if jit_restore_stack_roots is not None:
- jit_restore_stack_roots(walker, gcdata)
- return
- array = walker.gcptr_array
- addr = gcdata.root_stack_base
- gcdata.root_stack_top = addr + len(array) * sizeofaddr
- n = 0
- while n < len(array):
- addr.address[n] = llmemory.cast_ptr_to_adr(array[n])
- n += 1
- #
- self.ll_save_stack_roots_ptr = getfn(ll_save_stack_roots,
- [annmodel.SomePtr(WALKER_PTR)],
- annmodel.s_None,
- minimal_transform=False)
- self.ll_restore_stack_roots_ptr = getfn(ll_restore_stack_roots,
- [annmodel.SomePtr(WALKER_PTR)],
- annmodel.s_None,
- minimal_transform=False)
-
- def need_thread_support(self, gctransformer, getfn):
- from pypy.module.thread import ll_thread # xxx fish
- from pypy.rpython.memory.support import AddressDict
- from pypy.rpython.memory.support import copy_without_null_values
- gcdata = self.gcdata
- # the interfacing between the threads and the GC is done via
- # three completely ad-hoc operations at the moment:
- # gc_thread_prepare, gc_thread_run, gc_thread_die.
- # See docstrings below.
-
- def get_aid():
- """Return the thread identifier, cast to an (opaque) address."""
- return llmemory.cast_int_to_adr(ll_thread.get_ident())
-
- def thread_setup():
- """Called once when the program starts."""
- aid = get_aid()
- gcdata.main_thread = aid
- gcdata.active_thread = aid
- gcdata.thread_stacks = AddressDict() # {aid: root_stack_top}
- gcdata._fresh_rootstack = llmemory.NULL
- gcdata.dead_threads_count = 0
-
- def thread_prepare():
- """Called just before thread.start_new_thread(). This
- allocates a new shadow stack to be used by the future
- thread. If memory runs out, this raises a MemoryError
- (which can be handled by the caller instead of just getting
- ignored if it was raised in the newly starting thread).
- """
- if not gcdata._fresh_rootstack:
- gcdata._fresh_rootstack = self.allocate_stack()
- if not gcdata._fresh_rootstack:
- raise MemoryError
-
- def thread_run():
- """Called whenever the current thread (re-)acquired the GIL.
- This should ensure that the shadow stack installed in
- gcdata.root_stack_top/root_stack_base is the one corresponding
- to the current thread.
- """
- aid = get_aid()
- if gcdata.active_thread != aid:
- switch_shadow_stacks(aid)
-
- def thread_die():
- """Called just before the final GIL release done by a dying
- thread. After a thread_die(), no more gc operation should
- occur in this thread.
- """
- aid = get_aid()
- if aid == gcdata.main_thread:
- return # ignore calls to thread_die() in the main thread
- # (which can occur after a fork()).
- gcdata.thread_stacks.setitem(aid, llmemory.NULL)
- old = gcdata.root_stack_base
- if gcdata._fresh_rootstack == llmemory.NULL:
- gcdata._fresh_rootstack = old
- else:
- llmemory.raw_free(old)
- install_new_stack(gcdata.main_thread)
- # from time to time, rehash the dictionary to remove
- # old NULL entries
- gcdata.dead_threads_count += 1
- if (gcdata.dead_threads_count & 511) == 0:
- copy = copy_without_null_values(gcdata.thread_stacks)
- gcdata.thread_stacks.delete()
- gcdata.thread_stacks = copy
-
- def switch_shadow_stacks(new_aid):
- save_away_current_stack()
- install_new_stack(new_aid)
- switch_shadow_stacks._dont_inline_ = True
-
- def save_away_current_stack():
- old_aid = gcdata.active_thread
- # save root_stack_base on the top of the stack
- self.push_stack(gcdata.root_stack_base)
- # store root_stack_top into the dictionary
- gcdata.thread_stacks.setitem(old_aid, gcdata.root_stack_top)
-
- def install_new_stack(new_aid):
- # look for the new stack top
- top = gcdata.thread_stacks.get(new_aid, llmemory.NULL)
- if top == llmemory.NULL:
- # first time we see this thread. It is an error if no
- # fresh new stack is waiting.
- base = gcdata._fresh_rootstack
- gcdata._fresh_rootstack = llmemory.NULL
- ll_assert(base != llmemory.NULL, "missing gc_thread_prepare")
- gcdata.root_stack_top = base
- gcdata.root_stack_base = base
- else:
- # restore the root_stack_base from the top of the stack
- gcdata.root_stack_top = top
- gcdata.root_stack_base = self.pop_stack()
- # done
- gcdata.active_thread = new_aid
-
- def collect_stack(aid, stacktop, callback):
- if stacktop != llmemory.NULL and aid != gcdata.active_thread:
- # collect all valid stacks from the dict (the entry
- # corresponding to the current thread is not valid)
- gc = self.gc
- rootstackhook = self.rootstackhook
- end = stacktop - sizeofaddr
- addr = end.address[0]
- while addr != end:
- addr += rootstackhook(callback, gc, addr)
-
- def collect_more_stacks(callback):
- ll_assert(get_aid() == gcdata.active_thread,
- "collect_more_stacks(): invalid active_thread")
- gcdata.thread_stacks.foreach(collect_stack, callback)
-
- def _free_if_not_current(aid, stacktop, _):
- if stacktop != llmemory.NULL and aid != gcdata.active_thread:
- end = stacktop - sizeofaddr
- base = end.address[0]
- llmemory.raw_free(base)
-
- def thread_after_fork(result_of_fork, opaqueaddr):
- # we don't need a thread_before_fork in this case, so
- # opaqueaddr == NULL. This is called after fork().
- if result_of_fork == 0:
- # We are in the child process. Assumes that only the
- # current thread survived, so frees the shadow stacks
- # of all the other ones.
- gcdata.thread_stacks.foreach(_free_if_not_current, None)
- # Clears the dict (including the current thread, which
- # was an invalid entry anyway and will be recreated by
- # the next call to save_away_current_stack()).
- gcdata.thread_stacks.clear()
- # Finally, reset the stored thread IDs, in case it
- # changed because of fork(). Also change the main
- # thread to the current one (because there is not any
- # other left).
- aid = get_aid()
- gcdata.main_thread = aid
- gcdata.active_thread = aid
-
- self.thread_setup = thread_setup
- self.thread_prepare_ptr = getfn(thread_prepare, [], annmodel.s_None)
- self.thread_run_ptr = getfn(thread_run, [], annmodel.s_None,
- inline=True)
- # no thread_start_ptr here
- self.thread_die_ptr = getfn(thread_die, [], annmodel.s_None)
- # no thread_before_fork_ptr here
- self.thread_after_fork_ptr = getfn(thread_after_fork,
- [annmodel.SomeInteger(),
- annmodel.SomeAddress()],
- annmodel.s_None)
- self.collect_stacks_from_other_threads = collect_more_stacks
diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py
new file mode 100644
--- /dev/null
+++ b/pypy/rpython/memory/gctransform/shadowstack.py
@@ -0,0 +1,266 @@
+from pypy.rpython.memory.gctransform.framework import BaseRootWalker
+from pypy.rpython.memory.gctransform.framework import sizeofaddr
+from pypy.rlib.debug import ll_assert
+from pypy.rpython.lltypesystem import llmemory
+
+
+class ShadowStackRootWalker(BaseRootWalker):
+ need_root_stack = True
+ collect_stacks_from_other_threads = None
+
+ def __init__(self, gctransformer):
+ BaseRootWalker.__init__(self, gctransformer)
+ self.rootstacksize = sizeofaddr * gctransformer.root_stack_depth
+ # 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
+
+ self.jit2gc = getattr(gctransformer.translator, '_jit2gc', {})
+ try:
+ self.rootstackhook = self.jit2gc['rootstackhook']
+ except KeyError:
+ def collect_stack_root(callback, gc, addr):
+ if gc.points_to_valid_gc_object(addr):
+ callback(gc, addr)
+ return sizeofaddr
+ self.rootstackhook = collect_stack_root
+
+ 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 allocate_stack(self):
+ return llmemory.raw_malloc(self.rootstacksize)
+
+ def setup_root_walker(self):
+ stackbase = self.allocate_stack()
+ ll_assert(bool(stackbase), "could not allocate root stack")
+ self.gcdata.root_stack_top = stackbase
+ self.gcdata.root_stack_base = stackbase
+ BaseRootWalker.setup_root_walker(self)
+
+ def walk_stack_roots(self, collect_stack_root):
+ gcdata = self.gcdata
+ gc = self.gc
+ rootstackhook = self.rootstackhook
+ addr = gcdata.root_stack_base
+ end = gcdata.root_stack_top
+ while addr != end:
+ addr += rootstackhook(collect_stack_root, gc, addr)
+ if self.collect_stacks_from_other_threads is not None:
+ self.collect_stacks_from_other_threads(collect_stack_root)
+
+ def need_tealet_support(self, gctransformer, getfn):
+ GCPTR_ARRAY = lltype.Ptr(lltype.GcArray(llmemory.GCREF))
+ SIGNED_ARRAY = lltype.Ptr(lltype.GcArray(lltype.Signed))
+ WALKER_PTR = lltype.Ptr(lltype.Struct('walker',
+ ('gcptr_array', GCPTR_ARRAY),
+ ('signed_array', SIGNED_ARRAY)))
+ gcdata = self.gcdata
+ jit_save_stack_roots = self.jit2gc.get('savestackhook')
+ jit_restore_stack_roots = self.jit2gc.get('restorestackhook')
+ #
+ def ll_save_stack_roots(walker):
+ if jit_save_stack_roots is not None:
+ jit_save_stack_roots(walker, gcdata)
+ else:
+ addr = gcdata.root_stack_base
+ end = gcdata.root_stack_top
+ count = (end - addr) // sizeofaddr
+ walker.gcptr_array = array = lltype.malloc(GCPTR_ARRAY.TO,count)
+ n = 0
+ while n < len(array):
+ array[n] = llmemory.cast_adr_to_ptr(addr.address[n],
+ llmemory.GCREF)
+ n += 1
+ gcdata.root_stack_top = gcdata.root_stack_base # make it empty
+ #
+ def ll_restore_stack_roots(walker):
+ if jit_restore_stack_roots is not None:
+ jit_restore_stack_roots(walker, gcdata)
+ return
+ array = walker.gcptr_array
+ addr = gcdata.root_stack_base
+ gcdata.root_stack_top = addr + len(array) * sizeofaddr
+ n = 0
+ while n < len(array):
+ addr.address[n] = llmemory.cast_ptr_to_adr(array[n])
+ n += 1
+ #
+ self.ll_save_stack_roots_ptr = getfn(ll_save_stack_roots,
+ [annmodel.SomePtr(WALKER_PTR)],
+ annmodel.s_None,
+ minimal_transform=False)
+ self.ll_restore_stack_roots_ptr = getfn(ll_restore_stack_roots,
+ [annmodel.SomePtr(WALKER_PTR)],
+ annmodel.s_None,
+ minimal_transform=False)
+
+ def need_thread_support(self, gctransformer, getfn):
+ from pypy.module.thread import ll_thread # xxx fish
+ from pypy.rpython.memory.support import AddressDict
+ from pypy.rpython.memory.support import copy_without_null_values
+ gcdata = self.gcdata
+ # the interfacing between the threads and the GC is done via
+ # three completely ad-hoc operations at the moment:
+ # gc_thread_prepare, gc_thread_run, gc_thread_die.
+ # See docstrings below.
+
+ def get_aid():
+ """Return the thread identifier, cast to an (opaque) address."""
+ return llmemory.cast_int_to_adr(ll_thread.get_ident())
+
+ def thread_setup():
+ """Called once when the program starts."""
+ aid = get_aid()
+ gcdata.main_thread = aid
+ gcdata.active_thread = aid
+ gcdata.thread_stacks = AddressDict() # {aid: root_stack_top}
+ gcdata._fresh_rootstack = llmemory.NULL
+ gcdata.dead_threads_count = 0
+
+ def thread_prepare():
+ """Called just before thread.start_new_thread(). This
+ allocates a new shadow stack to be used by the future
+ thread. If memory runs out, this raises a MemoryError
+ (which can be handled by the caller instead of just getting
+ ignored if it was raised in the newly starting thread).
+ """
+ if not gcdata._fresh_rootstack:
+ gcdata._fresh_rootstack = self.allocate_stack()
+ if not gcdata._fresh_rootstack:
+ raise MemoryError
+
+ def thread_run():
+ """Called whenever the current thread (re-)acquired the GIL.
+ This should ensure that the shadow stack installed in
+ gcdata.root_stack_top/root_stack_base is the one corresponding
+ to the current thread.
+ """
+ aid = get_aid()
+ if gcdata.active_thread != aid:
+ switch_shadow_stacks(aid)
+
+ def thread_die():
+ """Called just before the final GIL release done by a dying
+ thread. After a thread_die(), no more gc operation should
+ occur in this thread.
+ """
+ aid = get_aid()
+ if aid == gcdata.main_thread:
+ return # ignore calls to thread_die() in the main thread
+ # (which can occur after a fork()).
+ gcdata.thread_stacks.setitem(aid, llmemory.NULL)
+ old = gcdata.root_stack_base
+ if gcdata._fresh_rootstack == llmemory.NULL:
+ gcdata._fresh_rootstack = old
+ else:
+ llmemory.raw_free(old)
+ install_new_stack(gcdata.main_thread)
+ # from time to time, rehash the dictionary to remove
+ # old NULL entries
+ gcdata.dead_threads_count += 1
+ if (gcdata.dead_threads_count & 511) == 0:
+ copy = copy_without_null_values(gcdata.thread_stacks)
+ gcdata.thread_stacks.delete()
+ gcdata.thread_stacks = copy
+
+ def switch_shadow_stacks(new_aid):
+ save_away_current_stack()
+ install_new_stack(new_aid)
+ switch_shadow_stacks._dont_inline_ = True
+
+ def save_away_current_stack():
+ old_aid = gcdata.active_thread
+ # save root_stack_base on the top of the stack
+ self.push_stack(gcdata.root_stack_base)
+ # store root_stack_top into the dictionary
+ gcdata.thread_stacks.setitem(old_aid, gcdata.root_stack_top)
+
+ def install_new_stack(new_aid):
+ # look for the new stack top
+ top = gcdata.thread_stacks.get(new_aid, llmemory.NULL)
+ if top == llmemory.NULL:
+ # first time we see this thread. It is an error if no
+ # fresh new stack is waiting.
+ base = gcdata._fresh_rootstack
+ gcdata._fresh_rootstack = llmemory.NULL
+ ll_assert(base != llmemory.NULL, "missing gc_thread_prepare")
+ gcdata.root_stack_top = base
+ gcdata.root_stack_base = base
+ else:
+ # restore the root_stack_base from the top of the stack
+ gcdata.root_stack_top = top
+ gcdata.root_stack_base = self.pop_stack()
+ # done
+ gcdata.active_thread = new_aid
+
+ def collect_stack(aid, stacktop, callback):
+ if stacktop != llmemory.NULL and aid != gcdata.active_thread:
+ # collect all valid stacks from the dict (the entry
+ # corresponding to the current thread is not valid)
+ gc = self.gc
+ rootstackhook = self.rootstackhook
+ end = stacktop - sizeofaddr
+ addr = end.address[0]
+ while addr != end:
+ addr += rootstackhook(callback, gc, addr)
+
+ def collect_more_stacks(callback):
+ ll_assert(get_aid() == gcdata.active_thread,
+ "collect_more_stacks(): invalid active_thread")
+ gcdata.thread_stacks.foreach(collect_stack, callback)
+
+ def _free_if_not_current(aid, stacktop, _):
+ if stacktop != llmemory.NULL and aid != gcdata.active_thread:
+ end = stacktop - sizeofaddr
+ base = end.address[0]
+ llmemory.raw_free(base)
+
+ def thread_after_fork(result_of_fork, opaqueaddr):
+ # we don't need a thread_before_fork in this case, so
+ # opaqueaddr == NULL. This is called after fork().
+ if result_of_fork == 0:
+ # We are in the child process. Assumes that only the
+ # current thread survived, so frees the shadow stacks
+ # of all the other ones.
+ gcdata.thread_stacks.foreach(_free_if_not_current, None)
+ # Clears the dict (including the current thread, which
+ # was an invalid entry anyway and will be recreated by
+ # the next call to save_away_current_stack()).
+ gcdata.thread_stacks.clear()
+ # Finally, reset the stored thread IDs, in case it
+ # changed because of fork(). Also change the main
+ # thread to the current one (because there is not any
+ # other left).
+ aid = get_aid()
+ gcdata.main_thread = aid
+ gcdata.active_thread = aid
+
+ self.thread_setup = thread_setup
+ self.thread_prepare_ptr = getfn(thread_prepare, [], annmodel.s_None)
+ self.thread_run_ptr = getfn(thread_run, [], annmodel.s_None,
+ inline=True)
+ # no thread_start_ptr here
+ self.thread_die_ptr = getfn(thread_die, [], annmodel.s_None)
+ # no thread_before_fork_ptr here
+ self.thread_after_fork_ptr = getfn(thread_after_fork,
+ [annmodel.SomeInteger(),
+ annmodel.SomeAddress()],
+ annmodel.s_None)
+ self.collect_stacks_from_other_threads = collect_more_stacks
More information about the pypy-commit
mailing list