Author: Armin Rigo <ar...@tunes.org>
Branch: py3k
Changeset: r79910:bed78253f4c5
Date: 2015-09-30 18:41 +0200
http://bitbucket.org/pypy/pypy/changeset/bed78253f4c5/

Log:    hg merge d12dfd19fd86

        same as 4fa19970ddeb for the py3k branch

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
@@ -166,7 +166,7 @@
 
 # The marking phase. We walk the list 'objects_to_trace' of all gray objects
 # and mark all of the things they point to gray. This step lasts until there
-# are no more gray objects.
+# are no more gray objects.  ('objects_to_trace' never contains pinned objs.)
 STATE_MARKING = 1
 
 # here we kill all the unvisited objects
@@ -1146,6 +1146,9 @@
                       "raw_malloc_might_sweep must be empty outside SWEEPING")
 
             if self.gc_state == STATE_MARKING:
+                self.objects_to_trace.foreach(self._check_not_in_nursery, None)
+                self.more_objects_to_trace.foreach(self._check_not_in_nursery,
+                                                   None)
                 self._debug_objects_to_trace_dict1 = \
                                             self.objects_to_trace.stack2dict()
                 self._debug_objects_to_trace_dict2 = \
@@ -1156,6 +1159,10 @@
             else:
                 MovingGCBase.debug_check_consistency(self)
 
+    def _check_not_in_nursery(self, obj, ignore):
+        ll_assert(not self.is_in_nursery(obj),
+                  "'objects_to_trace' contains a nursery object")
+
     def debug_check_object(self, obj):
         # We are after a minor collection, and possibly after a major
         # collection step.  No object should be in the nursery (except
@@ -1789,6 +1796,8 @@
                 # If we're incrementally marking right now, sorry, we also
                 # need to add the object to 'more_objects_to_trace' and have
                 # it fully traced once at the end of the current marking phase.
