mirror of
https://github.com/corda/corda.git
synced 2025-06-01 15:10:54 +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 MACRO_MakeNameXY(FX, LINE) MACRO_XY(FX, LINE)
|
||||||
#define MAKE_NAME(FX) MACRO_MakeNameXY(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
|
#endif//COMMON_H
|
||||||
|
749
src/heap.cpp
749
src/heap.cpp
@ -1,14 +1,652 @@
|
|||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
using namespace vm;
|
using namespace vm;
|
||||||
|
|
||||||
namespace {
|
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 {
|
class Context {
|
||||||
public:
|
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
|
void
|
||||||
collect(Context* c, void** p)
|
collect(Context* c, void** p)
|
||||||
{
|
{
|
||||||
@ -81,7 +719,6 @@ collect(Context* c, void** p)
|
|||||||
// descend
|
// descend
|
||||||
if (walker.visits > 1) {
|
if (walker.visits > 1) {
|
||||||
::parent(original) = parent;
|
::parent(original) = parent;
|
||||||
|
|
||||||
parent = original;
|
parent = original;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,7 +736,8 @@ collect(Context* c, void** p)
|
|||||||
|
|
||||||
class Walker : public Heap::Walker {
|
class Walker : public Heap::Walker {
|
||||||
public:
|
public:
|
||||||
Walker(uintptr_t* bitset):
|
Walker(Context* c, uintptr_t* bitset):
|
||||||
|
c(c),
|
||||||
bitset(bitset),
|
bitset(bitset),
|
||||||
next(0),
|
next(0),
|
||||||
total(0)
|
total(0)
|
||||||
@ -115,7 +753,7 @@ collect(Context* c, void** p)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
next = bitsetNext(bitset);
|
next = bitsetNext(c, bitset);
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -123,6 +761,7 @@ collect(Context* c, void** p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Context* c;
|
||||||
uintptr_t* bitset;
|
uintptr_t* bitset;
|
||||||
unsigned next;
|
unsigned next;
|
||||||
unsigned total;
|
unsigned total;
|
||||||
@ -138,11 +777,105 @@ collect(Context* c, void** p)
|
|||||||
|
|
||||||
original = cast<object>(copy, walker.next * sizeof(void*));
|
original = cast<object>(copy, walker.next * sizeof(void*));
|
||||||
cast<object>(copy, walker.next * sizeof(void*)) = follow(original);
|
cast<object>(copy, walker.next * sizeof(void*)) = follow(original);
|
||||||
|
goto visit;
|
||||||
} else {
|
} else {
|
||||||
return;
|
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
|
void
|
||||||
collect2(Context* c)
|
collect2(Context* c)
|
||||||
{
|
{
|
||||||
@ -150,11 +883,11 @@ collect2(Context* c)
|
|||||||
unsigned start = 0;
|
unsigned start = 0;
|
||||||
unsigned end = start + c->gen2.position();
|
unsigned end = start + c->gen2.position();
|
||||||
bool dirty;
|
bool dirty;
|
||||||
collect(m, &(c->map), start, end, &dirty, false);
|
collect(c, &(c->heapMap), start, end, &dirty, false);
|
||||||
} else if (c->mode == Gen2Collection) {
|
} else if (c->mode == Gen2Collection) {
|
||||||
unsigned ng2Position = c->nextGen2.position();
|
unsigned ng2Position = c->nextGen2.position();
|
||||||
collect(m, &(c->nextGen1), c->nextGen1.position());
|
collect(c, &(c->nextGen1), c->nextGen1.position());
|
||||||
collect(m, &(c->nextGen2), ng2Position);
|
collect(c, &(c->nextGen2), ng2Position);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Visitor : public Heap::Visitor {
|
class Visitor : public Heap::Visitor {
|
||||||
@ -170,7 +903,7 @@ collect2(Context* c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
collect1(Context* c)
|
collect(Context* c)
|
||||||
{
|
{
|
||||||
switch (c->mode) {
|
switch (c->mode) {
|
||||||
case MinorCollection: {
|
case MinorCollection: {
|
||||||
@ -192,7 +925,7 @@ collect1(Context* c)
|
|||||||
initNextGen1(c);
|
initNextGen1(c);
|
||||||
initNextGen2(c);
|
initNextGen2(c);
|
||||||
|
|
||||||
c->map.clear();
|
c->heapMap.clear();
|
||||||
|
|
||||||
collect2(c);
|
collect2(c);
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ class System {
|
|||||||
virtual ~System() { }
|
virtual ~System() { }
|
||||||
|
|
||||||
virtual bool success(Status) = 0;
|
virtual bool success(Status) = 0;
|
||||||
virtual void* allocate(unsigned size) = 0;
|
virtual void* allocate(unsigned* size) = 0;
|
||||||
virtual void free(void*) = 0;
|
virtual void free(void*) = 0;
|
||||||
virtual Status start(Thread*) = 0;
|
virtual Status start(Thread*) = 0;
|
||||||
virtual Status make(Monitor**) = 0;
|
virtual Status make(Monitor**) = 0;
|
||||||
|
19
src/vm.cpp
19
src/vm.cpp
@ -16,9 +16,6 @@ using namespace vm;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
typedef void* object;
|
|
||||||
typedef unsigned Type;
|
|
||||||
|
|
||||||
class Thread;
|
class Thread;
|
||||||
|
|
||||||
void assert(Thread*, bool);
|
void assert(Thread*, bool);
|
||||||
@ -30,8 +27,8 @@ void set(Thread*, object&, object);
|
|||||||
inline unsigned
|
inline unsigned
|
||||||
pad(unsigned n)
|
pad(unsigned n)
|
||||||
{
|
{
|
||||||
unsigned extra = n % sizeof(void*);
|
unsigned extra = n % BytesPerWord;
|
||||||
return (extra ? n + sizeof(void*) - extra : n);
|
return (extra ? n + BytesPerWord - extra : n);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
@ -996,7 +993,7 @@ fieldSize(Thread* t, object field)
|
|||||||
return 4;
|
return 4;
|
||||||
case 'L':
|
case 'L':
|
||||||
case '[':
|
case '[':
|
||||||
return sizeof(void*);
|
return BytesPerWord;
|
||||||
|
|
||||||
default: abort(t);
|
default: abort(t);
|
||||||
}
|
}
|
||||||
@ -1011,7 +1008,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
unsigned count = s.read2();
|
unsigned count = s.read2();
|
||||||
if (count) {
|
if (count) {
|
||||||
unsigned memberOffset
|
unsigned memberOffset
|
||||||
= classFixedSize(t, classSuper(t, class_)) * sizeof(void*);
|
= classFixedSize(t, classSuper(t, class_)) * BytesPerWord;
|
||||||
unsigned staticOffset = 0;
|
unsigned staticOffset = 0;
|
||||||
|
|
||||||
object fieldTable = makeArray(t, count);
|
object fieldTable = makeArray(t, count);
|
||||||
@ -1038,9 +1035,9 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
if (flags & ACC_STATIC) {
|
if (flags & ACC_STATIC) {
|
||||||
fieldOffset(t, value) = staticOffset++;
|
fieldOffset(t, value) = staticOffset++;
|
||||||
} else {
|
} else {
|
||||||
unsigned excess = memberOffset % sizeof(void*);
|
unsigned excess = memberOffset % BytesPerWord;
|
||||||
if (excess and isReferenceField(t, value)) {
|
if (excess and isReferenceField(t, value)) {
|
||||||
memberOffset += sizeof(void*) - excess;
|
memberOffset += BytesPerWord - excess;
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldOffset(t, value) = memberOffset;
|
fieldOffset(t, value) = memberOffset;
|
||||||
@ -1054,7 +1051,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
|
|
||||||
if (staticOffset) {
|
if (staticOffset) {
|
||||||
object staticTable = makeArray(t, 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);
|
set(t, classStaticTable(t, class_), staticTable);
|
||||||
}
|
}
|
||||||
@ -1604,7 +1601,7 @@ run(Thread* t)
|
|||||||
push(t, makeInt(t, objectArrayLength(t, array)));
|
push(t, makeInt(t, objectArrayLength(t, array)));
|
||||||
} else {
|
} else {
|
||||||
// for all other array types, the length follow the class pointer.
|
// 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 {
|
} else {
|
||||||
exception = makeNullPointerException(t);
|
exception = makeNullPointerException(t);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user