Author: Armin Rigo <[email protected]>
Branch:
Changeset: r45173:324a8265e420
Date: 2011-06-28 18:42 +0200
http://bitbucket.org/pypy/pypy/changeset/324a8265e420/
Log: (antocuni, lac, arigo)
Carefully change the world to fix corner-case bugs introduced by the
previous checkin.
A better version of writebarrier_before_copy() for list resizes,
copying the card marks over to the new array.
diff --git a/pypy/rlib/rgc.py b/pypy/rlib/rgc.py
--- a/pypy/rlib/rgc.py
+++ b/pypy/rlib/rgc.py
@@ -272,7 +272,9 @@
if isinstance(TP.OF, lltype.Ptr) and TP.OF.TO._gckind == 'gc':
# perform a write barrier that copies necessary flags from
# source to dest
- if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest):
+ if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest,
+ source_start, dest_start,
+ length):
# if the write barrier is not supported, copy by hand
for i in range(length):
dest[i + dest_start] = source[i + source_start]
diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py
--- a/pypy/rpython/llinterp.py
+++ b/pypy/rpython/llinterp.py
@@ -737,9 +737,12 @@
def op_zero_gc_pointers_inside(self, obj):
raise NotImplementedError("zero_gc_pointers_inside")
- def op_gc_writebarrier_before_copy(self, source, dest):
+ def op_gc_writebarrier_before_copy(self, source, dest,
+ source_start, dest_start, length):
if hasattr(self.heap, 'writebarrier_before_copy'):
- return self.heap.writebarrier_before_copy(source, dest)
+ return self.heap.writebarrier_before_copy(source, dest,
+ source_start, dest_start,
+ length)
else:
return True
diff --git a/pypy/rpython/lltypesystem/opimpl.py
b/pypy/rpython/lltypesystem/opimpl.py
--- a/pypy/rpython/lltypesystem/opimpl.py
+++ b/pypy/rpython/lltypesystem/opimpl.py
@@ -473,12 +473,16 @@
checkadr(addr2)
return addr1 - addr2
-def op_gc_writebarrier_before_copy(source, dest):
+def op_gc_writebarrier_before_copy(source, dest,
+ source_start, dest_start, length):
A = lltype.typeOf(source)
assert A == lltype.typeOf(dest)
assert isinstance(A.TO, lltype.GcArray)
assert isinstance(A.TO.OF, lltype.Ptr)
assert A.TO.OF.TO._gckind == 'gc'
+ assert type(source_start) is int
+ assert type(dest_start) is int
+ assert type(length) is int
return True
def op_getfield(p, name):
diff --git a/pypy/rpython/memory/gc/generation.py
b/pypy/rpython/memory/gc/generation.py
--- a/pypy/rpython/memory/gc/generation.py
+++ b/pypy/rpython/memory/gc/generation.py
@@ -517,7 +517,8 @@
objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS
self.last_generation_root_objects.append(addr_struct)
- def writebarrier_before_copy(self, source_addr, dest_addr):
+ def writebarrier_before_copy(self, source_addr, dest_addr,
+ source_start, dest_start, length):
""" This has the same effect as calling writebarrier over
each element in dest copied from source, except it might reset
one of the following flags a bit too eagerly, which means we'll have
diff --git a/pypy/rpython/memory/gc/minimark.py
b/pypy/rpython/memory/gc/minimark.py
--- a/pypy/rpython/memory/gc/minimark.py
+++ b/pypy/rpython/memory/gc/minimark.py
@@ -75,15 +75,16 @@
first_gcflag = 1 << (LONG_BIT//2)
-# The following flag is usually not set on young objects. It is initially set
-# on all prebuilt and old objects, and gets cleared by the write_barrier()
-# when we write in them a pointer to a young object. If the object is a
-# large array (young or old), then GCFLAG_HAS_CARDS is set; in this case,
-# GCFLAG_NO_YOUNG_PTRS is also generally set (a bit counter-intuitively).
-# However, if card-marking lost track and is now useless, then
-# GCFLAG_NO_YOUNG_PTRS is cleared: there might be young pointers anywhere
-# in the array.
-GCFLAG_NO_YOUNG_PTRS = first_gcflag << 0
+# The following flag is set on objects if we need to do something to
+# track the young pointers that it might contain. The flag is not set
+# on young objects (unless they are large arrays, see below), and we
+# simply assume that any young object can point to any other young object.
+# For old and prebuilt objects, the flag is usually set, and is cleared
+# when we write a young pointer to it. For large arrays with
+# GCFLAG_HAS_CARDS, we rely on card marking to track where the
+# young pointers are; the flag GCFLAG_TRACK_YOUNG_PTRS is set in this
+# case too, to speed up the write barrier.
+GCFLAG_TRACK_YOUNG_PTRS = first_gcflag << 0
# The following flag is set on some prebuilt objects. The flag is set
# unless the object is already listed in 'prebuilt_root_objects'.
@@ -251,15 +252,20 @@
self.ac = ArenaCollectionClass(arena_size, page_size,
small_request_threshold)
#
- # Used by minor collection: a list of non-young objects that
+ # Used by minor collection: a list of (mostly non-young) objects that
# (may) contain a pointer to a young object. Populated by
- # the write barrier.
- self.old_objects_pointing_to_young = self.AddressStack()
+ # the write barrier: when we clear GCFLAG_TRACK_YOUNG_PTRS, we
+ # add it to this list.
+ class Cls(self.AddressStack):
+ def append(self2, addr):
+ assert addr not in self2.tolist()
+ self.AddressStack.append(self2, addr)
+ self.objects_pointing_to_young = self.AddressStack()
#
- # Similar to 'old_objects_pointing_to_young', but lists objects
+ # Similar to 'objects_pointing_to_young', but lists objects
# that have the GCFLAG_CARDS_SET bit. For large arrays. Note
# that it is possible for an object to be listed both in here
- # and in 'old_objects_pointing_to_young', in which case we
+ # and in 'objects_pointing_to_young', in which case we
# should just clear the cards and trace it fully, as usual.
# Note also that young array objects may be added to this list.
self.objects_with_cards_set = self.AddressStack()
@@ -631,7 +637,7 @@
# if 'can_make_young'. The interesting case of 'can_make_young'
# is for large objects, bigger than the 'large_objects' threshold,
# which are raw-malloced but still young.
- extra_flags = GCFLAG_NO_YOUNG_PTRS
+ extra_flags = GCFLAG_TRACK_YOUNG_PTRS
#
else:
# No, so proceed to allocate it externally with raw_malloc().
@@ -649,7 +655,7 @@
# Reserve N extra words containing card bits before the object.
extra_words = self.card_marking_words_for_length(length)
cardheadersize = WORD * extra_words
- extra_flags = GCFLAG_HAS_CARDS | GCFLAG_NO_YOUNG_PTRS
+ extra_flags = GCFLAG_HAS_CARDS | GCFLAG_TRACK_YOUNG_PTRS
# note that if 'can_make_young', then card marking will only
# be used later, after (and if) the object becomes old
#
@@ -692,7 +698,7 @@
self.young_rawmalloced_objects.add(result + size_gc_header)
else:
self.old_rawmalloced_objects.append(result + size_gc_header)
- extra_flags |= GCFLAG_NO_YOUNG_PTRS
+ extra_flags |= GCFLAG_TRACK_YOUNG_PTRS
#
# Common code to fill the header and length of the object.
self.init_gc_object(result, typeid, extra_flags)
@@ -783,7 +789,7 @@
def init_gc_object_immortal(self, addr, typeid16, flags=0):
# For prebuilt GC objects, the flags must contain
# GCFLAG_NO_xxx_PTRS, at least initially.
- flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_NO_YOUNG_PTRS
+ flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_TRACK_YOUNG_PTRS
self.init_gc_object(addr, typeid16, flags)
def is_in_nursery(self, addr):
@@ -876,8 +882,8 @@
ll_assert(not self.is_in_nursery(obj),
"object in nursery after collection")
# similarily, all objects should have this flag:
- ll_assert(self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS,
- "missing GCFLAG_NO_YOUNG_PTRS")
+ ll_assert(self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS,
+ "missing GCFLAG_TRACK_YOUNG_PTRS")
# the GCFLAG_VISITED should not be set between collections
ll_assert(self.header(obj).tid & GCFLAG_VISITED == 0,
"unexpected GCFLAG_VISITED")
@@ -916,7 +922,7 @@
# for the JIT: a minimal description of the write_barrier() method
# (the JIT assumes it is of the shape
# "if addr_struct.int0 & JIT_WB_IF_FLAG: remember_young_pointer()")
- JIT_WB_IF_FLAG = GCFLAG_NO_YOUNG_PTRS
+ JIT_WB_IF_FLAG = GCFLAG_TRACK_YOUNG_PTRS
@classmethod
def JIT_max_size_of_young_obj(cls):
@@ -927,11 +933,11 @@
return cls.minimal_size_in_nursery
def write_barrier(self, newvalue, addr_struct):
- if self.header(addr_struct).tid & GCFLAG_NO_YOUNG_PTRS:
+ if self.header(addr_struct).tid & GCFLAG_TRACK_YOUNG_PTRS:
self.remember_young_pointer(addr_struct, newvalue)
def write_barrier_from_array(self, newvalue, addr_array, index):
- if self.header(addr_array).tid & GCFLAG_NO_YOUNG_PTRS:
+ if self.header(addr_array).tid & GCFLAG_TRACK_YOUNG_PTRS:
if self.card_page_indices > 0: # <- constant-folded
self.remember_young_pointer_from_array2(addr_array, index)
else:
@@ -949,20 +955,23 @@
def remember_young_pointer(addr_struct, newvalue):
# 'addr_struct' is the address of the object in which we write.
# 'newvalue' is the address that we are going to write in there.
+ # We know that 'addr_struct' has GCFLAG_TRACK_YOUNG_PTRS so far.
+ #
if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this
- ll_assert(self.debug_is_old_object(addr_struct),
- "young object with GCFLAG_NO_YOUNG_PTRS")
+ ll_assert(self.debug_is_old_object(addr_struct) or
+ self.header(addr_struct).tid & GCFLAG_HAS_CARDS != 0,
+ "young object with GCFLAG_TRACK_YOUNG_PTRS and no cards")
#
- # If it seems that what we are writing is a pointer to the nursery
+ # If it seems that what we are writing is a pointer to a young obj
# (as checked with appears_to_be_young()), then we need
- # to remove the flag GCFLAG_NO_YOUNG_PTRS and add the old object
- # to the list 'old_objects_pointing_to_young'. We know that
+ # to remove the flag GCFLAG_TRACK_YOUNG_PTRS and add the object
+ # to the list 'objects_pointing_to_young'. We know that
# 'addr_struct' cannot be in the nursery, because nursery objects
- # never have the flag GCFLAG_NO_YOUNG_PTRS to start with.
+ # never have the flag GCFLAG_TRACK_YOUNG_PTRS to start with.
objhdr = self.header(addr_struct)
if self.appears_to_be_young(newvalue):
- self.old_objects_pointing_to_young.append(addr_struct)
- objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS
+ self.objects_pointing_to_young.append(addr_struct)
+ objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS
#
# Second part: if 'addr_struct' is actually a prebuilt GC
# object and it's the first time we see a write to it, we
@@ -986,17 +995,18 @@
# 'addr_array' is the address of the object in which we write,
# which must have an array part; 'index' is the index of the
# item that is (or contains) the pointer that we write.
+ # We know that 'addr_array' has GCFLAG_TRACK_YOUNG_PTRS so far.
+ #
objhdr = self.header(addr_array)
if objhdr.tid & GCFLAG_HAS_CARDS == 0:
#
if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this
ll_assert(self.debug_is_old_object(addr_array),
- "young array with GCFLAG_NO_YOUNG_PTRS")
+ "young array with no card but GCFLAG_TRACK_YOUNG_PTRS")
#
# no cards, use default logic. Mostly copied from above.
- self.old_objects_pointing_to_young.append(addr_array)
- objhdr = self.header(addr_array)
- objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS
+ self.objects_pointing_to_young.append(addr_array)
+ objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS
if objhdr.tid & GCFLAG_NO_HEAP_PTRS:
objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS
self.prebuilt_root_objects.append(addr_array)
@@ -1009,9 +1019,7 @@
bitmask = 1 << (bitindex & 7)
#
# If the bit is already set, leave now.
- size_gc_header = self.gcheaderbuilder.size_gc_header
- addr_byte = addr_array - size_gc_header
- addr_byte = llarena.getfakearenaaddress(addr_byte) + (~byteindex)
+ addr_byte = self.get_card(addr_array, byteindex)
byte = ord(addr_byte.char[0])
if byte & bitmask:
return
@@ -1048,8 +1056,8 @@
else:
# case with cards.
#
- # If the newly written address does not actually point to the
- # nursery, leave now.
+ # If the newly written address does not actually point to a
+ # young object, leave now.
if not self.appears_to_be_young(newvalue):
return
#
@@ -1060,10 +1068,7 @@
bitmask = 1 << (bitindex & 7)
#
# If the bit is already set, leave now.
- size_gc_header = self.gcheaderbuilder.size_gc_header
- addr_byte = addr_array - size_gc_header
- addr_byte = llarena.getfakearenaaddress(addr_byte) + \
- (~byteindex)
+ addr_byte = self.get_card(addr_array, byteindex)
byte = ord(addr_byte.char[0])
if byte & bitmask:
return
@@ -1078,32 +1083,38 @@
# of checks done at the start of the function
if DEBUG: # note: PYPY_GC_DEBUG=1 does not enable this
ll_assert(self.debug_is_old_object(addr_array),
- "young array with GCFLAG_NO_YOUNG_PTRS")
+ "young array with no card but GCFLAG_TRACK_YOUNG_PTRS")
#
if self.appears_to_be_young(newvalue):
- self.old_objects_pointing_to_young.append(addr_array)
- objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS
+ self.objects_pointing_to_young.append(addr_array)
+ objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS
remember_young_pointer_from_array3._dont_inline_ = True
assert self.card_page_indices > 0
self.remember_young_pointer_from_array3 = (
remember_young_pointer_from_array3)
+ def get_card(self, obj, byteindex):
+ size_gc_header = self.gcheaderbuilder.size_gc_header
+ addr_byte = obj - size_gc_header
+ return llarena.getfakearenaaddress(addr_byte) + (~byteindex)
+
def assume_young_pointers(self, addr_struct):
"""Called occasionally by the JIT to mean ``assume that 'addr_struct'
may now contain young pointers.''
"""
objhdr = self.header(addr_struct)
- if objhdr.tid & GCFLAG_NO_YOUNG_PTRS:
- self.old_objects_pointing_to_young.append(addr_struct)
- objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS
+ if objhdr.tid & GCFLAG_TRACK_YOUNG_PTRS:
+ self.objects_pointing_to_young.append(addr_struct)
+ objhdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS
#
if objhdr.tid & GCFLAG_NO_HEAP_PTRS:
objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS
self.prebuilt_root_objects.append(addr_struct)
- def writebarrier_before_copy(self, source_addr, dest_addr):
+ def writebarrier_before_copy(self, source_addr, dest_addr,
+ source_start, dest_start, length):
""" This has the same effect as calling writebarrier over
each element in dest copied from source, except it might reset
one of the following flags a bit too eagerly, which means we'll have
@@ -1111,18 +1122,36 @@
"""
source_hdr = self.header(source_addr)
dest_hdr = self.header(dest_addr)
- if dest_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0:
+ if dest_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0:
return True
# ^^^ a fast path of write-barrier
#
- if source_hdr.tid & GCFLAG_CARDS_SET != 0:
- # there might be young objects, let ll_arraycopy find them
- return False
+ if source_hdr.tid & GCFLAG_HAS_CARDS != 0:
+ #
+ if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0:
+ # The source object may have random young pointers.
+ # Return False to mean "do it manually in ll_arraycopy".
+ return False
+ #
+ if source_hdr.tid & GCFLAG_CARDS_SET == 0:
+ # The source object has no young pointers at all. Done.
+ return True
+ #
+ if dest_hdr.tid & GCFLAG_HAS_CARDS == 0:
+ # The dest object doesn't have cards. Do it manually.
+ return False
+ #
+ if source_start != 0 or dest_start != 0:
+ # Misaligned. Do it manually.
+ return False
+ #
+ self.manually_copy_card_bits(source_addr, dest_addr, length)
+ return True
#
- if source_hdr.tid & GCFLAG_NO_YOUNG_PTRS == 0:
+ if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0:
# there might be in source a pointer to a young object
- self.old_objects_pointing_to_young.append(dest_addr)
- dest_hdr.tid &= ~GCFLAG_NO_YOUNG_PTRS
+ self.objects_pointing_to_young.append(dest_addr)
+ dest_hdr.tid &= ~GCFLAG_TRACK_YOUNG_PTRS
#
if dest_hdr.tid & GCFLAG_NO_HEAP_PTRS:
if source_hdr.tid & GCFLAG_NO_HEAP_PTRS == 0:
@@ -1130,6 +1159,22 @@
self.prebuilt_root_objects.append(dest_addr)
return True
+ def manually_copy_card_bits(self, source_addr, dest_addr, length):
+ # manually copy the individual card marks from source to dest
+ bytes = self.card_marking_bytes_for_length(length)
+ #
+ i = 0
+ while i < bytes:
+ addr_srcbyte = self.get_card(source_addr, i)
+ addr_dstbyte = self.get_card(dest_addr, i)
+ byte = ord(addr_srcbyte.char[0])
+ addr_dstbyte.char[0] = chr(ord(addr_dstbyte.char[0]) | byte)
+ i += 1
+ #
+ dest_hdr = self.header(dest_addr)
+ if dest_hdr.tid & GCFLAG_CARDS_SET == 0:
+ self.objects_with_cards_set.append(dest_addr)
+ dest_hdr.tid |= GCFLAG_CARDS_SET
# ----------
# Nursery collection
@@ -1146,7 +1191,7 @@
# Note that during this step, we ignore references to further
# young objects; only objects directly referenced by roots
# are copied out or flagged. They are also added to the list
- # 'old_objects_pointing_to_young'.
+ # 'objects_pointing_to_young'.
self.collect_roots_in_nursery()
#
while True:
@@ -1155,11 +1200,11 @@
if self.card_page_indices > 0:
self.collect_cardrefs_to_nursery()
#
- # Now trace objects from 'old_objects_pointing_to_young'.
+ # Now trace objects from 'objects_pointing_to_young'.
# All nursery objects they reference are copied out of the
- # nursery, and again added to 'old_objects_pointing_to_young'.
+ # nursery, and again added to 'objects_pointing_to_young'.
# All young raw-malloced object found is flagged GCFLAG_VISITED.
- # We proceed until 'old_objects_pointing_to_young' is empty.
+ # We proceed until 'objects_pointing_to_young' is empty.
self.collect_oldrefs_to_nursery()
#
# We have to loop back if collect_oldrefs_to_nursery caused
@@ -1200,7 +1245,7 @@
# we don't need to trace prebuilt GcStructs during a minor collect:
# if a prebuilt GcStruct contains a pointer to a young object,
# then the write_barrier must have ensured that the prebuilt
- # GcStruct is in the list self.old_objects_pointing_to_young.
+ # GcStruct is in the list self.objects_pointing_to_young.
self.root_walker.walk_roots(
MiniMarkGC._trace_drag_out1, # stack roots
MiniMarkGC._trace_drag_out1, # static in prebuilt non-gc
@@ -1224,11 +1269,11 @@
bytes = self.card_marking_bytes_for_length(length)
p = llarena.getfakearenaaddress(obj - size_gc_header)
#
- # If the object doesn't have GCFLAG_NO_YOUNG_PTRS, then it
- # means that it is in 'old_objects_pointing_to_young' and
+ # If the object doesn't have GCFLAG_TRACK_YOUNG_PTRS, then it
+ # means that it is in 'objects_pointing_to_young' and
# will be fully traced by collect_oldrefs_to_nursery() just
# afterwards.
- if self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS == 0:
+ if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0:
#
# In that case, we just have to reset all card bits.
while bytes > 0:
@@ -1264,19 +1309,30 @@
def collect_oldrefs_to_nursery(self):
- # Follow the old_objects_pointing_to_young list and move the
+ # Follow the objects_pointing_to_young list and move the
# young objects they point to out of the nursery.
- oldlist = self.old_objects_pointing_to_young
+ oldlist = self.objects_pointing_to_young
while oldlist.non_empty():
obj = oldlist.pop()
#
- # Add the flag GCFLAG_NO_YOUNG_PTRS. All live objects should have
- # this flag set after a nursery collection.
- self.header(obj).tid |= GCFLAG_NO_YOUNG_PTRS
+ # Check (somehow) that the flags are correct: we must not have
+ # GCFLAG_TRACK_YOUNG_PTRS so far. But in a rare case, it's
+ # possible that the same obj is appended twice to the list
+ # (see _trace_drag_out, GCFLAG_VISITED case). Filter it out
+ # here.
+ if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS != 0:
+ ll_assert(self.header(obj).tid & GCFLAG_VISITED != 0,
+ "objects_pointing_to_young contains obj with "
+ "GCFLAG_TRACK_YOUNG_PTRS and not GCFLAG_VISITED")
+ continue
+ #
+ # Add the flag GCFLAG_TRACK_YOUNG_PTRS. All live objects should
+ # have this flag set after a nursery collection.
+ self.header(obj).tid |= GCFLAG_TRACK_YOUNG_PTRS
#
# Trace the 'obj' to replace pointers to nursery with pointers
# outside the nursery, possibly forcing nursery objects out
- # and adding them to 'old_objects_pointing_to_young' as well.
+ # and adding them to 'objects_pointing_to_young' as well.
self.trace_and_drag_out_of_nursery(obj)
def trace_and_drag_out_of_nursery(self, obj):
@@ -1318,10 +1374,10 @@
#
# we just made 'obj' old, so we may need to add it
# in the correct list:
- if self.header(obj).tid & GCFLAG_NO_YOUNG_PTRS == 0:
- # common case: GCFLAG_NO_YOUNG_PTRS is not set, so
+ if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0:
+ # common case: GCFLAG_TRACK_YOUNG_PTRS is not set, so
# the object may contain young pointers anywhere
- self.old_objects_pointing_to_young.append(obj)
+ self.objects_pointing_to_young.append(obj)
else:
# large array case: the object contains card marks
# that tell us where young pointers are, and it
@@ -1374,11 +1430,11 @@
# Change the original pointer to this object.
root.address[0] = newobj
#
- # Add the newobj to the list 'old_objects_pointing_to_young',
+ # Add the newobj to the list 'objects_pointing_to_young',
# because it can contain further pointers to other young objects.
# We will fix such references to point to the copy of the young
- # objects when we walk 'old_objects_pointing_to_young'.
- self.old_objects_pointing_to_young.append(newobj)
+ # objects when we walk 'objects_pointing_to_young'.
+ self.objects_pointing_to_young.append(newobj)
def _malloc_out_of_nursery(self, totalsize):
diff --git a/pypy/rpython/memory/gc/test/test_direct.py
b/pypy/rpython/memory/gc/test/test_direct.py
--- a/pypy/rpython/memory/gc/test/test_direct.py
+++ b/pypy/rpython/memory/gc/test/test_direct.py
@@ -539,27 +539,61 @@
hdr_src = self.gc.header(addr_src)
hdr_dst = self.gc.header(addr_dst)
#
- assert hdr_src.tid & minimark.GCFLAG_NO_YOUNG_PTRS
- assert hdr_dst.tid & minimark.GCFLAG_NO_YOUNG_PTRS
+ assert hdr_src.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS
+ assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS
#
- res = self.gc.writebarrier_before_copy(addr_src, addr_dst)
+ res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10)
assert res
- assert hdr_dst.tid & minimark.GCFLAG_NO_YOUNG_PTRS
+ assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS
#
- hdr_src.tid &= ~minimark.GCFLAG_NO_YOUNG_PTRS # pretend we have young
ptrs
- res = self.gc.writebarrier_before_copy(addr_src, addr_dst)
+ hdr_src.tid &= ~minimark.GCFLAG_TRACK_YOUNG_PTRS # pretend we have
young ptrs
+ res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10)
assert res # we optimized it
- assert hdr_dst.tid & minimark.GCFLAG_NO_YOUNG_PTRS == 0 # and we
copied the flag
+ assert hdr_dst.tid & minimark.GCFLAG_TRACK_YOUNG_PTRS == 0 # and we
copied the flag
#
- # in this case, we have cards, so GCFLAG_NO_YOUNG_PTRS is set (because
- # cards takes precedence over it)
- hdr_src.tid |= minimark.GCFLAG_NO_YOUNG_PTRS
- hdr_dst.tid |= minimark.GCFLAG_NO_YOUNG_PTRS
+ hdr_src.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS
+ hdr_dst.tid |= minimark.GCFLAG_TRACK_YOUNG_PTRS
+ hdr_src.tid |= minimark.GCFLAG_HAS_CARDS
hdr_src.tid |= minimark.GCFLAG_CARDS_SET
- res = self.gc.writebarrier_before_copy(addr_src, addr_dst)
+ # hdr_dst.tid does not have minimark.GCFLAG_HAS_CARDS
+ res = self.gc.writebarrier_before_copy(addr_src, addr_dst, 0, 0, 10)
assert not res # there might be young ptrs, let ll_arraycopy to find
them
- assert hdr_dst.tid & minimark.GCFLAG_NO_YOUNG_PTRS
-
+ def test_writebarrier_before_copy_preserving_cards(self):
+ from pypy.rpython.lltypesystem import llarena
+ from pypy.rpython.memory.gc import minimark
+ tid = self.get_type_id(VAR)
+ largeobj_size = self.gc.nonlarge_max + 1
+ addr_src = self.gc.external_malloc(tid, largeobj_size)
+ addr_dst = self.gc.external_malloc(tid, largeobj_size)
+ hdr_src = self.gc.header(addr_src)
+ hdr_dst = self.gc.header(addr_dst)
+ #
+ assert hdr_src.tid & minimark.GCFLAG_HAS_CARDS
+ assert hdr_dst.tid & minimark.GCFLAG_HAS_CARDS
+ #
+ young_p = self.malloc(S)
+ self.gc.write_barrier_from_array(young_p, addr_src, 0)
+ index_in_third_page = int(2.5 * self.gc.card_page_indices)
+ assert index_in_third_page < largeobj_size
+ self.gc.write_barrier_from_array(young_p, addr_src,
+ index_in_third_page)
+ #
+ assert hdr_src.tid & minimark.GCFLAG_CARDS_SET
+ addr_byte = self.gc.get_card(addr_src, 0)
+ assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2
+ #
+ res = self.gc.writebarrier_before_copy(addr_src, addr_dst,
+ 0, 0, 2*self.gc.card_page_indices)
+ assert res
+ #
+ assert hdr_dst.tid & minimark.GCFLAG_CARDS_SET
+ addr_byte = self.gc.get_card(addr_dst, 0)
+ assert ord(addr_byte.char[0]) == 0x01 | 0x04 # bits 0 and 2
+
+ test_writebarrier_before_copy_preserving_cards.GC_PARAMS = {
+ "card_page_indices": 4}
+
+
class TestMiniMarkGCFull(DirectGCTest):
from pypy.rpython.memory.gc.minimark import MiniMarkGC as GCClass
diff --git a/pypy/rpython/memory/gctransform/framework.py
b/pypy/rpython/memory/gctransform/framework.py
--- a/pypy/rpython/memory/gctransform/framework.py
+++ b/pypy/rpython/memory/gctransform/framework.py
@@ -322,7 +322,8 @@
if hasattr(GCClass, 'writebarrier_before_copy'):
self.wb_before_copy_ptr = \
getfn(GCClass.writebarrier_before_copy.im_func,
- [s_gc] + [annmodel.SomeAddress()] * 2, annmodel.SomeBool())
+ [s_gc] + [annmodel.SomeAddress()] * 2 +
+ [annmodel.SomeInteger()] * 3, annmodel.SomeBool())
elif GCClass.needs_write_barrier:
raise NotImplementedError("GC needs write barrier, but does not
provide writebarrier_before_copy functionality")
@@ -884,7 +885,7 @@
dest_addr = hop.genop('cast_ptr_to_adr', [op.args[1]],
resulttype=llmemory.Address)
hop.genop('direct_call', [self.wb_before_copy_ptr, self.c_const_gc,
- source_addr, dest_addr],
+ source_addr, dest_addr] + op.args[2:],
resultvar=op.result)
def gct_weakref_create(self, hop):
diff --git a/pypy/rpython/memory/gctransform/test/test_framework.py
b/pypy/rpython/memory/gctransform/test/test_framework.py
--- a/pypy/rpython/memory/gctransform/test/test_framework.py
+++ b/pypy/rpython/memory/gctransform/test/test_framework.py
@@ -163,7 +163,8 @@
GC_PARAMS = {}
class GCClass(MarkSweepGC):
needs_write_barrier = True
- def writebarrier_before_copy(self, source, dest):
+ def writebarrier_before_copy(self, source, dest,
+ source_start, dest_start, length):
return True
def write_barrier_check(spaceop, needs_write_barrier=True):
diff --git a/pypy/rpython/memory/gcwrapper.py b/pypy/rpython/memory/gcwrapper.py
--- a/pypy/rpython/memory/gcwrapper.py
+++ b/pypy/rpython/memory/gcwrapper.py
@@ -136,11 +136,14 @@
ptr = lltype.cast_opaque_ptr(llmemory.GCREF, ptr)
return self.gc.id(ptr)
- def writebarrier_before_copy(self, source, dest):
+ def writebarrier_before_copy(self, source, dest,
+ source_start, dest_start, length):
if self.gc.needs_write_barrier:
source_addr = llmemory.cast_ptr_to_adr(source)
dest_addr = llmemory.cast_ptr_to_adr(dest)
- return self.gc.writebarrier_before_copy(source_addr, dest_addr)
+ return self.gc.writebarrier_before_copy(source_addr, dest_addr,
+ source_start, dest_start,
+ length)
else:
return True
diff --git a/pypy/rpython/memory/support.py b/pypy/rpython/memory/support.py
--- a/pypy/rpython/memory/support.py
+++ b/pypy/rpython/memory/support.py
@@ -140,6 +140,14 @@
self.foreach(_add_in_dict, result)
return result
+ def tolist(self):
+ """NOT_RPYTHON. Returns the content as a list."""
+ lst = []
+ def _add(obj, lst):
+ lst.append(obj)
+ self.foreach(_add, lst)
+ return lst
+
def remove(self, addr):
"""Remove 'addr' from the stack. The addr *must* be in the list,
and preferrably near the top.
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit