[pypy-svn] r50129 - pypy/branch/llvmgcroot/pypy/rpython/memory/gctransform

arigo at codespeak.net arigo at codespeak.net
Wed Dec 26 21:30:53 CET 2007


Author: arigo
Date: Wed Dec 26 21:30:53 2007
New Revision: 50129

Modified:
   pypy/branch/llvmgcroot/pypy/rpython/memory/gctransform/llvmgcroot.py
Log:
Sort the array when the program starts,
for faster searches in StackRootIterator.pop().


Modified: pypy/branch/llvmgcroot/pypy/rpython/memory/gctransform/llvmgcroot.py
==============================================================================
--- pypy/branch/llvmgcroot/pypy/rpython/memory/gctransform/llvmgcroot.py	(original)
+++ pypy/branch/llvmgcroot/pypy/rpython/memory/gctransform/llvmgcroot.py	Wed Dec 26 21:30:53 2007
@@ -42,14 +42,21 @@
         # 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
+                # 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)
             setup_root_stack = staticmethod(setup_root_stack)
 
             need_root_stack = False
@@ -96,6 +103,10 @@
                 # the frame.
                 #
                 callee_frame = self.stack_current
+                if llmemory.cast_adr_to_int(callee_frame) & 1:
+                    return False   # odd bit set here when the callee_frame
+                                   # is the frame of main(), i.e. when there
+                                   # is nothing more for us in the stack.
                 #
                 # XXX the details are completely specific to X86!!!
                 # a picture of the stack may help:
@@ -120,33 +131,28 @@
                 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.
                 #
                 gcmapstart = llop.llvm_gcmapstart(llmemory.Address)
                 gcmapend   = llop.llvm_gcmapend(llmemory.Address)
-                while gcmapstart != gcmapend:
-                    if gcmapstart.address[0] == retaddr:
-                        #
-                        # found!  Setup pointers allowing us to
-                        # parse the caller's frame structure...
-                        #
-                        shape = gcmapstart.address[1]
-                        # XXX assumes that .signed is 32-bit
-                        framesize = shape.signed[0]
-                        livecount = shape.signed[1]
-                        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 = shape + 8
-                        return True
-
-                    gcmapstart += 2 * sizeofaddr
-
-                # retaddr not found.  Assume that this is the system function
-                # that called the original entry point, i.e. it's the end of
-                # the stack for us
+                item = binary_search(gcmapstart, gcmapend, retaddr)
+                if item.address[0] == retaddr:
+                    #
+                    # found!  Setup pointers allowing us to
+                    # parse the caller's frame structure...
+                    #
+                    shape = item.address[1]
+                    # XXX assumes that .signed is 32-bit
+                    framesize = shape.signed[0]   # odd if it's main()
+                    livecount = shape.signed[1]
+                    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 = shape + 8
+                    return True
+
+                # retaddr not found!
+                llop.debug_fatalerror(lltype.Void, "cannot find gc roots!")
                 return False
 
             def next_gcroot_from_current_frame(self):
@@ -158,3 +164,49 @@
 
 
         return StackRootIterator
+
+
+sizeofaddr = llmemory.sizeof(llmemory.Address)
+arrayitemsize = 2 * sizeofaddr
+
+
+def binary_search(start, end, addr1):
+    """Search for an element in a sorted array.
+
+    The interval from the start address (included) to the end address
+    (excluded) is assumed to be a sorted arrays of pairs (addr1, addr2).
+    This searches for the item with a given addr1 and returns its
+    address.
+    """
+    count = (end - start) // arrayitemsize
+    while count > 1:
+        middleindex = count // 2
+        middle = start + middleindex * arrayitemsize
+        if addr1 < middle.address[0]:
+            count = middleindex
+        else:
+            start = middle
+            count -= middleindex
+    return start
+
+def insertion_sort(start, end):
+    """Sort an array of pairs of addresses.
+
+    This is an insertion sort, so it's slowish unless the array is mostly
+    sorted already (which is what I expect, but XXX check this).
+    """
+    next = start
+    while next < end:
+        # assuming the interval from start (included) to next (excluded)
+        # to be already sorted, move the next element back into the array
+        # until it reaches its proper place.
+        addr1 = next.address[0]
+        addr2 = next.address[1]
+        scan = next
+        while scan > start and addr1 < scan.address[-2]:
+            scan.address[0] = scan.address[-2]
+            scan.address[1] = scan.address[-1]
+            scan -= arrayitemsize
+        scan.address[0] = addr1
+        scan.address[1] = addr2
+        next += arrayitemsize



More information about the Pypy-commit mailing list