use atomic operations in MyHeap::mark to avoid need for mutex

This commit is contained in:
Joel Dice 2009-11-19 18:13:00 -07:00
parent 6475beda83
commit fdde34694c
4 changed files with 53 additions and 44 deletions

View File

@ -325,6 +325,14 @@ markBit(uintptr_t* map, unsigned i)
map[wordOf(i)] |= static_cast<uintptr_t>(1) << bitOf(i); map[wordOf(i)] |= static_cast<uintptr_t>(1) << bitOf(i);
} }
inline void
markBitAtomic(uintptr_t* map, unsigned i)
{
uintptr_t* p = map + wordOf(i);
uintptr_t v = static_cast<uintptr_t>(1) << bitOf(i);
while (not __sync_bool_compare_and_swap(p, *p, *p | v)) { }
}
inline void inline void
clearBit(uintptr_t* map, unsigned i) clearBit(uintptr_t* map, unsigned i)
{ {

View File

@ -303,6 +303,13 @@ class Segment {
if (child) child->set(p, v); if (child) child->set(p, v);
} }
void markAtomic(void* p) {
assert(segment->context, bitsPerRecord == 1);
markBitAtomic(data, indexOf(p));
assert(segment->context, getBit(data, indexOf(p)));
if (child) child->markAtomic(p);
}
unsigned get(void* p) { unsigned get(void* p) {
return getBits(data, bitsPerRecord, indexOf(p)); return getBits(data, bitsPerRecord, indexOf(p));
} }
@ -1013,8 +1020,12 @@ void
markDirty(Context* c, Fixie* f) markDirty(Context* c, Fixie* f)
{ {
if (not f->dirty) { if (not f->dirty) {
f->dirty = true; ACQUIRE(c->lock);
f->move(c, &(c->dirtyTenuredFixies));
if (not f->dirty) {
f->dirty = true;
f->move(c, &(c->dirtyTenuredFixies));
}
} }
} }
@ -1784,7 +1795,7 @@ class MyHeap: public Heap {
Fixie(&c, sizeInWords, objectMask, 0, true))->body(); Fixie(&c, sizeInWords, objectMask, 0, true))->body();
} }
virtual bool needsMark(void* p) { bool needsMark(void* p) {
assert(&c, c.client->isFixed(p) or (not immortalHeapContains(&c, p))); assert(&c, c.client->isFixed(p) or (not immortalHeapContains(&c, p)));
if (c.client->isFixed(p)) { if (c.client->isFixed(p)) {
@ -1794,11 +1805,6 @@ class MyHeap: public Heap {
} }
} }
virtual bool needsMark(void* p, unsigned offset) {
return needsMark(p) and targetNeedsMark
(mask(*(static_cast<void**>(p) + offset)));
}
bool targetNeedsMark(void* target) { bool targetNeedsMark(void* target) {
return target return target
and not c.gen2.contains(target) and not c.gen2.contains(target)
@ -1809,38 +1815,41 @@ class MyHeap: public Heap {
} }
virtual void mark(void* p, unsigned offset, unsigned count) { virtual void mark(void* p, unsigned offset, unsigned count) {
if (c.client->isFixed(p)) { if (needsMark(p)) {
Fixie* f = fixie(p); if (c.client->isFixed(p)) {
assert(&c, offset == 0 or f->hasMask); Fixie* f = fixie(p);
assert(&c, offset == 0 or f->hasMask);
bool dirty = false; bool dirty = false;
for (unsigned i = 0; i < count; ++i) { for (unsigned i = 0; i < count; ++i) {
void** target = static_cast<void**>(p) + offset + i; void** target = static_cast<void**>(p) + offset + i;
if (targetNeedsMark(mask(*target))) { if (targetNeedsMark(mask(*target))) {
if (DebugFixies) { if (DebugFixies) {
fprintf(stderr, "dirty fixie %p at %d (%p): %p\n", fprintf(stderr, "dirty fixie %p at %d (%p): %p\n",
f, offset, f->body() + offset, mask(*target)); f, offset, f->body() + offset, mask(*target));
}
dirty = true;
markBitAtomic(f->mask(), offset + i);
assert(&c, getBit(f->mask(), offset + i));
} }
dirty = true;
markBit(f->mask(), offset + i);
} }
}
if (dirty) markDirty(&c, f); if (dirty) markDirty(&c, f);
} else {
Segment::Map* map;
if (c.gen2.contains(p)) {
map = &(c.heapMap);
} else { } else {
assert(&c, c.nextGen2.contains(p)); Segment::Map* map;
map = &(c.nextHeapMap); if (c.gen2.contains(p)) {
} map = &(c.heapMap);
} else {
assert(&c, c.nextGen2.contains(p));
map = &(c.nextHeapMap);
}
for (unsigned i = 0; i < count; ++i) { for (unsigned i = 0; i < count; ++i) {
void** target = static_cast<void**>(p) + offset + i; void** target = static_cast<void**>(p) + offset + i;
if (targetNeedsMark(mask(*target))) { if (targetNeedsMark(mask(*target))) {
map->set(target); map->markAtomic(target);
}
} }
} }
} }

View File

@ -59,8 +59,6 @@ class Heap: public Allocator {
virtual void* allocateImmortalFixed(Allocator* allocator, virtual void* allocateImmortalFixed(Allocator* allocator,
unsigned sizeInWords, bool objectMask, unsigned sizeInWords, bool objectMask,
unsigned* totalInBytes) = 0; unsigned* totalInBytes) = 0;
virtual bool needsMark(void* p) = 0;
virtual bool needsMark(void* p, unsigned offset) = 0;
virtual void mark(void* p, unsigned offset, unsigned count) = 0; virtual void mark(void* p, unsigned offset, unsigned count) = 0;
virtual void pad(void* p) = 0; virtual void pad(void* p) = 0;
virtual void* follow(void* p) = 0; virtual void* follow(void* p) = 0;

View File

@ -1584,19 +1584,13 @@ allocate(Thread* t, unsigned sizeInBytes, bool objectMask)
inline void inline void
mark(Thread* t, object o, unsigned offset, unsigned count) mark(Thread* t, object o, unsigned offset, unsigned count)
{ {
if (t->m->heap->needsMark(o)) { t->m->heap->mark(o, offset / BytesPerWord, count);
ACQUIRE_RAW(t, t->m->heapLock);
t->m->heap->mark(o, offset / BytesPerWord, count);
}
} }
inline void inline void
mark(Thread* t, object o, unsigned offset) mark(Thread* t, object o, unsigned offset)
{ {
if (t->m->heap->needsMark(o, offset / BytesPerWord)) { t->m->heap->mark(o, offset / BytesPerWord, 1);
ACQUIRE_RAW(t, t->m->heapLock);
t->m->heap->mark(o, offset / BytesPerWord, 1);
}
} }
inline void inline void