[pypy-svn] r50290 - in pypy/branch/asmgcroot/pypy: rpython/memory/gctransform translator/c

arigo at codespeak.net arigo at codespeak.net
Thu Jan 3 17:36:57 CET 2008


Author: arigo
Date: Thu Jan  3 17:36:56 2008
New Revision: 50290

Modified:
   pypy/branch/asmgcroot/pypy/rpython/memory/gctransform/asmgcroot.py
   pypy/branch/asmgcroot/pypy/rpython/memory/gctransform/framework.py
   pypy/branch/asmgcroot/pypy/translator/c/trackgcroot.py
Log:
Invoke the GC root walking via a callback.  This allows us to
save and restore all the callee-saved registers into the stack
at a single clear place: pypy_asm_stackwalk().


Modified: pypy/branch/asmgcroot/pypy/rpython/memory/gctransform/asmgcroot.py
==============================================================================
--- pypy/branch/asmgcroot/pypy/rpython/memory/gctransform/asmgcroot.py	(original)
+++ pypy/branch/asmgcroot/pypy/rpython/memory/gctransform/asmgcroot.py	Thu Jan  3 17:36:56 2008
@@ -1,8 +1,8 @@
 from pypy.rpython.memory.gctransform.framework import FrameworkGCTransformer
+from pypy.rpython.memory.gctransform.framework import BaseRootWalker
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 from pypy.rpython.lltypesystem.lloperation import llop
-from pypy.rpython import rmodel
-from pypy.rpython.rbuiltin import gen_cast
+from pypy.rpython.annlowlevel import llhelper
 from pypy.rlib.debug import ll_assert
 
 
@@ -29,170 +29,174 @@
             hop.genop("asm_gcroot", [var])
 
     def build_root_walker(self):
-        gcdata = self.gcdata
-        gc = gcdata.gc
+        return AsmStackRootWalker(self)
+
+
+class AsmStackRootWalker(BaseRootWalker):
+
+    def __init__(self, gctransformer):
+        BaseRootWalker.__init__(self, gctransformer)
+
+        def _asm_callback(initialframedata):
+            self.walk_stack_from(initialframedata)
+        self._asm_callback = _asm_callback
+
+    def setup_root_walker(self):
+        # The gcmap table is a list of pairs of pointers:
+        #     void *SafePointAddress;
+        #     void *Shape;
+        # Here, i.e. when the program starts, we sort it
+        # in-place on the SafePointAddress to allow for more
+        # efficient searches.
+        gcmapstart = llop.llvm_gcmapstart(llmemory.Address)
+        gcmapend   = llop.llvm_gcmapend(llmemory.Address)
+        insertion_sort(gcmapstart, gcmapend)
 
-        class RootWalker:
-            _alloc_flavor_ = 'raw'
+    def walk_stack_roots(self, collect_stack_root):
+        gcdata = self.gcdata
+        gcdata._gc_collect_stack_root = collect_stack_root
+        pypy_asm_stackwalk(llhelper(ASM_CALLBACK_PTR, self._asm_callback))
 
-            def setup_root_stack(self):
-                # The gcmap table is a list of pairs of pointers:
-                #     void *SafePointAddress;
-                #     void *Shape;
-                # Here, i.e. when the program starts, we sort it
-                # in-place on the SafePointAddress to allow for more
-                # efficient searches.
-                gcmapstart = llop.llvm_gcmapstart(llmemory.Address)
-                gcmapend   = llop.llvm_gcmapend(llmemory.Address)
-                insertion_sort(gcmapstart, gcmapend)
-
-            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 walk_roots(self, collect_stack_root,
-                           collect_static_in_prebuilt_nongc,
-                           collect_static_in_prebuilt_gc,
-                           collect_finished):
-                ...
-                self.callee_data = lltype.malloc(ASM_STACKWALK, flavor="raw")
-                self.caller_data = lltype.malloc(ASM_STACKWALK, flavor="raw")
-                pypy_asm_stackwalk_init(self.caller_data)
-                self.remaining_roots_in_current_frame = 0
-                # We must walk at least a couple of frames up the stack
-                # *now*, i.e. before we leave __init__, otherwise
-                # the caller_data ends up pointing to a dead frame.
-                # We can walk until we find a real GC root; then we're
-                # definitely out of the GC code itself.
-                while self.remaining_roots_in_current_frame == 0:
-                    if not self.walk_to_parent_frame():
-                        break     # not a single GC root? unlikely but not
-                                  # impossible I guess
-                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):
-                if not self.caller_data:
-                    return False
-                #
-                # The gcmap table is a list of pairs of pointers:
-                #     void *SafePointAddress;
-                #     void *Shape;
-                #
-                # A "safe point" is the return address of a call.
-                # The "shape" of a safe point is a list of integers
-                # as follows:
-                #
-                #   * The size of the frame of the function containing the
-                #     call (in theory it can be different from call to call).
-                #     This size includes the return address (see picture
-                #     below).
-                #
-                #   * Four integers that specify where the function saves
-                #     each of the four callee-saved registers (%ebx, %esi,
-                #     %edi, %ebp).  This is a "location", see below.
-                #
-                #   * The number of live GC roots around the call.
-                #
-                #   * For each GC root, an integer that specify where the
-                #     GC pointer is stored.  This is a "location", see below.
-                #
-                # A "location" can be either in the stack or in a register.
-                # If it is in the stack, it is specified as an integer offset
-                # from the current frame (so it is typically < 0, as seen
-                # in the picture below, though it can also be > 0 if the
-                # location is an input argument to the current function and
-                # thus lives at the bottom of the caller's frame).
-                # A "location" can also be in a register; in our context it
-                # can only be a callee-saved register.  This is specified
-                # as a small odd-valued integer (1=%ebx, 3=%esi, etc.)
-
-                # In the code below, we walk the next older frame on the stack.
-                # The caller becomes the callee; we swap the two buffers and
-                # fill in the new caller's data.
-                callee = self.caller_data
-                caller = self.callee_data
-                self.caller_data = caller
-                self.callee_data = callee
-                #
-                # XXX the details are completely specific to X86!!!
-                # a picture of the stack may help:
-                #                                           ^ ^ ^
-                #     |     ...      |                 to older frames
-                #     +--------------+
-                #     |   ret addr   |  <------ caller_frame (addr of retaddr)
-                #     |     ...      |
-                #     | caller frame |
-                #     |     ...      |
-                #     +--------------+
-                #     |   ret addr   |  <------ callee_frame (addr of retaddr)
-                #     |     ...      |
-                #     | callee frame |
-                #     |     ...      |                 lower addresses
-                #     +--------------+                      v v v
-                #
-                callee_frame = callee[FRAME_PTR]
-                retaddr = callee[RET_ADDR]
-                #
-                # try to locate the caller function based on retaddr.
-                #
-                gcmapstart = llop.llvm_gcmapstart(llmemory.Address)
-                gcmapend   = llop.llvm_gcmapend(llmemory.Address)
-                item = binary_search(gcmapstart, gcmapend, retaddr)
-                if item.address[0] != retaddr:
-                    # retaddr not found!
-                    llop.debug_fatalerror(lltype.Void, "cannot find gc roots!")
-                    return False
-
-                # found!  Now we can fill in 'caller'.
-                shape = item.address[1]
-                framesize = shape.signed[0]
-                caller[FRAME_PTR] = callee_frame + framesize
-                caller[RET_ADDR] = caller[FRAME_PTR].address[0]
-                reg = 0
-                while reg < CALLEE_SAVED_REGS:
-                    caller[reg] = self.read_from_location(shape.signed[1+reg])
-                    reg += 1
-                livecount = shape.signed[1+CALLEE_SAVED_REGS]
-                self.remaining_roots_in_current_frame = livecount
-                self.liveoffsets = shape + 4 * (1+CALLEE_SAVED_REGS+1)
-                return True
-
-            def finished(self):
-                lltype.free(self.stackwalkcur, flavor='raw')
-                self.stackwalkcur = lltype.nullptr(ASM_STACKWALK)
-                lltype.free(self.stackwalknext, flavor='raw')
-                self.stackwalknext = lltype.nullptr(ASM_STACKWALK)
-
-            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.callee_data[FRAME_PTR] + liveoffset
+    def walk_stack_from(self, initialframedata):
+        curframe = lltype.malloc(WALKFRAME, flavor='raw')
+        otherframe = lltype.malloc(WALKFRAME, flavor='raw')
+        self.fill_initial_frame(curframe, initialframedata)
+        # Loop over all the frames in the stack
+        while self.walk_to_parent_frame(curframe, otherframe):
+            swap = curframe
+            curframe = otherframe    # caller becomes callee
+            otherframe = swap
+        lltype.free(otherframe, flavor='raw')
+        lltype.free(curframe, flavor='raw')
+
+    def fill_initial_frame(self, curframe, initialframedata):
+        # Read the information provided by initialframedata
+        reg = 0
+        while reg < CALLEE_SAVED_REGS:
+            # NB. 'initialframedata' stores the actual values of the
+            # registers %ebx etc., and if these values are modified
+            # they are reloaded by pypy_asm_stackwalk().  By contrast,
+            # 'regs_stored_at' merely points to the actual values
+            # from the 'initialframedata'.
+            curframe.regs_stored_at[reg] = initialframedata + reg*sizeofaddr
+            reg += 1
+        curframe.frame_address = initialframedata.address[CALLEE_SAVED_REGS]
+
+    def walk_to_parent_frame(self, callee, caller):
+        """Starting from 'callee', walk the next older frame on the stack
+        and fill 'caller' accordingly.  Also invokes the collect_stack_root()
+        callback from the GC code for each GC root found in 'caller'.
+        """
+        #
+        # The gcmap table is a list of pairs of pointers:
+        #     void *SafePointAddress;
+        #     void *Shape;
+        #
+        # A "safe point" is the return address of a call.
+        # The "shape" of a safe point is a list of integers
+        # as follows:
+        #
+        #   * The size of the frame of the function containing the
+        #     call (in theory it can be different from call to call).
+        #     This size includes the return address (see picture
+        #     below).
+        #
+        #   * Four integers that specify where the function saves
+        #     each of the four callee-saved registers (%ebx, %esi,
+        #     %edi, %ebp).  This is a "location", see below.
+        #
+        #   * The number of live GC roots around the call.
+        #
+        #   * For each GC root, an integer that specify where the
+        #     GC pointer is stored.  This is a "location", see below.
+        #
+        # A "location" can be either in the stack or in a register.
+        # If it is in the stack, it is specified as an integer offset
+        # from the current frame (so it is typically < 0, as seen
+        # in the picture below, though it can also be > 0 if the
+        # location is an input argument to the current function and
+        # thus lives at the bottom of the caller's frame).
+        # A "location" can also be in a register; in our context it
+        # can only be a callee-saved register.  This is specified
+        # as a small odd-valued integer (1=%ebx, 3=%esi, etc.)
+        #
+        # XXX the details are completely specific to X86!!!
+        # a picture of the stack may help:
+        #                                           ^ ^ ^
+        #     |     ...      |                 to older frames
+        #     +--------------+
+        #     |   ret addr   |  <------ caller_frame (addr of retaddr)
+        #     |     ...      |
+        #     | caller frame |
+        #     |     ...      |
+        #     +--------------+
+        #     |   ret addr   |  <------ callee_frame (addr of retaddr)
+        #     |     ...      |
+        #     | callee frame |
+        #     |     ...      |                 lower addresses
+        #     +--------------+                      v v v
+        #
+
+        retaddr = callee.frame_address.address[0]
+        #
+        # try to locate the caller function based on retaddr.
+        #
+        gcmapstart = llop.llvm_gcmapstart(llmemory.Address)
+        gcmapend   = llop.llvm_gcmapend(llmemory.Address)
+        item = binary_search(gcmapstart, gcmapend, retaddr)
+        if item.address[0] != retaddr:
+            # retaddr not found!
+            llop.debug_fatalerror(lltype.Void, "cannot find gc roots!")
+            return False
+        #
+        # found!  Now we can go to the caller_frame.
+        #
+        shape = item.address[1]
+        framesize = shape.signed[0]
+        caller.frame_address = callee.frame_address + framesize
+        #
+        # enumerate the GC roots in the caller frame
+        #
+        collect_stack_root = self.gcdata._gc_collect_stack_root
+        gc = self.gc
+        LIVELOCS = 1 + CALLEE_SAVED_REGS + 1  # index of the first gc root loc
+        livecount = shape.signed[LIVELOCS-1]
+        while livecount > 0:
+            livecount -= 1
+            location = shape.signed[LIVELOCS + livecount]
+            addr = self.getlocation(callee, caller, location)
+            if addr.address[0] != llmemory.NULL:
+                collect_stack_root(gc, addr)
+        #
+        # track where the caller_frame saved the registers from its own
+        # caller
+        #
+        if shape.signed[1] == -1:     # a marker that means "I'm the frame
+            return False              # of the entry point, stop walking"
+        reg = 0
+        while reg < CALLEE_SAVED_REGS:
+            location = shape.signed[1+reg]
+            addr = self.getlocation(callee, caller, location)
+            caller.regs_stored_at[reg] = addr
+            reg += 1
+        return True
+
+    def getlocation(self, callee, caller, location):
+        """Get the location in the 'caller' frame of a variable, based
+        on the integer 'location' that describes it.  The 'callee' is
+        only used if the location is in a register that was saved in the
+        callee.
+        """
+        if location & 1:     # register
+            reg = location >> 1
+            ll_assert(0 <= reg < CALLEE_SAVED_REGS, "bad register location")
+            return callee.regs_stored_at[reg]
+        else:
+            # in the stack frame
+            return caller.frame_address + location
 
