mirror of
https://github.com/corda/corda.git
synced 2024-12-28 16:58:55 +00:00
various GC bugfixes
This commit is contained in:
parent
09f6a34510
commit
3a6da507ec
@ -25,7 +25,7 @@ typedef void* object;
|
|||||||
const unsigned BytesPerWord = sizeof(uintptr_t);
|
const unsigned BytesPerWord = sizeof(uintptr_t);
|
||||||
const unsigned BitsPerWord = BytesPerWord * 8;
|
const unsigned BitsPerWord = BytesPerWord * 8;
|
||||||
|
|
||||||
const unsigned LikelyPageSize = 4 * 1024;
|
const unsigned LikelyPageSizeInBytes = 4 * 1024;
|
||||||
|
|
||||||
inline unsigned
|
inline unsigned
|
||||||
max(unsigned a, unsigned b)
|
max(unsigned a, unsigned b)
|
||||||
|
254
src/heap.cpp
254
src/heap.cpp
@ -12,8 +12,8 @@ namespace {
|
|||||||
// before being copied to gen2:
|
// before being copied to gen2:
|
||||||
const unsigned TenureThreshold = 3;
|
const unsigned TenureThreshold = 3;
|
||||||
|
|
||||||
const unsigned MinimumGen1Size = 64 * 1024;
|
const unsigned MinimumGen1SizeInBytes = 64 * 1024;
|
||||||
const unsigned MinimumGen2Size = 128 * 1024;
|
const unsigned MinimumGen2SizeInBytes = 128 * 1024;
|
||||||
|
|
||||||
const unsigned Top = ~static_cast<unsigned>(0);
|
const unsigned Top = ~static_cast<unsigned>(0);
|
||||||
|
|
||||||
@ -260,10 +260,9 @@ class Segment {
|
|||||||
Chain* next;
|
Chain* next;
|
||||||
Chain* previous;
|
Chain* previous;
|
||||||
|
|
||||||
Chain(Segment* segment, unsigned offset, unsigned capacity,
|
Chain(Segment* segment, unsigned capacity, Chain* previous):
|
||||||
Chain* previous):
|
|
||||||
segment(segment),
|
segment(segment),
|
||||||
offset(offset),
|
offset(previous ? previous->offset + previous->position : 0),
|
||||||
position(0),
|
position(0),
|
||||||
capacity(capacity),
|
capacity(capacity),
|
||||||
next(0),
|
next(0),
|
||||||
@ -272,6 +271,28 @@ class Segment {
|
|||||||
assert(segment->context, sizeof(Chain) % BytesPerWord == 0);
|
assert(segment->context, sizeof(Chain) % BytesPerWord == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Chain* make(Segment* s, unsigned minimum, unsigned desired) {
|
||||||
|
assert(s->context, minimum > 0);
|
||||||
|
assert(s->context, desired >= minimum);
|
||||||
|
|
||||||
|
void* p = 0;
|
||||||
|
unsigned capacity = desired;
|
||||||
|
while (p == 0) {
|
||||||
|
p = system(s->context)->tryAllocate
|
||||||
|
(footprint(capacity, s->rear, s->map) * BytesPerWord);
|
||||||
|
|
||||||
|
if (p == 0) {
|
||||||
|
if (capacity > minimum) {
|
||||||
|
capacity = minimum + ((capacity - minimum) / 2);
|
||||||
|
} else {
|
||||||
|
abort(s->context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new (p) Chain(s, capacity, s->rear);
|
||||||
|
}
|
||||||
|
|
||||||
static void dispose(Chain* c) {
|
static void dispose(Chain* c) {
|
||||||
if (c) {
|
if (c) {
|
||||||
if (c->next) dispose(c->next);
|
if (c->next) dispose(c->next);
|
||||||
@ -308,27 +329,22 @@ class Segment {
|
|||||||
Chain* rear;
|
Chain* rear;
|
||||||
Map* map;
|
Map* map;
|
||||||
|
|
||||||
Segment(Context* context, unsigned capacity, Map* map = 0,
|
Segment(Context* context, unsigned minimum, unsigned desired, Map* map = 0,
|
||||||
bool clearMap = true):
|
bool clearMap = true):
|
||||||
context(context),
|
context(context),
|
||||||
front(0),
|
front(0),
|
||||||
rear(0),
|
rear(0),
|
||||||
map(map)
|
map(map)
|
||||||
{
|
{
|
||||||
front = rear = 0;
|
if (desired) {
|
||||||
this->map = map;
|
front = rear = Chain::make(this, minimum, desired);
|
||||||
|
|
||||||
if (capacity) {
|
|
||||||
front = rear = new
|
|
||||||
(system(context)->allocate
|
|
||||||
(Chain::footprint(capacity, 0, map) * BytesPerWord))
|
|
||||||
Chain(this, 0, capacity, 0);
|
|
||||||
|
|
||||||
if (map) {
|
if (map) {
|
||||||
map->setSegment(this);
|
|
||||||
if (clearMap) {
|
if (clearMap) {
|
||||||
map->clear();
|
memset(front->data() + front->capacity, 0,
|
||||||
|
map->footprint(front->capacity) * BytesPerWord);
|
||||||
}
|
}
|
||||||
|
map->setSegment(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -356,18 +372,6 @@ class Segment {
|
|||||||
abort(context);
|
abort(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void copyTo(void* p) {
|
|
||||||
for (Chain* c = front; c; c = c->next) {
|
|
||||||
if (c->position) {
|
|
||||||
memcpy(static_cast<uintptr_t*>(p) + c->offset,
|
|
||||||
c->data(),
|
|
||||||
c->position * BytesPerWord);
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned footprint() {
|
unsigned footprint() {
|
||||||
unsigned n = 0;
|
unsigned n = 0;
|
||||||
for (Chain* c = front; c; c = c->next) n += c->footprint();
|
for (Chain* c = front; c; c = c->next) n += c->footprint();
|
||||||
@ -463,31 +467,14 @@ class Segment {
|
|||||||
assert(context, rear->position);
|
assert(context, rear->position);
|
||||||
assert(context, rear->next == 0);
|
assert(context, rear->next == 0);
|
||||||
|
|
||||||
if (Verbose) {
|
|
||||||
fprintf(stderr, "grow\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned desired = (position() + minimum) * 2;
|
unsigned desired = (position() + minimum) * 2;
|
||||||
|
|
||||||
void* p = 0;
|
Chain* c = Chain::make(this, minimum, desired);
|
||||||
unsigned newCapacity = desired;
|
|
||||||
while (p == 0) {
|
|
||||||
p = system(context)->tryAllocate
|
|
||||||
(Chain::footprint(newCapacity, rear, map) * BytesPerWord);
|
|
||||||
|
|
||||||
if (p == 0) {
|
|
||||||
if (newCapacity > minimum) {
|
|
||||||
newCapacity = minimum + ((newCapacity - minimum) / 2);
|
|
||||||
} else {
|
|
||||||
abort(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Chain* c = new (p) Chain
|
|
||||||
(this, rear->offset + rear->position, newCapacity, rear);
|
|
||||||
|
|
||||||
if (map) {
|
if (map) {
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -515,10 +502,10 @@ class Context {
|
|||||||
Context(System* system):
|
Context(System* system):
|
||||||
system(system),
|
system(system),
|
||||||
client(0),
|
client(0),
|
||||||
gen1(this, 0),
|
gen1(this, 0, 0),
|
||||||
nextGen1(this, 0),
|
nextGen1(this, 0, 0),
|
||||||
gen2(this, 0),
|
gen2(this, 0, 0),
|
||||||
nextGen2(this, 0)
|
nextGen2(this, 0, 0)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
@ -540,13 +527,34 @@ class Context {
|
|||||||
|
|
||||||
Segment::Map ageMap;
|
Segment::Map ageMap;
|
||||||
Segment::Map nextAgeMap;
|
Segment::Map nextAgeMap;
|
||||||
|
|
||||||
Segment::Map pointerMap;
|
Segment::Map pointerMap;
|
||||||
Segment::Map pageMap;
|
Segment::Map pageMap;
|
||||||
Segment::Map heapMap;
|
Segment::Map heapMap;
|
||||||
|
|
||||||
|
Segment::Map nextPointerMap;
|
||||||
|
Segment::Map nextPageMap;
|
||||||
|
Segment::Map nextHeapMap;
|
||||||
|
|
||||||
CollectionMode mode;
|
CollectionMode mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char*
|
||||||
|
segment(Context* c, void* p)
|
||||||
|
{
|
||||||
|
if (c->gen1.contains(p)) {
|
||||||
|
return "gen1";
|
||||||
|
} else if (c->nextGen1.contains(p)) {
|
||||||
|
return "nextGen1";
|
||||||
|
} else if (c->gen2.contains(p)) {
|
||||||
|
return "gen2";
|
||||||
|
} else if (c->nextGen2.contains(p)) {
|
||||||
|
return "nextGen2";
|
||||||
|
} else {
|
||||||
|
return "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline System*
|
inline System*
|
||||||
system(Context* c)
|
system(Context* c)
|
||||||
{
|
{
|
||||||
@ -569,43 +577,54 @@ assert(Context* c, bool v)
|
|||||||
void
|
void
|
||||||
initGen1(Context* c)
|
initGen1(Context* c)
|
||||||
{
|
{
|
||||||
new (&(c->ageMap)) Segment::Map(&(c->gen1), log(TenureThreshold));
|
unsigned minimum = MinimumGen1SizeInBytes / BytesPerWord;
|
||||||
new (&(c->gen1)) Segment
|
unsigned desired = minimum;
|
||||||
(c, MinimumGen1Size / BytesPerWord, &(c->ageMap), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
new (&(c->ageMap)) Segment::Map(&(c->gen1), log(TenureThreshold));
|
||||||
initGen2(Context* c)
|
|
||||||
{
|
new (&(c->gen1)) Segment(c, minimum, desired, &(c->ageMap), false);
|
||||||
new (&(c->pointerMap)) Segment::Map(&(c->gen2));
|
|
||||||
new (&(c->pageMap)) Segment::Map
|
|
||||||
(&(c->gen2), 1, LikelyPageSize / BytesPerWord, &(c->pointerMap));
|
|
||||||
new (&(c->heapMap)) Segment::Map
|
|
||||||
(&(c->gen2), 1, c->pageMap.scale * 1024, &(c->pageMap));
|
|
||||||
new (&(c->gen2)) Segment(c, MinimumGen2Size / BytesPerWord, &(c->heapMap));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
initNextGen1(Context* c)
|
initNextGen1(Context* c)
|
||||||
{
|
{
|
||||||
unsigned size = max(MinimumGen1Size / BytesPerWord,
|
unsigned minimum = MinimumGen1SizeInBytes / BytesPerWord;
|
||||||
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));
|
||||||
new (&(c->nextGen1)) Segment(c, size, &(c->nextAgeMap), false);
|
|
||||||
|
new (&(c->nextGen1)) Segment(c, minimum, desired, &(c->nextAgeMap), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
initGen2(Context* c)
|
||||||
|
{
|
||||||
|
unsigned minimum = MinimumGen2SizeInBytes / BytesPerWord;
|
||||||
|
unsigned desired = minimum;
|
||||||
|
|
||||||
|
new (&(c->pointerMap)) Segment::Map(&(c->gen2));
|
||||||
|
new (&(c->pageMap)) Segment::Map
|
||||||
|
(&(c->gen2), 1, LikelyPageSizeInBytes / BytesPerWord, &(c->pointerMap));
|
||||||
|
new (&(c->heapMap)) Segment::Map
|
||||||
|
(&(c->gen2), 1, c->pageMap.scale * 1024, &(c->pageMap));
|
||||||
|
|
||||||
|
new (&(c->gen2)) Segment(c, minimum, desired, &(c->heapMap));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
initNextGen2(Context* c)
|
initNextGen2(Context* c)
|
||||||
{
|
{
|
||||||
unsigned size = max(MinimumGen2Size / BytesPerWord,
|
unsigned minimum = MinimumGen2SizeInBytes / BytesPerWord;
|
||||||
nextPowerOfTwo(c->gen2.position()));
|
unsigned desired = max(minimum, nextPowerOfTwo(c->gen2.position()));
|
||||||
new (&(c->pointerMap)) Segment::Map(&(c->nextGen2));
|
|
||||||
new (&(c->pageMap)) Segment::Map
|
new (&(c->nextPointerMap)) Segment::Map(&(c->nextGen2));
|
||||||
(&(c->nextGen2), 1, LikelyPageSize / BytesPerWord, &(c->pointerMap));
|
new (&(c->nextPageMap)) Segment::Map
|
||||||
new (&(c->heapMap)) Segment::Map
|
(&(c->nextGen2), 1, LikelyPageSizeInBytes / BytesPerWord,
|
||||||
(&(c->nextGen2), 1, c->pageMap.scale * 1024, &(c->pageMap));
|
&(c->nextPointerMap));
|
||||||
new (&(c->nextGen2)) Segment(c, size, &(c->heapMap));
|
new (&(c->nextHeapMap)) Segment::Map
|
||||||
c->gen2.map = 0;
|
(&(c->nextGen2), 1, c->pageMap.scale * 1024, &(c->nextPageMap));
|
||||||
|
|
||||||
|
new (&(c->nextGen2)) Segment(c, minimum, desired, &(c->nextHeapMap));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
@ -644,9 +663,24 @@ bitset(Context* c, object o)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline object
|
inline object
|
||||||
copyTo(Context*, Segment* s, object o, unsigned size)
|
copyTo(Context* c, Segment* s, object o, unsigned size)
|
||||||
{
|
{
|
||||||
s->ensure(size);
|
if (s->remaining() < size) {
|
||||||
|
if (Verbose) {
|
||||||
|
if (s == &(c->gen2)) {
|
||||||
|
fprintf(stderr, "grow gen2\n");
|
||||||
|
} else if (s == &(c->nextGen1)) {
|
||||||
|
fprintf(stderr, "grow nextGen1\n");
|
||||||
|
} else if (s == &(c->nextGen2)) {
|
||||||
|
fprintf(stderr, "grow nextGen2\n");
|
||||||
|
} else {
|
||||||
|
abort(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s->ensure(size);
|
||||||
|
}
|
||||||
|
|
||||||
return static_cast<object>(s->add(o, size));
|
return static_cast<object>(s->add(o, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -707,7 +741,8 @@ copy(Context* c, object o)
|
|||||||
object r = copy2(c, o);
|
object r = copy2(c, o);
|
||||||
|
|
||||||
if (Debug) {
|
if (Debug) {
|
||||||
fprintf(stderr, "copy %p to %p\n", o, r);
|
fprintf(stderr, "copy %p (%s) to %p (%s)\n",
|
||||||
|
o, segment(c, o), r, segment(c, r));
|
||||||
}
|
}
|
||||||
|
|
||||||
// leave a pointer to the copy in the original
|
// leave a pointer to the copy in the original
|
||||||
@ -744,6 +779,8 @@ update2(Context* c, object* p, bool* needsVisit)
|
|||||||
if (c->gen2.contains(*p)) {
|
if (c->gen2.contains(*p)) {
|
||||||
return update3(c, p, needsVisit);
|
return update3(c, p, needsVisit);
|
||||||
} else {
|
} else {
|
||||||
|
assert(c, c->nextGen1.contains(*p) or c->nextGen2.contains(*p));
|
||||||
|
|
||||||
*needsVisit = false;
|
*needsVisit = false;
|
||||||
return *p;
|
return *p;
|
||||||
}
|
}
|
||||||
@ -769,11 +806,21 @@ update(Context* c, object* p, bool* needsVisit)
|
|||||||
if (r) {
|
if (r) {
|
||||||
if (c->mode == MinorCollection) {
|
if (c->mode == MinorCollection) {
|
||||||
if (c->gen2.contains(p) and not c->gen2.contains(r)) {
|
if (c->gen2.contains(p) and not c->gen2.contains(r)) {
|
||||||
|
if (Debug) {
|
||||||
|
fprintf(stderr, "mark %p (%s) at %p (%s)\n",
|
||||||
|
r, segment(c, r), p, segment(c, p));
|
||||||
|
}
|
||||||
|
|
||||||
c->heapMap.set(p);
|
c->heapMap.set(p);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (c->nextGen2.contains(p) and not c->nextGen2.contains(r)) {
|
if (c->nextGen2.contains(p) and not c->nextGen2.contains(r)) {
|
||||||
c->heapMap.set(p);
|
if (Debug) {
|
||||||
|
fprintf(stderr, "mark %p (%s) at %p (%s)\n",
|
||||||
|
r, segment(c, r), p, segment(c, p));
|
||||||
|
}
|
||||||
|
|
||||||
|
c->nextHeapMap.set(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -888,14 +935,16 @@ collect(Context* c, void** p)
|
|||||||
object parent = 0;
|
object parent = 0;
|
||||||
|
|
||||||
if (Debug) {
|
if (Debug) {
|
||||||
fprintf(stderr, "update %p at %p\n", *p, p);
|
fprintf(stderr, "update %p (%s) at %p (%s)\n",
|
||||||
|
*p, segment(c, *p), p, segment(c, p));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needsVisit;
|
bool needsVisit;
|
||||||
*p = update(c, p, &needsVisit);
|
*p = update(c, p, &needsVisit);
|
||||||
|
|
||||||
if (Debug) {
|
if (Debug) {
|
||||||
fprintf(stderr, " result: %p (visit? %d)\n", *p, needsVisit);
|
fprintf(stderr, " result: %p (%s) (visit? %d)\n",
|
||||||
|
*p, segment(c, *p), needsVisit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not needsVisit) return;
|
if (not needsVisit) return;
|
||||||
@ -918,11 +967,13 @@ collect(Context* c, void** p)
|
|||||||
|
|
||||||
virtual bool visit(unsigned offset) {
|
virtual bool visit(unsigned offset) {
|
||||||
if (Debug) {
|
if (Debug) {
|
||||||
fprintf(stderr, " update %p at %p - offset %d from %p\n",
|
fprintf(stderr, " update %p (%s) at %p - offset %d from %p (%s)\n",
|
||||||
cast<object>(copy, offset * BytesPerWord),
|
cast<object>(copy, offset * BytesPerWord),
|
||||||
|
segment(c, cast<object>(copy, offset * BytesPerWord)),
|
||||||
&cast<object>(copy, offset * BytesPerWord),
|
&cast<object>(copy, offset * BytesPerWord),
|
||||||
offset,
|
offset,
|
||||||
copy);
|
copy,
|
||||||
|
segment(c, copy));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needsVisit;
|
bool needsVisit;
|
||||||
@ -930,8 +981,8 @@ collect(Context* c, void** p)
|
|||||||
(c, &cast<object>(copy, offset * BytesPerWord), &needsVisit);
|
(c, &cast<object>(copy, offset * BytesPerWord), &needsVisit);
|
||||||
|
|
||||||
if (Debug) {
|
if (Debug) {
|
||||||
fprintf(stderr, " result: %p (visit? %d)\n",
|
fprintf(stderr, " result: %p (%s) (visit? %d)\n",
|
||||||
childCopy, needsVisit);
|
childCopy, segment(c, childCopy), needsVisit);
|
||||||
}
|
}
|
||||||
|
|
||||||
++ total;
|
++ total;
|
||||||
@ -980,7 +1031,7 @@ collect(Context* c, void** p)
|
|||||||
} walker(c, copy, bitset(c, original));
|
} walker(c, copy, bitset(c, original));
|
||||||
|
|
||||||
if (Debug) {
|
if (Debug) {
|
||||||
fprintf(stderr, "walk %p\n", copy);
|
fprintf(stderr, "walk %p (%s)\n", copy, segment(c, copy));
|
||||||
}
|
}
|
||||||
|
|
||||||
c->client->walk(copy, &walker);
|
c->client->walk(copy, &walker);
|
||||||
@ -1052,11 +1103,13 @@ collect(Context* c, void** p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Debug) {
|
if (Debug) {
|
||||||
fprintf(stderr, " next is %p at %p - offset %d from %p\n",
|
fprintf(stderr, " next is %p (%s) at %p - offset %d from %p (%s)\n",
|
||||||
cast<object>(copy, walker.next * BytesPerWord),
|
cast<object>(copy, walker.next * BytesPerWord),
|
||||||
|
segment(c, cast<object>(copy, walker.next * BytesPerWord)),
|
||||||
&cast<object>(copy, walker.next * BytesPerWord),
|
&cast<object>(copy, walker.next * BytesPerWord),
|
||||||
walker.next,
|
walker.next,
|
||||||
copy);
|
copy,
|
||||||
|
segment(c, copy));
|
||||||
}
|
}
|
||||||
|
|
||||||
original = cast<object>(copy, walker.next * BytesPerWord);
|
original = cast<object>(copy, walker.next * BytesPerWord);
|
||||||
@ -1082,9 +1135,7 @@ collect(Context* c, Segment::Map* map, unsigned start, unsigned end,
|
|||||||
map->clearOnly(s);
|
map->clearOnly(s);
|
||||||
bool childDirty = false;
|
bool childDirty = false;
|
||||||
collect(c, map->child, s, e, &childDirty, true);
|
collect(c, map->child, s, e, &childDirty, true);
|
||||||
if (c->mode == OverflowCollection) {
|
if (c->mode != OverflowCollection and childDirty) {
|
||||||
return;
|
|
||||||
} else if (childDirty) {
|
|
||||||
map->setOnly(s);
|
map->setOnly(s);
|
||||||
*dirty = true;
|
*dirty = true;
|
||||||
}
|
}
|
||||||
@ -1099,11 +1150,7 @@ collect(Context* c, Segment::Map* map, unsigned start, unsigned end,
|
|||||||
} else {
|
} else {
|
||||||
collect(c, p);
|
collect(c, p);
|
||||||
|
|
||||||
if (c->mode == OverflowCollection) {
|
if (c->mode != OverflowCollection and not c->gen2.contains(*p)) {
|
||||||
return;
|
|
||||||
} else if (c->gen2.contains(*p)) {
|
|
||||||
// done
|
|
||||||
} else {
|
|
||||||
map->setOnly(p);
|
map->setOnly(p);
|
||||||
*dirty = true;
|
*dirty = true;
|
||||||
}
|
}
|
||||||
@ -1290,6 +1337,11 @@ makeHeap(System* system)
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void mark(void** p) {
|
virtual void mark(void** p) {
|
||||||
|
if (Debug) {
|
||||||
|
fprintf(stderr, "mark %p (%s) at %p (%s)\n",
|
||||||
|
*p, segment(&c, *p), p, segment(&c, p));
|
||||||
|
}
|
||||||
|
|
||||||
c.heapMap.set(p);
|
c.heapMap.set(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1301,7 +1353,9 @@ makeHeap(System* system)
|
|||||||
virtual void* follow(void* p) {
|
virtual void* follow(void* p) {
|
||||||
if (wasCollected(&c, p)) {
|
if (wasCollected(&c, p)) {
|
||||||
if (Debug) {
|
if (Debug) {
|
||||||
fprintf(stderr, "follow: %p: %p\n", p, ::follow(&c, p));
|
fprintf(stderr, "follow %p (%s) to %p (%s)\n",
|
||||||
|
p, segment(&c, p),
|
||||||
|
::follow(&c, p), segment(&c, ::follow(&c, p)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ::follow(&c, p);
|
return ::follow(&c, p);
|
||||||
|
35
src/vm.cpp
35
src/vm.cpp
@ -91,8 +91,8 @@ class Thread {
|
|||||||
Protector* next;
|
Protector* next;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned HeapSize = 64 * 1024;
|
static const unsigned HeapSizeInBytes = 64 * 1024;
|
||||||
static const unsigned StackSize = 64 * 1024;
|
static const unsigned StackSizeInBytes = 64 * 1024;
|
||||||
|
|
||||||
Thread(Machine* m);
|
Thread(Machine* m);
|
||||||
|
|
||||||
@ -107,8 +107,8 @@ class Thread {
|
|||||||
unsigned ip;
|
unsigned ip;
|
||||||
unsigned sp;
|
unsigned sp;
|
||||||
unsigned heapIndex;
|
unsigned heapIndex;
|
||||||
object stack[StackSize];
|
object stack[StackSizeInBytes / BytesPerWord];
|
||||||
object heap[HeapSize];
|
object heap[HeapSizeInBytes / BytesPerWord];
|
||||||
Protector* protector;
|
Protector* protector;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -449,9 +449,9 @@ enter(Thread* t, Thread::State s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
maybeYieldAndMaybeCollect(Thread* t, unsigned size)
|
maybeYieldAndMaybeCollect(Thread* t, unsigned sizeInBytes)
|
||||||
{
|
{
|
||||||
if (size > Thread::HeapSize) {
|
if (sizeInBytes > Thread::HeapSizeInBytes) {
|
||||||
// large object support not yet implemented.
|
// large object support not yet implemented.
|
||||||
abort(t);
|
abort(t);
|
||||||
}
|
}
|
||||||
@ -465,7 +465,9 @@ maybeYieldAndMaybeCollect(Thread* t, unsigned size)
|
|||||||
enter(t, Thread::ActiveState);
|
enter(t, Thread::ActiveState);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->heapIndex + size >= Thread::HeapSize) {
|
if (t->heapIndex + divide(sizeInBytes, BytesPerWord)
|
||||||
|
>= (Thread::HeapSizeInBytes / BytesPerWord))
|
||||||
|
{
|
||||||
enter(t, Thread::ExclusiveState);
|
enter(t, Thread::ExclusiveState);
|
||||||
collect(t->vm, Heap::MinorCollection);
|
collect(t->vm, Heap::MinorCollection);
|
||||||
enter(t, Thread::ActiveState);
|
enter(t, Thread::ActiveState);
|
||||||
@ -473,16 +475,17 @@ maybeYieldAndMaybeCollect(Thread* t, unsigned size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline object
|
inline object
|
||||||
allocate(Thread* t, unsigned size)
|
allocate(Thread* t, unsigned sizeInBytes)
|
||||||
{
|
{
|
||||||
if (UNLIKELY(t->heapIndex + size >= Thread::HeapSize
|
if (UNLIKELY(t->heapIndex + divide(sizeInBytes, BytesPerWord)
|
||||||
|
>= (Thread::HeapSizeInBytes / BytesPerWord)
|
||||||
or t->vm->exclusive))
|
or t->vm->exclusive))
|
||||||
{
|
{
|
||||||
maybeYieldAndMaybeCollect(t, size);
|
maybeYieldAndMaybeCollect(t, sizeInBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
object o = t->heap + t->heapIndex;
|
object o = t->heap + t->heapIndex;
|
||||||
t->heapIndex += size;
|
t->heapIndex += divide(sizeInBytes, BytesPerWord);
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -518,11 +521,11 @@ inline object
|
|||||||
make(Thread* t, object class_)
|
make(Thread* t, object class_)
|
||||||
{
|
{
|
||||||
PROTECT(t, class_);
|
PROTECT(t, class_);
|
||||||
unsigned size = classFixedSize(t, class_);
|
unsigned sizeInBytes = classFixedSize(t, class_);
|
||||||
object instance = allocate(t, size);
|
object instance = allocate(t, sizeInBytes);
|
||||||
*static_cast<object*>(instance) = class_;
|
*static_cast<object*>(instance) = class_;
|
||||||
memset(static_cast<object*>(instance) + sizeof(object), 0,
|
memset(static_cast<object*>(instance) + sizeof(object), 0,
|
||||||
size - sizeof(object));
|
sizeInBytes - sizeof(object));
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1241,7 +1244,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
|
|
||||||
unsigned memberOffset = BytesPerWord;
|
unsigned memberOffset = BytesPerWord;
|
||||||
if (classSuper(t, class_)) {
|
if (classSuper(t, class_)) {
|
||||||
memberOffset = classFixedSize(t, classSuper(t, class_)) * BytesPerWord;
|
memberOffset = classFixedSize(t, classSuper(t, class_));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned count = s.read2();
|
unsigned count = s.read2();
|
||||||
@ -3033,7 +3036,7 @@ run(Thread* t)
|
|||||||
|
|
||||||
invoke:
|
invoke:
|
||||||
if (UNLIKELY(codeMaxStack(t, methodCode(t, code)) + sp - parameterCount
|
if (UNLIKELY(codeMaxStack(t, methodCode(t, code)) + sp - parameterCount
|
||||||
> Thread::StackSize))
|
> (Thread::StackSizeInBytes / BytesPerWord)))
|
||||||
{
|
{
|
||||||
exception = makeStackOverflowError(t);
|
exception = makeStackOverflowError(t);
|
||||||
goto throw_;
|
goto throw_;
|
||||||
|
Loading…
Reference in New Issue
Block a user