+                ll_assert(not self.is_in_nursery(obj),
+                          "expected nursery obj in 
collect_cardrefs_to_nursery")
                 if self.gc_state == STATE_MARKING:
                     self.header(obj).tid &= ~GCFLAG_VISITED
                     self.more_objects_to_trace.append(obj)
@@ -1845,8 +1854,11 @@
         # need to record the not-visited-yet (white) old objects.  So
         # as a conservative approximation, we need to add the object to
         # the list if and only if it doesn't have GCFLAG_VISITED yet.
+        #
+        # Additionally, ignore pinned objects.
+        #
         obj = root.address[0]
-        if not self.header(obj).tid & GCFLAG_VISITED:
+        if (self.header(obj).tid & (GCFLAG_VISITED | GCFLAG_PINNED)) == 0:
             self.more_objects_to_trace.append(obj)
 
     def _trace_drag_out(self, root, parent):
@@ -1899,7 +1911,7 @@
                 #
                 self.old_objects_pointing_to_pinned.append(parent)
                 self.updated_old_objects_pointing_to_pinned = True
-                self.header(parent).tid |= GCFLAG_PINNED
+                self.header(parent).tid |= GCFLAG_PINNED_OBJECT_PARENT_KNOWN
             #
             if hdr.tid & GCFLAG_VISITED:
                 return
@@ -2033,6 +2045,7 @@
         new.delete()
 
     def _add_to_more_objects_to_trace(self, obj, ignored):
+        ll_assert(not self.is_in_nursery(obj), "unexpected nursery obj here")
         self.header(obj).tid &= ~GCFLAG_VISITED
         self.more_objects_to_trace.append(obj)
 
@@ -2287,8 +2300,7 @@
     def collect_roots(self):
         # Collect all roots.  Starts from all the objects
         # from 'prebuilt_root_objects'.
-        self.prebuilt_root_objects.foreach(self._collect_obj,
-                                           self.objects_to_trace)
+        self.prebuilt_root_objects.foreach(self._collect_obj, None)
         #
         # Add the roots from the other sources.
         self.root_walker.walk_roots(
@@ -2298,43 +2310,48 @@
         #
         # If we are in an inner collection caused by a call to a finalizer,
         # the 'run_finalizers' objects also need to be kept alive.
-        self.run_finalizers.foreach(self._collect_obj,
-                                    self.objects_to_trace)
+        self.run_finalizers.foreach(self._collect_obj, None)
 
     def enumerate_all_roots(self, callback, arg):
         self.prebuilt_root_objects.foreach(callback, arg)
         MovingGCBase.enumerate_all_roots(self, callback, arg)
     enumerate_all_roots._annspecialcase_ = 'specialize:arg(1)'
 
-    @staticmethod
-    def _collect_obj(obj, objects_to_trace):
-        objects_to_trace.append(obj)
+    def _collect_obj(self, obj, ignored):
+        # Ignore pinned objects, which are the ones still in the nursery here.
+        # Cache effects: don't read any flag out of 'obj' at this point.
+        # But only checking if it is in the nursery or not is fine.
+        llop.debug_nonnull_pointer(lltype.Void, obj)
+        if not self.is_in_nursery(obj):
+            self.objects_to_trace.append(obj)
+        else:
+            # A pinned object can be found here. Such an object is handled
+            # by minor collections and shouldn't be specially handled by
+            # major collections. Therefore we only add non-pinned objects
+            # to the 'objects_to_trace' list.
+            ll_assert(self._is_pinned(obj),
+                      "non-pinned nursery obj in _collect_obj")
+    _collect_obj._always_inline_ = True
 
     def _collect_ref_stk(self, root):
-        obj = root.address[0]
-        llop.debug_nonnull_pointer(lltype.Void, obj)
-        if not self._is_pinned(obj):
-            # XXX: check if this is the right way (groggi).
-            # A pinned object can be on the stack. Such an object is handled
-            # by minor collections and shouldn't be specially handled by
-            # major collections. Therefore we only add not pinned objects to 
the
-            # list below.
-            self.objects_to_trace.append(obj)
+        self._collect_obj(root.address[0], None)
 
     def _collect_ref_rec(self, root, ignored):
-        self.objects_to_trace.append(root.address[0])
+        self._collect_obj(root.address[0], None)
 
     def visit_all_objects(self):
         while self.objects_to_trace.non_empty():
             self.visit_all_objects_step(sys.maxint)
 
+    TEST_VISIT_SINGLE_STEP = False    # for tests
+
     def visit_all_objects_step(self, size_to_track):
         # Objects can be added to pending by visit
         pending = self.objects_to_trace
         while pending.non_empty():
             obj = pending.pop()
             size_to_track -= self.visit(obj)
-            if size_to_track < 0:
+            if size_to_track < 0 or self.TEST_VISIT_SINGLE_STEP:
                 return 0
         return size_to_track
 
@@ -2349,10 +2366,17 @@
         # flag set, then the object should be in 'prebuilt_root_objects',
         # and the GCFLAG_VISITED will be reset at the end of the
         # collection.
-        # Objects with GCFLAG_PINNED can't have gcptrs (see pin()), they can be
-        # ignored.
+        # We shouldn't see an object with GCFLAG_PINNED here (the pinned
+        # objects are never added to 'objects_to_trace').  The same-valued
+        # flag GCFLAG_PINNED_OBJECT_PARENT_KNOWN is used during minor
+        # collections and shouldn't be set here either.
+        #
         hdr = self.header(obj)
-        if hdr.tid & (GCFLAG_VISITED | GCFLAG_NO_HEAP_PTRS | GCFLAG_PINNED):
+        ll_assert((hdr.tid & GCFLAG_PINNED) == 0,
+                  "pinned object in 'objects_to_trace'")
+        ll_assert(not self.is_in_nursery(obj),
+                  "nursery object in 'objects_to_trace'")
+        if hdr.tid & (GCFLAG_VISITED | GCFLAG_NO_HEAP_PTRS):
             return 0
         #
         # It's the first time.  We set the flag VISITED.  The trick is
@@ -2582,6 +2606,7 @@
         # recursively convert objects from state 1 to state 2.
         # The call to visit_all_objects() will add the GCFLAG_VISITED
         # recursively.
+        ll_assert(not self.is_in_nursery(obj), "pinned finalizer object??")
         self.objects_to_trace.append(obj)
         self.visit_all_objects()
 
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
@@ -88,7 +88,7 @@
 
 class TestIncminimark(PinningGCTest):
     from rpython.memory.gc.incminimark import IncrementalMiniMarkGC as GCClass
-    from rpython.memory.gc.incminimark import STATE_SCANNING
+    from rpython.memory.gc.incminimark import STATE_SCANNING, STATE_MARKING
 
     def test_try_pin_gcref_containing_type(self):
         # scenario: incminimark's object pinning can't pin objects that may
@@ -917,3 +917,65 @@
         py.test.raises(Exception, self.malloc, T)
     test_full_pinned_nursery_pin_fail.max_number_of_pinned_objects = 50
 
+
+    def test_pin_bug1(self):
+        #
+        # * the nursery contains a pinned object 'ptr1'
+        #
+        # * outside the nursery is another object 'ptr2' pointing to 'ptr1'
+        #
+        # * during one incremental tracing step, we see 'ptr2' but don't
+        #   trace 'ptr1' right now: it is left behind on the trace-me-later
+        #   list
+        #
+        # * then we run the program, unpin 'ptr1', and remove it from 'ptr2'
+        #
+        # * at the next minor collection, we free 'ptr1' because we don't
+        #   find anything pointing to it (it is removed from 'ptr2'),
+        #   but 'ptr1' is still in the trace-me-later list
+        #
+        # * the trace-me-later list is deep enough that 'ptr1' is not
+        #   seen right now!  it is only seen at some later minor collection
+        #
+        # * at that later point, crash, because 'ptr1' in the nursery was
+        #   overwritten
+        #
+        ptr2 = self.malloc(S)
+        ptr2.someInt = 102
+        self.stackroots.append(ptr2)
+
+        self.gc.collect()
+        ptr2 = self.stackroots[-1]    # now outside the nursery
+        adr2 = llmemory.cast_ptr_to_adr(ptr2)
+
+        ptr1 = self.malloc(T)
+        adr1 = llmemory.cast_ptr_to_adr(ptr1)
+        ptr1.someInt = 101
+        self.write(ptr2, 'data', ptr1)
+        res = self.gc.pin(adr1)
+        assert res
+
+        self.gc.minor_collection()
+        assert self.gc.gc_state == self.STATE_SCANNING
+        self.gc.major_collection_step()
+        assert self.gc.objects_to_trace.tolist() == [adr2]
+        assert self.gc.more_objects_to_trace.tolist() == []
+
+        self.gc.TEST_VISIT_SINGLE_STEP = True
+
+        self.gc.minor_collection()
+        assert self.gc.gc_state == self.STATE_MARKING
+        self.gc.major_collection_step()
+        assert self.gc.objects_to_trace.tolist() == []
+        assert self.gc.more_objects_to_trace.tolist() == [adr2]
+
+        self.write(ptr2, 'data', lltype.nullptr(T))
+        self.gc.unpin(adr1)
+
+        assert ptr1.someInt == 101
+        self.gc.minor_collection()        # should free 'ptr1'
+        py.test.raises(RuntimeError, "ptr1.someInt")
+        assert self.gc.gc_state == self.STATE_MARKING
+        self.gc.major_collection_step()   # should not crash reading 'ptr1'!
+
+        del self.gc.TEST_VISIT_SINGLE_STEP
diff --git a/rpython/rlib/rvmprof/cintf.py b/rpython/rlib/rvmprof/cintf.py
--- a/rpython/rlib/rvmprof/cintf.py
+++ b/rpython/rlib/rvmprof/cintf.py
@@ -90,8 +90,14 @@
         cont_name = '_' + cont_name
         tramp_name = '_' + tramp_name
         PLT = ""
+        size_decl = ""
+        type_decl = ""
     else:
         PLT = "@PLT"
+        type_decl = "\t.type\t%s, @function" % (tramp_name,)
+        size_decl = "\t.size\t%s, .-%s" % (
+            tramp_name, tramp_name)
+
 
     assert detect_cpu.autodetect().startswith(detect_cpu.MODEL_X86_64), (
         "rvmprof only supports x86-64 CPUs for now")
@@ -114,9 +120,12 @@
     target = udir.join('module_cache')
     target.ensure(dir=1)
     target = target.join('trampoline_%s_%s.vmprof.s' % (name, token))
+    # NOTE! the tabs in this file are absolutely essential, things
+    #       that don't start with \t are silently ignored (<arigato>: WAT!?)
     target.write("""\
 \t.text
 \t.globl\t%(tramp_name)s
+%(type_decl)s
 %(tramp_name)s:
 \t.cfi_startproc
 \tpushq\t%(reg)s
@@ -126,6 +135,7 @@
 \t.cfi_def_cfa_offset 8
 \tret
 \t.cfi_endproc
+%(size_decl)s
 """ % locals())
 
     def tok2cname(tok):
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to