mirror of
https://github.com/corda/corda.git
synced 2025-01-27 14:49:35 +00:00
enable large object support; various GC bugfixes and tweaks
This commit is contained in:
parent
4d202e4945
commit
5ee38e259a
@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
11
makefile
11
makefile
@ -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)
|
||||
|
64
src/heap.cpp
64
src/heap.cpp
@ -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));
|
||||
|
13
src/main.cpp
13
src/main.cpp
@ -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));
|
||||
}
|
||||
}
|
||||
|
108
src/vm.cpp
108
src/vm.cpp
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user