Author: Armin Rigo <[email protected]>
Branch: stm-thread-2
Changeset: r59380:d2c80171d20e
Date: 2012-12-10 00:07 +0100
http://bitbucket.org/pypy/pypy/changeset/d2c80171d20e/
Log: Trying to remove the hack around hashes. Now taking a hash for the
first time on an object is a write operation, but it simplifies the
(broken) logic.
diff --git a/pypy/rpython/lltypesystem/lloperation.py
b/pypy/rpython/lltypesystem/lloperation.py
--- a/pypy/rpython/lltypesystem/lloperation.py
+++ b/pypy/rpython/lltypesystem/lloperation.py
@@ -422,6 +422,8 @@
# to keep them as operations until the genc stage)
'stm_barrier': LLOp(sideeffects=False),
+ 'stm_read_barrier': LLOp(), # explicit read barrier, special case
+ 'stm_write_barrier': LLOp(), # explicit write barrier, special case
'stm_become_inevitable': LLOp(),
'stm_ptr_eq': LLOp(sideeffects=False),
'stm_start_transaction': LLOp(canrun=True, canmallocgc=True),
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
@@ -116,10 +116,10 @@
GCFLAG_LOCAL_COPY = first_gcflag << 3 # keep in sync with et.h
GCFLAG_VISITED = first_gcflag << 4 # keep in sync with et.h
GCFLAG_HASH_FIELD = first_gcflag << 5 # keep in sync with et.h
+GCFLAG_NEW_HASH = first_gcflag << 6 # keep in sync with et.h
GCFLAG_PREBUILT = GCFLAG_GLOBAL | GCFLAG_NOT_WRITTEN
REV_INITIAL = r_uint(1)
-REV_FLAG_NEW_HASH = r_uint(2)
def always_inline(fn):
@@ -352,8 +352,14 @@
return self.identityhash(gcobj)
def identityhash(self, gcobj):
+ gcobj = llop.stm_read_barrier(lltype.typeOf(gcobj), gcobj)
obj = llmemory.cast_ptr_to_adr(gcobj)
- obj = self.stm_operations.stm_HashObject(obj)
+ if not (self.header(obj).tid & (GCFLAG_HASH_FIELD | GCFLAG_NEW_HASH)):
+ # 'obj' has no hash so far. Force one; this is a write operation.
+ localgcobj = llop.stm_write_barrier(lltype.typeOf(gcobj), gcobj)
+ obj = llmemory.cast_ptr_to_adr(localgcobj)
+ self.header(obj).tid |= GCFLAG_NEW_HASH
+ #
return self._get_object_hash(obj)
def _get_object_hash(self, obj):
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
@@ -14,7 +14,7 @@
from pypy.rpython.memory.gc.stmgc import GCFLAG_LOCAL_COPY
from pypy.rpython.memory.gc.stmgc import GCFLAG_POSSIBLY_OUTDATED
from pypy.rpython.memory.gc.stmgc import GCFLAG_NOT_WRITTEN
-from pypy.rpython.memory.gc.stmgc import GCFLAG_HASH_FIELD, REV_FLAG_NEW_HASH
+from pypy.rpython.memory.gc.stmgc import GCFLAG_HASH_FIELD, GCFLAG_NEW_HASH
from pypy.rpython.memory.gc.stmgc import hdr_revision, set_hdr_revision
SIZE_OF_SIGNED = llmemory.sizeof(lltype.Signed)
@@ -453,8 +453,7 @@
size_gc_header = self.gc.gcheaderbuilder.size_gc_header
totalsize_without_hash = size_gc_header + objsize
hdr = self.gc.header(obj)
- has_hash = (hdr.tid & GCFLAG_HASH_FIELD != 0 or
- hdr.revision & REV_FLAG_NEW_HASH != 0)
+ has_hash = (hdr.tid & (GCFLAG_HASH_FIELD | GCFLAG_NEW_HASH))
if has_hash:
newtotalsize = totalsize_without_hash + (
llmemory.sizeof(lltype.Signed))
diff --git a/pypy/translator/stm/src_stm/et.c b/pypy/translator/stm/src_stm/et.c
--- a/pypy/translator/stm/src_stm/et.c
+++ b/pypy/translator/stm/src_stm/et.c
@@ -36,7 +36,7 @@
/************************************************************/
#define ABORT_REASONS 5
-#define SPINLOOP_REASONS 5
+#define SPINLOOP_REASONS 4
struct tx_descriptor {
jmp_buf *setjmp_buf;
@@ -55,7 +55,7 @@
struct FXCache recent_reads_cache;
};
-static volatile revision_t global_cur_time = 4; /* always mult of 4 */
+static volatile revision_t global_cur_time = 2; /* always mult of 2 */
static volatile revision_t next_locked_value = LOCKED + 3; /* always odd */
static __thread struct tx_descriptor *thread_descriptor = NULL;
@@ -559,7 +559,7 @@
{
// no-one else can have changed global_cur_time if I'm inevitable
cur_time = d->start_time;
- if (!bool_cas(&global_cur_time, INEVITABLE, cur_time + 4))
+ if (!bool_cas(&global_cur_time, INEVITABLE, cur_time + 2))
{
assert(!"global_cur_time modified even though we are inev.");
abort();
@@ -579,7 +579,7 @@
AcquireLocks(d);
continue;
}
- if (bool_cas(&global_cur_time, cur_time, cur_time + 4))
+ if (bool_cas(&global_cur_time, cur_time, cur_time + 2))
break;
}
// validate (but skip validation if nobody else committed)
@@ -684,56 +684,6 @@
return GlobalizeForComparison(d, P1) == GlobalizeForComparison(d, P2);
}
-gcptr stm_HashObject(gcptr P)
-{
- /* return one of the objects in the chained list following P out of
- which the stmgc can determine the hash of P. The first time we ask
- for the hash of an object, we set REV_FLAG_NEW_HASH on the last
- object of the chain. The hash is then the address of this object.
- When stm_duplicate further duplicates an object with
- REV_FLAG_NEW_HASH, it adds an extra field remembering the hash.
- From then on all stm_duplicates of this object have GCFLAG_HASH_FIELD
- and the same hash, copied over and over into the extra field. */
- revision_t v;
- volatile revision_t *vp;
-
- if ((P->h_tid & (GCFLAG_GLOBAL|GCFLAG_LOCAL_COPY)) == 0)
- {
- // a local object newly created in this transaction
- P->h_revision |= REV_FLAG_NEW_HASH;
- return P;
- }
-
- while (1)
- {
- if (P->h_tid & GCFLAG_HASH_FIELD)
- {
- return P; /* any HASH_FIELD object is fine; we'll read the hash
- out of the field. */
- }
- vp = (volatile revision_t *)&P->h_revision;
- v = *vp;
- if (!(v & 1)) // "is a pointer", i.e. "has a more recent revision"
- {
- P = (gcptr)v; // look into the next one in the chained list
- }
- else if (__builtin_expect(v >= LOCKED, 0))
- {
- SpinLoop(4); // spinloop until it is no longer LOCKED, then retry
- }
- else if (v & REV_FLAG_NEW_HASH)
- {
- return P; // already has the flag
- }
- else
- {
- // must add the flag
- if (bool_cas(vp, v, v | REV_FLAG_NEW_HASH))
- return P;
- }
- }
-}
-
/************************************************************/
int DescriptorInit(void)
diff --git a/pypy/translator/stm/src_stm/et.h b/pypy/translator/stm/src_stm/et.h
--- a/pypy/translator/stm/src_stm/et.h
+++ b/pypy/translator/stm/src_stm/et.h
@@ -27,11 +27,9 @@
GCFLAG_NOT_WRITTEN = _first_gcflag << 2,
GCFLAG_LOCAL_COPY = _first_gcflag << 3,
GCFLAG_VISITED = _first_gcflag << 4,
- GCFLAG_HASH_FIELD = _first_gcflag << 5,
GCFLAG_PREBUILT = GCFLAG_GLOBAL|GCFLAG_NOT_WRITTEN,
REV_INITIAL = 1,
- REV_FLAG_NEW_HASH = 2,
};
typedef struct pypy_header0 *gcptr;
diff --git a/pypy/translator/stm/stmgcintf.py b/pypy/translator/stm/stmgcintf.py
--- a/pypy/translator/stm/stmgcintf.py
+++ b/pypy/translator/stm/stmgcintf.py
@@ -70,6 +70,3 @@
# for testing
abort_and_retry = smexternal('stm_abort_and_retry', [], lltype.Void)
-
- stm_HashObject = smexternal('stm_HashObject',
- [llmemory.Address], llmemory.Address)
diff --git a/pypy/translator/stm/writebarrier.py
b/pypy/translator/stm/writebarrier.py
--- a/pypy/translator/stm/writebarrier.py
+++ b/pypy/translator/stm/writebarrier.py
@@ -86,6 +86,10 @@
elif (op.opname in ('ptr_eq', 'ptr_ne') and
op.args[0].concretetype.TO._gckind == 'gc'):
expand_comparison.add(op)
+ elif op.opname == 'stm_read_barrier':
+ wants_a_barrier[op] = 'R'
+ elif op.opname == 'stm_write_barrier':
+ wants_a_barrier[op] = 'W'
#
if wants_a_barrier or expand_comparison:
# note: 'renamings' maps old vars to new vars, but cast_pointers
@@ -96,7 +100,8 @@
newoperations = []
for op in block.operations:
#
- if op.opname == 'cast_pointer':
+ opname = op.opname
+ if opname == 'cast_pointer':
v = op.args[0]
renamings[op.result] = renamings.setdefault(v, [v])
continue
@@ -114,8 +119,10 @@
newoperations.append(newop)
v_holder[0] = w
category[w] = to
+ if opname in ('stm_read_barrier', 'stm_write_barrier'):
+ opname = 'same_as' # done its job, remove op
#
- newop = SpaceOperation(op.opname,
+ newop = SpaceOperation(opname,
[renamings_get(v) for v in op.args],
op.result)
newoperations.append(newop)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit