[pypy-svn] r50010 - in pypy/branch/llvmgcroot/pypy: config rpython/lltypesystem rpython/memory/gctransform translator/c
arigo at codespeak.net
arigo at codespeak.net
Sat Dec 22 16:18:43 CET 2007
Author: arigo
Date: Sat Dec 22 16:18:43 2007
New Revision: 50010
Added:
pypy/branch/llvmgcroot/pypy/rpython/memory/gctransform/llvmgcroot.py
Modified:
pypy/branch/llvmgcroot/pypy/config/translationoption.py
pypy/branch/llvmgcroot/pypy/rpython/lltypesystem/lloperation.py
pypy/branch/llvmgcroot/pypy/rpython/memory/gctransform/framework.py
pypy/branch/llvmgcroot/pypy/translator/c/gc.py
pypy/branch/llvmgcroot/pypy/translator/c/genc.py
Log:
In-progress: the llvmgcroot GC transformer, with its
custom StackRootIterator that walks the tables
produced by the llvm GC plugin.
Modified: pypy/branch/llvmgcroot/pypy/config/translationoption.py
==============================================================================
--- pypy/branch/llvmgcroot/pypy/config/translationoption.py (original)
+++ pypy/branch/llvmgcroot/pypy/config/translationoption.py Sat Dec 22 16:18:43 2007
@@ -62,6 +62,10 @@
requires=[("translation.gctransformer", "framework"),
("translation.stackless", True)],
suggests=[("translation.gc", "marksweep")]),
+ BoolOption("llvmgcroot", "Use the 'llvm.gcroot' primitive to find roots",
+ default=False, cmdline="--llvmgcroot",
+ requires=[("translation.backend", "llvm"),
+ ("translation.gctransformer", "framework")]),
BoolOption("thread", "enable use of threading primitives",
default=False, cmdline="--thread",
requires=[("translation.gc", "boehm")]),
Modified: pypy/branch/llvmgcroot/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/branch/llvmgcroot/pypy/rpython/lltypesystem/lloperation.py (original)
+++ pypy/branch/llvmgcroot/pypy/rpython/lltypesystem/lloperation.py Sat Dec 22 16:18:43 2007
@@ -408,6 +408,12 @@
# stackless:
'gc_x_become': LLOp(canraise=(RuntimeError,), canunwindgc=True),
+ # for llvm.gcroot() support. can change at any time
+ 'llvm_frameaddress': LLOp(),
+ 'llvm_gcmap_table': LLOp(),
+ 'llvm_store_gcroot': LLOp(),
+ 'llvm_load_gcroot': LLOp(),
+
# NOTE NOTE NOTE! don't forget *** canunwindgc=True *** for anything that
# can go through a stack unwind, in particular anything that mallocs!
Modified: pypy/branch/llvmgcroot/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/branch/llvmgcroot/pypy/rpython/memory/gctransform/framework.py (original)
+++ pypy/branch/llvmgcroot/pypy/rpython/memory/gctransform/framework.py Sat Dec 22 16:18:43 2007
@@ -732,9 +732,7 @@
def pop_alive_nopyobj(self, var, llops):
pass
- def push_roots(self, hop, keep_current_args=False):
- if self.incr_stack_ptr is None:
- return
+ def get_livevars_for_roots(self, hop, keep_current_args=False):
if self.gcdata.gc.moving_gc and not keep_current_args:
# moving GCs don't borrow, so the caller does not need to keep
# the arguments alive
@@ -743,6 +741,12 @@
else:
livevars = hop.livevars_after_op() + hop.current_op_keeps_alive()
livevars = [var for var in livevars if not var_ispyobj(var)]
+ return livevars
+
+ def push_roots(self, hop, keep_current_args=False):
+ if self.incr_stack_ptr is None:
+ return
+ livevars = self.get_livevars_for_roots(hop, keep_current_args)
self.num_pushs += len(livevars)
if not livevars:
return []
Added: pypy/branch/llvmgcroot/pypy/rpython/memory/gctransform/llvmgcroot.py
==============================================================================
--- (empty file)
+++ pypy/branch/llvmgcroot/pypy/rpython/memory/gctransform/llvmgcroot.py Sat Dec 22 16:18:43 2007
@@ -0,0 +1,159 @@
+from pypy.rpython.memory.gctransform.framework import FrameworkGCTransformer
+from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.lltypesystem.lloperation import llop
+from pypy.rpython import rmodel
+from pypy.rpython.rbuiltin import gen_cast
+from pypy.rlib.debug import ll_assert
+
+
+class LLVMGcRootFrameworkGCTransformer(FrameworkGCTransformer):
+ # XXX this is completely specific to the llvm backend at the moment.
+
+ 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 []
+ for k, var in enumerate(livevars):
+ c_k = rmodel.inputconst(lltype.Signed, k)
+ v_adr = gen_cast(hop.llops, llmemory.Address, var)
+ hop.genop("llvm_store_gcroot", [c_k, v_adr])
+ return livevars
+
+ def pop_roots(self, hop, livevars):
+ if not livevars:
+ return
+ 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)
+ v_newaddr = hop.genop("llvm_load_gcroot", [c_k],
+ resulttype=llmemory.Address)
+ hop.genop("gc_reload_possibly_moved", [v_newaddr, var])
+ # XXX for now, the values stay in the gcroots. It might keep
+ # some old objects alive for a bit longer than necessary.
+
+ def build_stack_root_iterator(self):
+ sizeofaddr = llmemory.sizeof(llmemory.Address)
+ gcdata = self.gcdata
+
+ class StackRootIterator:
+ _alloc_flavor_ = 'raw'
+
+ def setup_root_stack():
+ pass
+ setup_root_stack = staticmethod(setup_root_stack)
+
+ need_root_stack = False
+
+ def append_static_root(adr):
+ gcdata.static_root_end.address[0] = adr
+ gcdata.static_root_end += sizeofaddr
+ append_static_root = staticmethod(append_static_root)
+
+ def __init__(self, with_static=True):
+ self.stack_current = llop.llvm_frameaddress(llmemory.Address)
+ self.remaining_roots_in_current_frame = 0
+ if with_static:
+ self.static_current = gcdata.static_root_end
+ else:
+ self.static_current = gcdata.static_root_nongcend
+
+ def pop(self):
+ while self.static_current != gcdata.static_root_start:
+ self.static_current -= sizeofaddr
+ result = self.static_current.address[0]
+ if result.address[0] != llmemory.NULL:
+ return result
+
+ while True:
+ while self.remaining_roots_in_current_frame == 0:
+ if not self.walk_to_parent_frame():
+ return llmemory.NULL
+ result = self.next_gcroot_from_current_frame()
+ if result.address[0] != llmemory.NULL:
+ return result
+
+ def walk_to_parent_frame(self):
+ #
+ # XXX assumes a 32-bit machine for simplicity.
+ #
+ # The gcmap table is a list of pointers to gcmap_t
+ # structures, where the shape of each gcmap_t is:
+ # struct {
+ # int32_t FrameSize;
+ # int32_t PointCount;
+ # struct {
+ # void *SafePointAddress;
+ # int32_t LiveCount;
+ # int32_t LiveOffsets[LiveCount];
+ # } Points[PointCount];
+ # } gcmap_t;
+ #
+ callee_frame = self.stack_current
+ #
+ # XXX the details are completely specific to X86!!!
+ # a picture of the stack may help:
+ # ^ ^ ^
+ # | ... | to older frames
+ # +--------------+
+ # | first word | <------ caller_frame (addr of 1st word)
+ # + +
+ # | caller frame |
+ # | ... |
+ # | frame data | <------ frame_data_base
+ # +--------------+
+ # | ret addr |
+ # +--------------+
+ # | first word | <------ callee_frame (addr of 1st word)
+ # + +
+ # | callee frame |
+ # | ... |
+ # | frame data | lower addresses
+ # +--------------+ v v v
+ #
+ retaddr = callee_frame.address[1]
+ #
+ # try to locate the caller function based on retaddr.
+ # XXX this is just a linear scan for now, that's
+ # incredibly bad.
+ #
+ gcmaptbl = llop.llvm_gcmap_table(llmemory.Address)
+ i = 0
+ while True:
+ gcmap = gcmaptbl.address[i]
+ if not gcmap: # function not found
+ return False # => assume end of stack
+ framesize = gcmap.signed[0]
+ pointcount = gcmap.signed[1]
+ gcmap += 8
+ j = 0
+ while j < pointcount:
+ safepointaddr = gcmap.address[0]
+ livecount = gcmap.signed[1]
+ if safepointaddr == retaddr:
+ #
+ # found! Setup pointers allowing us to
+ # parse the caller's frame structure...
+ #
+ caller_frame = callee_frame + 4 + framesize
+ self.stack_current = caller_frame
+ self.frame_data_base = callee_frame + 8
+ self.remaining_roots_in_current_frame = livecount
+ self.liveoffsets = gcmap + 8
+ return True
+
+ # not found
+ gcmap += 8 + livecount * 4
+ j += 1
+ i += 1
+
+ def next_gcroot_from_current_frame(self):
+ i = self.remaining_roots_in_current_frame - 1
+ self.remaining_roots_in_current_frame = i
+ ll_assert(i >= 0, "bad call to next_gcroot_from_current_frame")
+ liveoffset = self.liveoffsets.signed[i]
+ return self.frame_data_base + liveoffset
+
+
+ return StackRootIterator
Modified: pypy/branch/llvmgcroot/pypy/translator/c/gc.py
==============================================================================
--- pypy/branch/llvmgcroot/pypy/translator/c/gc.py (original)
+++ pypy/branch/llvmgcroot/pypy/translator/c/gc.py Sat Dec 22 16:18:43 2007
@@ -5,7 +5,7 @@
typeOf, Ptr, ContainerType, RttiStruct, \
RuntimeTypeInfo, getRuntimeTypeInfo, top_container
from pypy.rpython.memory.gctransform import \
- refcounting, boehm, framework, stacklessframework
+ refcounting, boehm, framework, stacklessframework, llvmgcroot
from pypy.rpython.lltypesystem import lltype, llmemory
class BasicGcPolicy(object):
@@ -305,6 +305,9 @@
transformerclass = stacklessframework.StacklessFrameworkGCTransformer
requires_stackless = True
+class LLVMGcRootFrameworkGcPolicy(FrameworkGcPolicy):
+ transformerclass = llvmgcroot.LLVMGcRootFrameworkGCTransformer
+
name_to_gcpolicy = {
'boehm': BoehmGcPolicy,
@@ -312,6 +315,7 @@
'none': NoneGcPolicy,
'framework': FrameworkGcPolicy,
'framework+stacklessgc': StacklessFrameworkGcPolicy,
+ 'framework+llvmgcroot': LLVMGcRootFrameworkGcPolicy,
}
Modified: pypy/branch/llvmgcroot/pypy/translator/c/genc.py
==============================================================================
--- pypy/branch/llvmgcroot/pypy/translator/c/genc.py (original)
+++ pypy/branch/llvmgcroot/pypy/translator/c/genc.py Sat Dec 22 16:18:43 2007
@@ -93,6 +93,8 @@
name = self.config.translation.gctransformer
if self.config.translation.stacklessgc:
name = "%s+stacklessgc" % (name,)
+ if self.config.translation.llvmgcroot:
+ name = "%s+llvmgcroot" % (name,)
return gc.name_to_gcpolicy[name]
return self.gcpolicy
More information about the Pypy-commit
mailing list