initial work to support boot image creation and use

This commit is contained in:
Joel Dice 2008-11-21 16:20:35 -07:00
parent 15ea90cd0c
commit 6500f1eff6
15 changed files with 975 additions and 375 deletions

View File

@ -201,11 +201,6 @@ vm-sources = \
$(src)/process.cpp \
$(src)/$(asm).cpp
ifeq ($(heapdump),true)
vm-sources += $(src)/heapdump.cpp
cflags += -DAVIAN_HEAPDUMP
endif
vm-asm-sources = $(src)/$(asm).S
ifeq ($(process),compile)
@ -222,6 +217,21 @@ vm-cpp-objects = $(call cpp-objects,$(vm-sources),$(src),$(native-build))
vm-asm-objects = $(call asm-objects,$(vm-asm-sources),$(src),$(native-build))
vm-objects = $(vm-cpp-objects) $(vm-asm-objects)
heapwalk-sources = $(src)/heapwalk.cpp
heapwalk-objects = \
$(call cpp-objects,$(heapwalk-sources),$(src),$(native-build))
ifeq ($(heapdump),true)
vm-sources += $(src)/heapdump.cpp
vm-heapwalk-objects = $(heapwalk-objects)
cflags += -DAVIAN_HEAPDUMP
endif
bootimage-sources = $(src)/bootimage.cpp
bootimage-objects = \
$(call cpp-objects,$(bootimage-sources),$(src),$(native-build))
bootimage = $(native-build)/bootimage
driver-source = $(src)/main.cpp
driver-object = $(native-build)/main.o
driver-dynamic-object = $(native-build)/main-dynamic.o
@ -259,7 +269,7 @@ args = $(flags) $(input)
.PHONY: build
build: $(static-library) $(executable) $(dynamic-library) \
$(executable-dynamic) $(classpath-dep) $(test-dep)
$(executable-dynamic) $(classpath-dep) $(test-dep) $(bootimage)
$(test-classes): $(classpath-dep)
@ -346,6 +356,12 @@ $(vm-cpp-objects): $(native-build)/%.o: $(src)/%.cpp $(vm-depends)
$(vm-asm-objects): $(native-build)/%-asm.o: $(src)/%.S
$(compile-asm-object)
$(bootimage-objects): $(native-build)/%.o: $(src)/%.cpp $(vm-depends)
$(compile-object)
$(heapwalk-objects): $(native-build)/%.o: $(src)/%.cpp $(vm-depends)
$(compile-object)
$(driver-object): $(driver-source)
$(compile-object)
@ -395,7 +411,20 @@ $(static-library): $(vm-objects) $(jni-objects)
$(executable): \
$(vm-objects) $(classpath-object) $(jni-objects) $(driver-object) \
$(boot-object)
$(vm-heapwalk-objects) $(boot-object)
@echo "linking $(@)"
ifeq ($(platform),windows)
$(dlltool) -z $(@).def $(^)
$(dlltool) -d $(@).def -e $(@).exp
$(cc) $(@).exp $(^) $(lflags) -o $(@)
else
$(cc) $(^) $(rdynamic) $(lflags) -o $(@)
endif
$(strip) $(strip-all) $(@)
$(bootimage): \
$(vm-objects) $(classpath-object) $(jni-objects) $(heapwalk-objects) \
$(bootimage-objects)
@echo "linking $(@)"
ifeq ($(platform),windows)
$(dlltool) -z $(@).def $(^)
@ -408,7 +437,7 @@ endif
$(dynamic-library): \
$(vm-objects) $(classpath-object) $(dynamic-object) $(jni-objects) \
$(boot-object)
$(vm-heapwalk-objects) $(boot-object)
@echo "linking $(@)"
$(cc) $(^) $(shared) $(lflags) -o $(@)
$(strip) $(strip-all) $(@)

240
src/bootimage.cpp Normal file
View File

