[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