mirror of
https://github.com/corda/corda.git
synced 2025-01-27 14:49:35 +00:00
snapshot
This commit is contained in:
parent
caac00e5ff
commit
459acc3419
11
src/common.h
11
src/common.h
@ -15,4 +15,15 @@
|
||||
#define MACRO_MakeNameXY(FX, LINE) MACRO_XY(FX, LINE)
|
||||
#define MAKE_NAME(FX) MACRO_MakeNameXY(FX, __LINE__)
|
||||
|
||||
namespace vm {
|
||||
|
||||
typedef void* object;
|
||||
|
||||
const unsigned BytesPerWord = sizeof(uintptr_t);
|
||||
const unsigned BitsPerWord = BytesPerWord * 8;
|
||||
|
||||
const unsigned LikelyPageSize = 4 * 1024;
|
||||
|
||||
}
|
||||
|
||||
#endif//COMMON_H
|
||||
|
749
src/heap.cpp
749
src/heap.cpp
@ -1,14 +1,652 @@
|
||||
#include "heap.h"
|
||||
#include "system.h"
|
||||
#include "common.h"
|
||||
|
||||
using namespace vm;
|
||||
|
||||
namespace {
|
||||
|
||||
class Segment {
|
||||
public:
|
||||
class Map {
|
||||
public:
|
||||
class Iterator {
|
||||
public:
|
||||
Map* map;
|
||||
unsigned index;
|
||||
unsigned limit;
|
||||
|
||||
Iterator(Map* map, void** start, void** end):
|
||||
map(map)
|
||||
{
|
||||
assert(map);
|
||||
assert(map->bitsPerRecord == 1);
|
||||
assert(map->segment);
|
||||
|
||||
index = map->indexOf(start);
|
||||
assert(index == 0 or
|
||||
start != reinterpret_cast<void**>(map->segment->data));
|
||||
|
||||
void** p = reinterpret_cast<void**>(map->segment->data)
|
||||
+ map->segment->position;
|
||||
if (end > p) end = p;
|
||||
|
||||
limit = map->indexOf(end);
|
||||
if (static_cast<unsigned>(end - start) % map->scale) ++ limit;
|
||||
|
||||
// printf("iterating from %p (index %d) to %p (index %d) "
|
||||
// "(%d of %d bytes) (scale: %d)\n",
|
||||
// start, index, end, limit, (end - start) * sizeof(void*),
|
||||
// map->segment->position * sizeof(void*), map->scale);
|
||||
}
|
||||
|
||||
bool hasMore() {
|
||||
assert(map);
|
||||
|
||||
unsigned word = wordOf(index);
|
||||
unsigned bit = bitOf(index);
|
||||
unsigned wordLimit = wordOf(limit);
|
||||
unsigned bitLimit = bitOf(limit);
|
||||
|
||||
for (; word <= wordLimit and (word < wordLimit or bit < bitLimit);
|
||||
++word)
|
||||
{
|
||||
uintptr_t* p = map->data + word;
|
||||
if (*p) {
|
||||
for (; bit < BitsPerWord and (word < wordLimit or bit < bitLimit);
|
||||
++bit)
|
||||
{
|
||||
if (map->data[word] & (static_cast<uintptr_t>(1) << bit)) {
|
||||
index = ::indexOf(word, bit);
|
||||
// printf("hit at index %d\n", index);
|
||||
return true;
|
||||
} else {
|
||||
// printf("miss at index %d\n", indexOf(word, bit));
|
||||
}
|
||||
}
|
||||
}
|
||||
bit = 0;
|
||||
}
|
||||
|
||||
index = limit;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void** next() {
|
||||
assert(hasMore());
|
||||
assert(map->segment);
|
||||
|
||||
return reinterpret_cast<void**>(map->segment->data) +
|
||||
((index++) * map->scale);
|
||||
}
|
||||
};
|
||||
|
||||
Segment* segment;
|
||||
unsigned bitsPerRecord;
|
||||
unsigned scale;
|
||||
uintptr_t* data;
|
||||
Map* next;
|
||||
Map* child;
|
||||
|
||||
void init() {
|
||||
init(0);
|
||||
data = 0;
|
||||
}
|
||||
|
||||
void init(Segment* segment, unsigned bitsPerRecord = 1, unsigned scale = 1,
|
||||
Map* next = 0, Map* child = 0)
|
||||
{
|
||||
assert(bitsPerRecord);
|
||||
assert(scale);
|
||||
assert(powerOfTwo(scale));
|
||||
|
||||
this->segment = segment;
|
||||
this->bitsPerRecord = bitsPerRecord;
|
||||
this->scale = scale;
|
||||
this->next = next;
|
||||
this->child = child;
|
||||
}
|
||||
|
||||
void replaceWith(Map* m) {
|
||||
assert(m);
|
||||
assert(bitsPerRecord == m->bitsPerRecord);
|
||||
assert(scale == m->scale);
|
||||
|
||||
free(data);
|
||||
|
||||
data = m->data;
|
||||
m->data = 0;
|
||||
|
||||
if (next) next->replaceWith(m->next);
|
||||
if (child) child->replaceWith(m->child);
|
||||
}
|
||||
|
||||
unsigned size(unsigned capacity) {
|
||||
unsigned result = pad
|
||||
(divide(divide(capacity, scale) * bitsPerRecord, 8));
|
||||
assert(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned size() {
|
||||
assert(segment);
|
||||
return size(max(segment->capacity, 1));
|
||||
}
|
||||
|
||||
unsigned indexOf(void* p) {
|
||||
assert(segment);
|
||||
assert(segment->position
|
||||
and p >= segment->data
|
||||
and p <= segment->data + segment->position);
|
||||
assert(segment->data);
|
||||
return ((static_cast<void**>(p) - reinterpret_cast<void**>(segment->data))
|
||||
/ scale) * bitsPerRecord;
|
||||
}
|
||||
|
||||
void update() {
|
||||
data = static_cast<uintptr_t*>(realloc(data, size()));
|
||||
assert(data);
|
||||
|
||||
if (next) next->update();
|
||||
if (child) child->update();
|
||||
}
|
||||
|
||||
void reset(bool clear = true) {
|
||||
free(data);
|
||||
data = static_cast<uintptr_t*>(malloc(size()));
|
||||
assert(data);
|
||||
if (clear) memset(data, 0, size());
|
||||
|
||||
if (next) next->reset();
|
||||
if (child) child->reset();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
memset(data, 0, size());
|
||||
|
||||
if (next) next->clear();
|
||||
if (child) child->clear();
|
||||
}
|
||||
|
||||
void clear(unsigned i) {
|
||||
data[wordOf(i)] &= ~(static_cast<uintptr_t>(1) << bitOf(i));
|
||||
}
|
||||
|
||||
void set(unsigned i) {
|
||||
data[wordOf(i)] |= static_cast<uintptr_t>(1) << bitOf(i);
|
||||
}
|
||||
|
||||
void clearOnly(void* p) {
|
||||
unsigned index = indexOf(p);
|
||||
for (unsigned i = index, limit = index + bitsPerRecord; i < limit; ++i) {
|
||||
clear(i);
|
||||
}
|
||||
}
|
||||
|
||||
void clear(void* p) {
|
||||
clearOnly(p);
|
||||
if (child) child->clear(p);
|
||||
}
|
||||
|
||||
void setOnly(void* p, unsigned v = 1) {
|
||||
unsigned index = indexOf(p);
|
||||
unsigned i = index + bitsPerRecord - 1;
|
||||
while (true) {
|
||||
if (v & 1) set(i); else clear(i);
|
||||
v >>= 1;
|
||||
if (i == index) break;
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
void set(void* p, unsigned v = 1) {
|
||||
setOnly(p, v);
|
||||
assert(get(p) == v);
|
||||
if (child) child->set(p, v);
|
||||
}
|
||||
|
||||
unsigned get(void* p) {
|
||||
unsigned index = indexOf(p);
|
||||
unsigned v = 0;
|
||||
for (unsigned i = index, limit = index + bitsPerRecord; i < limit; ++i) {
|
||||
unsigned wi = bitOf(i);
|
||||
v <<= 1;
|
||||
v |= ((data[wordOf(i)]) & (static_cast<uintptr_t>(1) << wi))
|
||||
>> wi;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
free(data);
|
||||
data = 0;
|
||||
segment = 0;
|
||||
next = 0;
|
||||
|
||||
if (child) {
|
||||
child->dispose();
|
||||
child = 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned footprint(unsigned capacity) {
|
||||
unsigned n = size(capacity);
|
||||
if (next) n += next->footprint(capacity);
|
||||
if (child) n += child->footprint(capacity);
|
||||
return n;
|
||||
}
|
||||
|
||||
void setSegment(Segment* s) {
|
||||
segment = s;
|
||||
if (next) next->setSegment(s);
|
||||
if (child) child->setSegment(s);
|
||||
}
|
||||
};
|
||||
|
||||
uintptr_t* data;
|
||||
unsigned position;
|
||||
unsigned capacity;
|
||||
Map* map;
|
||||
|
||||
unsigned footprint(unsigned capacity) {
|
||||
unsigned n = capacity * BytesPerWord;
|
||||
if (map) n += map->size(capacity);
|
||||
return n;
|
||||
}
|
||||
|
||||
unsigned footprint() {
|
||||
return footprint(capacity);
|
||||
}
|
||||
|
||||
void init(unsigned capacityInBytes, Map* map = 0, bool clearMap = true) {
|
||||
this->capacity = divide(capacityInBytes, BytesPerWord);
|
||||
this->data = 0;
|
||||
this->position = 0;
|
||||
this->map = map;
|
||||
|
||||
if (capacity) {
|
||||
if (map) map->reset(clearMap);
|
||||
this->data = static_cast<uintptr_t*>(malloc(capacity * BytesPerWord));
|
||||
assert(this->data);
|
||||
}
|
||||
}
|
||||
|
||||
void* add(System* sys, void* p, unsigned size) {
|
||||
void* target = allocate(size);
|
||||
memcpy(target, p, size);
|
||||
return target;
|
||||
}
|
||||
|
||||
unsigned remaining() {
|
||||
return (capacity - position) * BytesPerWord;
|
||||
}
|
||||
|
||||
void replaceWith(Segment* s) {
|
||||
free(data);
|
||||
|
||||
data = s->data;
|
||||
s->data = 0;
|
||||
|
||||
position = s->position;
|
||||
s->position = 0;
|
||||
|
||||
capacity = s->capacity;
|
||||
s->capacity = 0;
|
||||
|
||||
if (s->map) {
|
||||
if (map) {
|
||||
map->replaceWith(s->map);
|
||||
} else {
|
||||
map = s->map;
|
||||
map->setSegment(this);
|
||||
}
|
||||
s->map = 0;
|
||||
} else {
|
||||
if (map) map->reset();
|
||||
}
|
||||
}
|
||||
|
||||
void grow(System* sys, unsigned extra) {
|
||||
if (remainingBytes() < extra) {
|
||||
unsigned minimumNeeded = s->usedBytes() + (extra * bytesPerWord);
|
||||
unsigned count = minimumNeeded * 2;
|
||||
|
||||
void* p = sys->allocate(&count);
|
||||
|
||||
if (count >= minimumNeeded) {
|
||||
memcpy(p, s->data, s->usedBytes());
|
||||
s->data = p;
|
||||
sys->free(s->data);
|
||||
} else {
|
||||
abort(sys);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned newCapacity = divide(newCapacityInBytes, BytesPerWord);
|
||||
assert(newCapacity > capacity);
|
||||
capacity = newCapacity;
|
||||
data = static_cast<uintptr_t*>(realloc(data, capacity * BytesPerWord));
|
||||
assert(data);
|
||||
if (map) map->update();
|
||||
}
|
||||
|
||||
bool contains(void* p) {
|
||||
return position and p >= data and p < data + position;
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
free(data);
|
||||
data = 0;
|
||||
position = 0;
|
||||
capacity = 0;
|
||||
|
||||
if (map) map->dispose();
|
||||
map = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class Context {
|
||||
public:
|
||||
};
|
||||
|
||||
void
|
||||
initGen1(Context* c)
|
||||
{
|
||||
c->ageMap.init(&(c->gen1), log(Arena::TenureThreshold));
|
||||
c->gen1.init(c->minimumGen1Size, &(c->ageMap), false);
|
||||
}
|
||||
|
||||
void
|
||||
initGen2(Context* c)
|
||||
{
|
||||
c->pointerMap.init(&(c->gen2));
|
||||
c->pageMap.init(&(c->gen2), 1, LikelyPageSize / BytesPerWord, 0,
|
||||
&(c->pointerMap));
|
||||
c->heapMap.init(&(c->gen2), 1, c->pageMap.scale * 1024, 0, &(c->pageMap));
|
||||
c->gen2.init(c->minimumGen2Size, &(c->heapMap));
|
||||
}
|
||||
|
||||
void
|
||||
initNextGen1(Context* c)
|
||||
{
|
||||
unsigned size = max(c->minimumGen1Size,
|
||||
nextPowerOfTwo(c->gen1.position() * BytesPerWord));
|
||||
c->nextAgeMap.init(&(c->nextGen1), log(Arena::TenureThreshold));
|
||||
c->nextGen1.init(size, &(c->nextAgeMap), false);
|
||||
}
|
||||
|
||||
void
|
||||
initNextGen2(Context* c)
|
||||
{
|
||||
unsigned size = max(c->minimumGen2Size,
|
||||
nextPowerOfTwo(c->gen2.position() * BytesPerWord));
|
||||
c->pointerMap.init(&(c->nextGen2));
|
||||
c->pageMap.init(&(c->nextGen2), 1, LikelyPageSize / BytesPerWord, 0,
|
||||
&(c->pointerMap));
|
||||
c->heapMap.init(&(c->nextGen2), 1, c->pageMap.scale * 1024, 0,
|
||||
&(c->pageMap));
|
||||
c->nextGen2.init(size, &(c->heapMap));
|
||||
c->gen2.map = 0;
|
||||
}
|
||||
|
||||
inline object&
|
||||
follow(object o)
|
||||
{
|
||||
return cast<object>(o, 0);
|
||||
}
|
||||
|
||||
inline object&
|
||||
parent(object o)
|
||||
{
|
||||
return cast<object>(o, BytesPerWord);
|
||||
}
|
||||
|
||||
inline uintptr_t*
|
||||
bitset(object o)
|
||||
{
|
||||
return &cast<uintptr_t>(o, BytesPerWord * 2);
|
||||
}
|
||||
|
||||
object
|
||||
copyTo(Context* c, Segment* s, object o, unsigned size)
|
||||
{
|
||||
assert(c, size >= BytesPerWord);
|
||||
assert(c, size % BytesPerWord == 0);
|
||||
|
||||
if (s->remainingBytes() < size) {
|
||||
s->grow(c->sys, size * bytesPerWord);
|
||||
}
|
||||
|
||||
return static_cast<object>(s->add(o, size));
|
||||
}
|
||||
|
||||
object
|
||||
copy2(Context* c, object o)
|
||||
{
|
||||
unsigned size = c->client->sizeOf(o);
|
||||
|
||||
if (c->gen2.contains(o)) {
|
||||
assert(c, c->mode == MajorCollection
|
||||
or c->mode == Gen2Collection);
|
||||
|
||||
return copyTo(c, &(c->nextGen2), o, size);
|
||||
} else if (c->gen1.contains(o)) {
|
||||
unsigned age = c->ageMap.get(o);
|
||||
if (age == Arena::TenureThreshold) {
|
||||
if (c->mode == MinorCollection) {
|
||||
if (c->gen2.front == 0) initGen2(a);
|
||||
|
||||
if (c->gen2.remainingBytes() >= size) {
|
||||
return copyTo(c, &(c->gen2), o, size);
|
||||
} else {
|
||||
c->mode = OverflowCollection;
|
||||
initNextGen2(a);
|
||||
return copyTo(c, &(c->nextGen2), o, size);
|
||||
}
|
||||
} else {
|
||||
return copyTo(c, &(c->nextGen2), o, size);
|
||||
}
|
||||
} else {
|
||||
o = copyTo(c, &(c->nextGen1), o, size);
|
||||
c->nextAgeMap.setOnly(o, age + 1);
|
||||
return o;
|
||||
}
|
||||
} else {
|
||||
assert(c, not c->nextGen1.contains(o));
|
||||
assert(c, not c->nextGen2.contains(o));
|
||||
|
||||
o = copyTo(c, &(c->nextGen1), o, size);
|
||||
|
||||
c->nextAgeMap.clear(o);
|
||||
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
copy(Context* c, object o)
|
||||
{
|
||||
object r = copy2(c, o);
|
||||
|
||||
// leave a pointer to the copy in the original
|
||||
follow(o) = r;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
inline bool
|
||||
wasCollected(Context* c, object o)
|
||||
{
|
||||
return o and (c->nextGen1.contains(follow(o)) or
|
||||
c->nextGen2.contains(follow(o)));
|
||||
}
|
||||
|
||||
object
|
||||
update3(Context* c, object *p, bool* needsVisit)
|
||||
{
|
||||
if (wasCollected(c, *p)) {
|
||||
*needsVisit = false;
|
||||
return follow(*p);
|
||||
} else {
|
||||
*needsVisit = true;
|
||||
return copy(c, *p);
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
update2(Context* c, object* p, bool* needsVisit)
|
||||
{
|
||||
switch (c->mode) {
|
||||
case MinorCollection:
|
||||
case OverflowCollection:
|
||||
if (c->gen2.contains(*p)) {
|
||||
*needsVisit = false;
|
||||
return *p;
|
||||
}
|
||||
break;
|
||||
|
||||
case Gen2Collection:
|
||||
if (c->gen2.contains(*p)) {
|
||||
return update3(c, p, needsVisit);
|
||||
} else {
|
||||
*needsVisit = false;
|
||||
return *p;
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
return update3(c, p, needsVisit);
|
||||
}
|
||||
|
||||
object
|
||||
update(Context* c, object* p, bool* needsVisit)
|
||||
{
|
||||
if (*p == 0) {
|
||||
*needsVisit = false;
|
||||
return *p;
|
||||
}
|
||||
|
||||
object r = update2(c, p, needsVisit);
|
||||
|
||||
// update heap map.
|
||||
if (r) {
|
||||
if (c->mode == MinorCollection) {
|
||||
if (c->gen2.contains(p) and not c->gen2.contains(r)) {
|
||||
c->heapMap.set(p);
|
||||
}
|
||||
} else {
|
||||
if (c->nextGen2.contains(p) and not c->nextGen2.contains(r)) {
|
||||
c->heapMap.set(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
const uintptr_t BitsetExtensionBit
|
||||
= (static_cast<uintptr_t>(1) << (BitsPerWord - 1));
|
||||
|
||||
void
|
||||
bitsetInit(uintptr_t* p)
|
||||
{
|
||||
memset(p, 0, BytesPerWord);
|
||||
}
|
||||
|
||||
void
|
||||
bitsetClear(uintptr_t* p, unsigned start, unsigned end)
|
||||
{
|
||||
if (end < BitsPerWord - 1) {
|
||||
// do nothing
|
||||
} else if (start < BitsPerWord - 1) {
|
||||
memset(p + 1, 0, (wordOf(end + (BitsPerWord * 2) + 1)) * BytesPerWord);
|
||||
} else {
|
||||
unsigned startWord = wordOf(start + (BitsPerWord * 2) + 1);
|
||||
unsigned endWord = wordOf(end + (BitsPerWord * 2) + 1);
|
||||
if (endWord > startWord) {
|
||||
memset(p + startWord + 1, 0, (endWord - startWord) * BytesPerWord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bitsetSet(uintptr_t* p, unsigned i, bool v)
|
||||
{
|
||||
if (i >= BitsPerWord - 1) {
|
||||
i += (BitsPerWord * 2) + 1;
|
||||
if (v) {
|
||||
p[0] |= BitsetExtensionBit;
|
||||
if (p[2] <= wordOf(i) - 3) p[2] = wordOf(i) - 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (v) {
|
||||
p[wordOf(i)] |= static_cast<uintptr_t>(1) << bitOf(i);
|
||||
} else {
|
||||
p[wordOf(i)] &= ~(static_cast<uintptr_t>(1) << bitOf(i));
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
bitsetHasMore(uintptr_t* p)
|
||||
{
|
||||
switch (*p) {
|
||||
case 0: return false;
|
||||
|
||||
case BitsetExtensionBit: {
|
||||
uintptr_t length = p[2];
|
||||
uintptr_t word = wordOf(p[1]);
|
||||
for (; word < length; ++word) {
|
||||
if (p[word + 3]) {
|
||||
p[1] = indexOf(word, 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
p[1] = indexOf(word, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
bitsetNext(Context* c, uintptr_t* p)
|
||||
{
|
||||
assert(c, bitsetHasMore(p));
|
||||
|
||||
switch (*p) {
|
||||
case 0: abort(c);
|
||||
|
||||
case BitsetExtensionBit: {
|
||||
uintptr_t i = p[1];
|
||||
uintptr_t word = wordOf(i);
|
||||
assert(c, word < p[2]);
|
||||
for (uintptr_t bit = bitOf(i); bit < BitsPerWord; ++bit) {
|
||||
if (p[word + 3] & (static_cast<uintptr_t>(1) << bit)) {
|
||||
p[1] = indexOf(word, bit) + 1;
|
||||
bitsetSet(p, p[1] + BitsPerWord - 2, false);
|
||||
return p[1] + BitsPerWord - 2;
|
||||
}
|
||||
}
|
||||
abort(c);
|
||||
}
|
||||
|
||||
default: {
|
||||
for (unsigned i = 0; i < BitsPerWord - 1; ++i) {
|
||||
if (*p & (static_cast<uintptr_t>(1) << i)) {
|
||||
bitsetSet(p, i, false);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
abort(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
collect(Context* c, void** p)
|
||||
{
|
||||
@ -81,7 +719,6 @@ collect(Context* c, void** p)
|
||||
// descend
|
||||
if (walker.visits > 1) {
|
||||
::parent(original) = parent;
|
||||
|
||||
parent = original;
|
||||
}
|
||||
|
||||
@ -99,7 +736,8 @@ collect(Context* c, void** p)
|
||||
|
||||
class Walker : public Heap::Walker {
|
||||
public:
|
||||
Walker(uintptr_t* bitset):
|
||||
Walker(Context* c, uintptr_t* bitset):
|
||||
c(c),
|
||||
bitset(bitset),
|
||||
next(0),
|
||||
total(0)
|
||||
@ -115,7 +753,7 @@ collect(Context* c, void** p)
|
||||
return true;
|
||||
|
||||
case 3:
|
||||
next = bitsetNext(bitset);
|
||||
next = bitsetNext(c, bitset);
|
||||
return false;
|
||||
|
||||
default:
|
||||
@ -123,6 +761,7 @@ collect(Context* c, void** p)
|
||||
}
|
||||
}
|
||||
|
||||
Context* c;
|
||||
uintptr_t* bitset;
|
||||
unsigned next;
|
||||
unsigned total;
|
||||
@ -138,11 +777,105 @@ collect(Context* c, void** p)
|
||||
|
||||
original = cast<object>(copy, walker.next * sizeof(void*));
|
||||
cast<object>(copy, walker.next * sizeof(void*)) = follow(original);
|
||||
goto visit;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
collect(Context* c, Segment::Map* map, unsigned start, unsigned end,
|
||||
bool* dirty, bool expectDirty UNUSED)
|
||||
{
|
||||
bool wasDirty = false;
|
||||
for (Segment::Map::Iterator it(map, start, end); it.hasMore();) {
|
||||
wasDirty = true;
|
||||
if (map->child) {
|
||||
assert(c, map->scale > 1);
|
||||
unsigned s = it.next();
|
||||
unsigned e = s + map->scale;
|
||||
|
||||
map->clearOnly(s);
|
||||
bool childDirty = false;
|
||||
collect(c, map->child, s, e, &childDirty, true);
|
||||
if (c->collectionMode == OverflowCollection) {
|
||||
return;
|
||||
} else if (childDirty) {
|
||||
map->setOnly(s);
|
||||
*dirty = true;
|
||||
}
|
||||
} else {
|
||||
assert(c, map->scale == 1);
|
||||
object* p = reinterpret_cast<object*>(map->heap->get(it.next()));
|
||||
|
||||
map->clearOnly(p);
|
||||
if (c->nextGen1.contains(*p)) {
|
||||
map->setOnly(p);
|
||||
*dirty = true;
|
||||
} else {
|
||||
collect(c, p);
|
||||
|
||||
if (c->collectionMode == OverflowCollection) {
|
||||
return;
|
||||
} else if (c->gen2.contains(*p)) {
|
||||
// done
|
||||
} else {
|
||||
map->setOnly(p);
|
||||
*dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(c, wasDirty or not expectDirty);
|
||||
}
|
||||
|
||||
class ObjectSegmentIterator {
|
||||
public:
|
||||
ObjectSegmentIterator(Context* c, Segment* s, unsigned end):
|
||||
c(c), s(s), index(0), end(end)
|
||||
{ }
|
||||
|
||||
bool hasNext() {
|
||||
return index < end;
|
||||
}
|
||||
|
||||
object next() {
|
||||
assert(c, hasNext());
|
||||
object p = s->data + (index * BytesPerWord);
|
||||
index += c->client->sizeOf(p) / BytesPerWord;
|
||||
return p;
|
||||
}
|
||||
|
||||
Context* c;
|
||||
Segment* s;
|
||||
unsigned index;
|
||||
unsigned end;
|
||||
};
|
||||
|
||||
void
|
||||
collect(Context* c, Segment* s, unsigned limit)
|
||||
{
|
||||
for (ObjectSegmentIterator it(c, s, limit); it.hasNext();) {
|
||||
object p = it.next();
|
||||
collect(c, &objectClass(p));
|
||||
|
||||
class Walker : public Heap::Walker {
|
||||
public:
|
||||
Walker(Context* c, object p): c(c), p(p) { }
|
||||
|
||||
virtual bool visit(unsigned offset) {
|
||||
collect(c, &cast<object>(p, offset * BytesPerWord));
|
||||
}
|
||||
|
||||
Context* c;
|
||||
object p;
|
||||
} walker(c, p);
|
||||
|
||||
c->client->walk(p, &walker);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
collect2(Context* c)
|
||||
{
|
||||
@ -150,11 +883,11 @@ collect2(Context* c)
|
||||
unsigned start = 0;
|
||||
unsigned end = start + c->gen2.position();
|
||||
bool dirty;
|
||||
collect(m, &(c->map), start, end, &dirty, false);
|
||||
collect(c, &(c->heapMap), start, end, &dirty, false);
|
||||
} else if (c->mode == Gen2Collection) {
|
||||
unsigned ng2Position = c->nextGen2.position();
|
||||
collect(m, &(c->nextGen1), c->nextGen1.position());
|
||||
collect(m, &(c->nextGen2), ng2Position);
|
||||
collect(c, &(c->nextGen1), c->nextGen1.position());
|
||||
collect(c, &(c->nextGen2), ng2Position);
|
||||
}
|
||||
|
||||
class Visitor : public Heap::Visitor {
|
||||
@ -170,7 +903,7 @@ collect2(Context* c)
|
||||
}
|
||||
|
||||
void
|
||||
collect1(Context* c)
|
||||
collect(Context* c)
|
||||
{
|
||||
switch (c->mode) {
|
||||
case MinorCollection: {
|
||||
@ -192,7 +925,7 @@ collect1(Context* c)
|
||||
initNextGen1(c);
|
||||
initNextGen2(c);
|
||||
|
||||
c->map.clear();
|
||||
c->heapMap.clear();
|
||||
|
||||
collect2(c);
|
||||
|
||||
|
@ -54,7 +54,7 @@ class System {
|
||||
virtual ~System() { }
|
||||
|
||||
virtual bool success(Status) = 0;
|
||||
virtual void* allocate(unsigned size) = 0;
|
||||
virtual void* allocate(unsigned* size) = 0;
|
||||
virtual void free(void*) = 0;
|
||||
virtual Status start(Thread*) = 0;
|
||||
virtual Status make(Monitor**) = 0;
|
||||
|
19
src/vm.cpp
19
src/vm.cpp
@ -16,9 +16,6 @@ using namespace vm;
|
||||
|
||||
namespace {
|
||||
|
||||
typedef void* object;
|
||||
typedef unsigned Type;
|
||||
|
||||
class Thread;
|
||||
|
||||
void assert(Thread*, bool);
|
||||
@ -30,8 +27,8 @@ void set(Thread*, object&, object);
|
||||
inline unsigned
|
||||
pad(unsigned n)
|
||||
{
|
||||
unsigned extra = n % sizeof(void*);
|
||||
return (extra ? n + sizeof(void*) - extra : n);
|
||||
unsigned extra = n % BytesPerWord;
|
||||
return (extra ? n + BytesPerWord - extra : n);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@ -996,7 +993,7 @@ fieldSize(Thread* t, object field)
|
||||
return 4;
|
||||
case 'L':
|
||||
case '[':
|
||||
return sizeof(void*);
|
||||
return BytesPerWord;
|
||||
|
||||
default: abort(t);
|
||||
}
|
||||
@ -1011,7 +1008,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
||||
unsigned count = s.read2();
|
||||
if (count) {
|
||||
unsigned memberOffset
|
||||
= classFixedSize(t, classSuper(t, class_)) * sizeof(void*);
|
||||
= classFixedSize(t, classSuper(t, class_)) * BytesPerWord;
|
||||
unsigned staticOffset = 0;
|
||||
|
||||
object fieldTable = makeArray(t, count);
|
||||
@ -1038,9 +1035,9 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
||||
if (flags & ACC_STATIC) {
|
||||
fieldOffset(t, value) = staticOffset++;
|
||||
} else {
|
||||
unsigned excess = memberOffset % sizeof(void*);
|
||||
unsigned excess = memberOffset % BytesPerWord;
|
||||
if (excess and isReferenceField(t, value)) {
|
||||
memberOffset += sizeof(void*) - excess;
|
||||
memberOffset += BytesPerWord - excess;
|
||||
}
|
||||
|
||||
fieldOffset(t, value) = memberOffset;
|
||||
@ -1054,7 +1051,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
||||
|
||||
if (staticOffset) {
|
||||
object staticTable = makeArray(t, staticOffset);
|
||||
memset(&arrayBody(t, staticTable, 0), 0, staticOffset * sizeof(void*));
|
||||
memset(&arrayBody(t, staticTable, 0), 0, staticOffset * BytesPerWord);
|
||||
|
||||
set(t, classStaticTable(t, class_), staticTable);
|
||||
}
|
||||
@ -1604,7 +1601,7 @@ run(Thread* t)
|
||||
push(t, makeInt(t, objectArrayLength(t, array)));
|
||||
} else {
|
||||
// for all other array types, the length follow the class pointer.
|
||||
push(t, makeInt(t, cast<uint32_t>(array, sizeof(void*))));
|
||||
push(t, makeInt(t, cast<uint32_t>(array, BytesPerWord)));
|
||||
}
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
|
Loading…
x
Reference in New Issue
Block a user