Author: Armin Rigo <ar...@tunes.org> Branch: py3.3 Changeset: r79909:4fa19970ddeb Date: 2015-09-30 17:39 +0100 http://bitbucket.org/pypy/pypy/changeset/4fa19970ddeb/
Log: hg merge d12dfd19fd86 This includes a few more commits from "default" which fix two problems: - an issue with pinned objects - linux asmgcc was broken 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