-        return RootWalker()
 
+# ____________________________________________________________
 
 sizeofaddr = llmemory.sizeof(llmemory.Address)
 arrayitemsize = 2 * sizeofaddr
@@ -239,11 +243,14 @@
         scan.address[1] = addr2
         next += arrayitemsize
 
+# ____________________________________________________________
+
 #
-# The special pypy_asm_stackwalk_init(), implemented directly in
-# assembler, initializes an ASM_STACKWALK array in order to bootstrap
-# the stack walking code.  An ASM_STACKWALK is an array of 6 values
-# that describe everything we need to know about a stack frame:
+# The special pypy_asm_stackwalk(), implemented directly in
+# assembler, fills information about the current stack top in an
+# ASM_FRAMEDATA array and invokes an RPython callback with it.
+# An ASM_FRAMEDATA is an array of 5 values that describe everything
+# we need to know about a stack frame:
 #
 #   - the value that %ebx had when the current function started
 #   - the value that %esi had when the current function started
@@ -251,16 +258,23 @@
 #   - the value that %ebp had when the current function started
 #   - frame address (actually the addr of the retaddr of the current function;
 #                    that's the last word of the frame in memory)
-#   - the return address for when the current function finishes
-#                   (which is usually just the word at "frame address")
 #
 CALLEE_SAVED_REGS = 4       # there are 4 callee-saved registers
