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];
}
for (int i = 0; i < 1024; ++i) {
for (int i = 0; i < 8; ++i) {
Object[] array = new Object[32];
for (int j = 0; j < 32; ++j) {
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
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
build: $(executable)
@ -89,11 +90,11 @@ $(input): $(input-depends)
.PHONY: run
run: $(executable) $(input)
$(<) -cp $(bld)/classes $(call gen-run-arg,$(input))
$(<) $(args)
.PHONY: debug
debug: $(executable) $(input)
gdb --args $(<) -cp $(bld)/classes $(call gen-run-arg,$(input))
gdb --args $(<) $(args)
.PHONY: fast
fast: $(fast-executable)
@ -101,15 +102,15 @@ fast: $(fast-executable)
.PHONY: vg
vg: $(executable) $(input)
$(vg) $(<) -cp $(bld)/classes $(call gen-run-arg,$(input))
$(vg) $(<) $(args)
.PHONY: test
test: $(test-executable) $(input)
$(vg) $(<) -cp $(bld)/classes $(call gen-run-arg,$(input))
$(vg) $(<) $(args)
.PHONY: stress
stress: $(stress-executable) $(input)
$(vg) $(<) -cp $(bld)/classes $(call gen-run-arg,$(input))
$(vg) $(<) $(args)
.PHONY: run-all
run-all: $(executable)

View File

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

View File

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

View File

@ -44,11 +44,7 @@ class Machine {
dispose();
}
void dispose() {
stateLock->dispose();
heapLock->dispose();
classLock->dispose();
}
void dispose();
System* system;
Heap* heap;
@ -65,6 +61,28 @@ class Machine {
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 {
public:
enum State {
@ -99,6 +117,8 @@ class Thread {
Thread(Machine* m);
void dispose();
Machine* vm;
Thread* next;
Thread* child;
@ -113,6 +133,7 @@ class Thread {
object stack[StackSizeInWords];
object heap[HeapSizeInWords];
Protector* protector;
Chain* chain;
};
#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):
vm(m),
next(0),
@ -198,7 +231,8 @@ Thread::Thread(Machine* m):
ip(0),
sp(0),
heapIndex(0),
protector(0)
protector(0),
chain(0)
{
if (m->rootThread == 0) {
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
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
collect(Machine* m, Heap::CollectionType type)
{
@ -350,6 +405,8 @@ collect(Machine* m, Heap::CollectionType type)
m->unsafe = true;
m->heap->collect(type, &it);
m->unsafe = false;
postCollect(m->rootThread);
}
void
@ -451,12 +508,27 @@ enter(Thread* t, Thread::State s)
}
}
void
maybeYieldAndMaybeCollect(Thread* t, unsigned sizeInBytes)
inline object
allocateLarge(Thread* t, unsigned sizeInBytes)
{
if (sizeInBytes > Thread::HeapSizeInBytes) {
// large object support not yet implemented.
abort(t);
void* p = t->vm->system->allocate(Chain::footprint(sizeInBytes));
t->chain = new (p) Chain(t->chain);
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);
@ -475,6 +547,12 @@ maybeYieldAndMaybeCollect(Thread* t, unsigned sizeInBytes)
collect(t->vm, Heap::MinorCollection);
enter(t, Thread::ActiveState);
}
if (sizeInBytes > Thread::HeapSizeInBytes) {
return allocateLarge(t, sizeInBytes);
} else {
return allocateSmall(t, sizeInBytes);
}
}
inline object
@ -484,12 +562,10 @@ allocate(Thread* t, unsigned sizeInBytes)
>= Thread::HeapSizeInWords
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