@ -0,0 +1,240 @@
#include "bootimage.h"
#include "heapwalk.h"
#include "common.h"
#include "machine.h"
#include "util.h"
using namespace vm;
namespace {
bool
endsWith(const char* suffix, const char* s, unsigned length)
{
unsigned suffixLength = strlen(suffix);
return length >= suffixLength
and memcmp(suffix, s + (length - suffixLength), suffixLength) == 0;
}
unsigned
codeMapSize(unsigned codeSize)
{
return ceiling(codeSize, BitsPerWord) * BytesPerWord;
}
object
makeCodeImage(Thread* t, BootImage* image, uint8_t* code, unsigned capacity)
{
unsigned size;
compileThunks(t, code, &size, image);
unsigned fixupCount = 0;
object table = makeHashMap(t, 0, 0);
PROTECT(t, table);
for (Finder::Iterator it(t->m->finder); it.hasMore();) {
unsigned nameSize;
const char* name = it.next(&nameSize);
if (endsWith(".class", name, nameSize)) {
object c = resolveClass
(t, makeByteArray(t, "%*s", nameSize - 5, name));
PROTECT(t, c);
for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) {
object method = arrayBody(t, classMethodTable(t, c), i);
if (methodCode(t, method)) {
compileMethod(t, method, code, &size, capacity,
&table, &fixupCount);
}
}
}
}
image->codeSize = size;
return table;
}
unsigned
heapMapSize(unsigned heapSize)
{
return ceiling(heapSize, BitsPerWord * 8) * BytesPerWord;
}
unsigned
objectSize(Thread* t, object o)
{
assert(t, not objectExtended(t, o));
return baseSize(t, o, objectClass(t, o));
}
HeapMap*
makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map,
unsigned capacity)
{
class Walker: public HeapWalker {
public:
Walker(Thread* t, uintptr_t* heap, uintptr_t* map, unsigned capacity):
t(t), currentObject(0), currentOffset(0), heap(heap), map(map),
position(0), capacity(capacity)
{ }
void visit(object p, unsigned number) {
if (currentObject) {
markBit(map, (currentObject - heap) + currentOffset);
currentObject[currentOffset] = number;
}
currentObject = reinterpret_cast<uintptr_t*>(p);
}
virtual void root() {
currentObject = 0;
}
virtual unsigned visitNew(object p) {
if (p) {
unsigned size = objectSize(t, p);
assert(t, position + size < capacity);
memcpy(heap + position, p, size * BytesPerWord);
unsigned number = position + 1;
position += size;
visit(p, number);
return number;
} else {
return 0;
}
}
virtual void visitOld(object, unsigned number) {
visit(0, number);
}
virtual void push(unsigned offset) {
currentOffset = offset;
}
virtual void pop() {
currentObject = 0;
}
Thread* t;
uintptr_t* currentObject;
unsigned currentOffset;
uintptr_t* heap;
uintptr_t* map;
unsigned position;
unsigned capacity;
} walker(t, heap, map, capacity / BytesPerWord);
HeapMap* table = walk(t, &walker);
image->heapSize = walker.position * BytesPerWord;
return table;
}
void
updateCodeTable(Thread* t, object codeTable, uint8_t* code, uintptr_t* codeMap,
HeapMap* heapTable)
{
intptr_t i = 0;
for (HashMapIterator it(t, codeTable); it.hasMore(); ++i) {
object mapEntry = it.next();
intptr_t target = heapTable->find(tripleFirst(t, mapEntry));
assert(t, target >= 0);
for (object fixup = tripleSecond(t, mapEntry);
fixup;
fixup = pairSecond(t, fixup))
{
int32_t v = intValue(t, pairFirst(t, fixup));
memcpy(code + v, &target, BytesPerWord);
markBit(codeMap, v);
}
}
}
unsigned
offset(object a, uintptr_t* b)
{
return reinterpret_cast<uintptr_t>(b) - reinterpret_cast<uintptr_t>(a);
}
void
writeBootImage(Thread* t, FILE* out)
{
BootImage image;
const unsigned CodeCapacity = 32 * 1024 * 1024;
uint8_t* code = static_cast<uint8_t*>(t->m->heap->allocate(CodeCapacity));
uintptr_t* codeMap = static_cast<uintptr_t*>
(t->m->heap->allocate(codeMapSize(CodeCapacity)));
memset(codeMap, 0, codeMapSize(CodeCapacity));
object codeTable = makeCodeImage(t, &image, code, CodeCapacity);
const unsigned HeapCapacity = 32 * 1024 * 1024;
uintptr_t* heap = static_cast<uintptr_t*>
(t->m->heap->allocate(HeapCapacity));
uintptr_t* heapMap = static_cast<uintptr_t*>
(t->m->heap->allocate(heapMapSize(HeapCapacity)));
memset(heapMap, 0, heapMapSize(HeapCapacity));
HeapMap* heapTable = makeHeapImage(t, &image, heap, heapMap, HeapCapacity);
updateCodeTable(t, codeTable, code, codeMap, heapTable);
image.magic = BootImage::Magic;
image.codeTable = offset(codeTable, heap);
image.loader = offset(t->m->loader, heap);
image.bootstrapClassMap = offset(t->m->bootstrapClassMap, heap);
image.stringMap = offset(t->m->stringMap, heap);
image.types = offset(t->m->types, heap);
image.jniMethodTable = offset(t->m->jniMethodTable, heap);
image.finalizers = offset(t->m->finalizers, heap);
image.tenuredFinalizers = offset(t->m->tenuredFinalizers, heap);
image.finalizeQueue = offset(t->m->finalizeQueue, heap);
image.weakReferences = offset(t->m->weakReferences, heap);
image.tenuredWeakReferences = offset(t->m->tenuredWeakReferences, heap);
fwrite(&image, sizeof(BootImage), 1, out);
fwrite(heapMap, pad(heapMapSize(image.heapSize)), 1, out);
fwrite(heap, pad(image.heapSize), 1, out);
fwrite(codeMap, pad(codeMapSize(image.codeSize)), 1, out);
fwrite(code, pad(image.codeSize), 1, out);
}
} // namespace
int
main(int ac, const char** av)
{
if (ac != 2) {
fprintf(stderr, "usage: %s <classpath>\n", av[0]);
return -1;
}
System* s = makeSystem(0);
Heap* h = makeHeap(s, 128 * 1024 * 1024);
Finder* f = makeFinder(s, av[0], 0);
Processor* p = makeProcessor(s, h);
Machine* m = new (h->allocate(sizeof(Machine))) Machine(s, h, f, p, 0, 0);
Thread* t = p->makeThread(m, 0, 0);
enter(t, Thread::ActiveState);
enter(t, Thread::IdleState);
writeBootImage(t, stdout);
return 0;
}