-FRAME_PTR      = CALLEE_SAVED_REGS
-RET_ADDR       = CALLEE_SAVED_REGS + 1
-ASM_STACKWALK  = lltype.FixedSizeArray(llmemory.Address, CALLEE_SAVED_REGS + 2)
-
-pypy_asm_stackwalk_init = rffi.llexternal('pypy_asm_stackwalk_init',
-                                          [lltype.Ptr(ASM_STACKWALK)],
-                                          lltype.Void,
-                                          sandboxsafe=True,
-                                          _nowrapper=True)
+FRAME_PTR         = CALLEE_SAVED_REGS    # the frame is at index 4 in the array
+
+ASM_CALLBACK_PTR = lltype.Ptr(lltype.FuncType([llmemory.Address],
+                                              lltype.Void))
+
+# used internally by walk_stack_from()
+WALKFRAME = lltype.Struct('WALKFRAME',
+        ('regs_stored_at',    # address of where the registers have been saved
+             lltype.FixedSizeArray(llmemory.Address, CALLEE_SAVED_REGS)),
+        ('frame_address',
+             llmemory.Address),
+    )
+
+pypy_asm_stackwalk = rffi.llexternal('pypy_asm_stackwalk',
+                                     [ASM_CALLBACK_PTR],
+                                     lltype.Void,
+                                     sandboxsafe=True,
+                                     _nowrapper=True)

Modified: pypy/branch/asmgcroot/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/branch/asmgcroot/pypy/rpython/memory/gctransform/framework.py	(original)
+++ pypy/branch/asmgcroot/pypy/rpython/memory/gctransform/framework.py	Thu Jan  3 17:36:56 2008
@@ -131,18 +131,16 @@
         self.gcdata = gcdata
         self.malloc_fnptr_cache = {}
 
-        sizeofaddr = llmemory.sizeof(llmemory.Address)
-
         gcdata.gc = GCClass(AddressLinkedList, **GC_PARAMS)
         root_walker = self.build_root_walker()
         gcdata.set_query_functions(gcdata.gc)
