enable large object support; various GC bugfixes and tweaks

This commit is contained in:
Joel Dice 2007-06-22 16:47:57 -06:00
parent 4d202e4945
commit 5ee38e259a
5 changed files with 162 additions and 40 deletions

View File

@ -5,12 +5,16 @@ public class Test {
byte[] a = new byte[4 * 1024]; byte[] a = new byte[4 * 1024];
} }
for (int i = 0; i < 1024; ++i) { for (int i = 0; i < 8; ++i) {
Object[] array = new Object[32]; Object[] array = new Object[32];
for (int j = 0; j < 32; ++j) { for (int j = 0; j < 32; ++j) {
array[j] = new byte[32 * 1024]; array[j] = new byte[32 * 1024];
} }
} }
for (int i = 0; i < 8; ++i) {
byte[] a = new byte[16 * 1024 * 1024];
}
} }
} }

View File

@ -81,6 +81,7 @@ input-depends = \
$(bld)/classes/vm/VM.class $(bld)/classes/vm/VM.class
gen-run-arg = $(shell echo $(1) | sed -e 's:$(bld)/classes/\(.*\)\.class:\1:') gen-run-arg = $(shell echo $(1) | sed -e 's:$(bld)/classes/\(.*\)\.class:\1:')
args = -cp $(bld)/classes -hs 67108864 $(call gen-run-arg,$(input))
.PHONY: build .PHONY: build
build: $(executable) build: $(executable)
@ -89,11 +90,11 @@ $(input): $(input-depends)
.PHONY: run .PHONY: run
run: $(executable) $(input) run: $(executable) $(input)
$(<) -cp $(bld)/classes $(call gen-run-arg,$(input)) $(<) $(args)
.PHONY: debug .PHONY: debug
debug: $(executable) $(input) debug: $(executable) $(input)
gdb --args $(<) -cp $(bld)/classes $(call gen-run-arg,$(input)) gdb --args $(<) $(args)
.PHONY: fast .PHONY: fast
fast: $(fast-executable) fast: $(fast-executable)
@ -101,15 +102,15 @@ fast: $(fast-executable)
.PHONY: vg .PHONY: vg
vg: $(executable) $(input) vg: $(executable) $(input)
$(vg) $(<) -cp $(bld)/classes $(call gen-run-arg,$(input)) $(vg) $(<) $(args)
.PHONY: test .PHONY: test
test: $(test-executable) $(input) test: $(test-executable) $(input)
$(vg) $(<) -cp $(bld)/classes $(call gen-run-arg,$(input)) $(vg) $(<) $(args)
.PHONY: stress .PHONY: stress
stress: $(stress-executable) $(input) stress: $(stress-executable) $(input)
$(vg) $(<) -cp $(bld)/classes $(call gen-run-arg,$(input)) $(vg) $(<) $(args)
.PHONY: run-all .PHONY: run-all
run-all: $(executable) run-all: $(executable)

View File

