mirror of
https://github.com/corda/corda.git
synced 2025-05-31 22:50:53 +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];
|
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];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
11
makefile
11
makefile
@ -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)
|
||||||
|
64
src/heap.cpp
64
src/heap.cpp
@ -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));
|
||||||
|
13
src/main.cpp
13
src/main.cpp
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
108
src/vm.cpp
108
src/vm.cpp
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user