-        gcdata.set_root_walker(gcdata.gc, root_walker)
+        gcdata.gc.set_root_walker(root_walker)
         self.num_pushs = 0
         self.write_barrier_calls = 0
 
         def frameworkgc_setup():
             # run-time initialization code
-            root_walker.setup_root_stack()
+            root_walker.setup_root_walker()
             gcdata.gc.setup()
 
         bk = self.translator.annotator.bookkeeper
@@ -173,25 +171,16 @@
 
         self.frameworkgc_setup_ptr = getfn(frameworkgc_setup, [],
                                            annmodel.s_None)
-        if RootWalker.need_root_stack:
-            #self.pop_root_ptr = getfn(RootWalker.pop_root, [],
-            #                          annmodel.SomeAddress(),
-            #                          inline = True)
-            #self.push_root_ptr = getfn(RootWalker.push_root,
-            #                           [annmodel.SomeAddress()],
-            #                           annmodel.s_None,
-            #                           inline = True)
-            self.incr_stack_ptr = getfn(RootWalker.incr_stack,
+        if root_walker.need_root_stack:
+            self.incr_stack_ptr = getfn(root_walker.incr_stack,
                                        [annmodel.SomeInteger()],
                                        annmodel.SomeAddress(),
                                        inline = True)
-            self.decr_stack_ptr = getfn(RootWalker.decr_stack,
+            self.decr_stack_ptr = getfn(root_walker.decr_stack,
                                        [annmodel.SomeInteger()],
                                        annmodel.SomeAddress(),
                                        inline = True)
         else:
-            #self.push_root_ptr = None
-            #self.pop_root_ptr = None
             self.incr_stack_ptr = None
             self.decr_stack_ptr = None
         self.weakref_deref_ptr = self.inittime_helper(
@@ -352,71 +341,7 @@
             fields.append(('_' + fldname, FLDTYPE))
 
     def build_root_walker(self):
-        gcdata = self.gcdata
-        sizeofaddr = llmemory.sizeof(llmemory.Address)
-        rootstacksize = sizeofaddr * self.root_stack_depth
-
-        class RootWalker:
-            _alloc_flavor_ = 'raw'
-            def setup_root_stack():
-                stackbase = llmemory.raw_malloc(rootstacksize)
-                ll_assert(bool(stackbase), "could not allocate root stack")
-                llmemory.raw_memclear(stackbase, rootstacksize)
-                gcdata.root_stack_top  = stackbase
-                gcdata.root_stack_base = stackbase
-            setup_root_stack = staticmethod(setup_root_stack)
-
-            need_root_stack = True
-            
-            def incr_stack(n):
-                top = gcdata.root_stack_top
-                gcdata.root_stack_top = top + n*sizeofaddr
-                return top
-            incr_stack = staticmethod(incr_stack)
-
-            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 decr_stack(n):
-                top = gcdata.root_stack_top - n*sizeofaddr
-                gcdata.root_stack_top = top
-                return top
-            decr_stack = staticmethod(decr_stack)
-                
-            def push_root(addr):
-                top = gcdata.root_stack_top
-                top.address[0] = addr
-                gcdata.root_stack_top = top + sizeofaddr
-            push_root = staticmethod(push_root)
-
-            def pop_root():
-                top = gcdata.root_stack_top - sizeofaddr
-                gcdata.root_stack_top = top
-                return top.address[0]
-            pop_root = staticmethod(pop_root)
-
-            def __init__(self, with_static=True):
-                self.stack_current = gcdata.root_stack_top
-                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 self.stack_current != gcdata.root_stack_base:
-                    self.stack_current -= sizeofaddr
-                    if self.stack_current.address[0] != llmemory.NULL:
-                        return self.stack_current
-                return llmemory.NULL
-
-        return StackRootIterator
+        return ShadowStackRootWalker(self)
 
     def consider_constant(self, TYPE, value):
         self.layoutbuilder.consider_constant(TYPE, value, self.gcdata.gc)
@@ -830,3 +755,87 @@
                             [v] + previous_steps + [c_name, c_null])
         elif isinstance(FIELD, lltype.Struct):
             gen_zero_gc_pointers(FIELD, v, llops, previous_steps + [c_name])
+
+# ____________________________________________________________
+
+
+sizeofaddr = llmemory.sizeof(llmemory.Address)
+
+
+class BaseRootWalker:
+    need_root_stack = False
+
+    def __init__(self, gctransformer):
+        self.gcdata = gctransformer.gcdata
+        self.gc = self.gcdata.gc
+
+    def _freeze_(self):
+        return True
+
+    def setup_root_walker(self):
+        pass
+
+    def append_static_root(self, adr):
+        self.gcdata.static_root_end.address[0] = adr
+        self.gcdata.static_root_end += sizeofaddr
+
+    def walk_roots(self, collect_stack_root,
+                   collect_static_in_prebuilt_nongc,
+                   collect_static_in_prebuilt_gc):
+        gcdata = self.gcdata
+        gc = self.gc
+        if collect_static_in_prebuilt_nongc:
+            addr = gcdata.static_root_start
+            end = gcdata.static_root_nongcend
+            while addr != end:
+                if addr.address[0] != llmemory.NULL:
+                    collect_static_in_prebuilt_nongc(gc, addr)
+                addr += sizeofaddr
+        if collect_static_in_prebuilt_gc:
+            addr = gcdata.static_root_nongcend
+            end = gcdata.static_root_end
+            while addr != end:
+                if addr.address[0] != llmemory.NULL:
+                    collect_static_in_prebuilt_gc(gc, addr)
+                addr += sizeofaddr
+        if collect_stack_root:
+            self.walk_stack_roots(collect_stack_root)     # abstract
+
+
+class ShadowStackRootWalker(BaseRootWalker):
+    need_root_stack = True
+
+    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
+
+    def setup_root_walker(self):
+        stackbase = llmemory.raw_malloc(self.rootstacksize)
+        ll_assert(bool(stackbase), "could not allocate root stack")
+        llmemory.raw_memclear(stackbase, self.rootstacksize)
+        self.gcdata.root_stack_top  = stackbase
+        self.gcdata.root_stack_base = stackbase
+
+    def walk_stack_roots(self, collect_stack_root):
+        gcdata = self.gcdata
+        gc = self.gc
+        addr = gcdata.root_stack_base
+        end = gcdata.root_stack_top
+        while addr != end:
+            if addr.address[0] != llmemory.NULL:
+                collect_stack_root(gc, addr)
+            addr += sizeofaddr

Modified: pypy/branch/asmgcroot/pypy/translator/c/trackgcroot.py
==============================================================================
--- pypy/branch/asmgcroot/pypy/translator/c/trackgcroot.py	(original)
+++ pypy/branch/asmgcroot/pypy/translator/c/trackgcroot.py	Thu Jan  3 17:36:56 2008
@@ -35,18 +35,26 @@
         assert self.seen_main
         shapes = {}
         print >> output, """\t.text
-        .globl pypy_asm_stackwalk_init
-            .type pypy_asm_stackwalk_init, @function
-        pypy_asm_stackwalk_init:
+        .globl pypy_asm_stackwalk
+            .type pypy_asm_stackwalk, @function
+        pypy_asm_stackwalk:
             /* See description in asmgcroot.py */
-            movl   4(%esp), %edx     /* argument */
-            movl   %ebx, (%edx)
-            movl   %esi, 4(%edx)
-            movl   %edi, 8(%edx)
-            movl   %ebp, 12(%edx)
-            movl   %esp, 16(%edx)
-            movl   (%esp), %eax
-            movl   %eax, 20(%edx)
+            movl   4(%esp), %edx     /* my argument, which is the callback */
+            movl   (%esp), %eax      /* my return address */
+            pushl  %eax              /* ASM_FRAMEDATA[4] */
+            pushl  %ebp              /* ASM_FRAMEDATA[3] */
+            pushl  %edi              /* ASM_FRAMEDATA[2] */
+            pushl  %esi              /* ASM_FRAMEDATA[1] */
+            pushl  %ebx              /* ASM_FRAMEDATA[0] */
+            movl   %esp, %eax        /* address of ASM_FRAMEDATA */
+            pushl  %eax
+            call   *%edx             /* invoke the callback */
+            popl   %eax
+            popl   %ebx              /* restore from ASM_FRAMEDATA[0] */
+            popl   %esi              /* restore from ASM_FRAMEDATA[1] */
+            popl   %edi              /* restore from ASM_FRAMEDATA[2] */
+            popl   %ebp              /* restore from ASM_FRAMEDATA[3] */
+            popl   %eax
             ret
         .size pypy_asm_stackwalk_init, .-pypy_asm_stackwalk_init
         """



More information about the Pypy-commit mailing list