@ -93,16 +93,18 @@ class Segment {
}; };
Segment* segment; Segment* segment;
Map* child;
unsigned bitsPerRecord; unsigned bitsPerRecord;
unsigned scale; unsigned scale;
Map* child; bool clearNewData;
Map(Segment* segment = 0, unsigned bitsPerRecord = 1, Map(Segment* segment = 0, unsigned bitsPerRecord = 1,
unsigned scale = 1, Map* child = 0): unsigned scale = 1, Map* child = 0, bool clearNewData = true):
segment(segment), segment(segment),
child(child),
bitsPerRecord(bitsPerRecord), bitsPerRecord(bitsPerRecord),
scale(scale), scale(scale),
child(child) clearNewData(clearNewData)
{ {
if (segment) { if (segment) {
assert(segment->context, bitsPerRecord); assert(segment->context, bitsPerRecord);
@ -329,8 +331,7 @@ class Segment {
Chain* rear; Chain* rear;
Map* map; Map* map;
Segment(Context* context, unsigned minimum, unsigned desired, Map* map = 0, Segment(Context* context, unsigned minimum, unsigned desired, Map* map = 0):
bool clearMap = true):
context(context), context(context),
front(0), front(0),
rear(0), rear(0),
@ -340,7 +341,7 @@ class Segment {
front = rear = Chain::make(this, minimum, desired); front = rear = Chain::make(this, minimum, desired);
if (map) { if (map) {
if (clearMap) { if (map->clearNewData) {
memset(front->data() + front->capacity, 0, memset(front->data() + front->capacity, 0,
map->footprint(front->capacity) * BytesPerWord); map->footprint(front->capacity) * BytesPerWord);
} }
@ -467,13 +468,15 @@ class Segment {
assert(context, rear->position); assert(context, rear->position);
assert(context, rear->next == 0); assert(context, rear->next == 0);
unsigned desired = (position() + minimum) * 2; unsigned desired = capacity() + minimum;
Chain* c = Chain::make(this, minimum, desired); Chain* c = Chain::make(this, minimum, desired);
if (map) { if (map) {
memset(c->data() + c->capacity, 0, if (map->clearNewData) {
map->footprint(c->offset + c->capacity) * BytesPerWord); memset(c->data() + c->capacity, 0,
map->footprint(c->offset + c->capacity) * BytesPerWord);
}
map->update(c->data() + c->capacity, c->offset + c->capacity); map->update(c->data() + c->capacity, c->offset + c->capacity);
} }
@ -580,9 +583,15 @@ initGen1(Context* c)
unsigned minimum = MinimumGen1SizeInBytes / BytesPerWord; unsigned minimum = MinimumGen1SizeInBytes / BytesPerWord;
unsigned desired = minimum; unsigned desired = minimum;
new (&(c->ageMap)) Segment::Map(&(c->gen1), log(TenureThreshold)); new (&(c->ageMap)) Segment::Map
(&(c->gen1), log(TenureThreshold), 1, 0, false);
new (&(c->gen1)) Segment(c, minimum, desired, &(c->ageMap), false); new (&(c->gen1)) Segment(c, minimum, desired, &(c->ageMap));
if (Verbose) {
fprintf(stderr, "init gen1 to %d bytes\n",
c->gen1.capacity() * BytesPerWord);
}
} }
void void
@ -591,9 +600,15 @@ initNextGen1(Context* c)
unsigned minimum = MinimumGen1SizeInBytes / BytesPerWord; unsigned minimum = MinimumGen1SizeInBytes / BytesPerWord;
unsigned desired = max(minimum, nextPowerOfTwo(c->gen1.position())); unsigned desired = max(minimum, nextPowerOfTwo(c->gen1.position()));
new (&(c->nextAgeMap)) Segment::Map(&(c->nextGen1), log(TenureThreshold)); new (&(c->nextAgeMap)) Segment::Map
(&(c->nextGen1), log(TenureThreshold), 1, 0, false);
new (&(c->nextGen1)) Segment(c, minimum, desired, &(c->nextAgeMap), false); new (&(c->nextGen1)) Segment(c, minimum, desired, &(c->nextAgeMap));
if (Verbose) {
fprintf(stderr, "init nextGen1 to %d bytes\n",
c->nextGen1.capacity() * BytesPerWord);
}
} }
void void
@ -609,6 +624,11 @@ initGen2(Context* c)
(&(c->gen2), 1, c->pageMap.scale * 1024, &(c->pageMap)); (&(c->gen2), 1, c->pageMap.scale * 1024, &(c->pageMap));
new (&(c->gen2)) Segment(c, minimum, desired, &(c->heapMap)); new (&(c->gen2)) Segment(c, minimum, desired, &(c->heapMap));
if (Verbose) {
fprintf(stderr, "init gen2 to %d bytes\n",
c->gen2.capacity() * BytesPerWord);
}
} }
void void
@ -625,6 +645,11 @@ initNextGen2(Context* c)
(&(c->nextGen2), 1, c->pageMap.scale * 1024, &(c->nextPageMap)); (&(c->nextGen2), 1, c->pageMap.scale * 1024, &(c->nextPageMap));
new (&(c->nextGen2)) Segment(c, minimum, desired, &(c->nextHeapMap)); new (&(c->nextGen2)) Segment(c, minimum, desired, &(c->nextHeapMap));
if (Verbose) {
fprintf(stderr, "init nextGen2 to %d bytes\n",
c->nextGen2.capacity() * BytesPerWord);
}
} }
inline bool inline bool
@ -666,19 +691,22 @@ inline object
copyTo(Context* c, Segment* s, object o, unsigned size) copyTo(Context* c, Segment* s, object o, unsigned size)
{ {
if (s->remaining() < size) { if (s->remaining() < size) {
s->ensure(size);
if (Verbose) { if (Verbose) {
if (s == &(c->gen2)) { if (s == &(c->gen2)) {
fprintf(stderr, "grow gen2\n"); fprintf(stderr, "grow gen2 to %d bytes\n",
c->gen2.capacity() * BytesPerWord);
} else if (s == &(c->nextGen1)) { } else if (s == &(c->nextGen1)) {
fprintf(stderr, "grow nextGen1\n"); fprintf(stderr, "grow nextGen1 to %d bytes\n",
c->nextGen1.capacity() * BytesPerWord);
} else if (s == &(c->nextGen2)) { } else if (s == &(c->nextGen2)) {
fprintf(stderr, "grow nextGen2\n"); fprintf(stderr, "grow nextGen2 to %d bytes\n",
c->nextGen2.capacity() * BytesPerWord);
} else { } else {
abort(c); abort(c);
} }
} }
s->ensure(size);
} }
return static_cast<object>(s->add(o, size)); return static_cast<object>(s->add(o, size));

View File

@ -2,6 +2,7 @@
#include "sys/types.h" #include "sys/types.h"
#include "sys/stat.h" #include "sys/stat.h"
#include "fcntl.h" #include "fcntl.h"
#include "common.h"
#include "system.h" #include "system.h"
#include "heap.h" #include "heap.h"
#include "vm.h" #include "vm.h"
@ -10,6 +11,8 @@ using namespace vm;
namespace { namespace {
const bool Verbose = false;
class System: public vm::System { class System: public vm::System {
public: public:
class Monitor: public vm::System::Monitor { class Monitor: public vm::System::Monitor {
@ -34,6 +37,11 @@ class System: public vm::System {
} }
virtual void* tryAllocate(unsigned size) { virtual void* tryAllocate(unsigned size) {
if (Verbose) {
fprintf(stderr, "try %d; count: %d; limit: %d\n",
size, count, limit);
}
if (count + size > limit) { if (count + size > limit) {
return 0; return 0;
} }
@ -55,6 +63,11 @@ class System: public vm::System {
} }
count -= *up; count -= *up;
if (Verbose) {
fprintf(stderr, "free %d; count: %d; limit: %d\n",
*up, count, limit);
}
::free(const_cast<uintptr_t*>(up)); ::free(const_cast<uintptr_t*>(up));
} }
} }

View File

@ -44,11 +44,7 @@ class Machine {
dispose(); dispose();
} }
void dispose() { void dispose();
stateLock->dispose();
heapLock->dispose();
classLock->dispose();
}
System* system; System* system;
Heap* heap; Heap* heap;
@ -65,6 +61,28 @@ class Machine {
bool unsafe; bool unsafe;
}; };
class Chain {
public:
Chain(Chain* next): next(next) { }
static unsigned footprint(unsigned sizeInBytes) {
return sizeof(Chain) + sizeInBytes;
}
uint8_t* data() {
return reinterpret_cast<uint8_t*>(this) + sizeof(Chain);
}
static void dispose(System* s, Chain* c) {
if (c) {
if (c->next) dispose(s, c->next);
s->free(c);
}
}
Chain* next;
};
class Thread { class Thread {
public: public:
enum State { enum State {
@ -99,6 +117,8 @@ class Thread {
Thread(Machine* m); Thread(Machine* m);
void dispose();
Machine* vm; Machine* vm;
Thread* next; Thread* next;
Thread* child; Thread* child;
@ -113,6 +133,7 @@ class Thread {
object stack[StackSizeInWords]; object stack[StackSizeInWords];
object heap[HeapSizeInWords]; object heap[HeapSizeInWords];
Protector* protector; Protector* protector;
Chain* chain;
}; };
#include "type-declarations.cpp" #include "type-declarations.cpp"
@ -186,6 +207,18 @@ Machine::Machine(System* system, Heap* heap, ClassFinder* classFinder):
} }
} }
void
Machine::dispose()
{
stateLock->dispose();
heapLock->dispose();
classLock->dispose();
if (rootThread) {
rootThread->dispose();
}
}
Thread::Thread(Machine* m): Thread::Thread(Machine* m):
vm(m), vm(m),
next(0), next(0),
@ -198,7 +231,8 @@ Thread::Thread(Machine* m):
ip(0), ip(0),
sp(0), sp(0),
heapIndex(0), heapIndex(0),
protector(0) protector(0),
chain(0)
{ {
if (m->rootThread == 0) { if (m->rootThread == 0) {
m->rootThread = this; m->rootThread = this;
@ -223,6 +257,16 @@ Thread::Thread(Machine* m):
} }
} }
void
Thread::dispose()
{
Chain::dispose(vm->system, chain);
for (Thread* c = child; c; c = c->next) {
c->dispose();
}
}
void void
visitRoots(Thread* t, Heap::Visitor* v) visitRoots(Thread* t, Heap::Visitor* v)
{ {
@ -246,6 +290,17 @@ visitRoots(Thread* t, Heap::Visitor* v)
} }
} }
void
postCollect(Thread* t)
{
Chain::dispose(t->vm->system, t->chain);
t->chain = 0;
for (Thread* c = t->child; c; c = c->next) {
postCollect(c);
}
}
void void
collect(Machine* m, Heap::CollectionType type) collect(Machine* m, Heap::CollectionType type)
{ {
@ -350,6 +405,8 @@ collect(Machine* m, Heap::CollectionType type)
m->unsafe = true; m->unsafe = true;
m->heap->collect(type, &it); m->heap->collect(type, &it);
m->unsafe = false; m->unsafe = false;
postCollect(m->rootThread);
} }
void void
@ -451,12 +508,27 @@ enter(Thread* t, Thread::State s)
} }
} }
void inline object
maybeYieldAndMaybeCollect(Thread* t, unsigned sizeInBytes) allocateLarge(Thread* t, unsigned sizeInBytes)
{ {
if (sizeInBytes > Thread::HeapSizeInBytes) { void* p = t->vm->system->allocate(Chain::footprint(sizeInBytes));
// large object support not yet implemented. t->chain = new (p) Chain(t->chain);
abort(t); return t->chain->data();
}
inline object
allocateSmall(Thread* t, unsigned sizeInBytes)
{
object o = t->heap + t->heapIndex;
t->heapIndex += divide(sizeInBytes, BytesPerWord);
return o;
}
object
allocate2(Thread* t, unsigned sizeInBytes)
{
if (sizeInBytes > Thread::HeapSizeInBytes and t->chain == 0) {
return allocateLarge(t, sizeInBytes);
} }
ACQUIRE_RAW(t, t->vm->stateLock); ACQUIRE_RAW(t, t->vm->stateLock);
@ -475,6 +547,12 @@ maybeYieldAndMaybeCollect(Thread* t, unsigned sizeInBytes)
collect(t->vm, Heap::MinorCollection); collect(t->vm, Heap::MinorCollection);
enter(t, Thread::ActiveState); enter(t, Thread::ActiveState);
} }
if (sizeInBytes > Thread::HeapSizeInBytes) {
return allocateLarge(t, sizeInBytes);
} else {
return allocateSmall(t, sizeInBytes);
}
} }
inline object inline object
@ -484,12 +562,10 @@ allocate(Thread* t, unsigned sizeInBytes)
>= Thread::HeapSizeInWords >= Thread::HeapSizeInWords
or t->vm->exclusive)) or t->vm->exclusive))
{ {
maybeYieldAndMaybeCollect(t, sizeInBytes); return allocate2(t, sizeInBytes);
} else {
return allocateSmall(t, sizeInBytes);
} }
object o = t->heap + t->heapIndex;
t->heapIndex += divide(sizeInBytes, BytesPerWord);
return o;
} }
inline void inline void