[pypy-commit] pypy gc-incminimark-pinning: renaming, rewriting, etc. for handling movable objects (i.e. ConstPtrs that have a pointer which isn't really constant) inside the JIT

groggi noreply at buildbot.pypy.org
Sat Aug 16 18:47:29 CEST 2014


Author: Gregor Wegberg <code at gregorwegberg.com>
Branch: gc-incminimark-pinning
Changeset: r72826:ed703b3e1311
Date: 2014-08-16 18:46 +0200
http://bitbucket.org/pypy/pypy/changeset/ed703b3e1311/

Log:	renaming, rewriting, etc. for handling movable objects (i.e.
	ConstPtrs that have a pointer which isn't really constant) inside
	the JIT

diff --git a/rpython/jit/backend/llsupport/gc.py b/rpython/jit/backend/llsupport/gc.py
--- a/rpython/jit/backend/llsupport/gc.py
+++ b/rpython/jit/backend/llsupport/gc.py
@@ -20,32 +20,36 @@
 from rpython.memory.gctransform import asmgcroot
 from rpython.rtyper.lltypesystem import llmemory
 
-class PinnedObjectTracker(object):
-    """Simple helper class to keep informations regarding the 'GcArray'
-    in one place that is used to double load pinned objects.
-    """
+class MovableObjectTracker(object):
 
-    _ref_array_type = lltype.GcArray(llmemory.GCREF)
+    ptr_array_type = lltype.GcArray(llmemory.GCREF)
 
-    def __init__(self, cpu, pointers):
-        # prepare GC array to hold the pointers
-        size = len(pointers)
-        self._ref_array = lltype.malloc(PinnedObjectTracker._ref_array_type, size)
-        self.ref_array_descr = cpu.arraydescrof(PinnedObjectTracker._ref_array_type)
-        self.ref_array_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, self._ref_array)
-        self.const_ptr_gcref_array = ConstPtr(self.ref_array_gcref)
+    def __init__(self, cpu, const_pointers):
+        size = len(const_pointers)
+        # check that there are any moving object (i.e. chaning pointers).
+        # Otherwise there is no reason for an instance of this class.
+        assert size > 0
         #
-        # assign each pointer an index and put the pointer into the GC array
+        # prepare GC array to hold the pointers that may change
+        self.ptr_array = lltype.malloc(MovableObjectTracker.ptr_array_type, size)
+        self.ptr_array_descr = cpu.arraydescrof(MovableObjectTracker.ptr_array_type)
+        self.ptr_array_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, self.ptr_array)
+        # use always the same ConstPtr to access the array
+        # (easer to read JIT trace)
+        self.const_ptr_gcref_array = ConstPtr(self.ptr_array_gcref)
+        #
+        # assign each pointer an index and put the pointer into the GC array.
+        # as pointers and addresses are not a good key to use before translation
+        # ConstPtrs are used as the key for the dict.
         self._indexes = {}
-        for index in range(len(pointers)):
-            ptr = pointers[index]
-            self._indexes[llmemory.cast_ptr_to_adr(ptr)] = llmemory.cast_int_to_adr(index)
-            self._ref_array[index] = ptr
+        for index in range(size):
+            ptr = const_pointers[index]
+            self._indexes[ptr] = index
+            self.ptr_array[index] = ptr.value
 
-    def add_ref(self, ptr):
-        assert llmemory.cast_ptr_to_adr(ptr) in self._indexes
-        index = llmemory.cast_adr_to_int(self._indexes[llmemory.cast_ptr_to_adr(ptr)])
-        assert ptr == self._ref_array[index]
+    def get_array_index(self, const_ptr):
+        index = self._indexes[const_ptr]
+        assert const_ptr.value == self.ptr_array[index]
         return index
 # ____________________________________________________________
 
@@ -120,9 +124,9 @@
     def gc_malloc_unicode(self, num_elem):
         return self._bh_malloc_array(num_elem, self.unicode_descr)
 
-    def _record_constptrs(self, op, gcrefs_output_list, moving_output_list,
-            known_pointers):
-        moving_output_list[op] = []
+    def _record_constptrs(self, op, gcrefs_output_list, ops_with_movable_const_ptr,
+            changeable_const_pointers):
+        ops_with_movable_const_ptr[op] = []
         for i in range(op.numargs()):
             v = op.getarg(i)
             if isinstance(v, ConstPtr) and bool(v.value):
@@ -130,33 +134,31 @@
                 if rgc._make_sure_does_not_move(p):
                     gcrefs_output_list.append(p)
                 else:
