Author: Gregor Wegberg <[email protected]>
Branch: gc-incminimark-pinning
Changeset: r72152:841b8277ef3a
Date: 2014-06-11 14:02 +0200
http://bitbucket.org/pypy/pypy/changeset/841b8277ef3a/

Log:    wip: adding JIT support in presence of pinned objects

        added _is_pinned method and _make_sure_does_not_move can fail now by
        returning a boolean

diff --git a/rpython/memory/gc/base.py b/rpython/memory/gc/base.py
--- a/rpython/memory/gc/base.py
+++ b/rpython/memory/gc/base.py
@@ -182,6 +182,9 @@
     def unpin(self, addr):
         pass
 
+    def _is_pinned(self, addr):
+        return False
+
     def set_max_heap_size(self, size):
         raise NotImplementedError
 
diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -960,24 +960,27 @@
             # to check if can_move(obj) already returns True in which
             # case a call to pin() is unnecessary.
             return False
-        if self.header(obj).tid & GCFLAG_PINNED:
+        if self._is_pinned(obj):
             # Already pinned, we do not allow to pin it again.
             # Reason: It would be possible that the first caller unpins
             # while the second caller thinks it's still pinned.
             return False
-
+        #
         self.header(obj).tid |= GCFLAG_PINNED
         self.pinned_objects_in_nursery += 1
         return True
 
 
     def unpin(self, obj):
