mirror of
https://github.com/corda/corda.git
synced 2025-01-05 20:54:13 +00:00
move fixed object (mark and sweep) support into heap.cpp and refine algorithms for determining when and how much to GC
This commit is contained in:
parent
60072b9fdc
commit
7f1837fecd
2
makefile
2
makefile
@ -28,7 +28,7 @@ src = src
|
|||||||
classpath = classpath
|
classpath = classpath
|
||||||
test = test
|
test = test
|
||||||
|
|
||||||
input = $(test-build)/Enums.class
|
input = $(test-build)/GC.class
|
||||||
|
|
||||||
build-cxx = g++
|
build-cxx = g++
|
||||||
build-cc = gcc
|
build-cc = gcc
|
||||||
|
@ -232,10 +232,6 @@ bitsToFloat(uint32_t bits)
|
|||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// an object must survive TenureThreshold + 2 garbage collections
|
|
||||||
// before being copied to gen2 (muat be at least 1):
|
|
||||||
const unsigned TenureThreshold = 3;
|
|
||||||
|
|
||||||
class Machine;
|
class Machine;
|
||||||
class Thread;
|
class Thread;
|
||||||
|
|
||||||
|
@ -674,7 +674,7 @@ class StackMapper {
|
|||||||
MyProtector(StackMapper* mapper): Protector(mapper->t), mapper(mapper) { }
|
MyProtector(StackMapper* mapper): Protector(mapper->t), mapper(mapper) { }
|
||||||
|
|
||||||
virtual void visit(Heap::Visitor* v) {
|
virtual void visit(Heap::Visitor* v) {
|
||||||
vm::visit(t, v, &(mapper->method));
|
v->visit(&(mapper->method));
|
||||||
}
|
}
|
||||||
|
|
||||||
StackMapper* mapper;
|
StackMapper* mapper;
|
||||||
@ -1073,14 +1073,14 @@ visitParameters(MyThread* t, Heap::Visitor* v, void* frame)
|
|||||||
|
|
||||||
unsigned index = 0;
|
unsigned index = 0;
|
||||||
if ((methodFlags(t, method) & ACC_STATIC) == 0) {
|
if ((methodFlags(t, method) & ACC_STATIC) == 0) {
|
||||||
visit(t, v, frameLocalObject(t, frame, index++));
|
v->visit(frameLocalObject(t, frame, index++));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (MethodSpecIterator it(t, spec); it.hasNext();) {
|
for (MethodSpecIterator it(t, spec); it.hasNext();) {
|
||||||
switch (*it.next()) {
|
switch (*it.next()) {
|
||||||
case 'L':
|
case 'L':
|
||||||
case '[':
|
case '[':
|
||||||
visit(t, v, frameLocalObject(t, frame, index++));
|
v->visit(frameLocalObject(t, frame, index++));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'J':
|
case 'J':
|
||||||
@ -1122,7 +1122,7 @@ visitStackAndLocals(MyThread* t, Heap::Visitor* v, void* frame)
|
|||||||
|
|
||||||
for (unsigned i = 0; i < count; ++i) {
|
for (unsigned i = 0; i < count; ++i) {
|
||||||
if (getBit(stackMap, i)) {
|
if (getBit(stackMap, i)) {
|
||||||
visit(t, v, frameLocalObject(t, frame, i + parameterFootprint));
|
v->visit(frameLocalObject(t, frame, i + parameterFootprint));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1134,7 +1134,7 @@ visitStack(MyThread* t, Heap::Visitor* v)
|
|||||||
void* frame = frameStart(t);
|
void* frame = frameStart(t);
|
||||||
|
|
||||||
if (frameValid(frame)) {
|
if (frameValid(frame)) {
|
||||||
visit(t, v, &frameMethod(frame));
|
v->visit(&frameMethod(frame));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; frameValid(frame); frame = frameNext(frame)) {
|
for (; frameValid(frame); frame = frameNext(frame)) {
|
||||||
@ -1142,7 +1142,7 @@ visitStack(MyThread* t, Heap::Visitor* v)
|
|||||||
// caller is native. Otherwise, the caller owns them.
|
// caller is native. Otherwise, the caller owns them.
|
||||||
void* next = frameNext(frame);
|
void* next = frameNext(frame);
|
||||||
if (frameValid(next)) {
|
if (frameValid(next)) {
|
||||||
visit(t, v, &frameMethod(next));
|
v->visit(&frameMethod(next));
|
||||||
|
|
||||||
if (methodFlags(t, frameMethod(next)) & ACC_NATIVE) {
|
if (methodFlags(t, frameMethod(next)) & ACC_NATIVE) {
|
||||||
visitParameters(t, v, frame);
|
visitParameters(t, v, frame);
|
||||||
@ -4573,10 +4573,10 @@ class JavaCompiler: public Compiler {
|
|||||||
MyProtector(JavaCompiler* c): Protector(c->t), c(c) { }
|
MyProtector(JavaCompiler* c): Protector(c->t), c(c) { }
|
||||||
|
|
||||||
virtual void visit(Heap::Visitor* v) {
|
virtual void visit(Heap::Visitor* v) {
|
||||||
vm::visit(t, v, &(c->method));
|
v->visit(&(c->method));
|
||||||
|
|
||||||
for (unsigned i = 0; i < c->pool.length(); i += BytesPerWord) {
|
for (unsigned i = 0; i < c->pool.length(); i += BytesPerWord) {
|
||||||
vm::visit(t, v, reinterpret_cast<object*>(&(c->pool.getAddress(i))));
|
v->visit(reinterpret_cast<object*>(&(c->pool.getAddress(i))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4799,7 +4799,7 @@ class ArgumentList {
|
|||||||
virtual void visit(Heap::Visitor* v) {
|
virtual void visit(Heap::Visitor* v) {
|
||||||
for (unsigned i = 0; i < list->position; ++i) {
|
for (unsigned i = 0; i < list->position; ++i) {
|
||||||
if (list->objectMask[i]) {
|
if (list->objectMask[i]) {
|
||||||
vm::visit(t, v, reinterpret_cast<object*>(list->array + i));
|
v->visit(reinterpret_cast<object*>(list->array + i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4984,7 +4984,7 @@ class MyProcessor: public Processor {
|
|||||||
|
|
||||||
if (t->m->active) {
|
if (t->m->active) {
|
||||||
for (Reference* r = t->reference; r; r = r->next) {
|
for (Reference* r = t->reference; r; r = r->next) {
|
||||||
visit(t, v, &(r->target));
|
v->visit(&(r->target));
|
||||||
}
|
}
|
||||||
|
|
||||||
visitStack(t, v);
|
visitStack(t, v);
|
||||||
|
298
src/heap.cpp
298
src/heap.cpp
@ -6,6 +6,12 @@ using namespace vm;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
// an object must survive TenureThreshold + 2 garbage collections
|
||||||
|
// before being copied to gen2 (muat be at least 1):
|
||||||
|
const unsigned TenureThreshold = 3;
|
||||||
|
|
||||||
|
const unsigned FixieTenureThreshold = TenureThreshold + 2;
|
||||||
|
|
||||||
const unsigned Top = ~static_cast<unsigned>(0);
|
const unsigned Top = ~static_cast<unsigned>(0);
|
||||||
|
|
||||||
const unsigned InitialGen2CapacityInBytes = 4 * 1024 * 1024;
|
const unsigned InitialGen2CapacityInBytes = 4 * 1024 * 1024;
|
||||||
@ -381,11 +387,77 @@ class Segment {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Fixie {
|
||||||
|
public:
|
||||||
|
Fixie(unsigned size, bool hasMask, Fixie** handle):
|
||||||
|
age(0),
|
||||||
|
hasMask(hasMask),
|
||||||
|
marked(false),
|
||||||
|
dirty(false)
|
||||||
|
{
|
||||||
|
memset(mask(size), 0, maskSize(size, hasMask));
|
||||||
|
add(handle);
|
||||||
|
if (Debug) {
|
||||||
|
fprintf(stderr, "make %p\n", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(Fixie** handle) {
|
||||||
|
this->handle = handle;
|
||||||
|
next = *handle;
|
||||||
|
if (next) next->handle = &next;
|
||||||
|
*handle = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove() {
|
||||||
|
*handle = next;
|
||||||
|
if (next) next->handle = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void move(Fixie** handle) {
|
||||||
|
remove();
|
||||||
|
add(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t* mask(unsigned size) {
|
||||||
|
return body + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned maskSize(unsigned size, bool hasMask) {
|
||||||
|
return hasMask * ceiling(size, BytesPerWord) * BytesPerWord;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned totalSize(unsigned size, bool hasMask) {
|
||||||
|
return sizeof(Fixie) + (size * BytesPerWord) + maskSize(size, hasMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned totalSize(unsigned size) {
|
||||||
|
return totalSize(size, hasMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t age;
|
||||||
|
bool hasMask;
|
||||||
|
bool marked;
|
||||||
|
bool dirty;
|
||||||
|
Fixie* next;
|
||||||
|
Fixie** handle;
|
||||||
|
uintptr_t body[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
Fixie*
|
||||||
|
fixie(void* body)
|
||||||
|
{
|
||||||
|
return static_cast<Fixie*>(body) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
free(Context* c, Fixie** fixies);
|
||||||
|
|
||||||
class Context {
|
class Context {
|
||||||
public:
|
public:
|
||||||
Context(System* system):
|
Context(System* system, Heap::Client* client):
|
||||||
system(system),
|
system(system),
|
||||||
client(0),
|
client(client),
|
||||||
|
|
||||||
ageMap(&gen1, log(TenureThreshold), 1, 0, false),
|
ageMap(&gen1, log(TenureThreshold), 1, 0, false),
|
||||||
gen1(this, &ageMap, 0, 0),
|
gen1(this, &ageMap, 0, 0),
|
||||||
@ -406,10 +478,17 @@ class Context {
|
|||||||
|
|
||||||
gen2Base(0),
|
gen2Base(0),
|
||||||
tenureFootprint(0),
|
tenureFootprint(0),
|
||||||
|
fixieTenureFootprint(0),
|
||||||
gen1padding(0),
|
gen1padding(0),
|
||||||
gen2padding(0),
|
gen2padding(0),
|
||||||
mode(Heap::MinorCollection),
|
mode(Heap::MinorCollection),
|
||||||
|
|
||||||
|
fixies(0),
|
||||||
|
tenuredFixies(0),
|
||||||
|
dirtyFixies(0),
|
||||||
|
markedFixies(0),
|
||||||
|
visitedFixies(0),
|
||||||
|
|
||||||
lastCollectionTime(system->now()),
|
lastCollectionTime(system->now()),
|
||||||
totalCollectionTime(0),
|
totalCollectionTime(0),
|
||||||
totalTime(0)
|
totalTime(0)
|
||||||
@ -420,6 +499,10 @@ class Context {
|
|||||||
nextGen1.dispose();
|
nextGen1.dispose();
|
||||||
gen2.dispose();
|
gen2.dispose();
|
||||||
nextGen2.dispose();
|
nextGen2.dispose();
|
||||||
|
free(this, &tenuredFixies);
|
||||||
|
free(this, &dirtyFixies);
|
||||||
|
free(this, &fixies);
|
||||||
|
client->dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
System* system;
|
System* system;
|
||||||
@ -444,11 +527,18 @@ class Context {
|
|||||||
unsigned gen2Base;
|
unsigned gen2Base;
|
||||||
|
|
||||||
unsigned tenureFootprint;
|
unsigned tenureFootprint;
|
||||||
|
unsigned fixieTenureFootprint;
|
||||||
unsigned gen1padding;
|
unsigned gen1padding;
|
||||||
unsigned gen2padding;
|
unsigned gen2padding;
|
||||||
|
|
||||||
Heap::CollectionType mode;
|
Heap::CollectionType mode;
|
||||||
|
|
||||||
|
Fixie* fixies;
|
||||||
|
Fixie* tenuredFixies;
|
||||||
|
Fixie* dirtyFixies;
|
||||||
|
Fixie* markedFixies;
|
||||||
|
Fixie* visitedFixies;
|
||||||
|
|
||||||
int64_t lastCollectionTime;
|
int64_t lastCollectionTime;
|
||||||
int64_t totalCollectionTime;
|
int64_t totalCollectionTime;
|
||||||
int64_t totalTime;
|
int64_t totalTime;
|
||||||
@ -568,6 +658,62 @@ bitset(Context* c UNUSED, void* o)
|
|||||||
return &cast<uintptr_t>(o, BytesPerWord * 2);
|
return &cast<uintptr_t>(o, BytesPerWord * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
free(Context* c, Fixie** fixies)
|
||||||
|
{
|
||||||
|
for (Fixie** p = fixies; *p;) {
|
||||||
|
Fixie* f = *p;
|
||||||
|
*p = f->next;
|
||||||
|
if (Debug) {
|
||||||
|
fprintf(stderr, "free %p\n", f);
|
||||||
|
}
|
||||||
|
c->system->free(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sweepFixies(Context* c)
|
||||||
|
{
|
||||||
|
assert(c, c->markedFixies == 0);
|
||||||
|
|
||||||
|
if (c->mode == Heap::MajorCollection) {
|
||||||
|
free(c, &(c->tenuredFixies));
|
||||||
|
free(c, &(c->dirtyFixies));
|
||||||
|
}
|
||||||
|
free(c, &(c->fixies));
|
||||||
|
|
||||||
|
for (Fixie** p = &(c->visitedFixies); *p;) {
|
||||||
|
Fixie* f = *p;
|
||||||
|
*p = f->next;
|
||||||
|
|
||||||
|
unsigned size = c->client->sizeInWords(f->body);
|
||||||
|
|
||||||
|
++ f->age;
|
||||||
|
if (f->age > FixieTenureThreshold) {
|
||||||
|
f->age = FixieTenureThreshold;
|
||||||
|
} else if (static_cast<unsigned>(f->age + 1) == FixieTenureThreshold) {
|
||||||
|
c->fixieTenureFootprint += f->totalSize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f->age == FixieTenureThreshold) {
|
||||||
|
if (Debug) {
|
||||||
|
fprintf(stderr, "tenure %p\n", f);
|
||||||
|
}
|
||||||
|
f->move(&(c->tenuredFixies));
|
||||||
|
|
||||||
|
if (f->dirty) {
|
||||||
|
uintptr_t* mask = f->mask(size);
|
||||||
|
memset(mask, 0, ceiling(size, BytesPerWord) * BytesPerWord);
|
||||||
|
f->dirty = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
f->move(&(c->fixies));
|
||||||
|
}
|
||||||
|
|
||||||
|
f->marked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline void*
|
inline void*
|
||||||
copyTo(Context* c, Segment* s, void* o, unsigned size)
|
copyTo(Context* c, Segment* s, void* o, unsigned size)
|
||||||
{
|
{
|
||||||
@ -644,7 +790,18 @@ update3(Context* c, void* o, bool* needsVisit)
|
|||||||
if (wasCollected(c, o)) {
|
if (wasCollected(c, o)) {
|
||||||
*needsVisit = false;
|
*needsVisit = false;
|
||||||
return follow(c, o);
|
return follow(c, o);
|
||||||
} else if (c->client->checkFixed(o)) {
|
} else if (c->client->isFixed(o)) {
|
||||||
|
Fixie* f = fixie(o);
|
||||||
|
if ((not f->marked)
|
||||||
|
and (c->mode == Heap::MajorCollection
|
||||||
|
or f->age < FixieTenureThreshold))
|
||||||
|
{
|
||||||
|
if (Debug) {
|
||||||
|
fprintf(stderr, "mark %p\n", f);
|
||||||
|
}
|
||||||
|
f->marked = true;
|
||||||
|
f->move(&(c->markedFixies));
|
||||||
|
}
|
||||||
*needsVisit = false;
|
*needsVisit = false;
|
||||||
return o;
|
return o;
|
||||||
} else {
|
} else {
|
||||||
@ -992,6 +1149,64 @@ collect(Context* c, void** p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
visitDirtyFixies(Context* c)
|
||||||
|
{
|
||||||
|
for (Fixie** p = &(c->dirtyFixies); *p;) {
|
||||||
|
Fixie* f = *p;
|
||||||
|
*p = f->next;
|
||||||
|
|
||||||
|
unsigned size = c->client->sizeInWords(f->body);
|
||||||
|
uintptr_t* mask = f->mask(size);
|
||||||
|
for (unsigned word = 0; word < wordOf(size); ++ word) {
|
||||||
|
if (mask[word]) {
|
||||||
|
for (unsigned bit = 0; bit < bitOf(size); ++ bit) {
|
||||||
|
unsigned index = indexOf(word, bit);
|
||||||
|
if (getBit(mask, index)) {
|
||||||
|
collect(c, reinterpret_cast<void**>(f->body) + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(mask, 0, ceiling(size, BytesPerWord) * BytesPerWord);
|
||||||
|
f->dirty = false;
|
||||||
|
f->move(&(c->tenuredFixies));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
visitMarkedFixies(Context* c)
|
||||||
|
{
|
||||||
|
for (Fixie** p = &(c->markedFixies); *p;) {
|
||||||
|
Fixie* f = *p;
|
||||||
|
*p = f->next;
|
||||||
|
|
||||||
|
if (Debug) {
|
||||||
|
fprintf(stderr, "visit %p\n", f);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Walker: public Heap::Walker {
|
||||||
|
public:
|
||||||
|
Walker(Context* c, void** p):
|
||||||
|
c(c), p(p)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
virtual bool visit(unsigned offset) {
|
||||||
|
collect(c, p + offset);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Context* c;
|
||||||
|
void** p;
|
||||||
|
} w(c, reinterpret_cast<void**>(f->body));
|
||||||
|
|
||||||
|
c->client->walk(reinterpret_cast<void**>(f->body), &w);
|
||||||
|
|
||||||
|
f->move(&(c->visitedFixies));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
collect(Context* c, Segment::Map* map, unsigned start, unsigned end,
|
collect(Context* c, Segment::Map* map, unsigned start, unsigned end,
|
||||||
bool* dirty, bool expectDirty UNUSED)
|
bool* dirty, bool expectDirty UNUSED)
|
||||||
@ -1038,6 +1253,7 @@ collect2(Context* c)
|
|||||||
{
|
{
|
||||||
c->gen2Base = Top;
|
c->gen2Base = Top;
|
||||||
c->tenureFootprint = 0;
|
c->tenureFootprint = 0;
|
||||||
|
c->fixieTenureFootprint = 0;
|
||||||
c->gen1padding = 0;
|
c->gen1padding = 0;
|
||||||
c->gen2padding = 0;
|
c->gen2padding = 0;
|
||||||
|
|
||||||
@ -1048,12 +1264,17 @@ collect2(Context* c)
|
|||||||
collect(c, &(c->heapMap), start, end, &dirty, false);
|
collect(c, &(c->heapMap), start, end, &dirty, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (c->mode == Heap::MinorCollection) {
|
||||||
|
visitDirtyFixies(c);
|
||||||
|
}
|
||||||
|
|
||||||
class Visitor : public Heap::Visitor {
|
class Visitor : public Heap::Visitor {
|
||||||
public:
|
public:
|
||||||
Visitor(Context* c): c(c) { }
|
Visitor(Context* c): c(c) { }
|
||||||
|
|
||||||
virtual void visit(void* p) {
|
virtual void visit(void* p) {
|
||||||
collect(c, static_cast<void**>(p));
|
collect(c, static_cast<void**>(p));
|
||||||
|
visitMarkedFixies(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
Context* c;
|
Context* c;
|
||||||
@ -1065,7 +1286,9 @@ collect2(Context* c)
|
|||||||
void
|
void
|
||||||
collect(Context* c, unsigned footprint)
|
collect(Context* c, unsigned footprint)
|
||||||
{
|
{
|
||||||
if (c->tenureFootprint > c->gen2.remaining()) {
|
if (c->tenureFootprint > c->gen2.remaining()
|
||||||
|
or c->fixieTenureFootprint)
|
||||||
|
{
|
||||||
c->mode = Heap::MajorCollection;
|
c->mode = Heap::MajorCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1092,6 +1315,8 @@ collect(Context* c, unsigned footprint)
|
|||||||
c->gen2.replaceWith(&(c->nextGen2));
|
c->gen2.replaceWith(&(c->nextGen2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sweepFixies(c);
|
||||||
|
|
||||||
if (Verbose) {
|
if (Verbose) {
|
||||||
int64_t now = c->system->now();
|
int64_t now = c->system->now();
|
||||||
int64_t collection = now - then;
|
int64_t collection = now - then;
|
||||||
@ -1114,32 +1339,61 @@ collect(Context* c, unsigned footprint)
|
|||||||
|
|
||||||
class MyHeap: public Heap {
|
class MyHeap: public Heap {
|
||||||
public:
|
public:
|
||||||
MyHeap(System* system): c(system) { }
|
MyHeap(System* system, Heap::Client* client): c(system, client) { }
|
||||||
|
|
||||||
virtual void collect(CollectionType type, Client* client, unsigned footprint)
|
virtual void collect(CollectionType type, unsigned footprint) {
|
||||||
{
|
|
||||||
c.mode = type;
|
c.mode = type;
|
||||||
c.client = client;
|
|
||||||
|
|
||||||
::collect(&c, footprint);
|
::collect(&c, footprint);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool needsMark(void* p) {
|
virtual void* allocateFixed(unsigned sizeInWords, bool objectMask,
|
||||||
return *static_cast<void**>(p)
|
unsigned* totalInBytes)
|
||||||
and c.gen2.contains(p)
|
{
|
||||||
and not c.gen2.contains(*static_cast<void**>(p));
|
*totalInBytes = Fixie::totalSize(sizeInWords, objectMask);
|
||||||
|
return (new (c.system->allocate(*totalInBytes))
|
||||||
|
Fixie(sizeInWords, objectMask, &(c.fixies)))->body;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void mark(void* p) {
|
virtual bool needsMark(void* p) {
|
||||||
if (Debug) {
|
if (c.client->isFixed(p)) {
|
||||||
fprintf(stderr, "mark %p (%s) at %p (%s)\n",
|
return fixie(p)->age == FixieTenureThreshold;
|
||||||
*static_cast<void**>(p),
|
} else {
|
||||||
segment(&c, *static_cast<void**>(p)),
|
return c.gen2.contains(p);
|
||||||
p,
|
|
||||||
segment(&c, p));
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
c.heapMap.set(p);
|
bool targetNeedsMark(void* target) {
|
||||||
|
return target
|
||||||
|
and not c.gen2.contains(target)
|
||||||
|
and not (c.client->isFixed(target)
|
||||||
|
and fixie(target)->age == FixieTenureThreshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void mark(void* p, unsigned offset, unsigned count) {
|
||||||
|
if (c.client->isFixed(p)) {
|
||||||
|
Fixie* f = fixie(p);
|
||||||
|
unsigned size = c.client->sizeInWords(p);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < count; ++i) {
|
||||||
|
void** target = static_cast<void**>(p) + offset + i;
|
||||||
|
if (targetNeedsMark(*target)) {
|
||||||
|
f->dirty = true;
|
||||||
|
markBit(f->mask(size), offset + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f->dirty) {
|
||||||
|
f->move(&(c.dirtyFixies));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (unsigned i = 0; i < count; ++i) {
|
||||||
|
void** target = static_cast<void**>(p) + offset + i;
|
||||||
|
if (targetNeedsMark(*target)) {
|
||||||
|
c.heapMap.set(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void pad(void* p, unsigned extra) {
|
virtual void pad(void* p, unsigned extra) {
|
||||||
@ -1207,9 +1461,9 @@ class MyHeap: public Heap {
|
|||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
Heap*
|
Heap*
|
||||||
makeHeap(System* system)
|
makeHeap(System* system, Heap::Client* client)
|
||||||
{
|
{
|
||||||
return new (system->allocate(sizeof(MyHeap))) MyHeap(system);
|
return new (system->allocate(sizeof(MyHeap))) MyHeap(system, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
|
13
src/heap.h
13
src/heap.h
@ -35,17 +35,20 @@ class Heap {
|
|||||||
public:
|
public:
|
||||||
virtual ~Client() { }
|
virtual ~Client() { }
|
||||||
virtual void visitRoots(Visitor*) = 0;
|
virtual void visitRoots(Visitor*) = 0;
|
||||||
virtual bool checkFixed(void*) = 0;
|
virtual bool isFixed(void*) = 0;
|
||||||
|
virtual unsigned sizeInWords(void*) = 0;
|
||||||
virtual unsigned copiedSizeInWords(void*) = 0;
|
virtual unsigned copiedSizeInWords(void*) = 0;
|
||||||
virtual void copy(void*, void*) = 0;
|
virtual void copy(void*, void*) = 0;
|
||||||
virtual void walk(void*, Walker*) = 0;
|
virtual void walk(void*, Walker*) = 0;
|
||||||
|
virtual void dispose() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual ~Heap() { }
|
virtual ~Heap() { }
|
||||||
virtual void collect(CollectionType type, Client* client, unsigned footprint)
|
virtual void collect(CollectionType type, unsigned footprint) = 0;
|
||||||
= 0;
|
virtual void* allocateFixed(unsigned sizeInWords, bool objectMask,
|
||||||
|
unsigned* totalInBytes) = 0;
|
||||||
virtual bool needsMark(void* p) = 0;
|
virtual bool needsMark(void* p) = 0;
|
||||||
virtual void mark(void* p) = 0;
|
virtual void mark(void* p, unsigned offset, unsigned count) = 0;
|
||||||
virtual void pad(void* p, unsigned extra) = 0;
|
virtual void pad(void* p, unsigned extra) = 0;
|
||||||
virtual void* follow(void* p) = 0;
|
virtual void* follow(void* p) = 0;
|
||||||
virtual Status status(void* p) = 0;
|
virtual Status status(void* p) = 0;
|
||||||
@ -53,7 +56,7 @@ class Heap {
|
|||||||
virtual void dispose() = 0;
|
virtual void dispose() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
Heap* makeHeap(System* system);
|
Heap* makeHeap(System* system, Heap::Client* client);
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
|
|
||||||
|
@ -2955,11 +2955,11 @@ class MyProcessor: public Processor {
|
|||||||
{
|
{
|
||||||
Thread* t = static_cast<Thread*>(vmt);
|
Thread* t = static_cast<Thread*>(vmt);
|
||||||
|
|
||||||
visit(t, v, &(t->code));
|
v->visit(&(t->code));
|
||||||
|
|
||||||
for (unsigned i = 0; i < t->sp; ++i) {
|
for (unsigned i = 0; i < t->sp; ++i) {
|
||||||
if (t->stack[i * 2] == ObjectTag) {
|
if (t->stack[i * 2] == ObjectTag) {
|
||||||
visit(t, v, reinterpret_cast<object*>(t->stack + (i * 2) + 1));
|
v->visit(reinterpret_cast<object*>(t->stack + (i * 2) + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@ DestroyJavaVM(Machine* m)
|
|||||||
{
|
{
|
||||||
System* s = m->system;
|
System* s = m->system;
|
||||||
Processor* p = m->processor;
|
Processor* p = m->processor;
|
||||||
Heap* h = m->heap;
|
|
||||||
Finder* f = m->finder;
|
Finder* f = m->finder;
|
||||||
Thread* t = m->rootThread;
|
Thread* t = m->rootThread;
|
||||||
|
|
||||||
@ -32,7 +31,6 @@ DestroyJavaVM(Machine* m)
|
|||||||
|
|
||||||
m->dispose();
|
m->dispose();
|
||||||
p->dispose();
|
p->dispose();
|
||||||
h->dispose();
|
|
||||||
f->dispose();
|
f->dispose();
|
||||||
s->dispose();
|
s->dispose();
|
||||||
|
|
||||||
@ -1884,10 +1882,9 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
|
|||||||
BUILTIN_CLASSPATH, s->pathSeparator(), a->classpath);
|
BUILTIN_CLASSPATH, s->pathSeparator(), a->classpath);
|
||||||
|
|
||||||
Finder* f = makeFinder(s, classpath);
|
Finder* f = makeFinder(s, classpath);
|
||||||
Heap* h = makeHeap(s);
|
|
||||||
Processor* p = makeProcessor(s);
|
Processor* p = makeProcessor(s);
|
||||||
|
|
||||||
*m = new (s->allocate(sizeof(Machine))) Machine(s, h, f, p);
|
*m = new (s->allocate(sizeof(Machine))) Machine(s, f, p);
|
||||||
|
|
||||||
if (a->properties) {
|
if (a->properties) {
|
||||||
for (const char** p = a->properties; *p; ++p) {
|
for (const char** p = a->properties; *p; ++p) {
|
||||||
|
480
src/machine.cpp
480
src/machine.cpp
@ -126,8 +126,8 @@ void
|
|||||||
visitRoots(Thread* t, Heap::Visitor* v)
|
visitRoots(Thread* t, Heap::Visitor* v)
|
||||||
{
|
{
|
||||||
if (t->state != Thread::ZombieState) {
|
if (t->state != Thread::ZombieState) {
|
||||||
visit(t, v, &(t->javaThread));
|
v->visit(&(t->javaThread));
|
||||||
visit(t, v, &(t->exception));
|
v->visit(&(t->exception));
|
||||||
|
|
||||||
t->m->processor->visitObjects(t, v);
|
t->m->processor->visitObjects(t, v);
|
||||||
|
|
||||||
@ -210,7 +210,7 @@ walk(Thread* t, object o, Heap::Walker* w)
|
|||||||
void
|
void
|
||||||
finalizerTargetUnreachable(Thread* t, Heap::Visitor* v, object* p)
|
finalizerTargetUnreachable(Thread* t, Heap::Visitor* v, object* p)
|
||||||
{
|
{
|
||||||
visit(t, v, &finalizerTarget(t, *p));
|
v->visit(&finalizerTarget(t, *p));
|
||||||
|
|
||||||
object finalizer = *p;
|
object finalizer = *p;
|
||||||
*p = finalizerNext(t, finalizer);
|
*p = finalizerNext(t, finalizer);
|
||||||
@ -226,7 +226,7 @@ referenceTargetUnreachable(Thread* t, Heap::Visitor* v, object* p)
|
|||||||
jreferenceTarget(t, *p), *p);
|
jreferenceTarget(t, *p), *p);
|
||||||
}
|
}
|
||||||
|
|
||||||
visit(t, v, p);
|
v->visit(p);
|
||||||
jreferenceTarget(t, *p) = 0;
|
jreferenceTarget(t, *p) = 0;
|
||||||
|
|
||||||
if (jreferenceQueue(t, *p)
|
if (jreferenceQueue(t, *p)
|
||||||
@ -234,7 +234,7 @@ referenceTargetUnreachable(Thread* t, Heap::Visitor* v, object* p)
|
|||||||
{
|
{
|
||||||
// queue is reachable - add the reference
|
// queue is reachable - add the reference
|
||||||
|
|
||||||
visit(t, v, &jreferenceQueue(t, *p));
|
v->visit(&jreferenceQueue(t, *p));
|
||||||
|
|
||||||
object q = jreferenceQueue(t, *p);
|
object q = jreferenceQueue(t, *p);
|
||||||
|
|
||||||
@ -278,89 +278,13 @@ referenceTargetReachable(Thread* t, Heap::Visitor* v, object* p)
|
|||||||
jreferenceTarget(t, *p), *p);
|
jreferenceTarget(t, *p), *p);
|
||||||
}
|
}
|
||||||
|
|
||||||
visit(t, v, p);
|
v->visit(p);
|
||||||
visit(t, v, &jreferenceTarget(t, *p));
|
v->visit(&jreferenceTarget(t, *p));
|
||||||
|
|
||||||
if (t->m->heap->status(jreferenceQueue(t, *p)) == Heap::Unreachable) {
|
if (t->m->heap->status(jreferenceQueue(t, *p)) == Heap::Unreachable) {
|
||||||
jreferenceQueue(t, *p) = 0;
|
jreferenceQueue(t, *p) = 0;
|
||||||
} else {
|
} else {
|
||||||
visit(t, v, &jreferenceQueue(t, *p));
|
v->visit(&jreferenceQueue(t, *p));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
freeFixies(Thread* t, object* fixies)
|
|
||||||
{
|
|
||||||
for (object* p = fixies; *p;) {
|
|
||||||
object o = *p;
|
|
||||||
*p = fixedNext(t, o);
|
|
||||||
|
|
||||||
t->m->system->free(fixedStart(t, o));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sweepFixies(Thread* t)
|
|
||||||
{
|
|
||||||
Machine* m = t->m;
|
|
||||||
|
|
||||||
assert(t, m->markedFixies == 0);
|
|
||||||
|
|
||||||
if (m->heap->collectionType() == Heap::MajorCollection) {
|
|
||||||
freeFixies(t, &(m->tenuredFixies));
|
|
||||||
freeFixies(t, &(m->dirtyFixies));
|
|
||||||
}
|
|
||||||
freeFixies(t, &(m->fixies));
|
|
||||||
|
|
||||||
for (object* p = &(m->visitedFixies); *p;) {
|
|
||||||
object o = *p;
|
|
||||||
*p = fixedNext(t, o);
|
|
||||||
|
|
||||||
fixedAge(t, o) = (fixedAge(t, o) + 1);
|
|
||||||
if (fixedAge(t, o) > TenureThreshold) {
|
|
||||||
fixedAge(t, o) = TenureThreshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fixedAge(t, o) == TenureThreshold) {
|
|
||||||
fixedMove(t, o, &(m->tenuredFixies));
|
|
||||||
|
|
||||||
if (fixedDirty(t, o)) {
|
|
||||||
unsigned size = baseSize(t, o, objectClass(t, o));
|
|
||||||
uintptr_t* mask = fixedMask(t, o, size);
|
|
||||||
memset(mask, 0, ceiling(size, BytesPerWord) * BytesPerWord);
|
|
||||||
fixedDirty(t, o) = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fixedMove(t, o, &(m->fixies));
|
|
||||||
}
|
|
||||||
|
|
||||||
fixedMarked(t, o) = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visitDirtyFixies(Thread* t, Heap::Visitor* v)
|
|
||||||
{
|
|
||||||
for (object* p = &(t->m->dirtyFixies); *p;) {
|
|
||||||
object o = *p;
|
|
||||||
*p = fixedNext(t, o);
|
|
||||||
|
|
||||||
unsigned size = baseSize(t, o, objectClass(t, o));
|
|
||||||
uintptr_t* mask = fixedMask(t, o, size);
|
|
||||||
for (unsigned word = 0; word < wordOf(size); ++ word) {
|
|
||||||
if (mask[word]) {
|
|
||||||
for (unsigned bit = 0; bit < bitOf(size); ++ bit) {
|
|
||||||
unsigned index = indexOf(word, bit);
|
|
||||||
if (getBit(mask, index)) {
|
|
||||||
visit(t, v, &cast<object>(o, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(mask, 0, ceiling(size, BytesPerWord) * BytesPerWord);
|
|
||||||
fixedDirty(t, o) = 0;
|
|
||||||
fixedMove(t, o, &(t->m->tenuredFixies));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,27 +295,27 @@ postVisit(Thread* t, Heap::Visitor* v)
|
|||||||
bool major = m->heap->collectionType() == Heap::MajorCollection;
|
bool major = m->heap->collectionType() == Heap::MajorCollection;
|
||||||
|
|
||||||
for (object* p = &(m->finalizeQueue); *p; p = &(finalizerNext(t, *p))) {
|
for (object* p = &(m->finalizeQueue); *p; p = &(finalizerNext(t, *p))) {
|
||||||
visit(t, v, p);
|
v->visit(p);
|
||||||
visit(t, v, &finalizerTarget(t, *p));
|
v->visit(&finalizerTarget(t, *p));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (object* p = &(m->finalizeQueue); *p; p = &(finalizerNext(t, *p))) {
|
for (object* p = &(m->finalizeQueue); *p; p = &(finalizerNext(t, *p))) {
|
||||||
visit(t, v, p);
|
v->visit(p);
|
||||||
visit(t, v, &finalizerTarget(t, *p));
|
v->visit(&finalizerTarget(t, *p));
|
||||||
}
|
}
|
||||||
|
|
||||||
object firstNewTenuredFinalizer = 0;
|
object firstNewTenuredFinalizer = 0;
|
||||||
object lastNewTenuredFinalizer = 0;
|
object lastNewTenuredFinalizer = 0;
|
||||||
|
|
||||||
for (object* p = &(m->finalizers); *p;) {
|
for (object* p = &(m->finalizers); *p;) {
|
||||||
visit(t, v, p);
|
v->visit(p);
|
||||||
|
|
||||||
if (m->heap->status(finalizerTarget(t, *p)) == Heap::Unreachable) {
|
if (m->heap->status(finalizerTarget(t, *p)) == Heap::Unreachable) {
|
||||||
// target is unreachable - queue it up for finalization
|
// target is unreachable - queue it up for finalization
|
||||||
finalizerTargetUnreachable(t, v, p);
|
finalizerTargetUnreachable(t, v, p);
|
||||||
} else {
|
} else {
|
||||||
// target is reachable
|
// target is reachable
|
||||||
visit(t, v, &finalizerTarget(t, *p));
|
v->visit(&finalizerTarget(t, *p));
|
||||||
|
|
||||||
if (m->heap->status(*p) == Heap::Tenured) {
|
if (m->heap->status(*p) == Heap::Tenured) {
|
||||||
// the finalizer is tenured, so we remove it from
|
// the finalizer is tenured, so we remove it from
|
||||||
@ -448,14 +372,14 @@ postVisit(Thread* t, Heap::Visitor* v)
|
|||||||
|
|
||||||
if (major) {
|
if (major) {
|
||||||
for (object* p = &(m->tenuredFinalizers); *p;) {
|
for (object* p = &(m->tenuredFinalizers); *p;) {
|
||||||
visit(t, v, p);
|
v->visit(p);
|
||||||
|
|
||||||
if (m->heap->status(finalizerTarget(t, *p)) == Heap::Unreachable) {
|
if (m->heap->status(finalizerTarget(t, *p)) == Heap::Unreachable) {
|
||||||
// target is unreachable - queue it up for finalization
|
// target is unreachable - queue it up for finalization
|
||||||
finalizerTargetUnreachable(t, v, p);
|
finalizerTargetUnreachable(t, v, p);
|
||||||
} else {
|
} else {
|
||||||
// target is reachable
|
// target is reachable
|
||||||
visit(t, v, &finalizerTarget(t, *p));
|
v->visit(&finalizerTarget(t, *p));
|
||||||
p = &finalizerNext(t, *p);
|
p = &finalizerNext(t, *p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -500,7 +424,6 @@ postCollect(Thread* t)
|
|||||||
t->heap = t->defaultHeap;
|
t->heap = t->defaultHeap;
|
||||||
t->heapOffset = 0;
|
t->heapOffset = 0;
|
||||||
t->heapIndex = 0;
|
t->heapIndex = 0;
|
||||||
t->allocatedLarge = false;
|
|
||||||
|
|
||||||
for (Thread* c = t->child; c; c = c->peer) {
|
for (Thread* c = t->child; c; c = c->peer) {
|
||||||
postCollect(c);
|
postCollect(c);
|
||||||
@ -1505,15 +1428,109 @@ invoke(Thread* t, const char* className, int argc, const char** argv)
|
|||||||
(t, className, "main", "([Ljava/lang/String;)V", 0, args);
|
(t, className, "main", "([Ljava/lang/String;)V", 0, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class HeapClient: public Heap::Client {
|
||||||
|
public:
|
||||||
|
HeapClient(Machine* m): m(m) { }
|
||||||
|
|
||||||
|
virtual void visitRoots(Heap::Visitor* v) {
|
||||||
|
v->visit(&(m->loader));
|
||||||
|
v->visit(&(m->bootstrapClassMap));
|
||||||
|
v->visit(&(m->monitorMap));
|
||||||
|
v->visit(&(m->stringMap));
|
||||||
|
v->visit(&(m->types));
|
||||||
|
v->visit(&(m->jniInterfaceTable));
|
||||||
|
|
||||||
|
for (Reference* r = m->jniReferences; r; r = r->next) {
|
||||||
|
v->visit(&(r->target));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Thread* t = m->rootThread; t; t = t->peer) {
|
||||||
|
::visitRoots(t, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
postVisit(m->rootThread, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isFixed(void* p) {
|
||||||
|
return objectFixed(m->rootThread, static_cast<object>(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual unsigned sizeInWords(void* p) {
|
||||||
|
Thread* t = m->rootThread;
|
||||||
|
|
||||||
|
object o = static_cast<object>(m->heap->follow(mask(p)));
|
||||||
|
|
||||||
|
unsigned n = baseSize(t, o, static_cast<object>
|
||||||
|
(m->heap->follow(objectClass(t, o))));
|
||||||
|
|
||||||
|
if (objectExtended(t, o)) {
|
||||||
|
++ n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual unsigned copiedSizeInWords(void* p) {
|
||||||
|
Thread* t = m->rootThread;
|
||||||
|
|
||||||
|
object o = static_cast<object>(m->heap->follow(mask(p)));
|
||||||
|
assert(t, not objectFixed(t, o));
|
||||||
|
|
||||||
|
unsigned n = baseSize(t, o, static_cast<object>
|
||||||
|
(m->heap->follow(objectClass(t, o))));
|
||||||
|
|
||||||
|
if (objectExtended(t, o) or hashTaken(t, o)) {
|
||||||
|
++ n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void copy(void* srcp, void* dstp) {
|
||||||
|
Thread* t = m->rootThread;
|
||||||
|
|
||||||
|
object src = static_cast<object>(m->heap->follow(mask(srcp)));
|
||||||
|
assert(t, not objectFixed(t, src));
|
||||||
|
|
||||||
|
object class_ = static_cast<object>
|
||||||
|
(m->heap->follow(objectClass(t, src)));
|
||||||
|
|
||||||
|
unsigned base = baseSize(t, src, class_);
|
||||||
|
unsigned n = extendedSize(t, src, base);
|
||||||
|
|
||||||
|
object dst = static_cast<object>(dstp);
|
||||||
|
|
||||||
|
memcpy(dst, src, n * BytesPerWord);
|
||||||
|
|
||||||
|
if (hashTaken(t, src)) {
|
||||||
|
cast<uintptr_t>(dst, 0) &= PointerMask;
|
||||||
|
cast<uintptr_t>(dst, 0) |= ExtendedMark;
|
||||||
|
extendedWord(t, dst, base) = takeHash(t, src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void walk(void* p, Heap::Walker* w) {
|
||||||
|
object o = static_cast<object>(m->heap->follow(mask(p)));
|
||||||
|
::walk(m->rootThread, o, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void dispose() {
|
||||||
|
m->system->free(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Machine* m;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
Machine::Machine(System* system, Heap* heap, Finder* finder,
|
Machine::Machine(System* system, Finder* finder, Processor* processor):
|
||||||
Processor* processor):
|
|
||||||
vtable(&javaVMVTable),
|
vtable(&javaVMVTable),
|
||||||
system(system),
|
system(system),
|
||||||
heap(heap),
|
heap(makeHeap(system, new (system->allocate(sizeof(HeapClient)))
|
||||||
|
HeapClient(this))),
|
||||||
finder(finder),
|
finder(finder),
|
||||||
processor(processor),
|
processor(processor),
|
||||||
rootThread(0),
|
rootThread(0),
|
||||||
@ -1522,6 +1539,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
|
|||||||
builtins(0),
|
builtins(0),
|
||||||
activeCount(0),
|
activeCount(0),
|
||||||
liveCount(0),
|
liveCount(0),
|
||||||
|
fixedFootprint(0),
|
||||||
localThread(0),
|
localThread(0),
|
||||||
stateLock(0),
|
stateLock(0),
|
||||||
heapLock(0),
|
heapLock(0),
|
||||||
@ -1539,11 +1557,6 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
|
|||||||
finalizeQueue(0),
|
finalizeQueue(0),
|
||||||
weakReferences(0),
|
weakReferences(0),
|
||||||
tenuredWeakReferences(0),
|
tenuredWeakReferences(0),
|
||||||
fixies(0),
|
|
||||||
tenuredFixies(0),
|
|
||||||
dirtyFixies(0),
|
|
||||||
markedFixies(0),
|
|
||||||
visitedFixies(0),
|
|
||||||
unsafe(false),
|
unsafe(false),
|
||||||
heapPoolIndex(0)
|
heapPoolIndex(0)
|
||||||
{
|
{
|
||||||
@ -1583,6 +1596,8 @@ Machine::dispose()
|
|||||||
system->free(heapPool[i]);
|
system->free(heapPool[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
heap->dispose();
|
||||||
|
|
||||||
system->free(this);
|
system->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1593,7 +1608,6 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent):
|
|||||||
peer((parent ? parent->child : 0)),
|
peer((parent ? parent->child : 0)),
|
||||||
child(0),
|
child(0),
|
||||||
state(NoState),
|
state(NoState),
|
||||||
allocatedLarge(false),
|
|
||||||
criticalLevel(0),
|
criticalLevel(0),
|
||||||
systemThread(0),
|
systemThread(0),
|
||||||
javaThread(javaThread),
|
javaThread(javaThread),
|
||||||
@ -1769,10 +1783,6 @@ exit(Thread* t)
|
|||||||
function(t, finalizerTarget(t, f));
|
function(t, finalizerTarget(t, f));
|
||||||
}
|
}
|
||||||
|
|
||||||
freeFixies(t, &(t->m->tenuredFixies));
|
|
||||||
freeFixies(t, &(t->m->dirtyFixies));
|
|
||||||
freeFixies(t, &(t->m->fixies));
|
|
||||||
|
|
||||||
disposeAll(t, t->m->rootThread);
|
disposeAll(t, t->m->rootThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1887,44 +1897,7 @@ enter(Thread* t, Thread::State s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
allocateFixed(Thread* t, unsigned sizeInBytes, bool objectMask)
|
allocate2(Thread* t, unsigned sizeInBytes, bool objectMask, bool fixed)
|
||||||
{
|
|
||||||
ENTER(t, Thread::ExclusiveState);
|
|
||||||
|
|
||||||
unsigned mask = objectMask
|
|
||||||
* ceiling(sizeInBytes / BytesPerWord, BytesPerWord)
|
|
||||||
* BytesPerWord;
|
|
||||||
unsigned total = sizeInBytes + FixedFootprint + mask;
|
|
||||||
|
|
||||||
uint8_t* p = static_cast<uint8_t*>(t->m->system->tryAllocate(total));
|
|
||||||
if (p == 0) {
|
|
||||||
collect(t, Heap::MajorCollection);
|
|
||||||
|
|
||||||
p = static_cast<uint8_t*>(t->m->system->allocate(total));
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(p + FixedFootprint + sizeInBytes, 0, mask);
|
|
||||||
|
|
||||||
object o = reinterpret_cast<object>(p + FixedFootprint);
|
|
||||||
|
|
||||||
cast<uintptr_t>(o, 0) = FixedMark;
|
|
||||||
fixedAge(t, o) = 0;
|
|
||||||
fixedMarked(t, o) = 0;
|
|
||||||
fixedDirty(t, o) = 0;
|
|
||||||
fixedAdd(t, o, &(t->m->fixies));
|
|
||||||
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
object
|
|
||||||
allocateLarge(Thread* t, unsigned sizeInBytes, bool objectMask)
|
|
||||||
{
|
|
||||||
t->allocatedLarge = true;
|
|
||||||
return allocateFixed(t, sizeInBytes, objectMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
object
|
|
||||||
allocate2(Thread* t, unsigned sizeInBytes, bool objectMask)
|
|
||||||
{
|
{
|
||||||
ACQUIRE_RAW(t, t->m->stateLock);
|
ACQUIRE_RAW(t, t->m->stateLock);
|
||||||
|
|
||||||
@ -1934,14 +1907,17 @@ allocate2(Thread* t, unsigned sizeInBytes, bool objectMask)
|
|||||||
ENTER(t, Thread::IdleState);
|
ENTER(t, Thread::IdleState);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sizeInBytes <= Thread::HeapSizeInBytes
|
if (fixed) {
|
||||||
and t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
if (t->m->fixedFootprint + sizeInBytes
|
||||||
>= Thread::HeapSizeInWords)
|
> Machine::FixedFootprintThresholdInBytes)
|
||||||
|
{
|
||||||
|
t->heap = 0;
|
||||||
|
}
|
||||||
|
} else if (t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
||||||
|
>= Thread::HeapSizeInWords)
|
||||||
{
|
{
|
||||||
t->heap = 0;
|
t->heap = 0;
|
||||||
if ((not t->allocatedLarge)
|
if (t->m->heapPoolIndex < Machine::HeapPoolSize) {
|
||||||
and t->m->heapPoolIndex < Machine::HeapPoolSize)
|
|
||||||
{
|
|
||||||
t->heap = static_cast<uintptr_t*>
|
t->heap = static_cast<uintptr_t*>
|
||||||
(t->m->system->tryAllocate(Thread::HeapSizeInBytes));
|
(t->m->system->tryAllocate(Thread::HeapSizeInBytes));
|
||||||
if (t->heap) {
|
if (t->heap) {
|
||||||
@ -1950,15 +1926,24 @@ allocate2(Thread* t, unsigned sizeInBytes, bool objectMask)
|
|||||||
t->heapIndex = 0;
|
t->heapIndex = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->heap == 0) {
|
|
||||||
ENTER(t, Thread::ExclusiveState);
|
|
||||||
collect(t, Heap::MinorCollection);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sizeInBytes > Thread::HeapSizeInBytes) {
|
if (t->heap == 0) {
|
||||||
return allocateLarge(t, sizeInBytes, objectMask);
|
ENTER(t, Thread::ExclusiveState);
|
||||||
|
collect(t, Heap::MinorCollection);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fixed) {
|
||||||
|
unsigned total;
|
||||||
|
object o = static_cast<object>
|
||||||
|
(t->m->heap->allocateFixed
|
||||||
|
(ceiling(sizeInBytes, BytesPerWord), objectMask, &total));
|
||||||
|
|
||||||
|
cast<uintptr_t>(o, 0) = FixedMark;
|
||||||
|
|
||||||
|
t->m->fixedFootprint += total;
|
||||||
|
|
||||||
|
return o;
|
||||||
} else {
|
} else {
|
||||||
return allocateSmall(t, sizeInBytes);
|
return allocateSmall(t, sizeInBytes);
|
||||||
}
|
}
|
||||||
@ -2705,107 +2690,8 @@ collect(Thread* t, Heap::CollectionType type)
|
|||||||
{
|
{
|
||||||
Machine* m = t->m;
|
Machine* m = t->m;
|
||||||
|
|
||||||
class Client: public Heap::Client {
|
|
||||||
public:
|
|
||||||
Client(Machine* m): m(m) { }
|
|
||||||
|
|
||||||
virtual void visitRoots(Heap::Visitor* v) {
|
|
||||||
Thread* t = m->rootThread;
|
|
||||||
|
|
||||||
visit(t, v, &(m->loader));
|
|
||||||
visit(t, v, &(m->bootstrapClassMap));
|
|
||||||
visit(t, v, &(m->monitorMap));
|
|
||||||
visit(t, v, &(m->stringMap));
|
|
||||||
visit(t, v, &(m->types));
|
|
||||||
visit(t, v, &(m->jniInterfaceTable));
|
|
||||||
|
|
||||||
for (Reference* r = m->jniReferences; r; r = r->next) {
|
|
||||||
visit(t, v, &(r->target));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Thread* t = m->rootThread; t; t = t->peer) {
|
|
||||||
::visitRoots(t, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m->heap->collectionType() == Heap::MinorCollection) {
|
|
||||||
visitDirtyFixies(t, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
postVisit(m->rootThread, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool checkFixed(void* p) {
|
|
||||||
Thread* t = m->rootThread;
|
|
||||||
object o = static_cast<object>(p);
|
|
||||||
|
|
||||||
if (objectFixed(t, o)) {
|
|
||||||
if ((not fixedMarked(t, o))
|
|
||||||
and m->heap->collectionType() == Heap::MajorCollection
|
|
||||||
or fixedAge(t, o) < TenureThreshold)
|
|
||||||
{
|
|
||||||
fixedMarked(t, o) = 1;
|
|
||||||
fixedMove(t, o, &(m->markedFixies));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual unsigned copiedSizeInWords(void* p) {
|
|
||||||
Thread* t = m->rootThread;
|
|
||||||
|
|
||||||
object o = static_cast<object>(m->heap->follow(mask(p)));
|
|
||||||
assert(t, not objectFixed(t, o));
|
|
||||||
|
|
||||||
unsigned n = baseSize(t, o, static_cast<object>
|
|
||||||
(m->heap->follow(objectClass(t, o))));
|
|
||||||
|
|
||||||
if (objectExtended(t, o) or hashTaken(t, o)) {
|
|
||||||
++ n;
|
|
||||||
}
|
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void copy(void* srcp, void* dstp) {
|
|
||||||
Thread* t = m->rootThread;
|
|
||||||
|
|
||||||
object src = static_cast<object>(m->heap->follow(mask(srcp)));
|
|
||||||
assert(t, not objectFixed(t, src));
|
|
||||||
|
|
||||||
object class_ = static_cast<object>
|
|
||||||
(m->heap->follow(objectClass(t, src)));
|
|
||||||
|
|
||||||
unsigned base = baseSize(t, src, class_);
|
|
||||||
unsigned n = extendedSize(t, src, base);
|
|
||||||
|
|
||||||
object dst = static_cast<object>(dstp);
|
|
||||||
|
|
||||||
memcpy(dst, src, n * BytesPerWord);
|
|
||||||
|
|
||||||
if (hashTaken(t, src)) {
|
|
||||||
cast<uintptr_t>(dst, 0) &= PointerMask;
|
|
||||||
cast<uintptr_t>(dst, 0) |= ExtendedMark;
|
|
||||||
extendedWord(t, dst, base) = takeHash(t, src);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void walk(void* p, Heap::Walker* w) {
|
|
||||||
Thread* t = m->rootThread;
|
|
||||||
|
|
||||||
object o = static_cast<object>(m->heap->follow(mask(p)));
|
|
||||||
assert(t, not objectFixed(t, o));
|
|
||||||
|
|
||||||
::walk(m->rootThread, o, w);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Machine* m;
|
|
||||||
} it(m);
|
|
||||||
|
|
||||||
m->unsafe = true;
|
m->unsafe = true;
|
||||||
m->heap->collect(type, &it, footprint(m->rootThread));
|
m->heap->collect(type, footprint(m->rootThread));
|
||||||
m->unsafe = false;
|
m->unsafe = false;
|
||||||
|
|
||||||
postCollect(m->rootThread);
|
postCollect(m->rootThread);
|
||||||
@ -2824,7 +2710,7 @@ collect(Thread* t, Heap::CollectionType type)
|
|||||||
}
|
}
|
||||||
m->heapPoolIndex = 0;
|
m->heapPoolIndex = 0;
|
||||||
|
|
||||||
sweepFixies(t);
|
m->fixedFootprint = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -2907,84 +2793,6 @@ makeTrace(Thread* t, uintptr_t start)
|
|||||||
return trace;
|
return trace;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
mark(Thread* t, object o, unsigned offset)
|
|
||||||
{
|
|
||||||
if (objectFixed(t, o)) {
|
|
||||||
if (fixedAge(t, o) == TenureThreshold) {
|
|
||||||
ACQUIRE_RAW(t, t->m->heapLock);
|
|
||||||
|
|
||||||
markBit(fixedMask(t, o), offset / BytesPerWord);
|
|
||||||
|
|
||||||
fixedDirty(t, o) = 1;
|
|
||||||
fixedMove(t, o, &(t->m->dirtyFixies));
|
|
||||||
}
|
|
||||||
} else if (t->m->heap->needsMark(&cast<void*>(o, offset))) {
|
|
||||||
ACQUIRE_RAW(t, t->m->heapLock);
|
|
||||||
|
|
||||||
t->m->heap->mark(&cast<void*>(o, offset));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
mark(Thread* t, object o, unsigned offset, unsigned count)
|
|
||||||
{
|
|
||||||
if (objectFixed(t, o)) {
|
|
||||||
if (fixedAge(t, o) == TenureThreshold) {
|
|
||||||
ACQUIRE_RAW(t, t->m->heapLock);
|
|
||||||
|
|
||||||
uintptr_t* mask = fixedMask(t, o);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < count; ++i) {
|
|
||||||
markBit(mask, (offset / BytesPerWord) + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
fixedDirty(t, o) = 1;
|
|
||||||
fixedMove(t, o, &(t->m->dirtyFixies));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ACQUIRE_RAW(t, t->m->heapLock);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < count; ++i) {
|
|
||||||
unsigned j = offset + (i * BytesPerWord);
|
|
||||||
if (t->m->heap->needsMark(&cast<void*>(o, j))) {
|
|
||||||
t->m->heap->mark(&cast<void*>(o, j));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
visit(Thread* t, Heap::Visitor* v, object* p)
|
|
||||||
{
|
|
||||||
v->visit(p);
|
|
||||||
|
|
||||||
for (object* p = &(t->m->markedFixies); *p;) {
|
|
||||||
object o = *p;
|
|
||||||
*p = fixedNext(t, o);
|
|
||||||
|
|
||||||
class Walker: public Heap::Walker {
|
|
||||||
public:
|
|
||||||
Walker(Thread* t, Heap::Visitor* v, object o):
|
|
||||||
t(t), v(v), o(o)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
virtual bool visit(unsigned offset) {
|
|
||||||
::visit(t, v, &cast<object>(o, offset * BytesPerWord));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread* t;
|
|
||||||
Heap::Visitor* v;
|
|
||||||
object o;
|
|
||||||
} w(t, v, o);
|
|
||||||
|
|
||||||
walk(t, o, &w);
|
|
||||||
|
|
||||||
fixedMove(t, o, &(t->m->visitedFixies));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
noop()
|
noop()
|
||||||
{ }
|
{ }
|
||||||
|
137
src/machine.h
137
src/machine.h
@ -34,13 +34,6 @@ const uintptr_t HashTakenMark = 1;
|
|||||||
const uintptr_t ExtendedMark = 2;
|
const uintptr_t ExtendedMark = 2;
|
||||||
const uintptr_t FixedMark = 3;
|
const uintptr_t FixedMark = 3;
|
||||||
|
|
||||||
const unsigned FixedAge = 0;
|
|
||||||
const unsigned FixedMarked = 1;
|
|
||||||
const unsigned FixedDirty = 2;
|
|
||||||
const unsigned FixedHandle = BytesPerWord;
|
|
||||||
const unsigned FixedNext = BytesPerWord * 2;
|
|
||||||
const unsigned FixedFootprint = BytesPerWord * 3;
|
|
||||||
|
|
||||||
enum FieldCode {
|
enum FieldCode {
|
||||||
VoidField,
|
VoidField,
|
||||||
ByteField,
|
ByteField,
|
||||||
@ -1116,7 +1109,7 @@ class Machine {
|
|||||||
ActiveState
|
ActiveState
|
||||||
};
|
};
|
||||||
|
|
||||||
Machine(System* system, Heap* heap, Finder* finder, Processor* processor);
|
Machine(System* system, Finder* finder, Processor* processor);
|
||||||
|
|
||||||
~Machine() {
|
~Machine() {
|
||||||
dispose();
|
dispose();
|
||||||
@ -1124,6 +1117,8 @@ class Machine {
|
|||||||
|
|
||||||
static const unsigned HeapPoolSize = 8;
|
static const unsigned HeapPoolSize = 8;
|
||||||
|
|
||||||
|
static const unsigned FixedFootprintThresholdInBytes = 256 * 1024;
|
||||||
|
|
||||||
void dispose();
|
void dispose();
|
||||||
|
|
||||||
JavaVMVTable* vtable;
|
JavaVMVTable* vtable;
|
||||||
@ -1137,6 +1132,7 @@ class Machine {
|
|||||||
const char* builtins;
|
const char* builtins;
|
||||||
unsigned activeCount;
|
unsigned activeCount;
|
||||||
unsigned liveCount;
|
unsigned liveCount;
|
||||||
|
unsigned fixedFootprint;
|
||||||
System::Local* localThread;
|
System::Local* localThread;
|
||||||
System::Monitor* stateLock;
|
System::Monitor* stateLock;
|
||||||
System::Monitor* heapLock;
|
System::Monitor* heapLock;
|
||||||
@ -1154,11 +1150,6 @@ class Machine {
|
|||||||
object finalizeQueue;
|
object finalizeQueue;
|
||||||
object weakReferences;
|
object weakReferences;
|
||||||
object tenuredWeakReferences;
|
object tenuredWeakReferences;
|
||||||
object fixies;
|
|
||||||
object tenuredFixies;
|
|
||||||
object dirtyFixies;
|
|
||||||
object markedFixies;
|
|
||||||
object visitedFixies;
|
|
||||||
bool unsafe;
|
bool unsafe;
|
||||||
JavaVMVTable javaVMVTable;
|
JavaVMVTable javaVMVTable;
|
||||||
JNIEnvVTable jniEnvVTable;
|
JNIEnvVTable jniEnvVTable;
|
||||||
@ -1175,9 +1166,6 @@ threadInterrupted(Thread* t, object thread);
|
|||||||
void
|
void
|
||||||
enterActiveState(Thread* t);
|
enterActiveState(Thread* t);
|
||||||
|
|
||||||
void
|
|
||||||
visit(Thread* t, Heap::Visitor* v, object* p);
|
|
||||||
|
|
||||||
class Thread {
|
class Thread {
|
||||||
public:
|
public:
|
||||||
enum State {
|
enum State {
|
||||||
@ -1211,7 +1199,7 @@ class Thread {
|
|||||||
SingleProtector(Thread* t, object* p): Protector(t), p(p) { }
|
SingleProtector(Thread* t, object* p): Protector(t), p(p) { }
|
||||||
|
|
||||||
virtual void visit(Heap::Visitor* v) {
|
virtual void visit(Heap::Visitor* v) {
|
||||||
vm::visit(t, v, p);
|
v->visit(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
object* p;
|
object* p;
|
||||||
@ -1266,7 +1254,6 @@ class Thread {
|
|||||||
Thread* peer;
|
Thread* peer;
|
||||||
Thread* child;
|
Thread* child;
|
||||||
State state;
|
State state;
|
||||||
bool allocatedLarge;
|
|
||||||
unsigned criticalLevel;
|
unsigned criticalLevel;
|
||||||
System::Thread* systemThread;
|
System::Thread* systemThread;
|
||||||
object javaThread;
|
object javaThread;
|
||||||
@ -1422,10 +1409,7 @@ expect(Thread* t, bool v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
allocateFixed(Thread* t, unsigned sizeInBytes, bool objectMask);
|
allocate2(Thread* t, unsigned sizeInBytes, bool objectMask, bool fixed);
|
||||||
|
|
||||||
object
|
|
||||||
allocate2(Thread* t, unsigned sizeInBytes, bool objectMask);
|
|
||||||
|
|
||||||
inline object
|
inline object
|
||||||
allocateSmall(Thread* t, unsigned sizeInBytes)
|
allocateSmall(Thread* t, unsigned sizeInBytes)
|
||||||
@ -1445,17 +1429,27 @@ allocate(Thread* t, unsigned sizeInBytes, bool objectMask)
|
|||||||
>= Thread::HeapSizeInWords
|
>= Thread::HeapSizeInWords
|
||||||
or t->m->exclusive))
|
or t->m->exclusive))
|
||||||
{
|
{
|
||||||
return allocate2(t, sizeInBytes, objectMask);
|
return allocate2(t, sizeInBytes, objectMask,
|
||||||
|
sizeInBytes > Thread::HeapSizeInBytes);
|
||||||
} else {
|
} else {
|
||||||
return allocateSmall(t, sizeInBytes);
|
return allocateSmall(t, sizeInBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
inline void
|
||||||
mark(Thread* t, object target, unsigned offset);
|
mark(Thread* t, object o, unsigned offset, unsigned count)
|
||||||
|
{
|
||||||
|
if (t->m->heap->needsMark(o)) {
|
||||||
|
ACQUIRE_RAW(t, t->m->heapLock);
|
||||||
|
t->m->heap->mark(o, offset / BytesPerWord, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
inline void
|
||||||
mark(Thread* t, object target, unsigned offset, unsigned count);
|
mark(Thread* t, object o, unsigned offset)
|
||||||
|
{
|
||||||
|
mark(t, o, offset, 1);
|
||||||
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
set(Thread* t, object target, unsigned offset, object value)
|
set(Thread* t, object target, unsigned offset, object value)
|
||||||
@ -1505,95 +1499,6 @@ baseSize(Thread* t, object o, object class_)
|
|||||||
BytesPerWord);
|
BytesPerWord);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void*
|
|
||||||
fixedStart(Thread* t UNUSED, object o)
|
|
||||||
{
|
|
||||||
assert(t, objectFixed(t, o));
|
|
||||||
return &cast<object>(o, - FixedFootprint);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint8_t&
|
|
||||||
fixedAge(Thread* t UNUSED, object o)
|
|
||||||
{
|
|
||||||
assert(t, objectFixed(t, o));
|
|
||||||
return cast<uint8_t>(o, - (FixedFootprint - FixedAge));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint8_t&
|
|
||||||
fixedMarked(Thread* t UNUSED, object o)
|
|
||||||
{
|
|
||||||
assert(t, objectFixed(t, o));
|
|
||||||
return cast<uint8_t>(o, - (FixedFootprint - FixedMarked));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint8_t&
|
|
||||||
fixedDirty(Thread* t UNUSED, object o)
|
|
||||||
{
|
|
||||||
assert(t, objectFixed(t, o));
|
|
||||||
return cast<uint8_t>(o, - (FixedFootprint - FixedDirty));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline object*&
|
|
||||||
fixedHandle(Thread* t UNUSED, object o)
|
|
||||||
{
|
|
||||||
assert(t, objectFixed(t, o));
|
|
||||||
return cast<object*>(o, - (FixedFootprint - FixedHandle));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline object&
|
|
||||||
fixedNext(Thread* t UNUSED, object o)
|
|
||||||
{
|
|
||||||
assert(t, objectFixed(t, o));
|
|
||||||
return cast<object>(o, - (FixedFootprint - FixedNext));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
fixedAdd(Thread* t, object o, object* handle)
|
|
||||||
{
|
|
||||||
// fprintf(stderr, "add %p to %s\n", o,
|
|
||||||
// handle == &(t->m->fixies) ? "fixies" :
|
|
||||||
// handle == &(t->m->tenuredFixies) ? "tenured" :
|
|
||||||
// handle == &(t->m->dirtyFixies) ? "dirty" :
|
|
||||||
// handle == &(t->m->markedFixies) ? "marked" :
|
|
||||||
// handle == &(t->m->visitedFixies) ? "visited" : "unknown");
|
|
||||||
|
|
||||||
fixedHandle(t, o) = handle;
|
|
||||||
fixedNext(t, o) = *handle;
|
|
||||||
if (*handle) {
|
|
||||||
fixedHandle(t, *handle) = &fixedNext(t, o);
|
|
||||||
}
|
|
||||||
*handle = o;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
fixedRemove(Thread* t, object o)
|
|
||||||
{
|
|
||||||
*fixedHandle(t, o) = fixedNext(t, o);
|
|
||||||
if (fixedNext(t, o)) {
|
|
||||||
fixedHandle(t, fixedNext(t, o)) = fixedHandle(t, o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
fixedMove(Thread* t, object o, object* handle)
|
|
||||||
{
|
|
||||||
fixedRemove(t, o);
|
|
||||||
fixedAdd(t, o, handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uintptr_t*
|
|
||||||
fixedMask(Thread* t UNUSED, object o, unsigned size)
|
|
||||||
{
|
|
||||||
assert(t, objectFixed(t, o));
|
|
||||||
return &cast<uintptr_t>(o, size * BytesPerWord);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uintptr_t*
|
|
||||||
fixedMask(Thread* t, object o)
|
|
||||||
{
|
|
||||||
return fixedMask(t, o, baseSize(t, o, objectClass(t, o)));
|
|
||||||
}
|
|
||||||
|
|
||||||
object
|
object
|
||||||
makeTrace(Thread* t, uintptr_t start);
|
makeTrace(Thread* t, uintptr_t start);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user