-                    moving_output_list[op].append(i)
-                    if p not in known_pointers:
-                        known_pointers.append(p)
+                    ops_with_movable_const_ptr[op].append(i)
+                    if v not in changeable_const_pointers:
+                        changeable_const_pointers.append(v)
         #
         if op.is_guard() or op.getopnum() == rop.FINISH:
             llref = cast_instance_to_gcref(op.getdescr())
             assert rgc._make_sure_does_not_move(llref)
             gcrefs_output_list.append(llref)
         #
-        if len(moving_output_list[op]) == 0:
-            del moving_output_list[op]
+        if len(ops_with_movable_const_ptr[op]) == 0:
+            del ops_with_movable_const_ptr[op]
 
-    def _rewrite_constptrs(self, op, moving_output_list, pinned_obj_tracker):
+    def _rewrite_changeable_constptrs(self, op, ops_with_movable_const_ptr, moving_obj_tracker):
         newops = []
-        for arg_i in moving_output_list[op]:
+        for arg_i in ops_with_movable_const_ptr[op]:
             v = op.getarg(arg_i)
             # assert to make sure we got what we expected
             assert isinstance(v, ConstPtr)
-            assert bool(v.value)
-            p = v.value
             result_ptr = BoxPtr()
-            array_index = pinned_obj_tracker.add_ref(p)
+            array_index = moving_obj_tracker.get_array_index(v)
             load_op = ResOperation(rop.GETARRAYITEM_GC,
-                    [pinned_obj_tracker.const_ptr_gcref_array,
+                    [moving_obj_tracker.const_ptr_gcref_array,
                         ConstInt(array_index)],
                     result_ptr,
-                    descr=pinned_obj_tracker.ref_array_descr)
+                    descr=moving_obj_tracker.ptr_array_descr)
             newops.append(load_op)
             op.setarg(arg_i, result_ptr)
         #
@@ -166,37 +168,48 @@
     def rewrite_assembler(self, cpu, operations, gcrefs_output_list):
         rewriter = GcRewriterAssembler(self, cpu)
         newops = rewriter.rewrite(operations)
-        # record all GCREFs, because the GC (or Boehm) cannot see them and
-        # keep them alive if they end up as constants in the assembler
-        
-        # XXX add comment (groggi)
-       
-        newnewops = [] # XXX better name... (groggi)
 
-        moving_output_list = {}
-        known_pointers = []
+        # the key is an operation that contains a ConstPtr as an argument and
+        # this ConstPtrs pointer might change as it points to an object that
+        # can't be made non-moving (e.g. the object is pinned).
+        ops_with_movable_const_ptr = {}
+        #
+        # a list of such not really constant ConstPtrs.
+        changeable_const_pointers = []
         for op in newops:
-            self._record_constptrs(op, gcrefs_output_list, moving_output_list,
-                    known_pointers)
+            # record all GCREFs, because the GC (or Boehm) cannot see them and
+            # keep them alive if they end up as constants in the assembler.
+            # If such a GCREF can change and we can't make the object it points
+            # to non-movable, we have to handle it seperatly. Such GCREF's are
+            # returned as ConstPtrs in 'changeable_const_pointers' and the
+            # affected operation is returned in 'op_with_movable_const_ptr'.
+            # For this special case see 'rewrite_changeable_constptrs'.
+            self._record_constptrs(op, gcrefs_output_list,
+                    ops_with_movable_const_ptr, changeable_const_pointers)
         #
-        if len(moving_output_list) > 0:
-            pinned_obj_tracker = PinnedObjectTracker(cpu, known_pointers)
+        # handle pointers that are not guaranteed to stay the same
+        if len(ops_with_movable_const_ptr) > 0:
+            moving_obj_tracker = MovableObjectTracker(cpu, changeable_const_pointers)
+            #
             if not we_are_translated():
-                self.last_pinned_object_tracker = pinned_obj_tracker
-            gcrefs_output_list.append(pinned_obj_tracker.ref_array_gcref)
-            rgc._make_sure_does_not_move(pinned_obj_tracker.ref_array_gcref)
+                # used for testing
+                self.last_moving_obj_tracker = moving_obj_tracker
+            # make sure the array containing the pointers is not collected by
+            # the GC (or Boehm)
+            gcrefs_output_list.append(moving_obj_tracker.ptr_array_gcref)
+            rgc._make_sure_does_not_move(moving_obj_tracker.ptr_array_gcref)
 