-        ll_assert(self.header(obj).tid & GCFLAG_PINNED != 0,
+        ll_assert(self._is_pinned(obj),
             "unpin: object is already not pinned")
         #
         self.header(obj).tid &= ~GCFLAG_PINNED
         self.pinned_objects_in_nursery -= 1
 
+    def _is_pinned(self, obj):
+        return (self.header(obj).tid & GCFLAG_PINNED) != 0
+
     def shrink_array(self, obj, smallerlength):
         #
         # Only objects in the nursery can be "resized".  Resizing them
@@ -1148,7 +1151,7 @@
         # We are after a minor collection, and possibly after a major
         # collection step.  No object should be in the nursery (except
         # pinned ones)
-        if self.header(obj).tid & GCFLAG_PINNED == 0:
+        if not self._is_pinned(obj):
             ll_assert(not self.is_in_nursery(obj),
                       "object in nursery after collection")
             ll_assert(self.header(obj).tid & GCFLAG_VISITED_RMY == 0,
@@ -1204,7 +1207,7 @@
         # All objects should have this flag, except if they
         # don't have any GC pointer
         typeid = self.get_type_id(obj)
-        if not self.header(obj).tid & GCFLAG_PINNED:
+        if not self._is_pinned(obj):
             # XXX do we need checks if the object is actually pinned? (groggi)
             if self.has_gcptr(typeid):
                 ll_assert(self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS != 0,
@@ -1818,7 +1821,7 @@
             root.address[0] = self.get_forwarding_address(obj)
             return
             #
-        elif self.header(obj).tid & GCFLAG_PINNED:
+        elif self._is_pinned(obj):
             hdr = self.header(obj)
             if hdr.tid & GCFLAG_VISITED:
                 # already visited and keeping track of the object
diff --git a/rpython/memory/gc/test/test_object_pinning.py 
b/rpython/memory/gc/test/test_object_pinning.py
--- a/rpython/memory/gc/test/test_object_pinning.py
+++ b/rpython/memory/gc/test/test_object_pinning.py
@@ -31,6 +31,15 @@
         py.test.raises(Exception,
             self.gc.unpin, llmemory.cast_ptr_to_adr(ptr))
 
+    def test__is_pinned(self):
+        ptr = self.malloc(S)
+        adr = llmemory.cast_ptr_to_adr(ptr)
+        assert not self.gc._is_pinned(adr)
+        assert self.gc.pin(adr)
+        assert self.gc._is_pinned(adr)
+        self.gc.unpin(adr)
+        assert not self.gc._is_pinned(adr)
+
     # XXX test with multiple mallocs, and only part of them is pinned
 
 
diff --git a/rpython/memory/gctransform/framework.py 
b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -466,6 +466,10 @@
                                [s_gc, SomeAddress()],
                                annmodel.s_None)
 
+        self._is_pinned_ptr = getfn(GCClass._is_pinned,
+                                    [s_gc, SomeAddress()],
+                                    annmodel.SomeBool())
+
         self.write_barrier_ptr = None
         self.write_barrier_from_array_ptr = None
         if GCClass.needs_write_barrier:
@@ -986,6 +990,11 @@
         op = hop.spaceop
         hop.genop("direct_call", [self.unpin_ptr, self.c_const_gc, op.args[0]])
 
+    def gct_gc__is_pinned(self, hop):
+        op = hop.spaceop
+        hop.genop("direct_call", [self._is_pinned_ptr, self.c_const_gc, 
op.args[0]],
+                    resultvar=op.result)
+
     def gct_gc_thread_run(self, hop):
         assert self.translator.config.translation.thread
         if hasattr(self.root_walker, 'thread_run_ptr'):
diff --git a/rpython/memory/gctransform/transform.py 
b/rpython/memory/gctransform/transform.py
--- a/rpython/memory/gctransform/transform.py
+++ b/rpython/memory/gctransform/transform.py
@@ -356,6 +356,12 @@
     def gct_gc_unpin(self, hop):
         pass
 
+    def gct_gc__is_pinned(self, hop):
+        op = hop.spaceop
+        hop.genop("same_as",
+                  [rmodel.inputconst(lltype.Bool, False)],
+                  resultvar=op.result)
+
     def gct_gc_identityhash(self, hop):
         # must be implemented in the various GCs
         raise NotImplementedError
diff --git a/rpython/memory/gcwrapper.py b/rpython/memory/gcwrapper.py
--- a/rpython/memory/gcwrapper.py
+++ b/rpython/memory/gcwrapper.py
@@ -128,6 +128,9 @@
     def unpin(self, addr):
         self.gc.unpin(addr)
 
+    def _is_pinned(self, addr):
+        return self.gc._is_pinned(addr)
+
     def weakref_create_getlazy(self, objgetter):
         # we have to be lazy in reading the llinterp variable containing
         # the 'obj' pointer, because the gc.malloc() call below could
diff --git a/rpython/memory/test/gc_test_base.py 
b/rpython/memory/test/gc_test_base.py
--- a/rpython/memory/test/gc_test_base.py
+++ b/rpython/memory/test/gc_test_base.py
@@ -810,6 +810,27 @@
         else:
             assert res == 0 or res == 13
 
+    def test__is_pinned(self):
+        def fn(n):
+            from rpython.rlib.debug import debug_print
+            s = str(n)
+            if not rgc.can_move(s):
+                return 13
+            res = int(rgc.pin(s))
+            if res:
+                res += int(rgc._is_pinned(s))
+                rgc.unpin(s)
+            return res
+
+        res = self.interpret(fn, [10])
+        if not self.GCClass.moving_gc:
+            assert res == 13
+        elif self.GCClass.can_usually_pin_objects:
+            assert res == 2
+        else:
+            assert res == 0 or res == 13
+
+
 from rpython.rlib.objectmodel import UnboxedValue
 
 class TaggedBase(object):
diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py
--- a/rpython/rlib/rgc.py
+++ b/rpython/rlib/rgc.py
@@ -76,6 +76,24 @@
                            resulttype=llmemory.Address)
         hop.genop('gc_unpin', [v_addr])
 
+def _is_pinned(obj):
+    """Method to check if 'obj' is pinned."""
+    return False
+
+class IsPinnedEntry(ExtRegistryEntry):
+    _about_ = _is_pinned
+
+    def compute_result_annotation(self, s_arg):
+        from rpython.annotator.model import s_Bool
+        return s_Bool
+
+    def specialize_call(self, hop):
+        hop.exception_cannot_occur()
+        v_obj, = hop.inputargs(hop.args_r[0])
+        v_addr = hop.genop('cast_ptr_to_adr', [v_obj],
+                           resulttype=llmemory.Address)
+        return hop.genop('gc__is_pinned', [v_addr], resulttype=lltype.Bool)
+
 # ____________________________________________________________
 # Annotation and specialization
 
@@ -136,13 +154,16 @@
     on objects that are already a bit old, so have a chance to be
     already non-movable."""
     if not we_are_translated():
-        return
+        return True # XXX: check if True is the right return (groggi)
+    if _is_pinned(p):
+        return False
     i = 0
     while can_move(p):
         if i > 6:
             raise NotImplementedError("can't make object non-movable!")
         collect(i)
         i += 1
+    return True
 
 def _heap_stats():
     raise NotImplementedError # can't be run directly
diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py
--- a/rpython/rtyper/llinterp.py
+++ b/rpython/rtyper/llinterp.py
@@ -865,6 +865,9 @@
     def op_gc_unpin(self, obj):
         self.heap.unpin(obj)
 
+    def op_gc__is_pinned(self, obj):
+        return self.heap._is_pinned(obj)
+
     def op_gc_detach_callback_pieces(self):
         raise NotImplementedError("gc_detach_callback_pieces")
     def op_gc_reattach_callback_pieces(self):
diff --git a/rpython/rtyper/lltypesystem/llheap.py 
b/rpython/rtyper/lltypesystem/llheap.py
--- a/rpython/rtyper/lltypesystem/llheap.py
+++ b/rpython/rtyper/lltypesystem/llheap.py
@@ -39,3 +39,6 @@
 def unpin(obj):
     raise AssertionError("pin() always returns False, "
                          "so unpin() should not be called")
+
+def _is_pinned(obj):
+    return False
diff --git a/rpython/rtyper/lltypesystem/lloperation.py 
b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -482,6 +482,7 @@
     'gc_heap_stats'       : LLOp(canmallocgc=True),
     'gc_pin'              : LLOp(canrun=True), # XXX understand this, correct? 
(groggi)
     'gc_unpin'            : LLOp(canrun=True), # XXX understand this, correct? 
(groggi)
+    'gc_is__pinned'        : LLOp(canrun=True), # XXX understand this, 
correct? (groggi)
 
     'gc_get_rpy_roots'    : LLOp(),
     'gc_get_rpy_referents': LLOp(),
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to