2007-06-20 02:28:31 +00:00
|
|
|
#include "heap.h"
|
|
|
|
#include "system.h"
|
2007-06-20 04:26:36 +00:00
|
|
|
#include "common.h"
|
2007-06-20 02:28:31 +00:00
|
|
|
|
|
|
|
using namespace vm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2007-06-20 16:58:35 +00:00
|
|
|
// an object must survive TenureThreshold + 2 garbage collections
|
|
|
|
// before being copied to gen2:
|
|
|
|
static const unsigned TenureThreshold = 3;
|
|
|
|
|
|
|
|
static const unsigned MinimumGen1Size = 64 * 1024;
|
|
|
|
static const unsigned MinimumGen2Size = 128 * 1024;
|
|
|
|
|
|
|
|
class Context;
|
|
|
|
|
|
|
|
System* system(Context*);
|
|
|
|
void NO_RETURN abort(Context*);
|
|
|
|
void assert(Context*, bool);
|
|
|
|
|
2007-06-21 18:35:24 +00:00
|
|
|
void
|
2007-06-21 19:43:33 +00:00
|
|
|
indent(unsigned /*i*/)
|
2007-06-21 18:35:24 +00:00
|
|
|
{
|
2007-06-21 19:43:33 +00:00
|
|
|
//for (; i > 0; --i) fprintf(stderr, " ");
|
2007-06-21 18:35:24 +00:00
|
|
|
}
|
|
|
|
|
2007-06-20 04:26:36 +00:00
|
|
|
class Segment {
|
|
|
|
public:
|
|
|
|
class Map {
|
|
|
|
public:
|
|
|
|
class Iterator {
|
|
|
|
public:
|
|
|
|
Map* map;
|
|
|
|
unsigned index;
|
|
|
|
unsigned limit;
|
|
|
|
|
2007-06-20 17:42:13 +00:00
|
|
|
Iterator(Map* map, unsigned start, unsigned end):
|
2007-06-20 04:26:36 +00:00
|
|
|
map(map)
|
|
|
|
{
|
2007-06-20 16:58:35 +00:00
|
|
|
assert(map->segment->context, map);
|
|
|
|
assert(map->segment->context, map->bitsPerRecord == 1);
|
|
|
|
assert(map->segment->context, map->segment);
|
2007-06-20 04:26:36 +00:00
|
|
|
|
2007-06-20 17:42:13 +00:00
|
|
|
index = map->indexOf(map->segment->data + start);
|
|
|
|
assert(map->segment->context, index == 0 or start != 0);
|
2007-06-20 04:26:36 +00:00
|
|
|
|
2007-06-20 17:42:13 +00:00
|
|
|
if (end > map->segment->position) end = map->segment->position;
|
2007-06-20 04:26:36 +00:00
|
|
|
|
2007-06-20 17:42:13 +00:00
|
|
|
limit = map->indexOf(map->segment->data + end);
|
|
|
|
if (end - start % map->scale) ++ limit;
|
2007-06-20 04:26:36 +00:00
|
|
|
|
|
|
|
// printf("iterating from %p (index %d) to %p (index %d) "
|
|
|
|
// "(%d of %d bytes) (scale: %d)\n",
|
2007-06-20 05:16:43 +00:00
|
|
|
// start, index, end, limit, (end - start) * BytesPerWord,
|
|
|
|
// map->segment->position * BytesPerWord, map->scale);
|
2007-06-20 04:26:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool hasMore() {
|
2007-06-20 16:58:35 +00:00
|
|
|
assert(map->segment->context, map);
|
2007-06-20 04:26:36 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2007-06-20 05:16:43 +00:00
|
|
|
uintptr_t* p = map->data() + word;
|
2007-06-20 04:26:36 +00:00
|
|
|
if (*p) {
|
|
|
|
for (; bit < BitsPerWord and (word < wordLimit or bit < bitLimit);
|
|
|
|
++bit)
|
|
|
|
{
|
2007-06-20 05:16:43 +00:00
|
|
|
if (map->data()[word] & (static_cast<uintptr_t>(1) << bit)) {
|
2007-06-20 04:26:36 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2007-06-20 17:42:13 +00:00
|
|
|
unsigned next() {
|
2007-06-20 05:16:43 +00:00
|
|
|
assert(map->segment->context, hasMore());
|
|
|
|
assert(map->segment->context, map->segment);
|
2007-06-20 04:26:36 +00:00
|
|
|
|
2007-06-20 17:42:13 +00:00
|
|
|
return (index++) * map->scale;
|
2007-06-20 04:26:36 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Segment* segment;
|
|
|
|
unsigned bitsPerRecord;
|
|
|
|
unsigned scale;
|
|
|
|
Map* child;
|
|
|
|
|
2007-06-20 16:58:35 +00:00
|
|
|
Map(Segment* segment = 0, unsigned bitsPerRecord = 1,
|
|
|
|
unsigned scale = 1, Map* child = 0):
|
|
|
|
segment(segment),
|
|
|
|
bitsPerRecord(bitsPerRecord),
|
|
|
|
scale(scale),
|
|
|
|
child(child)
|
2007-06-20 04:26:36 +00:00
|
|
|
{
|
2007-06-20 21:27:22 +00:00
|
|
|
if (segment) {
|
|
|
|
assert(segment->context, bitsPerRecord);
|
|
|
|
assert(segment->context, scale);
|
|
|
|
assert(segment->context, powerOfTwo(scale));
|
|
|
|
}
|
2007-06-20 16:58:35 +00:00
|
|
|
}
|
2007-06-20 04:26:36 +00:00
|
|
|
|
2007-06-21 20:44:35 +00:00
|
|
|
void replaceWith(Map* m) {
|
|
|
|
assert(segment->context, m);
|
|
|
|
assert(segment->context, bitsPerRecord == m->bitsPerRecord);
|
|
|
|
assert(segment->context, scale == m->scale);
|
|
|
|
|
|
|
|
m->segment = 0;
|
|
|
|
|
|
|
|
if (child) child->replaceWith(m->child);
|
|
|
|
}
|
|
|
|
|
2007-06-20 16:58:35 +00:00
|
|
|
unsigned offset() {
|
|
|
|
unsigned n = segment->capacity;
|
2007-06-20 17:42:13 +00:00
|
|
|
if (child) n += child->footprint(segment->capacity);
|
2007-06-20 16:58:35 +00:00
|
|
|
return n;
|
2007-06-20 04:26:36 +00:00
|
|
|
}
|
|
|
|
|
2007-06-20 05:16:43 +00:00
|
|
|
uintptr_t* data() {
|
2007-06-20 16:58:35 +00:00
|
|
|
return segment->data + offset();
|
2007-06-20 04:26:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned size(unsigned capacity) {
|
2007-06-20 16:58:35 +00:00
|
|
|
unsigned result
|
|
|
|
= divide(divide(capacity, scale) * bitsPerRecord, BitsPerWord);
|
2007-06-20 05:16:43 +00:00
|
|
|
assert(segment->context, result);
|
2007-06-20 04:26:36 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned size() {
|
|
|
|
return size(max(segment->capacity, 1));
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned indexOf(void* p) {
|
2007-06-20 05:16:43 +00:00
|
|
|
assert(segment->context,
|
|
|
|
segment->position
|
2007-06-20 04:26:36 +00:00
|
|
|
and p >= segment->data
|
|
|
|
and p <= segment->data + segment->position);
|
2007-06-20 05:16:43 +00:00
|
|
|
assert(segment->context, segment->data);
|
2007-06-20 04:26:36 +00:00
|
|
|
|
2007-06-20 05:16:43 +00:00
|
|
|
return ((static_cast<void**>(p)
|
|
|
|
- reinterpret_cast<void**>(segment->data))
|
|
|
|
/ scale) * bitsPerRecord;
|
2007-06-20 04:26:36 +00:00
|
|
|
}
|
|
|
|
|
2007-06-20 05:16:43 +00:00
|
|
|
void update(uintptr_t* segmentData) {
|
2007-06-20 16:58:35 +00:00
|
|
|
uintptr_t* p = segmentData + offset();
|
|
|
|
memcpy(p, data(), size(segment->position) * BytesPerWord);
|
2007-06-20 04:26:36 +00:00
|
|
|
|
2007-06-20 05:16:43 +00:00
|
|
|
if (child) child->update(segmentData);
|
2007-06-20 04:26:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void clear() {
|
2007-06-20 16:58:35 +00:00
|
|
|
memset(data(), 0, size() * BytesPerWord);
|
2007-06-20 04:26:36 +00:00
|
|
|
|
|
|
|
if (child) child->clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void clear(unsigned i) {
|
2007-06-20 16:58:35 +00:00
|
|
|
data()[wordOf(i)] &= ~(static_cast<uintptr_t>(1) << bitOf(i));
|
2007-06-20 04:26:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void set(unsigned i) {
|
2007-06-20 16:58:35 +00:00
|
|
|
data()[wordOf(i)] |= static_cast<uintptr_t>(1) << bitOf(i);
|
2007-06-20 04:26:36 +00:00
|
|
|
}
|
|
|
|
|
2007-06-20 17:42:13 +00:00
|
|
|
void clearOnly(unsigned index) {
|
2007-06-20 04:26:36 +00:00
|
|
|
for (unsigned i = index, limit = index + bitsPerRecord; i < limit; ++i) {
|
|
|
|
clear(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-20 17:42:13 +00:00
|
|
|
void clearOnly(void* p) {
|
|
|
|
clearOnly(indexOf(p));
|
|
|
|
}
|
|
|
|
|
2007-06-20 04:26:36 +00:00
|
|
|
void clear(void* p) {
|
|
|
|
clearOnly(p);
|
|
|
|
if (child) child->clear(p);
|
|
|
|
}
|
|
|
|
|
2007-06-20 17:42:13 +00:00
|
|
|
void setOnly(unsigned index, unsigned v = 1) {
|
2007-06-20 04:26:36 +00:00
|
|
|
unsigned i = index + bitsPerRecord - 1;
|
|
|
|
while (true) {
|
|
|
|
if (v & 1) set(i); else clear(i);
|
|
|
|
v >>= 1;
|
|
|
|
if (i == index) break;
|
|
|
|
--i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-20 17:42:13 +00:00
|
|
|
void setOnly(void* p, unsigned v = 1) {
|
|
|
|
setOnly(indexOf(p), v);
|
|
|
|
}
|
|
|
|
|
2007-06-20 04:26:36 +00:00
|
|
|
void set(void* p, unsigned v = 1) {
|
|
|
|
setOnly(p, v);
|
2007-06-20 16:58:35 +00:00
|
|
|
assert(segment->context, get(p) == v);
|
2007-06-20 04:26:36 +00:00
|
|
|
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;
|
2007-06-20 16:58:35 +00:00
|
|
|
v |= ((data()[wordOf(i)]) & (static_cast<uintptr_t>(1) << wi)) >> wi;
|
2007-06-20 04:26:36 +00:00
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned footprint(unsigned capacity) {
|
|
|
|
unsigned n = size(capacity);
|
|
|
|
if (child) n += child->footprint(capacity);
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2007-06-20 16:58:35 +00:00
|
|
|
void setSegment(Segment* s) {
|
2007-06-20 04:26:36 +00:00
|
|
|
segment = s;
|
2007-06-20 16:58:35 +00:00
|
|
|
|
2007-06-20 04:26:36 +00:00
|
|
|
if (child) child->setSegment(s);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2007-06-20 17:42:13 +00:00
|
|
|
Context* context;
|
2007-06-20 04:26:36 +00:00
|
|
|
uintptr_t* data;
|
|
|
|
unsigned position;
|
|
|
|
unsigned capacity;
|
|
|
|
Map* map;
|
|
|
|
|
2007-06-20 16:58:35 +00:00
|
|
|
Segment(Context* context, unsigned capacity, Map* map = 0,
|
|
|
|
bool clearMap = true):
|
|
|
|
context(context),
|
|
|
|
data(0),
|
|
|
|
position(0),
|
|
|
|
capacity(capacity),
|
|
|
|
map(map)
|
2007-06-20 05:16:43 +00:00
|
|
|
{
|
2007-06-20 04:26:36 +00:00
|
|
|
if (capacity) {
|
2007-06-20 19:20:25 +00:00
|
|
|
data = static_cast<uintptr_t*>
|
|
|
|
(system(context)->allocate(footprint(capacity) * BytesPerWord));
|
2007-06-20 05:16:43 +00:00
|
|
|
|
|
|
|
if (map) {
|
2007-06-20 16:58:35 +00:00
|
|
|
map->setSegment(this);
|
|
|
|
if (clearMap) map->clear();
|
2007-06-20 05:16:43 +00:00
|
|
|
}
|
2007-06-20 04:26:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-20 16:58:35 +00:00
|
|
|
unsigned footprint(unsigned capacity) {
|
|
|
|
unsigned n = capacity;
|
2007-06-21 20:44:35 +00:00
|
|
|
if (map) n += map->footprint(capacity);
|
2007-06-20 16:58:35 +00:00
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned footprint() {
|
|
|
|
return footprint(capacity);
|
|
|
|
}
|
|
|
|
|
2007-06-20 05:16:43 +00:00
|
|
|
void* allocate(unsigned size) {
|
2007-06-20 17:42:13 +00:00
|
|
|
assert(context, size);
|
|
|
|
assert(context, position + size <= capacity);
|
2007-06-20 05:16:43 +00:00
|
|
|
void* p = reinterpret_cast<void**>(data) + position;
|
|
|
|
position += size;
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
void* add(void* p, unsigned size) {
|
2007-06-20 04:26:36 +00:00
|
|
|
void* target = allocate(size);
|
2007-06-20 05:16:43 +00:00
|
|
|
memcpy(target, p, size * BytesPerWord);
|
2007-06-20 04:26:36 +00:00
|
|
|
return target;
|
|
|
|
}
|
|
|
|
|
2007-06-20 17:42:13 +00:00
|
|
|
void* get(unsigned offset) {
|
|
|
|
assert(context, offset < position);
|
|
|
|
return data + offset;
|
|
|
|
}
|
|
|
|
|
2007-06-20 04:26:36 +00:00
|
|
|
unsigned remaining() {
|
2007-06-20 05:16:43 +00:00
|
|
|
return capacity - position;
|
2007-06-20 04:26:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void replaceWith(Segment* s) {
|
2007-06-21 20:44:35 +00:00
|
|
|
if (data) system(context)->free(data);
|
2007-06-20 04:26:36 +00:00
|
|
|
|
|
|
|
data = s->data;
|
|
|
|
s->data = 0;
|
|
|
|
|
|
|
|
position = s->position;
|
|
|
|
s->position = 0;
|
|
|
|
|
|
|
|
capacity = s->capacity;
|
|
|
|
s->capacity = 0;
|
|
|
|
|
|
|
|
if (s->map) {
|
2007-06-21 20:44:35 +00:00
|
|
|
if (map) {
|
|
|
|
map->replaceWith(s->map);
|
|
|
|
} else {
|
|
|
|
map = s->map;
|
|
|
|
map->setSegment(this);
|
|
|
|
}
|
2007-06-20 04:26:36 +00:00
|
|
|
s->map = 0;
|
|
|
|
} else {
|
2007-06-20 16:58:35 +00:00
|
|
|
map = 0;
|
2007-06-20 04:26:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-20 05:16:43 +00:00
|
|
|
void grow(unsigned extra) {
|
|
|
|
if (remaining() < extra) {
|
|
|
|
unsigned minimumNeeded = position + extra;
|
2007-06-20 04:26:36 +00:00
|
|
|
unsigned count = minimumNeeded * 2;
|
2007-06-20 05:16:43 +00:00
|
|
|
|
2007-06-20 16:58:35 +00:00
|
|
|
minimumNeeded = footprint(minimumNeeded) * BytesPerWord;
|
|
|
|
count = footprint(count) * BytesPerWord;
|
2007-06-20 04:26:36 +00:00
|
|
|
|
2007-06-20 05:16:43 +00:00
|
|
|
uintptr_t* p = static_cast<uintptr_t*>
|
|
|
|
(system(context)->allocate(&count));
|
2007-06-20 04:26:36 +00:00
|
|
|
|
|
|
|
if (count >= minimumNeeded) {
|
2007-06-20 05:16:43 +00:00
|
|
|
memcpy(p, data, position * BytesPerWord);
|
|
|
|
|
|
|
|
if (map) {
|
|
|
|
map->update(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
data = p;
|
|
|
|
system(context)->free(data);
|
2007-06-20 04:26:36 +00:00
|
|
|
} else {
|
2007-06-20 05:16:43 +00:00
|
|
|
abort(context);
|
2007-06-20 04:26:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool contains(void* p) {
|
|
|
|
return position and p >= data and p < data + position;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dispose() {
|
2007-06-20 16:58:35 +00:00
|
|
|
system(context)->free(data);
|
2007-06-20 04:26:36 +00:00
|
|
|
data = 0;
|
|
|
|
position = 0;
|
|
|
|
capacity = 0;
|
|
|
|
|
|
|
|
map = 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2007-06-20 16:58:35 +00:00
|
|
|
enum CollectionMode {
|
|
|
|
MinorCollection,
|
|
|
|
MajorCollection,
|
|
|
|
OverflowCollection,
|
|
|
|
Gen2Collection
|
|
|
|
};
|
|
|
|
|
2007-06-20 02:28:31 +00:00
|
|
|
class Context {
|
|
|
|
public:
|
2007-06-20 17:42:13 +00:00
|
|
|
Context(System* system):
|
|
|
|
system(system),
|
|
|
|
client(0),
|
|
|
|
gen1(this, 0),
|
|
|
|
nextGen1(this, 0),
|
|
|
|
gen2(this, 0),
|
|
|
|
nextGen2(this, 0)
|
|
|
|
{ }
|
2007-06-20 16:58:35 +00:00
|
|
|
|
|
|
|
void dispose() {
|
|
|
|
gen1.dispose();
|
|
|
|
nextGen1.dispose();
|
|
|
|
gen2.dispose();
|
|
|
|
nextGen2.dispose();
|
|
|
|
}
|
|
|
|
|
|
|
|
System* system;
|
2007-06-20 17:42:13 +00:00
|
|
|
Heap::Client* client;
|
2007-06-20 16:58:35 +00:00
|
|
|
|
|
|
|
Segment gen1;
|
|
|
|
Segment nextGen1;
|
|
|
|
Segment gen2;
|
|
|
|
Segment nextGen2;
|
|
|
|
|
|
|
|
Segment::Map ageMap;
|
2007-06-20 17:42:13 +00:00
|
|
|
Segment::Map nextAgeMap;
|
2007-06-20 16:58:35 +00:00
|
|
|
Segment::Map pointerMap;
|
|
|
|
Segment::Map pageMap;
|
|
|
|
Segment::Map heapMap;
|
|
|
|
|
|
|
|
CollectionMode mode;
|
2007-06-21 18:35:24 +00:00
|
|
|
|
|
|
|
unsigned depth;
|
2007-06-20 02:28:31 +00:00
|
|
|
};
|
|
|
|
|
2007-06-20 16:58:35 +00:00
|
|
|
inline System*
|
|
|
|
system(Context* c)
|
|
|
|
{
|
|
|
|
return c->system;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void NO_RETURN
|
|
|
|
abort(Context* c)
|
|
|
|
{
|
|
|
|
c->system->abort(); // this should not return
|
|
|
|
::abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
assert(Context* c, bool v)
|
|
|
|
{
|
|
|
|
if (UNLIKELY(not v)) abort(c);
|
|
|
|
}
|
|
|
|
|
2007-06-20 04:26:36 +00:00
|
|
|
void
|
|
|
|
initGen1(Context* c)
|
|
|
|
{
|
2007-06-20 16:58:35 +00:00
|
|
|
new (&(c->ageMap)) Segment::Map(&(c->gen1), log(TenureThreshold));
|
|
|
|
new (&(c->gen1)) Segment
|
2007-06-20 17:42:13 +00:00
|
|
|
(c, MinimumGen1Size / BytesPerWord, &(c->ageMap), false);
|
2007-06-20 04:26:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
initGen2(Context* c)
|
|
|
|
{
|
2007-06-20 16:58:35 +00:00
|
|
|
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));
|
2007-06-20 17:42:13 +00:00
|
|
|
new (&(c->gen2)) Segment(c, MinimumGen2Size / BytesPerWord, &(c->heapMap));
|
2007-06-20 04:26:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
initNextGen1(Context* c)
|
|
|
|
{
|
2007-06-20 16:58:35 +00:00
|
|
|
unsigned size = max(MinimumGen1Size / BytesPerWord,
|
2007-06-20 17:42:13 +00:00
|
|
|
nextPowerOfTwo(c->gen1.position));
|
2007-06-20 16:58:35 +00:00
|
|
|
new (&(c->nextAgeMap)) Segment::Map(&(c->nextGen1), log(TenureThreshold));
|
2007-06-20 17:42:13 +00:00
|
|
|
new (&(c->nextGen1)) Segment(c, size, &(c->nextAgeMap), false);
|
2007-06-20 04:26:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
initNextGen2(Context* c)
|
|
|
|
{
|
2007-06-20 16:58:35 +00:00
|
|
|
unsigned size = max(MinimumGen2Size / BytesPerWord,
|
2007-06-20 17:42:13 +00:00
|
|
|
nextPowerOfTwo(c->gen2.position));
|
2007-06-20 16:58:35 +00:00
|
|
|
new (&(c->pointerMap)) Segment::Map(&(c->nextGen2));
|
|
|
|
new (&(c->pageMap)) Segment::Map
|
|
|
|
(&(c->nextGen2), 1, LikelyPageSize / BytesPerWord, &(c->pointerMap));
|
|
|
|
new (&(c->heapMap)) Segment::Map
|
|
|
|
(&(c->nextGen2), 1, c->pageMap.scale * 1024, &(c->pageMap));
|
2007-06-20 17:42:13 +00:00
|
|
|
new (&(c->nextGen2)) Segment(c, size, &(c->heapMap));
|
2007-06-20 04:26:36 +00:00
|
|
|
c->gen2.map = 0;
|
|
|
|
}
|
|
|
|
|
2007-06-21 18:35:24 +00:00
|
|
|
inline bool
|
|
|
|
wasCollected(Context* c, object o)
|
2007-06-20 04:26:36 +00:00
|
|
|
{
|
2007-06-21 18:35:24 +00:00
|
|
|
return o and
|
|
|
|
(not c->nextGen1.contains(o)) and
|
|
|
|
(not c->nextGen2.contains(o)) and
|
|
|
|
(c->nextGen1.contains(cast<object>(o, 0)) or
|
|
|
|
c->nextGen2.contains(cast<object>(o, 0)));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline object
|
|
|
|
follow(Context* c, object o)
|
|
|
|
{
|
|
|
|
assert(c, wasCollected(c, o));
|
2007-06-20 04:26:36 +00:00
|
|
|
return cast<object>(o, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline object&
|
2007-06-21 18:35:24 +00:00
|
|
|
parent(Context* c, object o)
|
2007-06-20 04:26:36 +00:00
|
|
|
{
|
2007-06-21 18:35:24 +00:00
|
|
|
assert(c, wasCollected(c, o));
|
2007-06-20 04:26:36 +00:00
|
|
|
return cast<object>(o, BytesPerWord);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline uintptr_t*
|
2007-06-21 18:35:24 +00:00
|
|
|
bitset(Context* c, object o)
|
2007-06-20 04:26:36 +00:00
|
|
|
{
|
2007-06-21 18:35:24 +00:00
|
|
|
assert(c, wasCollected(c, o));
|
2007-06-20 04:26:36 +00:00
|
|
|
return &cast<uintptr_t>(o, BytesPerWord * 2);
|
|
|
|
}
|
|
|
|
|
2007-06-20 17:42:13 +00:00
|
|
|
inline object
|
|
|
|
copyTo(Context*, Segment* s, object o, unsigned size)
|
2007-06-20 04:26:36 +00:00
|
|
|
{
|
2007-06-20 05:16:43 +00:00
|
|
|
if (s->remaining() < size) {
|
2007-06-20 17:42:13 +00:00
|
|
|
s->grow(size);
|
2007-06-20 04:26:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return static_cast<object>(s->add(o, size));
|
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
copy2(Context* c, object o)
|
|
|
|
{
|
2007-06-20 05:16:43 +00:00
|
|
|
unsigned size = c->client->sizeInWords(o);
|
2007-06-20 04:26:36 +00:00
|
|
|
|
|
|
|
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);
|
2007-06-20 17:42:13 +00:00
|
|
|
if (age == TenureThreshold) {
|
2007-06-20 04:26:36 +00:00
|
|
|
if (c->mode == MinorCollection) {
|
2007-06-20 17:42:13 +00:00
|
|
|
if (c->gen2.data == 0) initGen2(c);
|
2007-06-20 04:26:36 +00:00
|
|
|
|
2007-06-20 05:16:43 +00:00
|
|
|
if (c->gen2.remaining() >= size) {
|
2007-06-20 04:26:36 +00:00
|
|
|
return copyTo(c, &(c->gen2), o, size);
|
|
|
|
} else {
|
|
|
|
c->mode = OverflowCollection;
|
2007-06-20 17:42:13 +00:00
|
|
|
initNextGen2(c);
|
2007-06-20 04:26:36 +00:00
|
|
|
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);
|
|
|
|
|
2007-06-21 18:35:24 +00:00
|
|
|
indent(c->depth);
|
|
|
|
fprintf(stderr, "copy %p to %p\n", o, r);
|
|
|
|
|
2007-06-20 04:26:36 +00:00
|
|
|
// leave a pointer to the copy in the original
|
2007-06-21 18:35:24 +00:00
|
|
|
cast<object>(o, 0) = r;
|
2007-06-20 04:26:36 +00:00
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
update3(Context* c, object *p, bool* needsVisit)
|
|
|
|
{
|
|
|
|
if (wasCollected(c, *p)) {
|
|
|
|
*needsVisit = false;
|
2007-06-21 18:35:24 +00:00
|
|
|
return follow(c, *p);
|
2007-06-20 04:26:36 +00:00
|
|
|
} 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-20 02:28:31 +00:00
|
|
|
void
|
|
|
|
collect(Context* c, void** p)
|
|
|
|
{
|
|
|
|
object original = *p;
|
|
|
|
object parent = 0;
|
|
|
|
|
2007-06-21 18:35:24 +00:00
|
|
|
indent(c->depth);
|
|
|
|
fprintf(stderr, "update %p at %p\n", *p, p);
|
|
|
|
|
2007-06-20 02:28:31 +00:00
|
|
|
bool needsVisit;
|
|
|
|
*p = update(c, p, &needsVisit);
|
|
|
|
|
2007-06-21 18:35:24 +00:00
|
|
|
indent(c->depth);
|
|
|
|
fprintf(stderr, " result: %p (visit? %d)\n", *p, needsVisit);
|
|
|
|
|
2007-06-20 02:28:31 +00:00
|
|
|
if (not needsVisit) return;
|
|
|
|
|
|
|
|
visit: {
|
2007-06-21 18:35:24 +00:00
|
|
|
object copy = follow(c, original);
|
2007-06-20 02:28:31 +00:00
|
|
|
|
|
|
|
class Walker : public Heap::Walker {
|
|
|
|
public:
|
|
|
|
Walker(Context* c, object copy, uintptr_t* bitset):
|
|
|
|
c(c),
|
|
|
|
copy(copy),
|
|
|
|
bitset(bitset),
|
|
|
|
first(0),
|
2007-06-21 18:35:24 +00:00
|
|
|
second(0),
|
2007-06-20 02:28:31 +00:00
|
|
|
last(0),
|
|
|
|
visits(0),
|
|
|
|
total(0)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual bool visit(unsigned offset) {
|
2007-06-21 18:35:24 +00:00
|
|
|
indent(c->depth);
|
|
|
|
fprintf(stderr, " update %p at %p - offset %d from %p\n",
|
|
|
|
cast<object>(copy, offset * BytesPerWord),
|
|
|
|
&cast<object>(copy, offset * BytesPerWord),
|
|
|
|
offset,
|
|
|
|
copy);
|
|
|
|
|
2007-06-20 02:28:31 +00:00
|
|
|
bool needsVisit;
|
|
|
|
object childCopy = update
|
2007-06-20 05:16:43 +00:00
|
|
|
(c, &cast<object>(copy, offset * BytesPerWord), &needsVisit);
|
2007-06-20 02:28:31 +00:00
|
|
|
|
2007-06-21 18:35:24 +00:00
|
|
|
indent(c->depth);
|
|
|
|
fprintf(stderr, " result: %p (visit? %d)\n", childCopy, needsVisit);
|
|
|
|
|
2007-06-20 02:28:31 +00:00
|
|
|
++ total;
|
|
|
|
|
|
|
|
if (total == 3) {
|
|
|
|
bitsetInit(bitset);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (needsVisit) {
|
|
|
|
++ visits;
|
|
|
|
|
|
|
|
if (visits == 1) {
|
|
|
|
first = offset;
|
2007-06-21 18:35:24 +00:00
|
|
|
} else if (visits == 2) {
|
|
|
|
second = offset;
|
2007-06-20 02:28:31 +00:00
|
|
|
}
|
2007-06-21 18:35:24 +00:00
|
|
|
} else {
|
|
|
|
cast<object>(copy, offset * BytesPerWord) = childCopy;
|
|
|
|
}
|
2007-06-20 02:28:31 +00:00
|
|
|
|
2007-06-21 19:43:33 +00:00
|
|
|
if (visits > 1 and total > 2 and (second or needsVisit)) {
|
2007-06-21 18:35:24 +00:00
|
|
|
bitsetClear(bitset, last, offset);
|
|
|
|
last = offset;
|
2007-06-20 02:28:31 +00:00
|
|
|
|
2007-06-21 18:35:24 +00:00
|
|
|
if (second) {
|
|
|
|
bitsetSet(bitset, second, true);
|
|
|
|
second = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (needsVisit) {
|
2007-06-20 02:28:31 +00:00
|
|
|
bitsetSet(bitset, offset, true);
|
2007-06-21 18:35:24 +00:00
|
|
|
}
|
2007-06-20 02:28:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Context* c;
|
|
|
|
object copy;
|
|
|
|
uintptr_t* bitset;
|
|
|
|
unsigned first;
|
2007-06-21 18:35:24 +00:00
|
|
|
unsigned second;
|
2007-06-20 02:28:31 +00:00
|
|
|
unsigned last;
|
|
|
|
unsigned visits;
|
|
|
|
unsigned total;
|
2007-06-21 18:35:24 +00:00
|
|
|
} walker(c, copy, bitset(c, original));
|
|
|
|
|
|
|
|
indent(c->depth);
|
|
|
|
fprintf(stderr, "walk %p\n", copy);
|
2007-06-20 02:28:31 +00:00
|
|
|
|
|
|
|
c->client->walk(copy, &walker);
|
|
|
|
|
|
|
|
if (walker.visits) {
|
|
|
|
// descend
|
2007-06-21 18:35:24 +00:00
|
|
|
++ c->depth;
|
2007-06-20 02:28:31 +00:00
|
|
|
if (walker.visits > 1) {
|
2007-06-21 18:35:24 +00:00
|
|
|
::parent(c, original) = parent;
|
2007-06-20 02:28:31 +00:00
|
|
|
parent = original;
|
|
|
|
}
|
|
|
|
|
2007-06-20 05:16:43 +00:00
|
|
|
original = cast<object>(copy, walker.first * BytesPerWord);
|
2007-06-21 18:35:24 +00:00
|
|
|
cast<object>(copy, walker.first * BytesPerWord) = follow(c, original);
|
2007-06-20 02:28:31 +00:00
|
|
|
goto visit;
|
|
|
|
} else {
|
|
|
|
// ascend
|
2007-06-21 18:35:24 +00:00
|
|
|
-- c->depth;
|
2007-06-20 02:28:31 +00:00
|
|
|
original = parent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (original) {
|
2007-06-21 18:35:24 +00:00
|
|
|
object copy = follow(c, original);
|
2007-06-20 02:28:31 +00:00
|
|
|
|
|
|
|
class Walker : public Heap::Walker {
|
|
|
|
public:
|
2007-06-20 04:26:36 +00:00
|
|
|
Walker(Context* c, uintptr_t* bitset):
|
|
|
|
c(c),
|
2007-06-20 02:28:31 +00:00
|
|
|
bitset(bitset),
|
|
|
|
next(0),
|
|
|
|
total(0)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual bool visit(unsigned offset) {
|
|
|
|
switch (++ total) {
|
|
|
|
case 1:
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
next = offset;
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case 3:
|
2007-06-20 04:26:36 +00:00
|
|
|
next = bitsetNext(c, bitset);
|
2007-06-20 02:28:31 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
default:
|
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-20 04:26:36 +00:00
|
|
|
Context* c;
|
2007-06-20 02:28:31 +00:00
|
|
|
uintptr_t* bitset;
|
|
|
|
unsigned next;
|
|
|
|
unsigned total;
|
2007-06-21 18:35:24 +00:00
|
|
|
} walker(c, bitset(c, original));
|
|
|
|
|
|
|
|
indent(c->depth);
|
|
|
|
fprintf(stderr, "scan %p\n", copy);
|
|
|
|
|
|
|
|
c->client->walk(copy, &walker);
|
2007-06-20 02:28:31 +00:00
|
|
|
|
|
|
|
assert(c, walker.total > 1);
|
|
|
|
|
2007-06-21 18:35:24 +00:00
|
|
|
if (walker.total == 3 and bitsetHasMore(bitset(c, original))) {
|
2007-06-20 02:28:31 +00:00
|
|
|
parent = original;
|
|
|
|
} else {
|
2007-06-21 18:35:24 +00:00
|
|
|
parent = ::parent(c, original);
|
2007-06-20 02:28:31 +00:00
|
|
|
}
|
|
|
|
|
2007-06-21 18:35:24 +00:00
|
|
|
indent(c->depth);
|
|
|
|
fprintf(stderr, " next is %p at %p - offset %d from %p\n",
|
|
|
|
cast<object>(copy, walker.next * BytesPerWord),
|
|
|
|
&cast<object>(copy, walker.next * BytesPerWord),
|
|
|
|
walker.next,
|
|
|
|
copy);
|
|
|
|
|
2007-06-20 05:16:43 +00:00
|
|
|
original = cast<object>(copy, walker.next * BytesPerWord);
|
2007-06-21 18:35:24 +00:00
|
|
|
cast<object>(copy, walker.next * BytesPerWord) = follow(c, original);
|
2007-06-20 04:26:36 +00:00
|
|
|
goto visit;
|
2007-06-20 02:28:31 +00:00
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-20 04:26:36 +00:00
|
|
|
void
|
|
|
|
collect(Context* c, Segment::Map* map, unsigned start, unsigned end,
|
2007-06-20 17:42:13 +00:00
|
|
|
bool* dirty, bool expectDirty)
|
2007-06-20 04:26:36 +00:00
|
|
|
{
|
|
|
|
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);
|
2007-06-20 17:42:13 +00:00
|
|
|
if (c->mode == OverflowCollection) {
|
2007-06-20 04:26:36 +00:00
|
|
|
return;
|
|
|
|
} else if (childDirty) {
|
|
|
|
map->setOnly(s);
|
|
|
|
*dirty = true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
assert(c, map->scale == 1);
|
2007-06-20 17:42:13 +00:00
|
|
|
object* p = reinterpret_cast<object*>(map->segment->get(it.next()));
|
2007-06-20 04:26:36 +00:00
|
|
|
|
|
|
|
map->clearOnly(p);
|
|
|
|
if (c->nextGen1.contains(*p)) {
|
|
|
|
map->setOnly(p);
|
|
|
|
*dirty = true;
|
|
|
|
} else {
|
|
|
|
collect(c, p);
|
|
|
|
|
2007-06-20 17:42:13 +00:00
|
|
|
if (c->mode == OverflowCollection) {
|
2007-06-20 04:26:36 +00:00
|
|
|
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);
|
2007-06-20 05:16:43 +00:00
|
|
|
index += c->client->sizeInWords(p);
|
2007-06-20 04:26:36 +00:00
|
|
|
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();
|
|
|
|
|
|
|
|
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));
|
2007-06-20 17:42:13 +00:00
|
|
|
return true;
|
2007-06-20 04:26:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Context* c;
|
|
|
|
object p;
|
|
|
|
} walker(c, p);
|
|
|
|
|
|
|
|
c->client->walk(p, &walker);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-20 02:28:31 +00:00
|
|
|
void
|
|
|
|
collect2(Context* c)
|
|
|
|
{
|
2007-06-20 17:42:13 +00:00
|
|
|
if (c->mode == MinorCollection and c->gen2.position) {
|
2007-06-20 02:28:31 +00:00
|
|
|
unsigned start = 0;
|
2007-06-20 17:42:13 +00:00
|
|
|
unsigned end = start + c->gen2.position;
|
2007-06-20 02:28:31 +00:00
|
|
|
bool dirty;
|
2007-06-20 04:26:36 +00:00
|
|
|
collect(c, &(c->heapMap), start, end, &dirty, false);
|
2007-06-20 02:28:31 +00:00
|
|
|
} else if (c->mode == Gen2Collection) {
|
2007-06-20 17:42:13 +00:00
|
|
|
unsigned ng2Position = c->nextGen2.position;
|
|
|
|
collect(c, &(c->nextGen1), c->nextGen1.position);
|
2007-06-20 04:26:36 +00:00
|
|
|
collect(c, &(c->nextGen2), ng2Position);
|
2007-06-20 02:28:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class Visitor : public Heap::Visitor {
|
|
|
|
public:
|
|
|
|
Visitor(Context* c): c(c) { }
|
|
|
|
|
|
|
|
virtual void visit(void** p) {
|
|
|
|
collect(c, p);
|
|
|
|
}
|
2007-06-20 17:42:13 +00:00
|
|
|
|
|
|
|
Context* c;
|
2007-06-20 02:28:31 +00:00
|
|
|
} v(c);
|
|
|
|
|
2007-06-20 17:42:13 +00:00
|
|
|
c->client->visitRoots(&v);
|
2007-06-20 02:28:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-06-20 04:26:36 +00:00
|
|
|
collect(Context* c)
|
2007-06-20 02:28:31 +00:00
|
|
|
{
|
2007-06-21 20:44:35 +00:00
|
|
|
if (c->gen1.data == 0) initGen1(c);
|
|
|
|
|
2007-06-20 02:28:31 +00:00
|
|
|
switch (c->mode) {
|
|
|
|
case MinorCollection: {
|
|
|
|
initNextGen1(c);
|
|
|
|
|
|
|
|
collect2(c);
|
|
|
|
|
|
|
|
if (c->mode == OverflowCollection) {
|
|
|
|
c->mode = Gen2Collection;
|
|
|
|
collect2(c);
|
|
|
|
|
|
|
|
c->gen2.replaceWith(&(c->nextGen2));
|
|
|
|
}
|
|
|
|
|
|
|
|
c->gen1.replaceWith(&(c->nextGen1));
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case MajorCollection: {
|
|
|
|
initNextGen1(c);
|
|
|
|
initNextGen2(c);
|
|
|
|
|
2007-06-20 04:26:36 +00:00
|
|
|
c->heapMap.clear();
|
2007-06-20 02:28:31 +00:00
|
|
|
|
|
|
|
collect2(c);
|
|
|
|
|
|
|
|
c->gen1.replaceWith(&(c->nextGen1));
|
|
|
|
c->gen2.replaceWith(&(c->nextGen2));
|
|
|
|
} break;
|
2007-06-20 17:42:13 +00:00
|
|
|
|
|
|
|
default: abort(c);
|
2007-06-20 02:28:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
2007-06-20 19:20:25 +00:00
|
|
|
namespace vm {
|
|
|
|
|
2007-06-20 02:28:31 +00:00
|
|
|
Heap*
|
|
|
|
makeHeap(System* system)
|
|
|
|
{
|
2007-06-20 16:58:35 +00:00
|
|
|
class Heap: public vm::Heap {
|
|
|
|
public:
|
|
|
|
Heap(System* system): c(system) { }
|
|
|
|
|
|
|
|
virtual void collect(CollectionType type, Client* client) {
|
|
|
|
switch (type) {
|
|
|
|
case MinorCollection:
|
|
|
|
c.mode = ::MinorCollection;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MajorCollection:
|
|
|
|
c.mode = ::MajorCollection;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: abort(&c);
|
|
|
|
}
|
|
|
|
|
|
|
|
c.client = client;
|
2007-06-21 18:35:24 +00:00
|
|
|
c.depth = 0;
|
2007-06-20 16:58:35 +00:00
|
|
|
|
|
|
|
::collect(&c);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool needsMark(void** p) {
|
|
|
|
return *p and c.gen2.contains(p) and not c.gen2.contains(*p);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void mark(void** p) {
|
|
|
|
c.heapMap.set(p);
|
|
|
|
}
|
2007-06-20 02:28:31 +00:00
|
|
|
|
2007-06-20 16:58:35 +00:00
|
|
|
virtual void dispose() {
|
|
|
|
c.dispose();
|
|
|
|
c.system->free(this);
|
|
|
|
}
|
|
|
|
|
2007-06-20 17:42:13 +00:00
|
|
|
virtual void* follow(void* p) {
|
|
|
|
if (wasCollected(&c, p)) {
|
2007-06-21 18:35:24 +00:00
|
|
|
indent(c.depth);
|
|
|
|
fprintf(stderr, "follow: %p: %p\n", p, ::follow(&c, p));
|
|
|
|
|
|
|
|
return ::follow(&c, p);
|
2007-06-20 17:42:13 +00:00
|
|
|
} else {
|
2007-06-21 18:35:24 +00:00
|
|
|
//indent(c.depth);
|
|
|
|
//fprintf(stderr, "follow: %p: %p\n", p, p);
|
|
|
|
|
2007-06-20 17:42:13 +00:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-20 16:58:35 +00:00
|
|
|
Context c;
|
|
|
|
};
|
|
|
|
|
2007-06-20 19:20:25 +00:00
|
|
|
return new (system->allocate(sizeof(Heap))) Heap(system);
|
2007-06-20 02:28:31 +00:00
|
|
|
}
|
2007-06-20 19:20:25 +00:00
|
|
|
|
|
|
|
} // namespace vm
|