-            for op in newops:
-                if op in moving_output_list:
-                    reops = self._rewrite_constptrs(op, moving_output_list,
-                            pinned_obj_tracker)
-                    newnewops.extend(reops)
+            ops = newops
+            newops = []
+            for op in ops:
+                if op in ops_with_movable_const_ptr:
+                    rewritten_ops = self._rewrite_changeable_constptrs(op,
+                            ops_with_movable_const_ptr, moving_obj_tracker)
+                    newops.extend(rewritten_ops)
                 else:
-                    newnewops.append(op)
-            #
-            return newnewops
-        else:
-            return newops
+                    newops.append(op)
+        #
+        return newops
 
     @specialize.memo()
     def getframedescrs(self, cpu):
diff --git a/rpython/jit/backend/llsupport/test/test_pinned_object_rewrite.py b/rpython/jit/backend/llsupport/test/test_pinned_object_rewrite.py
--- a/rpython/jit/backend/llsupport/test/test_pinned_object_rewrite.py
+++ b/rpython/jit/backend/llsupport/test/test_pinned_object_rewrite.py
@@ -3,7 +3,7 @@
      get_field_descr, get_array_descr, ArrayDescr, FieldDescr,\
      SizeDescrWithVTable, get_interiorfield_descr
 from rpython.jit.backend.llsupport.gc import GcLLDescr_boehm,\
-     GcLLDescr_framework, PinnedObjectTracker
+     GcLLDescr_framework, MovableObjectTracker
 from rpython.jit.backend.llsupport import jitframe, gc
 from rpython.jit.metainterp.gc import get_description
 from rpython.jit.tool.oparser import parse
@@ -45,7 +45,7 @@
         notpinned_obj_ptr = lltype.malloc(notpinned_obj_type)
         notpinned_obj_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, notpinned_obj_ptr)
         #
-        ref_array_descr = self.cpu.arraydescrof(PinnedObjectTracker._ref_array_type)
+        ptr_array_descr = self.cpu.arraydescrof(MovableObjectTracker.ptr_array_type)
         #
         vtable_descr = self.gc_ll_descr.fielddescr_vtable
         O = lltype.GcStruct('O', ('parent', rclass.OBJECT),
@@ -92,9 +92,9 @@
                                                         [])
         # make the array containing the GCREF's accessible inside the tests.
         # This must be done after we call 'rewrite_assembler'. Before that
-        # call 'last_pinned_object_tracker' is None or filled with some old
+        # call 'last_moving_obj_tracker' is None or filled with some old
         # value.
-        namespace['ref_array_gcref'] = self.gc_ll_descr.last_pinned_object_tracker.ref_array_gcref
+        namespace['ptr_array_gcref'] = self.gc_ll_descr.last_moving_obj_tracker.ptr_array_gcref
         expected = parse(to_operations % Evaluator(namespace),
                          namespace=namespace)
         equaloplists(operations, expected.operations)
@@ -127,7 +127,7 @@
             i0 = getfield_gc(ConstPtr(pinned_obj_gcref), descr=pinned_obj_my_int_descr)
             """, """
             []
-            p1 = getarrayitem_gc(ConstPtr(ref_array_gcref), 0, descr=ref_array_descr)
+            p1 = getarrayitem_gc(ConstPtr(ptr_array_gcref), 0, descr=ptr_array_descr)
             i0 = getfield_gc(p1, descr=pinned_obj_my_int_descr)
             """)
 
@@ -139,9 +139,9 @@
             i2 = getfield_gc(ConstPtr(pinned_obj_gcref), descr=pinned_obj_my_int_descr)
             """, """
             []
-            p1 = getarrayitem_gc(ConstPtr(ref_array_gcref), 0, descr=ref_array_descr)
+            p1 = getarrayitem_gc(ConstPtr(ptr_array_gcref), 0, descr=ptr_array_descr)
             i0 = getfield_gc(p1, descr=pinned_obj_my_int_descr)
             i1 = getfield_gc(ConstPtr(notpinned_obj_gcref), descr=notpinned_obj_my_int_descr)
-            p2 = getarrayitem_gc(ConstPtr(ref_array_gcref), 1, descr=ref_array_descr)
+            p2 = getarrayitem_gc(ConstPtr(ptr_array_gcref), 1, descr=ptr_array_descr)
             i2 = getfield_gc(p2, descr=pinned_obj_my_int_descr)
             """)


More information about the pypy-commit mailing list