Author: Armin Rigo <[email protected]>
Branch: stacklet
Changeset: r46557:6634ec220528
Date: 2011-08-17 09:59 +0200
http://bitbucket.org/pypy/pypy/changeset/6634ec220528/
Log: Work in progress...
diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py
--- a/pypy/config/translationoption.py
+++ b/pypy/config/translationoption.py
@@ -69,7 +69,8 @@
"statistics": [("translation.gctransformer",
"framework")],
"generation": [("translation.gctransformer",
"framework")],
"hybrid": [("translation.gctransformer", "framework")],
- "boehm": [("translation.gctransformer", "boehm")],
+ "boehm": [("translation.gctransformer", "boehm"),
+ ("translation.continuation", False)], # breaks
"markcompact": [("translation.gctransformer",
"framework")],
"minimark": [("translation.gctransformer", "framework")],
},
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
@@ -367,44 +367,91 @@
def add_jit2gc_hooks(self, jit2gc):
#
- def collect_jit_stack_root(callback, gc, addr):
- # Note: first check with 'points_to_valid_gc_object' if the
- # addr.address[0] appears to be a valid pointer. It returns
- # False if it's NULL, and may also check for tagged integers.
- # The important part here is that it will return True for a
- # pointer to a MARKER (which is word-aligned), even though it's
- # not pointing to a valid GC object.
- if gc.points_to_valid_gc_object(addr):
- if addr.address[0].signed[0] != GcRootMap_shadowstack.MARKER:
- # common case
- callback(gc, addr)
+ # ---------------
+ # This is used to enumerate the shadowstack in the presence
+ # of the JIT. It is also used by the stacklet support in
+ # rlib/_stacklet_shadowstack. That's why it is written as
+ # an iterator that can also be used with a custom_trace.
+ #
+ def iterator_setup():
+ self._iter_frame_addr = llmemory.NULL
+ self._iter_callshape = llmemory.NULL
+ self._iter_saved_prev = llmemory.NULL
+ #
+ def iterator_next(gc, prev, range_lowest):
+ # Return the "next" valid GC object' address. "prev" is the
+ # previous result (or the highest end of the shadowstack to start
+ # with), and "range_lowest" is the lowest end of the shadowstack.
+ # We enumerating backwards, starting from the higher addresses.
+ #
+ while True:
+ #
+ # If we are not iterating right now in a JIT frame
+ if self._iter_frame_addr == llmemory.NULL:
+ #
+ # Look for the previous shadowstack address that contains
+ # a valid pointer
+ while prev != range_lowest:
+ prev -= llmemory.sizeof(llmemory.Address)
+ if gc.points_to_valid_gc_object(prev):
+ break
+ else:
+ return llmemory.NULL
+ #
+ # Now a "valid" pointer can be either really valid, or it
+ # can be a pointer to a JIT frame in the stack. The
+ # 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:
+ return prev
+ #
+ # It's a JIT frame. Save away 'prev' for later, and
+ # go into JIT-frame-exploring mode.
+ self._iter_saved_prev = prev
+ frame_addr = prev.signed[0] - self.marker_ofs
+ self._iter_frame_addr = frame_addr
+ addr = llmemory.cast_int_to_adr(frame_addr +
+ self.force_index_ofs)
+ force_index = addr.signed[0]
+ if force_index < 0:
+ force_index = ~force_index
+ # NB: the next line reads a still-alive _callshapes,
+ # because we ensure that just before we called this piece
+ # of assembler, we put on the (same) stack a pointer to a
+ # loop_token that keeps the force_index alive.
+ callshape = self._callshapes[force_index]
else:
- # points to a MARKER
- follow_stack_frame_of_assembler(callback, gc, addr)
- #
- def follow_stack_frame_of_assembler(callback, gc, addr):
- frame_addr = addr.signed[0] - self.marker_ofs
- addr = llmemory.cast_int_to_adr(frame_addr + self.force_index_ofs)
- force_index = addr.signed[0]
- if force_index < 0:
- force_index = ~force_index
- callshape = self._callshapes[force_index]
- # NB: the previous line reads a still-alive _callshapes,
- # because we ensure that just before we called this piece of
- # assembler, we put on the (same) stack a pointer to a
- # loop_token that keeps the force_index alive.
- n = 0
- while True:
- offset = rffi.cast(lltype.Signed, callshape[n])
- if offset == 0:
- break
- addr = llmemory.cast_int_to_adr(frame_addr + offset)
- if gc.points_to_valid_gc_object(addr):
- callback(gc, addr)
- n += 1
+ # Continuing to explore this JIT frame
+ callshape = self._iter_callshape
+ #
+ # 'callshape' points to the next INT of the callshape.
+ # If it's zero we are done with the JIT frame.
+ while callshape[0] != 0:
+ #
+ # Non-zero: it's an offset inside the JIT frame.
+ # Read it and increment 'callshape'.
+ offset = callshape[0]
+ callshape = lltype.direct_ptradd(callshape, 1)
+ addr = llmemory.cast_int_to_adr(self._iter_frame_addr +
+ offset)
+ if gc.points_to_valid_gc_object(addr):
+ #
+ # The JIT frame contains a valid GC pointer at
+ # this address (and not e.g. NULL). Save 'callshape'
+ # for the next call, and return it.
+ self._iter_callshape = callshape
+ return addr
+ #
+ # Restore 'prev' and loop back to the start.
+ prev = self._iter_saved_prev
+ self._iter_frame_addr = llmemory.NULL
+
+ # ---------------
#
jit2gc.update({
- 'rootstackhook': collect_jit_stack_root,
+ 'root_iterator_setup': iterator_setup,
+ 'root_iterator_next': iterator_next,
})
def initialize(self):
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
@@ -149,13 +149,8 @@
# for regular translation: pick the GC from the config
GCClass, GC_PARAMS = choose_gc_from_config(translator.config)
- self.root_stack_jit_hook = None
if hasattr(translator, '_jit2gc'):
self.layoutbuilder = translator._jit2gc['layoutbuilder']
- try:
- self.root_stack_jit_hook = translator._jit2gc['rootstackhook']
- except KeyError:
- pass
else:
self.layoutbuilder = TransformerLayoutBuilder(translator, GCClass)
self.layoutbuilder.transformer = self
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
@@ -27,12 +27,27 @@
return top
self.decr_stack = decr_stack
- self.rootstackhook = gctransformer.root_stack_jit_hook
- if self.rootstackhook is None:
- def collect_stack_root(callback, gc, addr):
- if gc.points_to_valid_gc_object(addr):
- callback(gc, addr)
- self.rootstackhook = collect_stack_root
+ translator = gctransformer.translator
+ if hasattr(translator, '_jit2gc'):
+ iterator_setup = translator._jit2gc['root_iterator_setup']
+ iterator_next = translator._jit2gc['root_iterator_next']
+ def jit_walk_stack_root(callback, addr, end):
+ gc = self.gc
+ iterator_setup()
+ while True:
+ end = iterator_next(end, addr)
+ if end == llmemory.NULL:
+ return
+ callback(gc, end)
+ self.rootstackhook = jit_walk_stack_root
+ else:
+ def default_walk_stack_root(callback, addr, end):
+ gc = self.gc
+ while addr != end:
+ if gc.points_to_valid_gc_object(addr):
+ callback(gc, addr)
+ addr += sizeofaddr
+ self.rootstackhook = default_walk_stack_root
def push_stack(self, addr):
top = self.incr_stack(1)
@@ -54,20 +69,18 @@
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:
- rootstackhook(collect_stack_root, gc, addr)
- addr += sizeofaddr
+ self.rootstackhook(collect_stack_root,
+ gcdata.root_stack_base, gcdata.root_stack_top)
if self.collect_stacks_from_other_threads is not None:
self.collect_stacks_from_other_threads(collect_stack_root)
def need_stacklet_support(self):
- pass # no special code needed here
+ # stacklet support: BIG HACK for rlib.rstacklet
+ from pypy.rlib import _stacklet_shadowstack
+ _stacklet_shadowstack._shadowstackrootwalker = self # as a global! argh
def need_thread_support(self, gctransformer, getfn):
+ XXXXXX # FIXME
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
diff --git a/pypy/translator/goal/targetpypystandalone.py
b/pypy/translator/goal/targetpypystandalone.py
--- a/pypy/translator/goal/targetpypystandalone.py
+++ b/pypy/translator/goal/targetpypystandalone.py
@@ -174,9 +174,14 @@
config.objspace.usemodules.thread = False
if config.translation.continuation:
- config.objspace.usemodules._stacklet = True
- elif config.objspace.usemodules._stacklet:
- config.translation.continuation = True
+ config.objspace.usemodules._continuation = True
+ elif config.objspace.usemodules._continuation:
+ try:
+ config.translation.continuation = True
+ except ConflictConfigError:
+ # Same as above: try to auto-disable the _continuation
+ # module if translation.continuation cannot be enabled
+ config.objspace.usemodules._continuation = False
if not config.translation.rweakref:
config.objspace.usemodules._weakref = False
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit