Author: Armin Rigo <ar...@tunes.org> Branch: stm-gc Changeset: r52360:07551dfda0ea Date: 2012-02-10 17:47 +0100 http://bitbucket.org/pypy/pypy/changeset/07551dfda0ea/
Log: id() and identityhash(). 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 @@ -2,6 +2,7 @@ from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.lltypesystem.llmemory import raw_malloc_usage from pypy.rpython.memory.gc.base import GCBase +from pypy.rpython.memory.support import mangle_hash from pypy.rpython.annlowlevel import llhelper from pypy.rlib.rarithmetic import LONG_BIT from pypy.rlib.debug import ll_assert, debug_start, debug_stop, fatalerror @@ -15,7 +16,8 @@ GCFLAG_GLOBAL = first_gcflag << 0 # keep in sync with et.c GCFLAG_WAS_COPIED = first_gcflag << 1 # keep in sync with et.c -GCFLAG_HAS_HASH = first_gcflag << 2 +GCFLAG_HAS_SHADOW = first_gcflag << 2 +GCFLAG_FIXED_HASH = first_gcflag << 3 PRIMITIVE_SIZES = {1: lltype.Char, 2: rffi.SHORT, @@ -45,7 +47,7 @@ HDR = lltype.Struct('header', ('tid', lltype.Signed), ('version', llmemory.Address)) typeid_is_in_field = 'tid' - withhash_flag_is_in_field = 'tid', GCFLAG_HAS_HASH + withhash_flag_is_in_field = 'tid', GCFLAG_FIXED_HASH GCTLS = lltype.Struct('GCTLS', ('nursery_free', llmemory.Address), ('nursery_top', llmemory.Address), @@ -360,12 +362,63 @@ ll_thread.release_NOAUTO(lock) # ---------- + # id() and identityhash() support + + def id_or_identityhash(self, gcobj, is_hash): + """Implement the common logic of id() and identityhash() + of an object, given as a GCREF. + """ + obj = llmemory.cast_ptr_to_adr(gcobj) + hdr = self.header(obj) + # + if hdr.tid & GCFLAG_GLOBAL == 0: + # + # The object is a local object. Find or allocate a corresponding + # global object. + if hdr.tid & (GCFLAG_WAS_COPIED | GCFLAG_HAS_SHADOW) == 0: + # + # We need to allocate a global object here. We only allocate + # it for now; it is left completely uninitialized. + size = self.get_size(obj) + self.acquire(self.mutex_lock) + main_tls = self.main_thread_tls + globalobj = self._malloc_local_raw(main_tls, size) + self.header(globalobj).tid = GCFLAG_GLOBAL + self.release(self.mutex_lock) + # + # Update the header of the local 'obj' + hdr.tid |= GCFLAG_HAS_SHADOW + hdr.version = globalobj + # + else: + # There is already a corresponding globalobj + globalobj = hdr.version + # + obj = globalobj + # + ll_assert(self.header(obj).tid & GCFLAG_GLOBAL != 0, + "id_or_identityhash: unexpected local object") + i = llmemory.cast_adr_to_int(obj) + if is_hash: + # For identityhash(), we need a special case for some + # prebuilt objects: their hash must be the same before + # and after translation. It is stored as an extra word + # after the object. But we cannot use it for id() + # because the stored value might clash with a real one. + if self.header(obj).tid & GCFLAG_FIXED_HASH: + size = self.get_size(obj) + i = (obj + size).signed[0] + else: + # mangle the hash value to increase the dispertion + # on the trailing bits, but only if !GCFLAG_FIXED_HASH + i = mangle_hash(i) + return i def id(self, gcobj): - raise NotImplementedError("XXX") + return self.id_or_identityhash(gcobj, False) def identityhash(self, gcobj): - raise NotImplementedError("XXX") + return self.id_or_identityhash(gcobj, True) # ------------------------------------------------------------ @@ -512,17 +565,31 @@ ll_assert(hdr.tid & GCFLAG_GLOBAL == 0, "trace_and_mark: GLOBAL obj in nursery") # - if hdr.tid & GCFLAG_WAS_COPIED != 0: - # this local object is a root or was already marked. Either - # way, its 'version' field should point to the corresponding - # global object. - globalobj = hdr.version - # - else: - # First visit to a local-only 'obj': copy it into the global area + if hdr.tid & (GCFLAG_WAS_COPIED | GCFLAG_HAS_SHADOW) == 0: + # First visit to a local-only 'obj': allocate a corresponding + # global object size = self.gc.get_size(obj) main_tls = self.gc.main_thread_tls globalobj = self.gc._malloc_local_raw(main_tls, size) + need_to_copy = True + # + else: + globalobj = hdr.version + if hdr.tid & GCFLAG_WAS_COPIED != 0: + # this local object is a root or was already marked. Either + # way, its 'version' field should point to the corresponding + # global object. + size = 0 + need_to_copy = False + else: + # this local object has a shadow made by id_or_identityhash(); + # and the 'version' field points to the global shadow. + ll_assert(hdr.tid & GCFLAG_HAS_SHADOW != 0, "uh?") + size = self.gc.get_size(obj) + need_to_copy = True + # + if need_to_copy: + # Copy the data of the object from the local to the global llmemory.raw_memcopy(obj, globalobj, size) # # Initialize the header of the 'globalobj' 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 @@ -2,6 +2,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory, llarena, rffi from pypy.rpython.memory.gc.stmgc import StmGC, PRIMITIVE_SIZES, WORD, CALLBACK from pypy.rpython.memory.gc.stmgc import GCFLAG_GLOBAL, GCFLAG_WAS_COPIED +from pypy.rpython.memory.support import mangle_hash S = lltype.GcStruct('S', ('a', lltype.Signed), ('b', lltype.Signed), @@ -392,3 +393,88 @@ s1, s1_adr = self.malloc(S) assert (repr(self.gc.stm_operations._getsize_fn(s1_adr)) == repr(fake_get_size(s1_adr))) + + def test_id_of_global(self): + s, s_adr = self.malloc(S) + i = self.gc.id(s) + assert i == llmemory.cast_adr_to_int(s_adr) + + def test_id_of_globallocal(self): + s, s_adr = self.malloc(S) + self.select_thread(1) + t_adr = self.gc.stm_writebarrier(s_adr) # make a local copy + t = llmemory.cast_adr_to_ptr(t_adr, llmemory.GCREF) + i = self.gc.id(t) + assert i == llmemory.cast_adr_to_int(s_adr) + assert i == self.gc.id(s) + self.gc.commit_transaction() + assert i == self.gc.id(s) + + def test_id_of_local_nonsurviving(self): + self.select_thread(1) + s, s_adr = self.malloc(S) + i = self.gc.id(s) + assert i != llmemory.cast_adr_to_int(s_adr) + assert i == self.gc.id(s) + self.gc.commit_transaction() + + def test_id_of_local_surviving(self): + sr1, sr1_adr = self.malloc(SR) + self.select_thread(1) + t2, t2_adr = self.malloc(S) + tr1_adr = self.gc.stm_writebarrier(sr1_adr) + assert tr1_adr != sr1_adr + tr1 = llmemory.cast_adr_to_ptr(tr1_adr, lltype.Ptr(SR)) + tr1.s1 = t2 + i = self.gc.id(t2) + assert i not in (llmemory.cast_adr_to_int(sr1_adr), + llmemory.cast_adr_to_int(t2_adr), + llmemory.cast_adr_to_int(tr1_adr)) + assert i == self.gc.id(t2) + self.gc.commit_transaction() + s2 = tr1.s1 # tr1 is a root, so not copied yet + assert s2 and s2 != t2 + assert self.gc.id(s2) == i + + def test_hash_of_global(self): + s, s_adr = self.malloc(S) + i = self.gc.identityhash(s) + assert i == mangle_hash(llmemory.cast_adr_to_int(s_adr)) + + def test_hash_of_globallocal(self): + s, s_adr = self.malloc(S) + self.select_thread(1) + t_adr = self.gc.stm_writebarrier(s_adr) # make a local copy + t = llmemory.cast_adr_to_ptr(t_adr, llmemory.GCREF) + i = self.gc.identityhash(t) + assert i == mangle_hash(llmemory.cast_adr_to_int(s_adr)) + assert i == self.gc.identityhash(s) + self.gc.commit_transaction() + assert i == self.gc.identityhash(s) + + def test_hash_of_local_nonsurviving(self): + self.select_thread(1) + s, s_adr = self.malloc(S) + i = self.gc.identityhash(s) + assert i != mangle_hash(llmemory.cast_adr_to_int(s_adr)) + assert i == self.gc.identityhash(s) + self.gc.commit_transaction() + + def test_hash_of_local_surviving(self): + sr1, sr1_adr = self.malloc(SR) + self.select_thread(1) + t2, t2_adr = self.malloc(S) + tr1_adr = self.gc.stm_writebarrier(sr1_adr) + assert tr1_adr != sr1_adr + tr1 = llmemory.cast_adr_to_ptr(tr1_adr, lltype.Ptr(SR)) + tr1.s1 = t2 + i = self.gc.identityhash(t2) + assert i not in map(mangle_hash, + (llmemory.cast_adr_to_int(sr1_adr), + llmemory.cast_adr_to_int(t2_adr), + llmemory.cast_adr_to_int(tr1_adr))) + assert i == self.gc.identityhash(t2) + self.gc.commit_transaction() + s2 = tr1.s1 # tr1 is a root, so not copied yet + assert s2 and s2 != t2 + assert self.gc.identityhash(s2) == i _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit