This commit is contained in:
Joel Dice 2007-06-20 10:58:35 -06:00
parent a6e79cc417
commit 1a05eb2739
4 changed files with 280 additions and 136 deletions

View File

@ -46,7 +46,8 @@ interpreter-depends = \
$(src)/constants.h \ $(src)/constants.h \
$(src)/vm.h $(src)/vm.h
interpreter-sources = \ interpreter-sources = \
$(src)/vm.cpp $(src)/vm.cpp \
$(src)/heap.cpp
interpreter-objects = $(call cpp-objects,$(interpreter-sources),$(src)) interpreter-objects = $(call cpp-objects,$(interpreter-sources),$(src))
interpreter-cflags = $(slow) $(cflags) interpreter-cflags = $(slow) $(cflags)

View File

@ -6,6 +6,19 @@ using namespace vm;
namespace { namespace {
// an object must survive TenureThreshold + 2 garbage collections
// before being copied to gen2:
static const unsigned TenureThreshold = 3;
static const unsigned MinimumGen1Size = 64 * 1024;
static const unsigned MinimumGen2Size = 128 * 1024;
class Context;
System* system(Context*);
void NO_RETURN abort(Context*);
void assert(Context*, bool);
class Segment { class Segment {
public: public:
class Map { class Map {
@ -19,12 +32,13 @@ class Segment {
Iterator(Map* map, void** start, void** end): Iterator(Map* map, void** start, void** end):
map(map) map(map)
{ {
assert(map); assert(map->segment->context, map);
assert(map->bitsPerRecord == 1); assert(map->segment->context, map->bitsPerRecord == 1);
assert(map->segment); assert(map->segment->context, map->segment);
index = map->indexOf(start); index = map->indexOf(start);
assert(index == 0 or assert(map->segment->context,
index == 0 or
start != reinterpret_cast<void**>(map->segment->data)); start != reinterpret_cast<void**>(map->segment->data));
void** p = reinterpret_cast<void**>(map->segment->data) void** p = reinterpret_cast<void**>(map->segment->data)
@ -41,7 +55,7 @@ class Segment {
} }
bool hasMore() { bool hasMore() {
assert(map); assert(map->segment->context, map);
unsigned word = wordOf(index); unsigned word = wordOf(index);
unsigned bit = bitOf(index); unsigned bit = bitOf(index);
@ -83,38 +97,37 @@ class Segment {
}; };
Segment* segment; Segment* segment;
unsigned offset;
unsigned bitsPerRecord; unsigned bitsPerRecord;
unsigned scale; unsigned scale;
Map* next;
Map* child; Map* child;
void init() { Map(): Map(0) { }
init(0);
Map(Segment* segment = 0, unsigned bitsPerRecord = 1,
unsigned scale = 1, Map* child = 0):
segment(segment),
bitsPerRecord(bitsPerRecord),
scale(scale),
child(child)
{
assert(segment->context, bitsPerRecord);
assert(segment->context, scale);
assert(segment->context, powerOfTwo(scale));
} }
void init(Segment* segment, unsigned offset, unsigned bitsPerRecord = 1, unsigned offset() {
unsigned scale = 1, Map* next = 0, Map* child = 0) unsigned n = segment->capacity;
{ if (child) n += child->footprint(capacity);
assert(bitsPerRecord); return n;
assert(scale);
assert(powerOfTwo(scale));
this->segment = segment;
this->offset = offset;
this->bitsPerRecord = bitsPerRecord;
this->scale = scale;
this->next = next;
this->child = child;
} }
uintptr_t* data() { uintptr_t* data() {
return segment->data + offset; return segment->data + offset();
} }
unsigned size(unsigned capacity) { unsigned size(unsigned capacity) {
unsigned result = pad unsigned result
(divide(divide(capacity, scale) * bitsPerRecord, 8)); = divide(divide(capacity, scale) * bitsPerRecord, BitsPerWord);
assert(segment->context, result); assert(segment->context, result);
return result; return result;
} }
@ -138,26 +151,24 @@ class Segment {
} }
void update(uintptr_t* segmentData) { void update(uintptr_t* segmentData) {
uintptr_t* p = segmentData + offset; uintptr_t* p = segmentData + offset();
memcpy(p, data(), size(segment->position)); memcpy(p, data(), size(segment->position) * BytesPerWord);
if (next) next->update(segmentData);
if (child) child->update(segmentData); if (child) child->update(segmentData);
} }
void clear() { void clear() {
memset(data, 0, size()); memset(data(), 0, size() * BytesPerWord);
if (next) next->clear();
if (child) child->clear(); if (child) child->clear();
} }
void clear(unsigned i) { void clear(unsigned i) {
data[wordOf(i)] &= ~(static_cast<uintptr_t>(1) << bitOf(i)); data()[wordOf(i)] &= ~(static_cast<uintptr_t>(1) << bitOf(i));
} }
void set(unsigned i) { void set(unsigned i) {
data[wordOf(i)] |= static_cast<uintptr_t>(1) << bitOf(i); data()[wordOf(i)] |= static_cast<uintptr_t>(1) << bitOf(i);
} }
void clearOnly(void* p) { void clearOnly(void* p) {
@ -185,7 +196,7 @@ class Segment {
void set(void* p, unsigned v = 1) { void set(void* p, unsigned v = 1) {
setOnly(p, v); setOnly(p, v);
assert(get(p) == v); assert(segment->context, get(p) == v);
if (child) child->set(p, v); if (child) child->set(p, v);
} }
@ -195,33 +206,20 @@ class Segment {
for (unsigned i = index, limit = index + bitsPerRecord; i < limit; ++i) { for (unsigned i = index, limit = index + bitsPerRecord; i < limit; ++i) {
unsigned wi = bitOf(i); unsigned wi = bitOf(i);
v <<= 1; v <<= 1;
v |= ((data[wordOf(i)]) & (static_cast<uintptr_t>(1) << wi)) v |= ((data()[wordOf(i)]) & (static_cast<uintptr_t>(1) << wi)) >> wi;
>> wi;
} }
return v; return v;
} }
void dispose() {
offset = 0;
segment = 0;
next = 0;
if (child) {
child->dispose();
child = 0;
}
}
unsigned footprint(unsigned capacity) { unsigned footprint(unsigned capacity) {
unsigned n = size(capacity); unsigned n = size(capacity);
if (next) n += next->footprint(capacity);
if (child) n += child->footprint(capacity); if (child) n += child->footprint(capacity);
return n; return n;
} }
void setSegment(Segment* s, bool clear = true) { void setSegment(Segment* s) {
segment = s; segment = s;
if (next) next->setSegment(s);
if (child) child->setSegment(s); if (child) child->setSegment(s);
} }
}; };
@ -231,8 +229,32 @@ class Segment {
unsigned capacity; unsigned capacity;
Map* map; Map* map;
Segment(Context* context, unsigned capacity, Map* map = 0,
bool clearMap = true):
context(context),
capacity(capacity),
data(0),
position(0),
capacity(capacity),
map(map)
{
if (capacity) {
unsigned count = footprint(capacity) * BytesPerWord;
data = static_cast<uintptr_t*>(system(context)->allocate(&count));
if (count != footprint(capacity) * BytesPerWord) {
abort(context);
}
if (map) {
map->setSegment(this);
if (clearMap) map->clear();
}
}
}
unsigned footprint(unsigned capacity) { unsigned footprint(unsigned capacity) {
unsigned n = capacity * BytesPerWord; unsigned n = capacity;
if (map) n += map->size(capacity); if (map) n += map->size(capacity);
return n; return n;
} }
@ -241,29 +263,6 @@ class Segment {
return footprint(capacity); return footprint(capacity);
} }
void init(Context* context, unsigned capacity, Map* map = 0,
bool clearMap = true)
{
this->context = context;
this->capacity = capacity;
this->data = 0;
this->position = 0;
this->map = map;
if (capacity) {
unsigned count = footprint(capacity);
this->data = static_cast<uintptr_t*>(system(context)->allocate(&count));
if (count != footprint(capacity)) {
abort(context);
}
if (map) {
map->setSegment(this, clearMap);
}
}
}
void* allocate(unsigned size) { void* allocate(unsigned size) {
assert(c, size); assert(c, size);
assert(c, position + size <= capacity); assert(c, position + size <= capacity);
@ -284,7 +283,7 @@ class Segment {
} }
void replaceWith(Segment* s) { void replaceWith(Segment* s) {
free(data); system(context)->free(data);
data = s->data; data = s->data;
s->data = 0; s->data = 0;
@ -296,15 +295,11 @@ class Segment {
s->capacity = 0; s->capacity = 0;
if (s->map) { if (s->map) {
if (map) {
map->replaceWith(s->map);
} else {
map = s->map; map = s->map;
map->setSegment(this); map->setSegment(this);
}
s->map = 0; s->map = 0;
} else { } else {
if (map) map->reset(); map = 0;
} }
} }
@ -313,8 +308,8 @@ class Segment {
unsigned minimumNeeded = position + extra; unsigned minimumNeeded = position + extra;
unsigned count = minimumNeeded * 2; unsigned count = minimumNeeded * 2;
minimumNeeded = footprint(minimumNeeded); minimumNeeded = footprint(minimumNeeded) * BytesPerWord;
count = footprint(count); count = footprint(count) * BytesPerWord;
uintptr_t* p = static_cast<uintptr_t*> uintptr_t* p = static_cast<uintptr_t*>
(system(context)->allocate(&count)); (system(context)->allocate(&count));
@ -339,57 +334,107 @@ class Segment {
} }
void dispose() { void dispose() {
free(data); system(context)->free(data);
data = 0; data = 0;
position = 0; position = 0;
capacity = 0; capacity = 0;
if (map) map->dispose();
map = 0; map = 0;
} }
}; };
enum CollectionMode {
MinorCollection,
MajorCollection,
OverflowCollection,
Gen2Collection
};
class Context { class Context {
public: public:
Context(System* system, Client* client): system(system), client(client) { }
void dispose() {
gen1.dispose();
nextGen1.dispose();
gen2.dispose();
nextGen2.dispose();
}
System* system;
Client* client;
Segment gen1;
Segment nextGen1;
Segment gen2;
Segment nextGen2;
Segment::Map ageMap;
Segment::Map pointerMap;
Segment::Map pageMap;
Segment::Map heapMap;
CollectionMode mode;
}; };
inline System*
system(Context* c)
{
return c->system;
}
inline void NO_RETURN
abort(Context* c)
{
c->system->abort(); // this should not return
::abort();
}
inline void
assert(Context* c, bool v)
{
if (UNLIKELY(not v)) abort(c);
}
void void
initGen1(Context* c) initGen1(Context* c)
{ {
c->ageMap.init(&(c->gen1), log(Arena::TenureThreshold)); new (&(c->ageMap)) Segment::Map(&(c->gen1), log(TenureThreshold));
c->gen1.init(c->minimumGen1Size / BytesPerWord, &(c->ageMap), false); new (&(c->gen1)) Segment
(MinimumGen1Size / BytesPerWord, &(c->ageMap), false);
} }
void void
initGen2(Context* c) initGen2(Context* c)
{ {
c->pointerMap.init(&(c->gen2)); new (&(c->pointerMap)) Segment::Map(&(c->gen2));
c->pageMap.init(&(c->gen2), 1, LikelyPageSize / BytesPerWord, 0, new (&(c->pageMap)) Segment::Map
&(c->pointerMap)); (&(c->gen2), 1, LikelyPageSize / BytesPerWord, &(c->pointerMap));
c->heapMap.init(&(c->gen2), 1, c->pageMap.scale * 1024, 0, &(c->pageMap)); new (&(c->heapMap)) Segment::Map
c->gen2.init(c->minimumGen2Size / BytesPerWord, &(c->heapMap)); (&(c->gen2), 1, c->pageMap.scale * 1024, &(c->pageMap));
new (&(c->gen2)) Segment(MinimumGen2Size / BytesPerWord, &(c->heapMap));
} }
void void
initNextGen1(Context* c) initNextGen1(Context* c)
{ {
unsigned size = max(c->minimumGen1Size / BytesPerWord, unsigned size = max(MinimumGen1Size / BytesPerWord,
nextPowerOfTwo(c->gen1.position())); nextPowerOfTwo(c->gen1.position()));
c->nextAgeMap.init(&(c->nextGen1), log(Arena::TenureThreshold)); new (&(c->nextAgeMap)) Segment::Map(&(c->nextGen1), log(TenureThreshold));
c->nextGen1.init(size, &(c->nextAgeMap), false); new (&(c->nextGen1)) Segment(size, &(c->nextAgeMap), false);
} }
void void
initNextGen2(Context* c) initNextGen2(Context* c)
{ {
unsigned size = max(c->minimumGen2Size / BytesPerWord, unsigned size = max(MinimumGen2Size / BytesPerWord,
nextPowerOfTwo(c->gen2.position())); nextPowerOfTwo(c->gen2.position()));
c->pointerMap.init(&(c->nextGen2)); new (&(c->pointerMap)) Segment::Map(&(c->nextGen2));
c->pageMap.init(&(c->nextGen2), 1, LikelyPageSize / BytesPerWord, 0, new (&(c->pageMap)) Segment::Map
&(c->pointerMap)); (&(c->nextGen2), 1, LikelyPageSize / BytesPerWord, &(c->pointerMap));
c->heapMap.init(&(c->nextGen2), 1, c->pageMap.scale * 1024, 0, new (&(c->heapMap)) Segment::Map
&(c->pageMap)); (&(c->nextGen2), 1, c->pageMap.scale * 1024, &(c->pageMap));
c->nextGen2.init(size, &(c->heapMap)); new (&(c->nextGen2)) Segment(size, &(c->heapMap));
c->gen2.map = 0; c->gen2.map = 0;
} }
@ -940,9 +985,43 @@ collect(Context* c)
Heap* Heap*
makeHeap(System* system) makeHeap(System* system)
{ {
class Heap: public vm::Heap {
public:
Heap(System* system): c(system) { }
virtual void collect(CollectionType type, Client* client) {
switch (type) {
case MinorCollection:
c.mode = ::MinorCollection;
break;
HeapImp* h = static_cast<HeapImp*>(system->allocate(sizeof(HeapImp))); case MajorCollection:
init(h, system); c.mode = ::MajorCollection;
return h; break;
default: abort(&c);
}
c.client = client;
::collect(&c);
}
virtual bool needsMark(void** p) {
return *p and c.gen2.contains(p) and not c.gen2.contains(*p);
}
virtual void mark(void** p) {
c.heapMap.set(p);
}
virtual void dispose() {
c.dispose();
c.system->free(this);
}
Context c;
};
return new (system->allocate(sizeof(Heap))) Heap(system);
} }

View File

@ -16,14 +16,22 @@ class Heap {
virtual void visit(void**) = 0; virtual void visit(void**) = 0;
}; };
class Iterator { class Walker {
public: public:
virtual ~Iterator() { } virtual ~Walker() { }
virtual void iterate(Visitor*) = 0; virtual bool visit(unsigned) = 0;
};
class Client {
public:
virtual ~Client() { }
virtual void visitRoots(Visitor*) = 0;
virtual void sizeInWords(void*) = 0;
virtual void walk(void*, Walker*) = 0;
}; };
virtual ~Heap() { } virtual ~Heap() { }
virtual void collect(CollectionType type, Iterator* it) = 0; virtual void collect(CollectionType type, Client* client) = 0;
virtual bool needsMark(void** p) = 0; virtual bool needsMark(void** p) = 0;
virtual void mark(void** p) = 0; virtual void mark(void** p) = 0;
virtual void dispose() = 0; virtual void dispose() = 0;

View File

@ -50,6 +50,8 @@ class Machine {
#include "type-enums.cpp" #include "type-enums.cpp"
} Type; } Type;
Machine(System* system, Heap* heap, ClassFinder* classFinder);
System* sys; System* sys;
Heap* heap; Heap* heap;
ClassFinder* classFinder; ClassFinder* classFinder;
@ -157,19 +159,25 @@ assert(Thread* t, bool v)
if (UNLIKELY(not v)) abort(t); if (UNLIKELY(not v)) abort(t);
} }
void Machine::Machine(System* system, Heap* heap, ClassFinder* classFinder):
init(Machine* m, System* sys, Heap* heap, ClassFinder* classFinder) system(system),
heap(heap),
classFinder(classFinder),
rootThread(0),
exclusive(0),
activeCount(0),
liveCount(0),
stateLock(0),
heapLock(0),
classLock(0),
classMap(0),
types(0)
{ {
memset(m, 0, sizeof(Machine)); if (not system->success(system->make(&(m->stateLock))) or
m->sys = sys; not system->success(system->make(&(m->heapLock))) or
m->heap = heap; not system->success(system->make(&(m->classLock))))
m->classFinder = classFinder;
if (not sys->success(sys->make(&(m->stateLock))) or
not sys->success(sys->make(&(m->heapLock))) or
not sys->success(sys->make(&(m->classLock))))
{ {
sys->abort(); system->abort();
} }
} }
@ -182,12 +190,20 @@ dispose(Machine* m)
} }
void void
init(Thread* t, Machine* m) Thread::Thread(Machine* m):
vm(m),
next(0),
child(0),
state(NoState),
thread(0),
frame(0),
code(0),
exception(0),
ip(0),
sp(0),
heapIndex(0),
protector(0)
{ {
memset(t, 0, sizeof(Thread));
t->vm = m;
t->state = Thread::NoState;
if (m->rootThread == 0) { if (m->rootThread == 0) {
m->rootThread = t; m->rootThread = t;
@ -198,7 +214,7 @@ init(Thread* t, Machine* m)
} }
void void
iterate(Thread* t, Heap::Visitor* v) visitRoots(Thread* t, Heap::Visitor* v)
{ {
t->heapIndex = 0; t->heapIndex = 0;
@ -216,23 +232,63 @@ iterate(Thread* t, Heap::Visitor* v)
} }
for (Thread* t = t->child; t; t = t->next) { for (Thread* t = t->child; t; t = t->next) {
iterate(t, v); visitRoots(t, v);
} }
} }
void void
collect(Machine* m, Heap::CollectionType type) collect(Machine* m, Heap::CollectionType type)
{ {
class Iterator: public Heap::Iterator { class Client: public Heap::Client {
public: public:
Iterator(Machine* m): m(m) { } Client(Machine* m): m(m) { }
void iterate(Heap::Visitor* v) { virtual void visitRoots(Heap::Visitor* v) {
v->visit(&(m->classMap)); v->visit(&(m->classMap));
v->visit(&(m->types)); v->visit(&(m->types));
for (Thread* t = m->rootThread; t; t = t->next) { for (Thread* t = m->rootThread; t; t = t->next) {
::iterate(t, v); ::visitRoots(t, v);
}
}
virtual unsigned sizeInWords(void* p) {
p = m->heap->follow(p);
object class_ = m->heap->follow(objectClass(p));
unsigned n = classFixedSize(t, class_);
if (classArrayElementSize(t, class_)) {
n += classArrayElementSize(t, class_)
* cast<uint32_t>(p, (classFixedSize(t, class_) - 1) * BytesPerWord);
}
return n;
}
virtual void walk(void* p, Heap::Walker* w) {
p = m->heap->follow(p);
object class_ = m->heap->follow(objectClass(p));
unsigned fixedSize = classFixedSize(t, class_);
unsigned arrayLength = cast<uint32_t>(p, (fixedSize - 1) * BytesPerWord);
unsigned arrayElementSize = classArrayElementSize(t, class_);
object objectMask = m->heap->follow(classObjectMask(t, class_));
int mask[intArrayLength(t, objectMask)];
memcpy(mask, &intArrayBody(t, objectMask),
intArrayLength(t, objectMask) * 4);
for (unsigned i = 0; i < fixedSize; ++i) {
if (mask[wordOf(i)] & (static_cast<uintptr_t>(1) << bitOf(i))) {
if (not w->visit(i)) return;
}
}
for (unsigned i = 0; i < arrayLength; ++i) {
for (unsigned j = 0; j < arrayElementSize; ++j) {
unsigned k = fixedSize + j;
if (mask[wordOf(k)] & (static_cast<uintptr_t>(1) << bitOf(k))) {
if (not w->visit(fixedSize + (i * arrayElementSize) + j)) return;
}
}
} }
} }
@ -2920,11 +2976,11 @@ run(Thread* t, const char* className, int argc, const char** argv)
namespace vm { namespace vm {
void void
run(System* sys, Heap* heap, ClassFinder* classFinder, run(System* system, Heap* heap, ClassFinder* classFinder,
const char* className, int argc, const char** argv) const char* className, int argc, const char** argv)
{ {
Machine m; init(&m, sys, heap, classFinder); Machine m(system, heap, classFinder);
Thread t; init(&t, &m); Thread t(&m);
run(&t, className, argc, argv); run(&t, className, argc, argv);
} }