34
src/bootimage.h Normal file
View File

@ -0,0 +1,34 @@
namespace vm {
class BootImage {
public:
static const unsigned Magic = 0x22377322;
unsigned magic;
unsigned heapSize;
unsigned codeSize;
unsigned codeTable;
unsigned loader;
unsigned bootstrapClassMap;
unsigned stringMap;
unsigned types;
unsigned jniMethodTable;
unsigned finalizers;
unsigned tenuredFinalizers;
unsigned finalizeQueue;
unsigned weakReferences;
unsigned tenuredWeakReferences;
unsigned defaultThunk;
unsigned nativeThunk;
unsigned aioobThunk;
#define THUNK(s) unsigned s##Thunk;
#include "thunks.cpp"
#undef THUNK
};
} // namespace vm

View File

@ -59,8 +59,15 @@ equal(const void* a, unsigned al, const void* b, unsigned bl)
class Element {
public:
class Iterator {
public:
virtual const char* next(unsigned* size) = 0;
virtual void dispose() = 0;
};
Element(): next(0) { }
virtual Iterator* iterator() = 0;
virtual System::Region* find(const char* name) = 0;
virtual bool exists(const char* name) = 0;
virtual void dispose() = 0;
@ -70,10 +77,45 @@ class Element {
class DirectoryElement: public Element {
public:
class Iterator: public Element::Iterator {
public:
Iterator(System* s, const char* name):
s(s), directory(0)
{
if (not s->success(s->open(&directory, name))) {
directory = 0;
}
}
virtual const char* next(unsigned* size) {
if (directory) {
for (const char* v = directory->next(); v; v = directory->next()) {
if (v[0] != '.') {
*size = strlen(v);
return v;
}
}
}
return 0;
}
virtual void dispose() {
directory->dispose();
s->free(this);
}
System* s;
System::Directory* directory;
};
DirectoryElement(System* s, const char* name):
s(s), name(name)
{ }
virtual Element::Iterator* iterator() {
return new (allocate(s, sizeof(Iterator))) Iterator(s, name);
}
virtual System::Region* find(const char* name) {
const char* file = append(s, this->name, "/", name);
System::Region* region;
@ -91,7 +133,7 @@ class DirectoryElement: public Element {
const char* file = append(s, this->name, "/", name);
System::FileType type = s->identify(file);
s->free(file);
return type != System::DoesNotExist;
return type != System::TypeDoesNotExist;
}
virtual void dispose() {
@ -379,10 +421,37 @@ class JarIndex {
class JarElement: public Element {
public:
class Iterator: public Element::Iterator {
public:
Iterator(System* s, JarIndex* index): s(s), index(index), position(0) { }
virtual const char* next(unsigned* size) {
if (position < index->position) {
JarIndex::Node* n = index->nodes + (position++);
*size = JarIndex::fileNameLength(n->entry);
return reinterpret_cast<const char*>(JarIndex::fileName(n->entry));
} else {
return 0;
}
}
virtual void dispose() {
s->free(this);
}
System* s;
JarIndex* index;
unsigned position;
};
JarElement(System* s, const char* name):
s(s), name(name), region(0), index(0)
{ }
virtual Element::Iterator* iterator() {
return new (allocate(s, sizeof(Iterator))) Iterator(s, index);
}
virtual void init() {
if (index == 0) {
System::Region* r;
@ -512,11 +581,11 @@ parsePath(System* s, const char* path, const char* bootLibrary)
name[token.length] = 0;
switch (s->identify(name)) {
case System::File: {
case System::TypeFile: {
e = new (allocate(s, sizeof(JarElement))) JarElement(s, name);
} break;
case System::Directory: {
case System::TypeDirectory: {
e = new (allocate(s, sizeof(DirectoryElement)))
DirectoryElement(s, name);
} break;
@ -541,6 +610,38 @@ parsePath(System* s, const char* path, const char* bootLibrary)
return first;
}
class MyIterator: public Finder::IteratorImp {
public:
MyIterator(System* s, Element* path):
s(s), e(path ? path->next : 0), it(path ? path->iterator() : 0)
{ }
virtual const char* next(unsigned* size) {
while (it) {
const char* v = it->next(size);
if (v) {
return v;
} else {
it->dispose();
if (e) {
it = e->iterator();
e = e->next;
}
}
}
return 0;
}
virtual void dispose() {
if (it) it->dispose();
s->free(this);
}
System* s;
Element* e;
Element::Iterator* it;
};
class MyFinder: public Finder {
public:
MyFinder(System* system, const char* path, const char* bootLibrary):
@ -549,6 +650,11 @@ class MyFinder: public Finder {
pathString(copy(system, path))
{ }
virtual IteratorImp* iterator() {
return new (allocate(system, sizeof(MyIterator)))
MyIterator(system, path_);
}
virtual System::Region* find(const char* name) {
for (Element* e = path_; e; e = e->next) {
System::Region* r = e->find(name);

View File

@ -19,6 +19,44 @@ namespace vm {
class Finder {
public:
class IteratorImp {
public:
virtual const char* next(unsigned* size) = 0;
virtual void dispose() = 0;
};
class Iterator {
public:
Iterator(Finder* finder):
it(finder->iterator()),
current(it->next(&currentSize))
{ }
~Iterator() {
it->dispose();
}
bool hasMore() {
return current != 0;
}
const char* next(unsigned* size) {
if (current) {
const char* v = current;
*size = currentSize;
current = it->next(&currentSize);
return v;
} else {
return 0;
}
}
IteratorImp* it;
const char* current;
unsigned currentSize;
};
virtual IteratorImp* iterator();
virtual System::Region* find(const char* name) = 0;
virtual bool exists(const char* name) = 0;
virtual const char* path() = 0;

View File

@ -8,195 +8,12 @@
There is NO WARRANTY for this software. See license.txt for
details. */
#include "machine.h"
#include "heapwalk.h"
using namespace vm;
namespace {
const uintptr_t PointerShift = log(BytesPerWord);
class Set {
public:
class Entry {
public:
object value;
uint32_t number;
int next;
};
static unsigned footprint(unsigned capacity) {
return sizeof(Set)
+ pad(sizeof(int) * capacity)
+ pad(sizeof(Set::Entry) * capacity);
}
Set(unsigned capacity):
size(0),
capacity(capacity),
index(reinterpret_cast<int*>
(reinterpret_cast<uint8_t*>(this)
+ sizeof(Set))),
entries(reinterpret_cast<Entry*>
(reinterpret_cast<uint8_t*>(index)
+ pad(sizeof(int) * capacity)))
{ }
unsigned size;
unsigned capacity;
int* index;
Entry* entries;
};
class Stack {
public:
class Entry {
public:
object value;
int offset;
};
static const unsigned Capacity = 4096;
Stack(Stack* next): next(next), entryCount(0) { }
Stack* next;
unsigned entryCount;
Entry entries[Capacity];
};
class Context {
public:
Context(Thread* thread, FILE* out):
thread(thread), out(out), objects(0), stack(0), nextNumber(1)
{ }
~Context() {
if (objects) {
thread->m->heap->free(objects, Set::footprint(objects->capacity));
}
while (stack) {
Stack* dead = stack;
stack = dead->next;
thread->m->heap->free(stack, sizeof(Stack));
}
}
Thread* thread;
FILE* out;
Set* objects;
Stack* stack;
uint32_t nextNumber;
};
void
push(Context* c, object p, int offset)
{
if (c->stack == 0 or c->stack->entryCount == Stack::Capacity) {
c->stack = new (c->thread->m->heap->allocate(sizeof(Stack)))
Stack(c->stack);
}
Stack::Entry* e = c->stack->entries + (c->stack->entryCount++);
e->value = p;
e->offset = offset;
}
bool
pop(Context* c, object* p, int* offset)
{
if (c->stack) {
if (c->stack->entryCount == 0) {
if (c->stack->next) {
Stack* dead = c->stack;
c->stack = dead->next;
c->thread->m->heap->free(dead, sizeof(Stack));
} else {
return false;
}
}
Stack::Entry* e = c->stack->entries + (--c->stack->entryCount);
*p = e->value;
*offset = e->offset;
return true;
} else {
return false;
}
}
unsigned
hash(object p, unsigned capacity)
{
return (reinterpret_cast<uintptr_t>(p) >> PointerShift)
& (capacity - 1);
}
Set::Entry*
find(Context* c, object p)
{
if (c->objects == 0) return 0;
for (int i = c->objects->index[hash(p, c->objects->capacity)]; i >= 0;) {
Set::Entry* e = c->objects->entries + i;
if (e->value == p) {
return e;
}
i = e->next;
}
return 0;
}
Set::Entry*
add(Context* c UNUSED, Set* set, object p, uint32_t number)
{
assert(c->thread, set->size < set->capacity);
unsigned index = hash(p, set->capacity);
int offset = set->size++;
Set::Entry* e = set->entries + offset;
e->value = p;
e->number = number;
e->next = set->index[index];
set->index[index] = offset;
return e;
}
Set::Entry*
add(Context* c, object p)
{
if (c->objects == 0 or c->objects->size == c->objects->capacity) {
unsigned capacity;
if (c->objects) {
capacity = c->objects->capacity * 2;
} else {
capacity = 4096; // must be power of two
}
Set* set = new (c->thread->m->heap->allocate(Set::footprint(capacity)))
Set(capacity);
memset(set->index, 0xFF, sizeof(int) * capacity);
if (c->objects) {
for (unsigned i = 0; i < c->objects->capacity; ++i) {
for (int j = c->objects->index[i]; j >= 0;) {
Set::Entry* e = c->objects->entries + j;
add(c, set, e->value, e->number);
j = e->next;
}
}
c->thread->m->heap->free
(c->objects, Set::footprint(c->objects->capacity));
}
c->objects = set;
}
return add(c, c->objects, p, 0);
}
enum {
Root,
Size,
@ -205,100 +22,30 @@ enum {
Pop
};
inline object
get(object o, unsigned offsetInWords)
void
write1(FILE* out, uint8_t v)
{
return static_cast<object>
(mask(cast<void*>(o, offsetInWords * BytesPerWord)));
fwrite(&v, 1, 1, out);
}
void
write1(Context* c, uint8_t v)
{
fwrite(&v, 1, 1, c->out);
}
void
write4(Context* c, uint32_t v)
write4(FILE* out, uint32_t v)
{
uint8_t b[] = { v >> 24, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF };
fwrite(b, 4, 1, c->out);
fwrite(b, 4, 1, out);
}
void
writeString(Context* c, int8_t* p, unsigned size)
writeString(FILE* out, int8_t* p, unsigned size)
{
write4(c, size);
fwrite(p, size, 1, c->out);
write4(out, size);
fwrite(p, size, 1, out);
}
unsigned
objectSize(Thread* t, object o)
{
unsigned n = baseSize(t, o, objectClass(t, o));
if (objectExtended(t, o)) {
++ n;
}
return n;
}
void
visit(Context* c, object p)
{
Thread* t = c->thread;
int nextChildOffset;
write1(c, Root);
visit: {
Set::Entry* e = find(c, p);
if (e) {
write4(c, e->number);
} else {
e = add(c, p);
e->number = c->nextNumber++;
write4(c, e->number);
write1(c, Size);
write4(c, objectSize(t, p));
if (objectClass(t, p) == arrayBody(t, t->m->types, Machine::ClassType)) {
object name = className(t, p);
if (name) {
write1(c, ClassName);
writeString(c, &byteArrayBody(t, name, 0),
byteArrayLength(t, name) - 1);
}
}
nextChildOffset = walkNext(t, p, -1);
if (nextChildOffset != -1) {
goto children;
}
}
}
goto pop;
children: {
write1(c, Push);
push(c, p, nextChildOffset);
p = get(p, nextChildOffset);
goto visit;
}
pop: {
if (pop(c, &p, &nextChildOffset)) {
write1(c, Pop);
nextChildOffset = walkNext(t, p, nextChildOffset);
if (nextChildOffset >= 0) {
goto children;
} else {
goto pop;
}
}
}
return extendedSize(t, o, baseSize(t, o, objectClass(t, o)));
}
} // namespace
@ -308,22 +55,56 @@ namespace vm {
void
dumpHeap(Thread* t, FILE* out)
{
Context context(t, out);
class Visitor : public Heap::Visitor {
class Walker: public HeapWalker {
public:
Visitor(Context* c): c(c) { }
Walker(Thread* t, FILE* out): t(t), out(out), nextNumber(1) { }
virtual void visit(void* p) {
::visit(c, static_cast<object>(mask(*static_cast<void**>(p))));
virtual void root() {
write1(out, Root);
}
Context* c;
} v(&context);
virtual unsigned visitNew(object p) {
if (p) {
unsigned number = nextNumber++;
write4(out, number);
add(&context, 0)->number = 0;
write1(out, Size);
write4(out, objectSize(t, p));
visitRoots(t->m, &v);
if (objectClass(t, p) == arrayBody(t, t->m->types, Machine::ClassType))
{
object name = className(t, p);
if (name) {
write1(out, ClassName);
writeString(out, &byteArrayBody(t, name, 0),
byteArrayLength(t, name) - 1);
}
}
return number;
} else {
return 0;
}
}
virtual void visitOld(object, unsigned number) {
write4(out, number);
}
virtual void push(unsigned) {
write1(out, Push);
}
virtual void pop() {
write1(out, Pop);
}
Thread* t;
FILE* out;
unsigned nextNumber;
} walker(t, out);
walk(t, &walker)->dispose();
}
} // namespace vm

300
src/heapwalk.cpp Normal file
View File

@ -0,0 +1,300 @@
#include "heapwalk.h"
using namespace vm;
namespace {
const uintptr_t PointerShift = log(BytesPerWord);
class Context;
class Set: public HeapMap {
public:
class Entry {
public:
object value;
uint32_t number;
int next;
};
static unsigned footprint(unsigned capacity) {
return sizeof(Set)
+ pad(sizeof(int) * capacity)
+ pad(sizeof(Set::Entry) * capacity);
}
Set(Context* context, unsigned capacity):
context(context),
index(reinterpret_cast<int*>
(reinterpret_cast<uint8_t*>(this)
+ sizeof(Set))),
entries(reinterpret_cast<Entry*>
(reinterpret_cast<uint8_t*>(index)
+ pad(sizeof(int) * capacity))),
size(0),
capacity(capacity)
{ }
virtual int find(object value);
virtual void dispose();
Context* context;
int* index;
Entry* entries;
unsigned size;
unsigned capacity;
};
class Stack {
public:
class Entry {
public:
object value;
int offset;
};
static const unsigned Capacity = 4096;
Stack(Stack* next): next(next), entryCount(0) { }
Stack* next;
unsigned entryCount;
Entry entries[Capacity];
};
class Context {
public:
Context(Thread* thread):
thread(thread), objects(0), stack(0)
{ }
~Context() {
while (stack) {
Stack* dead = stack;
stack = dead->next;
thread->m->heap->free(stack, sizeof(Stack));
}
}
Thread* thread;
Set* objects;
Stack* stack;
};
void
push(Context* c, object p, int offset)
{
if (c->stack == 0 or c->stack->entryCount == Stack::Capacity) {
c->stack = new (c->thread->m->heap->allocate(sizeof(Stack)))
Stack(c->stack);
}
Stack::Entry* e = c->stack->entries + (c->stack->entryCount++);
e->value = p;
e->offset = offset;
}
bool
pop(Context* c, object* p, int* offset)
{
if (c->stack) {
if (c->stack->entryCount == 0) {
if (c->stack->next) {
Stack* dead = c->stack;
c->stack = dead->next;
c->thread->m->heap->free(dead, sizeof(Stack));
} else {
return false;
}
}
Stack::Entry* e = c->stack->entries + (--c->stack->entryCount);
*p = e->value;
*offset = e->offset;
return true;
} else {
return false;
}
}
unsigned
hash(object p, unsigned capacity)
{
return (reinterpret_cast<uintptr_t>(p) >> PointerShift)
& (capacity - 1);
}
Set::Entry*
find(Context* c, object p)
{
if (c->objects == 0) return 0;
for (int i = c->objects->index[hash(p, c->objects->capacity)]; i >= 0;) {
Set::Entry* e = c->objects->entries + i;
if (e->value == p) {
return e;
}
i = e->next;
}
return 0;
}
int
Set::find(object value)
{
Set::Entry* e = ::find(context, value);
if (e) {
return e->number;
} else {
return -1;
}
}
void
Set::dispose()
{
context->thread->m->heap->free(this, footprint(capacity));
}
Set::Entry*
add(Context* c UNUSED, Set* set, object p, uint32_t number)
{
assert(c->thread, set->size < set->capacity);
unsigned index = hash(p, set->capacity);
int offset = set->size++;
Set::Entry* e = set->entries + offset;
e->value = p;
e->number = number;
e->next = set->index[index];
set->index[index] = offset;
return e;
}
Set::Entry*
add(Context* c, object p)
{
if (c->objects == 0 or c->objects->size == c->objects->capacity) {
unsigned capacity;
if (c->objects) {
capacity = c->objects->capacity * 2;
} else {
capacity = 4096; // must be power of two
}
Set* set = new (c->thread->m->heap->allocate(Set::footprint(capacity)))
Set(c, capacity);
memset(set->index, 0xFF, sizeof(int) * capacity);
if (c->objects) {
for (unsigned i = 0; i < c->objects->capacity; ++i) {
for (int j = c->objects->index[i]; j >= 0;) {
Set::Entry* e = c->objects->entries + j;
add(c, set, e->value, e->number);
j = e->next;
}
}
c->thread->m->heap->free
(c->objects, Set::footprint(c->objects->capacity));
}
c->objects = set;
}
return add(c, c->objects, p, 0);
}
inline object
get(object o, unsigned offsetInWords)
{
return static_cast<object>
(mask(cast<void*>(o, offsetInWords * BytesPerWord)));
}
unsigned
objectSize(Thread* t, object o)
{
unsigned n = baseSize(t, o, objectClass(t, o));
if (objectExtended(t, o)) {
++ n;
}
return n;
}
void
walk(Context* c, HeapWalker* w, object p)
{
Thread* t = c->thread;
int nextChildOffset;
w->root();
visit: {
Set::Entry* e = find(c, p);
if (e) {
w->visitOld(p, e->number);
} else {
e = add(c, p);
e->number = w->visitNew(p);
nextChildOffset = walkNext(t, p, -1);
if (nextChildOffset != -1) {
goto children;
}
}
}
goto pop;
children: {
w->push(nextChildOffset);
push(c, p, nextChildOffset);
p = get(p, nextChildOffset);
goto visit;
}
pop: {
if (pop(c, &p, &nextChildOffset)) {
w->pop();
nextChildOffset = walkNext(t, p, nextChildOffset);
if (nextChildOffset >= 0) {
goto children;
} else {
goto pop;
}
}
}
}
} // namespace
namespace vm {
HeapMap*
walk(Thread* t, HeapWalker* w)
{
Context context(t);
class Visitor: public Heap::Visitor {
public:
Visitor(Context* c, HeapWalker* w): c(c), w(w) { }
virtual void visit(void* p) {
walk(c, w, static_cast<object>(mask(*static_cast<void**>(p))));
}
Context* c;
HeapWalker* w;
} v(&context, w);
add(&context, 0)->number = w->visitNew(0);
visitRoots(t->m, &v);
return context.objects;
}
} // namespace vm

23
src/heapwalk.h Normal file
View File

@ -0,0 +1,23 @@
#include "machine.h"
namespace vm {
class HeapMap {
public:
virtual int find(object value) = 0;
virtual void dispose() = 0;
};
class HeapWalker {
public:
virtual void root() = 0;
virtual unsigned visitNew(object value) = 0;
virtual void visitOld(object value, unsigned number) = 0;
virtual void push(unsigned offset) = 0;
virtual void pop() = 0;
};
HeapMap*
walk(Thread* t, HeapWalker* w);
} // namespace vm

View File

@ -248,38 +248,6 @@ walk(Thread*, Heap::Walker* w, uint32_t* mask, unsigned fixedSize,
}
}
void
walk(Thread* t, Heap::Walker* w, object o, unsigned start)
{
object class_ = static_cast<object>(t->m->heap->follow(objectClass(t, o)));
object objectMask = static_cast<object>
(t->m->heap->follow(classObjectMask(t, class_)));
if (objectMask) {
unsigned fixedSize = classFixedSize(t, class_);
unsigned arrayElementSize = classArrayElementSize(t, class_);
unsigned arrayLength
= (arrayElementSize ?
cast<uintptr_t>(o, fixedSize - BytesPerWord) : 0);
uint32_t mask[intArrayLength(t, objectMask)];
memcpy(mask, &intArrayBody(t, objectMask, 0),
intArrayLength(t, objectMask) * 4);
walk(t, w, mask, fixedSize, arrayElementSize, arrayLength, start);
} else if (classVmFlags(t, class_) & SingletonFlag) {
unsigned length = singletonLength(t, o);
if (length) {
walk(t, w, singletonMask(t, o),
(singletonCount(t, o) + 2) * BytesPerWord, 0, 0, start);
} else if (start == 0) {
w->visit(0);
}
} else if (start == 0) {
w->visit(0);
}
}
void
finalizerTargetUnreachable(Thread* t, Heap::Visitor* v, object* p)
{
@ -770,12 +738,8 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
PROTECT(t, interfaceTable);
unsigned i = 0;
object it = hashMapIterator(t, map);
PROTECT(t, it);
for (; it; it = hashMapIteratorNext(t, it)) {
object interface = resolveClass
(t, tripleFirst(t, hashMapIteratorNode(t, it)));
for (HashMapIterator it(t, map); it.hasMore();) {
object interface = resolveClass(t, tripleFirst(t, it.next()));
if (UNLIKELY(t->exception)) return;
set(t, interfaceTable, ArrayBody + (i * BytesPerWord), interface);
@ -1243,10 +1207,8 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
if (classFlags(t, class_) & ACC_INTERFACE) {
PROTECT(t, vtable);
for (object it = hashMapIterator(t, virtualMap); it;
it = hashMapIteratorNext(t, it))
{
object method = tripleFirst(t, hashMapIteratorNode(t, it));
for (HashMapIterator it(t, virtualMap); it.hasMore();) {
object method = tripleFirst(t, it.next());
assert(t, arrayBody(t, vtable, methodOffset(t, method)) == 0);
set(t, vtable, ArrayBody + (methodOffset(t, method) * BytesPerWord),
method);
@ -2769,6 +2731,38 @@ collect(Thread* t, Heap::CollectionType type)
#endif
}
void
walk(Thread* t, Heap::Walker* w, object o, unsigned start)
{
object class_ = static_cast<object>(t->m->heap->follow(objectClass(t, o)));
object objectMask = static_cast<object>
(t->m->heap->follow(classObjectMask(t, class_)));
if (objectMask) {
unsigned fixedSize = classFixedSize(t, class_);
unsigned arrayElementSize = classArrayElementSize(t, class_);
unsigned arrayLength
= (arrayElementSize ?
cast<uintptr_t>(o, fixedSize - BytesPerWord) : 0);
uint32_t mask[intArrayLength(t, objectMask)];
memcpy(mask, &intArrayBody(t, objectMask, 0),
intArrayLength(t, objectMask) * 4);
::walk(t, w, mask, fixedSize, arrayElementSize, arrayLength, start);
} else if (classVmFlags(t, class_) & SingletonFlag) {
unsigned length = singletonLength(t, o);
if (length) {
::walk(t, w, singletonMask(t, o),
(singletonCount(t, o) + 2) * BytesPerWord, 0, 0, start);
} else if (start == 0) {
w->visit(0);
}
} else if (start == 0) {
w->visit(0);
}
}
int
walkNext(Thread* t, object o, int previous)
{

View File

@ -1128,7 +1128,7 @@ class Machine {
dispose();
}
static const unsigned HeapPoolSize = 8;
static const unsigned HeapPoolSize = 64;
static const unsigned FixedFootprintThresholdInBytes = 256 * 1024;
@ -2208,6 +2208,9 @@ intern(Thread* t, object s);
void
exit(Thread* t);
void
walk(Thread* t, Heap::Walker* w, object o, unsigned start);
int
walkNext(Thread* t, object o, int previous);

View File

@ -25,6 +25,7 @@
#include "signal.h"
#include "ucontext.h"
#include "stdint.h"
#include "dirent.h"
#include "x86.h"
#include "system.h"
@ -463,6 +464,31 @@ class MySystem: public System {
size_t length_;
};
class Directory: public System::Directory {
public:
Directory(System* s, DIR* directory): s(s), directory(directory) { }
virtual const char* next() {
if (directory) {
dirent* e = readdir(directory);
if (e) {
return e->d_name;
}
}
return 0;
}
virtual void dispose() {
if (directory) {
closedir(directory);
}
s->free(this);
}
System* s;
DIR* directory;
};
class Library: public System::Library {
public:
Library(System* s, void* p, const char* name, unsigned nameLength,
@ -658,7 +684,7 @@ class MySystem: public System {
virtual Status map(System::Region** region, const char* name) {
Status status = 1;
int fd = open(name, O_RDONLY);
int fd = ::open(name, O_RDONLY);
if (fd != -1) {
struct stat s;
int r = fstat(fd, &s);
@ -676,19 +702,31 @@ class MySystem: public System {
return status;
}
virtual Status open(System::Directory** directory, const char* name) {
Status status = 1;
DIR* d = opendir(name);
if (d) {
*directory = new (allocate(this, sizeof(Directory))) Directory(this, d);
status = 0;
}
return status;
}
virtual FileType identify(const char* name) {
struct stat s;
int r = stat(name, &s);
if (r == 0) {
if (S_ISREG(s.st_mode)) {
return File;
return TypeFile;
} else if (S_ISDIR(s.st_mode)) {
return Directory;
return TypeDirectory;
} else {
return Unknown;
return TypeUnknown;
}
} else {
return DoesNotExist;
return TypeDoesNotExist;
}
}

View File

@ -20,10 +20,10 @@ class System {
typedef intptr_t Status;
enum FileType {
Unknown,
DoesNotExist,
File,
Directory
TypeUnknown,
TypeDoesNotExist,
TypeFile,
TypeDirectory
};
class Thread {
@ -79,6 +79,12 @@ class System {
virtual void dispose() = 0;
};
class Directory {
public:
virtual const char* next() = 0;
virtual void dispose() = 0;
};
class Library {
public:
virtual void* resolve(const char* function) = 0;
@ -128,6 +134,7 @@ class System {
unsigned returnType) = 0;
virtual Status map(Region**, const char* name) = 0;
virtual FileType identify(const char* name) = 0;
virtual Status open(Directory**, const char* name) = 0;
virtual Status load(Library**, const char* name, bool mapName) = 0;
virtual char pathSeparator() = 0;
virtual int64_t now() = 0;

View File

@ -73,11 +73,6 @@
(type weakHashMap
(extends hashMap))
(type hashMapIterator
(object map)
(object node)
(unsigned index))
(type list
(uint32_t size)
(object front)

View File

@ -442,40 +442,6 @@ hashMapRemove(Thread* t, object map, object key,
return o;
}
object
hashMapIterator(Thread* t, object map)
{
object array = hashMapArray(t, map);
if (array) {
for (unsigned i = 0; i < arrayLength(t, array); ++i) {
if (arrayBody(t, array, i)) {
return makeHashMapIterator(t, map, arrayBody(t, array, i), i + 1);
}
}
}
return 0;
}
object
hashMapIteratorNext(Thread* t, object it)
{
object map = hashMapIteratorMap(t, it);
object node = hashMapIteratorNode(t, it);
unsigned index = hashMapIteratorIndex(t, it);
if (tripleThird(t, node)) {
return makeHashMapIterator(t, map, tripleThird(t, node), index);
} else {
object array = hashMapArray(t, map);
for (unsigned i = index; i < arrayLength(t, array); ++i) {
if (arrayBody(t, array, i)) {
return makeHashMapIterator(t, map, arrayBody(t, array, i), i + 1);
}
}
return 0;
}
}
void
listAppend(Thread* t, object list, object value)
{

View File

@ -92,6 +92,52 @@ treeInsertNode(Thread* t, object tree, intptr_t key, object node,
object sentinal,
intptr_t (*compare)(Thread* t, intptr_t key, object b));
class HashMapIterator: public Thread::Protector {
public:
HashMapIterator(Thread* t, object map):
Protector(t), map(map), node(0), index(0)
{
find();
}
void find() {
object array = hashMapArray(t, map);
for (unsigned i = index; i < arrayLength(t, array); ++i) {
if (arrayBody(t, array, i)) {
node = arrayBody(t, array, i);
index = i + 1;
}
}
}
bool hasMore() {
return node != 0;
}
object next() {
if (node) {
object n = node;
if (tripleThird(t, node)) {
node = tripleThird(t, node);
} else {
find();
}
return n;
} else {
return 0;
}
}
virtual void visit(Heap::Visitor* v) {
v->visit(&map);
v->visit(&node);
}
object map;
object node;
unsigned index;
};
} // vm
#endif//UTIL_H