Author: Armin Rigo <[email protected]>
Branch: stm-thread-2
Changeset: r57203:f23da2c9b5f4
Date: 2012-09-07 10:01 +0200
http://bitbucket.org/pypy/pypy/changeset/f23da2c9b5f4/
Log: Fix 'stmgc': in-progress
diff --git a/pypy/annotation/model.py b/pypy/annotation/model.py
--- a/pypy/annotation/model.py
+++ b/pypy/annotation/model.py
@@ -203,7 +203,6 @@
class SomeInteger(SomeFloat):
"Stands for an object which is known to be an integer."
knowntype = int
- # size is in multiples of C's sizeof(long)!
def __init__(self, nonneg=False, unsigned=None, knowntype=None):
assert (knowntype is None or knowntype is int or
issubclass(knowntype, base_int))
diff --git a/pypy/rpython/lltypesystem/llmemory.py
b/pypy/rpython/lltypesystem/llmemory.py
--- a/pypy/rpython/lltypesystem/llmemory.py
+++ b/pypy/rpython/lltypesystem/llmemory.py
@@ -515,6 +515,13 @@
else:
return 0
+ def _cast_to_uint(self, symbolic=False):
+ if self:
+ assert not isinstance(self.ptr._obj0, int)
+ return AddressAsUInt(self)
+ else:
+ return r_uint(0)
+
def _fixup(self):
if self.ptr is not None and self.ptr._was_freed():
# hack to support llarena.test_replace_object_with_stub()
@@ -549,10 +556,18 @@
return AddressAsInt(cast_ptr_to_adr(fieldadr))
return NotImplemented
def __repr__(self):
+ clsname = self.__class__.__name__
try:
- return '<AddressAsInt %s>' % (self.adr.ptr,)
+ return '<%s %s>' % (clsname, self.adr.ptr)
except AttributeError:
- return '<AddressAsInt at 0x%x>' % (uid(self),)
+ return '<%s at 0x%x>' % (clsname, uid(self))
+
+class AddressAsUInt(AddressAsInt):
+ def annotation(self):
+ from pypy.annotation import model
+ return model.SomeInteger(unsigned=True)
+ def lltype(self):
+ return lltype.Unsigned
# ____________________________________________________________
@@ -678,6 +693,9 @@
res = cast(lltype.Signed, res)
return res
+def cast_adr_to_uint_symbolic(adr):
+ return adr._cast_to_uint()
+
_NONGCREF = lltype.Ptr(lltype.OpaqueType('NONGCREF'))
def cast_int_to_adr(int):
if isinstance(int, AddressAsInt):
diff --git a/pypy/rpython/memory/gc/stmgc.py b/pypy/rpython/memory/gc/stmgc.py
--- a/pypy/rpython/memory/gc/stmgc.py
+++ b/pypy/rpython/memory/gc/stmgc.py
@@ -119,8 +119,9 @@
GCFLAG_POSSIBLY_OUTDATED = first_gcflag << 1 # keep in sync with et.h
GCFLAG_NOT_WRITTEN = first_gcflag << 2 # keep in sync with et.h
GCFLAG_LOCAL_COPY = first_gcflag << 3 # keep in sync with et.h
-GCFLAG_HAS_SHADOW = first_gcflag << 4
-GCFLAG_FIXED_HASH = first_gcflag << 5
+GCFLAG_VISITED = first_gcflag << 4
+GCFLAG_HAS_SHADOW = first_gcflag << 5
+GCFLAG_FIXED_HASH = first_gcflag << 6
def always_inline(fn):
@@ -188,8 +189,8 @@
# The following line causes the _stm_getsize() function to be
# generated in the C source with a specific signature, where it
# can be called by the C code.
- llop.nop(lltype.Void, llhelper(self.stm_operations.GETSIZE,
- self._stm_getsize))
+ llop.nop(lltype.Void, llhelper(self.stm_operations.DUPLICATE,
+ self._stm_duplicate))
#
self.sharedarea.setup()
#
@@ -278,7 +279,7 @@
def collect(self, gen=1):
self.get_tls().local_collection()
if gen > 0:
- debug_print("XXX not doing a global collect()")
+ debug_print("XXX not implemented: global collect()")
def start_transaction(self):
self.get_tls().start_transaction()
@@ -305,6 +306,12 @@
flags |= GCFLAG_GLOBAL
self.init_gc_object(addr, typeid16, flags)
+ def obj_revision(obj):
+ return hdr_revision(self.header(obj))
+
+ def set_obj_revision(obj, nrevision):
+ set_hdr_revision(self.header(obj), nrevision)
+
def stm_duplicate(self, obj):
size_gc_header = self.gcheaderbuilder.size_gc_header
size = self.get_size(obj)
@@ -357,11 +364,11 @@
#
# Update the header of the local 'obj'
hdr.tid |= GCFLAG_HAS_SHADOW
- hdr.version = fixedobj
+ set_hdr_revision(hdr, fixedobj)
#
else:
# There is already a corresponding fixedobj
- fixedobj = hdr.version
+ fixedobj = hdr_revision(hdr)
#
obj = fixedobj
#
@@ -391,3 +398,13 @@
def identityhash(self, gcobj):
return self.id_or_identityhash(gcobj, True)
+
+
+# ____________________________________________________________
+# helpers
+
+def hdr_revision(hdr):
+ return llmemory.cast_int_to_adr(hdr.revision)
+
+def set_hdr_revision(hdr, nrevision):
+ hdr.revision = llmemory.cast_adr_to_uint_symbolic(nrevision)
diff --git a/pypy/rpython/memory/gc/stmshared.py
b/pypy/rpython/memory/gc/stmshared.py
--- a/pypy/rpython/memory/gc/stmshared.py
+++ b/pypy/rpython/memory/gc/stmshared.py
@@ -52,5 +52,9 @@
self.free_object(obj)
obj = next
+ def free_and_clear_list(self, lst):
+ while lst.non_empty():
+ self.free_object(lst.pop())
+
def delete(self):
free_non_gc_object(self)
diff --git a/pypy/rpython/memory/gc/stmtls.py b/pypy/rpython/memory/gc/stmtls.py
--- a/pypy/rpython/memory/gc/stmtls.py
+++ b/pypy/rpython/memory/gc/stmtls.py
@@ -10,7 +10,9 @@
from pypy.rpython.memory.gc.stmgc import WORD, NULL
from pypy.rpython.memory.gc.stmgc import always_inline, dont_inline
from pypy.rpython.memory.gc.stmgc import GCFLAG_GLOBAL, GCFLAG_VISITED
-from pypy.rpython.memory.gc.stmgc import GCFLAG_WAS_COPIED, GCFLAG_HAS_SHADOW
+from pypy.rpython.memory.gc.stmgc import GCFLAG_LOCAL_COPY, GCFLAG_HAS_SHADOW
+from pypy.rpython.memory.gc.stmgc import GCFLAG_POSSIBLY_OUTDATED
+from pypy.rpython.memory.gc.stmgc import hdr_revision
class StmGCTLS(object):
@@ -41,7 +43,9 @@
# --- a thread-local allocator for the shared area
from pypy.rpython.memory.gc.stmshared import StmGCThreadLocalAllocator
self.sharedarea_tls = StmGCThreadLocalAllocator(self.gc.sharedarea)
- # --- the LOCAL objects with GCFLAG_WAS_COPIED
+ # --- the GCFLAG_LOCAL_COPY objects are also allocated with
+ # self.sharedarea_tls, but we need their 'revision', so we
+ # can't do add_regular() on them. They go here instead:
self.copied_local_objects = self.AddressStack()
# --- the LOCAL objects which are weakrefs. They are also listed
# in the appropriate place, like sharedarea_tls, if needed.
@@ -122,7 +126,7 @@
# malloced objects will be LOCAL.
if self.gc.DEBUG:
self.check_all_global_objects()
- self.relocalize_from_stack()
+ #self.relocalize_from_stack()
def stop_transaction(self):
"""Stop a transaction: do a local collection to empty the
@@ -157,9 +161,9 @@
debug_start("gc-local")
#
if end_of_transaction:
- self.detect_flag_combination = GCFLAG_WAS_COPIED | GCFLAG_VISITED
+ self.replace_pointers_following_revision = GCFLAG_LOCAL_COPY
else:
- self.detect_flag_combination = -1
+ self.replace_pointers_following_revision = 0
#
# Move away the previous sharedarea_tls and start a new one.
from pypy.rpython.memory.gc.stmshared import StmGCThreadLocalAllocator
@@ -251,6 +255,7 @@
return localobj
def fresh_new_weakref(self, obj):
+ XXX # review
self.local_weakrefs.append(obj)
# ------------------------------------------------------------
@@ -258,7 +263,8 @@
def _promote_locals_to_globals(self):
ll_assert(self.local_nursery_is_empty(), "nursery must be empty [1]")
#
- # Promote all objects in sharedarea_tls to global
+ # Promote all objects in sharedarea_tls to global.
+ # This is the "real" equivalent of _FakeReach() in et.c.
obj = self.sharedarea_tls.chained_list
self.sharedarea_tls.chained_list = NULL
#
@@ -267,18 +273,19 @@
obj = hdr.version
ll_assert(hdr.tid & GCFLAG_GLOBAL == 0, "already GLOBAL [1]")
ll_assert(hdr.tid & GCFLAG_VISITED == 0, "unexpected VISITED [1]")
- hdr.tid |= GCFLAG_GLOBAL
- self._clear_version_for_global_object(hdr)
+ hdr.tid |= GCFLAG_GLOBAL | GCFLAG_NOT_WRITTEN
+ if hdr.tid & GCFLAG_LOCAL_COPY == 0:
+ self._clear_version_for_global_object(hdr)
def _clear_version_for_global_object(self, hdr):
# Reset the 'version' to initialize a newly global object.
- # When translated with C code, we set it to NULL (version 0).
+ # When translated with C code, we set it to 1.
# When non-translated, we reset it instead to '_uninitialized'
# to simulate the fact that the C code might change it.
if we_are_translated():
- hdr.version = NULL
+ hdr.revision = r_uint(1)
else:
- del hdr.version
+ del hdr.revision
def _cleanup_state(self):
#if self.rawmalloced_objects:
@@ -287,57 +294,50 @@
# free the old unused local objects still allocated in the
# StmGCThreadLocalAllocator
self.sharedarea_tls.free_and_clear()
- # free the local copies. Note that commonly, they are leftovers
- # from the previous transaction running in this thread. The C code
- # has just copied them over the corresponding GLOBAL objects at the
- # very end of that transaction.
- self._free_and_clear_list(self.copied_local_objects)
+ # free these ones too
+ self.sharedarea_tls.free_and_clear_list(self.copied_local_objects)
# forget the local weakrefs.
self.local_weakrefs.clear()
- def _free_and_clear_list(self, lst):
- while lst.non_empty():
- self.sharedarea_tls.free_object(lst.pop())
-
def collect_roots_from_stack(self, end_of_transaction):
- if end_of_transaction:
- # in this mode, we flag the reference to local objects in order
- # to re-localize them when we later start the next transaction
- # using this section of the shadowstack
- self.gc.root_walker.walk_current_stack_roots(
- StmGCTLS._trace_drag_out_and_flag_local, self)
- else:
+## if end_of_transaction:
+## # in this mode, we flag the reference to local objects in order
+## # to re-localize them when we later start the next transaction
+## # using this section of the shadowstack
+## self.gc.root_walker.walk_current_stack_roots(
+## StmGCTLS._trace_drag_out_and_flag_local, self)
+## else:
self.gc.root_walker.walk_current_stack_roots(
StmGCTLS._trace_drag_out1, self)
- def _trace_drag_out_and_flag_local(self, root):
- x = llmemory.cast_adr_to_int(root.address[0])
- if x & 2:
- root.address[0] -= 2
- old_tid = self.gc.header(root.address[0]).tid
- #
- self._trace_drag_out1(root)
- #
- # if root.address[0] used to point to a local object, then flag
- # this by adding the bit of value 2.
- if old_tid & GCFLAG_GLOBAL == 0:
- obj = root.address[0]
- x = llmemory.cast_adr_to_int(obj)
- ll_assert(x & 3 == 0, "flag_local: misaligned obj")
- obj = llarena.getfakearenaaddress(obj)
- root.address[0] = obj + 2
+## def _trace_drag_out_and_flag_local(self, root):
+## x = llmemory.cast_adr_to_int(root.address[0])
+## if x & 2:
+## root.address[0] -= 2
+## old_tid = self.gc.header(root.address[0]).tid
+## #
+## self._trace_drag_out1(root)
+## #
+## # if root.address[0] used to point to a local object, then flag
+## # this by adding the bit of value 2.
+## if old_tid & GCFLAG_GLOBAL == 0:
+## obj = root.address[0]
+## x = llmemory.cast_adr_to_int(obj)
+## ll_assert(x & 3 == 0, "flag_local: misaligned obj")
+## obj = llarena.getfakearenaaddress(obj)
+## root.address[0] = obj + 2
- def relocalize_from_stack(self):
- self.gc.root_walker.walk_current_stack_roots(
- StmGCTLS._relocalize_from_stack, self)
+## def relocalize_from_stack(self):
+## self.gc.root_walker.walk_current_stack_roots(
+## StmGCTLS._relocalize_from_stack, self)
- def _relocalize_from_stack(self, root):
- x = llmemory.cast_adr_to_int(root.address[0])
- if x & 2:
- obj = root.address[0] - 2
- localobj = self.gc.stm_writebarrier(obj)
- root.address[0] = localobj
+## def _relocalize_from_stack(self, root):
+## x = llmemory.cast_adr_to_int(root.address[0])
+## if x & 2:
+## obj = root.address[0] - 2
+## localobj = self.gc.stm_writebarrier(obj)
+## root.address[0] = localobj
def collect_from_raw_structures(self):
self.gc.root_walker.walk_current_nongc_roots(
@@ -360,19 +360,19 @@
"""Return the current surviving state of the object:
0: not marked as surviving, so far
1: survives and does not move
- 2: survives, but moves to 'hdr.version'
+ 2: survives, but moves to 'hdr.revision'
"""
hdr = self.gc.header(obj)
flag_combination = hdr.tid & (GCFLAG_GLOBAL |
- GCFLAG_WAS_COPIED |
+ GCFLAG_LOCAL_COPY |
GCFLAG_VISITED)
if flag_combination == 0:
return 0 # not marked as surviving, so far
- if flag_combination == self.detect_flag_combination:
- # At a normal time, self.detect_flag_combination is -1
- # and this case is never seen. At end of transactions,
- # detect_flag_combination is GCFLAG_WAS_COPIED|GCFLAG_VISITED.
+ if flag_combination & self.replace_pointers_following_revision:
+ # At a normal time, self.replace_pointers_following_revision
+ # is 0 and this case is never seen. At end of transactions,
+ # detect_flag_combination is GCFLAG_LOCAL_COPY.
# This case is to force pointers to the LOCAL copy to be
# replaced with pointers to the GLOBAL copy.
return 2
@@ -484,19 +484,19 @@
def _stm_enum_callback(tlsaddr, globalobj, localobj):
self = StmGCTLS.cast_address_to_tls_object(tlsaddr)
localhdr = self.gc.header(localobj)
- ll_assert(localhdr.version == globalobj,
+ ll_assert(hdr_revision(localhdr) == globalobj,
"in a root: localobj.version != globalobj")
ll_assert(localhdr.tid & GCFLAG_GLOBAL == 0,
"in a root: unexpected GCFLAG_GLOBAL")
- ll_assert(localhdr.tid & GCFLAG_WAS_COPIED != 0,
- "in a root: missing GCFLAG_WAS_COPIED")
- ll_assert(localhdr.tid & GCFLAG_VISITED != 0,
- "in a root: missing GCFLAG_VISITED")
+ ll_assert(localhdr.tid & GCFLAG_LOCAL_COPY != 0,
+ "in a root: missing GCFLAG_LOCAL_COPY")
+ ll_assert(localhdr.tid & GCFLAG_VISITED == 0,
+ "in a root: unexpected GCFLAG_VISITED")
globalhdr = self.gc.header(globalobj)
ll_assert(globalhdr.tid & GCFLAG_GLOBAL != 0,
"in a root: GLOBAL: missing GCFLAG_GLOBAL")
- ll_assert(globalhdr.tid & GCFLAG_WAS_COPIED != 0,
- "in a root: GLOBAL: missing GCFLAG_WAS_COPIED")
+ ll_assert(globalhdr.tid & GCFLAG_POSSIBLY_OUTDATED != 0,
+ "in a root: GLOBAL: missing GCFLAG_POSSIBLY_OUTDATED")
ll_assert(globalhdr.tid & GCFLAG_VISITED == 0,
"in a root: GLOBAL: unexpected GCFLAG_VISITED")
TL = lltype.cast_primitive(lltype.Signed,
@@ -505,7 +505,8 @@
self.gc.get_type_id(globalobj))
ll_assert(TL == TG, "in a root: type(LOCAL) != type(GLOBAL)")
#
- self.trace_and_drag_out_of_nursery(localobj)
+ localhdr.tid |= GCFLAG_VISITED
+ self.pending.append(localobj)
def collect_flush_pending(self):
# Follow the objects in the 'pending' stack and move the
@@ -566,8 +567,8 @@
def _debug_check_all_global_from_stack_1(self, root):
obj = root.address[0]
- if llmemory.cast_adr_to_int(obj) & 2:
- obj -= 2 # will be fixed by relocalize_from_stack()
+## if llmemory.cast_adr_to_int(obj) & 2:
+## obj -= 2 # will be fixed by relocalize_from_stack()
self._debug_check_all_global_obj(obj)
def _debug_check_all_global(self, root, ignored):
diff --git a/pypy/rpython/memory/gc/test/test_stmgc.py
b/pypy/rpython/memory/gc/test/test_stmgc.py
--- a/pypy/rpython/memory/gc/test/test_stmgc.py
+++ b/pypy/rpython/memory/gc/test/test_stmgc.py
@@ -1,8 +1,10 @@
import py
from pypy.rpython.lltypesystem import lltype, llmemory, llarena, llgroup, rffi
from pypy.rpython.memory.gc.stmgc import StmGC, WORD
-from pypy.rpython.memory.gc.stmgc import GCFLAG_GLOBAL, GCFLAG_WAS_COPIED
-from pypy.rpython.memory.gc.stmgc import GCFLAG_VISITED
+from pypy.rpython.memory.gc.stmgc import GCFLAG_GLOBAL, GCFLAG_NOT_WRITTEN
+from pypy.rpython.memory.gc.stmgc import GCFLAG_POSSIBLY_OUTDATED
+from pypy.rpython.memory.gc.stmgc import GCFLAG_LOCAL_COPY
+from pypy.rpython.memory.gc.stmgc import hdr_revision, set_hdr_revision
from pypy.rpython.memory.support import mangle_hash
@@ -86,20 +88,20 @@
for key, value in self._tldicts[self.threadnum].iteritems():
callback(tls, key, value)
- def read_attribute(self, obj, name):
- obj = llmemory.cast_ptr_to_adr(obj)
- hdr = self._gc.header(obj)
- localobj = self.tldict_lookup(obj)
- if localobj == llmemory.NULL:
- localobj = obj
- else:
- assert hdr.tid & GCFLAG_GLOBAL != 0
- localobj = llmemory.cast_adr_to_ptr(localobj, lltype.Ptr(SR))
- return getattr(localobj, name)
+## def read_attribute(self, obj, name):
+## obj = llmemory.cast_ptr_to_adr(obj)
+## hdr = self._gc.header(obj)
+## localobj = self.tldict_lookup(obj)
+## if localobj == llmemory.NULL:
+## localobj = obj
+## else:
+## assert hdr.tid & GCFLAG_GLOBAL != 0
+## localobj = llmemory.cast_adr_to_ptr(localobj, lltype.Ptr(SR))
+## return getattr(localobj, name)
- def stm_copy_transactional_to_raw(self, srcobj, dstobj, size):
- llmemory.raw_memcopy(srcobj, dstobj, size)
- self._transactional_copies.append((srcobj, dstobj))
+## def stm_copy_transactional_to_raw(self, srcobj, dstobj, size):
+## llmemory.raw_memcopy(srcobj, dstobj, size)
+## self._transactional_copies.append((srcobj, dstobj))
def fake_get_size(obj):
@@ -179,7 +181,8 @@
1)
llarena.arena_reserve(adr1, totalsize)
addr = adr1 + self.gc.gcheaderbuilder.size_gc_header
- self.gc.header(addr).tid = self.gc.combine(tid, GCFLAG_GLOBAL)
+ self.gc.header(addr).tid = self.gc.combine(
+ tid, GCFLAG_GLOBAL | GCFLAG_NOT_WRITTEN)
realobj = llmemory.cast_adr_to_ptr(addr, lltype.Ptr(STRUCT))
else:
gcref = self.gc.malloc_fixedsize_clear(tid, size,
@@ -205,9 +208,27 @@
assert (hdr.tid & GCFLAG_WAS_COPIED != 0) == must_have_was_copied
if must_have_version != '?':
assert hdr.version == must_have_version
- def read_signed(self, obj, offset):
- meth = getattr(self.gc, 'read_int%d' % WORD)
- return meth(obj, offset)
+
+ def stm_writebarrier(self, P):
+ if lltype.typeOf(P) != llmemory.Address:
+ P = llmemory.cast_ptr_to_adr(P)
+ hdr = self.gc.header(P)
+ if hdr.tid & GCFLAG_NOT_WRITTEN == 0:
+ # already a local, written-to object
+ assert hdr.tid & GCFLAG_GLOBAL == 0
+ assert hdr.tid & GCFLAG_POSSIBLY_OUTDATED == 0
+ W = P
+ else:
+ # slow case of the write barrier
+ if hdr.tid & GCFLAG_GLOBAL == 0:
+ W = P
+ R = hdr_revision(hdr)
+ else:
+ R = P
+ W = self.gc.stm_operations.tldict_lookup(R)
+ self.gc.header(W).tid &= ~GCFLAG_NOT_WRITTEN
+ self.gc.header(R).tid |= GCFLAG_POSSIBLY_OUTDATED
+ return W
class TestBasic(StmGCTests):
@@ -246,18 +267,20 @@
def test_write_barrier_exists(self):
self.select_thread(1)
t, t_adr = self.malloc(S)
- obj = self.gc.stm_writebarrier(t_adr) # local object
+ obj = self.stm_writebarrier(t_adr) # local object
assert obj == t_adr
#
self.select_thread(0)
s, s_adr = self.malloc(S)
#
self.select_thread(1)
- self.gc.header(s_adr).tid |= GCFLAG_WAS_COPIED
- self.gc.header(t_adr).tid |= GCFLAG_WAS_COPIED | GCFLAG_VISITED
- self.gc.header(t_adr).version = s_adr
+ assert self.gc.header(s_adr).tid & GCFLAG_GLOBAL != 0
+ assert self.gc.header(t_adr).tid & GCFLAG_GLOBAL == 0
+ self.gc.header(s_adr).tid |= GCFLAG_POSSIBLY_OUTDATED
+ self.gc.header(t_adr).tid |= GCFLAG_LOCAL_COPY
+ set_hdr_revision(self.gc.header(t_adr), s_adr)
self.gc.stm_operations._tldicts[1][s_adr] = t_adr
- obj = self.gc.stm_writebarrier(s_adr) # global copied object
+ obj = self.stm_writebarrier(s_adr) # global copied object
assert obj == t_adr
assert self.gc.stm_operations._transactional_copies == []
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit