Merge branch 'bootimage' of oss.readytalk.com:/var/local/git/avian

Conflicts:

	src/heapdump.cpp
This commit is contained in:
Joel Dice 2008-12-04 14:29:17 -07:00
commit 7d68c9b0a5
28 changed files with 2914 additions and 1069 deletions

View File

@ -14,8 +14,6 @@ import java.net.URL;
import java.net.MalformedURLException;
public class SystemClassLoader extends ClassLoader {
private Object map;
protected native Class findClass(String name) throws ClassNotFoundException;
protected native Class findLoadedClass(String name);

View File

@ -22,7 +22,7 @@ public class Method<T> extends AccessibleObject implements Member {
private byte[] spec;
private Class<T> class_;
private Object code;
private Object compiled;
private long compiled;
private Method() { }

View File

@ -59,7 +59,6 @@ warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \
common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \
"-I$(JAVA_HOME)/include" -idirafter $(src) -I$(native-build) \
-D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \
-DBOOT_CLASSPATH=\"[classpathJar]\"
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \
"-I$(JAVA_HOME)/include/linux" -I$(src) -pthread
@ -186,7 +185,9 @@ vm-depends = \
$(src)/util.h \
$(src)/zone.h \
$(src)/assembler.h \
$(src)/compiler.h
$(src)/compiler.h \
$(src)/heapwalk.h \
$(src)/bootimage.h
vm-sources = \
$(src)/$(system).cpp \
@ -200,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)
@ -221,6 +217,32 @@ 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-generator-sources = $(src)/bootimage.cpp
bootimage-generator-objects = \
$(call cpp-objects,$(bootimage-generator-sources),$(src),$(native-build))
bootimage-generator = $(native-build)/bootimage-generator
bootimage-bin = $(native-build)/bootimage.bin
bootimage-object = $(native-build)/bootimage-bin.o
ifeq ($(bootimage),true)
vm-classpath-object = $(bootimage-object)
cflags += -DBOOT_IMAGE=\"bootimageBin\"
else
vm-classpath-object = $(classpath-object)
cflags += -DBOOT_CLASSPATH=\"[classpathJar]\"
endif
driver-source = $(src)/main.cpp
driver-object = $(native-build)/main.o
driver-dynamic-object = $(native-build)/main-dynamic.o
@ -345,6 +367,12 @@ $(vm-cpp-objects): $(native-build)/%.o: $(src)/%.cpp $(vm-depends)
$(vm-asm-objects): $(native-build)/%-asm.o: $(src)/%.S
$(compile-asm-object)
$(bootimage-generator-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)
@ -386,15 +414,32 @@ $(generator-objects): $(native-build)/%.o: $(src)/%.cpp
$(jni-objects): $(native-build)/%.o: $(classpath)/%.cpp
$(compile-object)
$(static-library): $(vm-objects) $(jni-objects)
$(static-library): $(vm-objects) $(jni-objects) $(vm-heapwalk-objects)
@echo "creating $(@)"
rm -rf $(@)
$(ar) cru $(@) $(^)
$(ranlib) $(@)
$(bootimage-bin): $(bootimage-generator)
$(<) $(classpath-build) > $(@)
$(bootimage-object): $(bootimage-bin)
@echo "creating $(@)"
ifeq ($(platform),darwin)
$(binaryToMacho) $(<) \
__binary_bootimage_bin_start __binary_bootimage_bin_end > $(@)
else
(wd=$$(pwd); \
cd $(native-build); \
$(objcopy) --rename-section=.data=.boot -I binary bootimage.bin \
-O $(object-format) -B $(object-arch) "$${wd}/$(@).tmp"; \
$(objcopy) --set-section-flags .boot=alloc,load,code "$${wd}/$(@).tmp" \
"$${wd}/$(@)")
endif
$(executable): \
$(vm-objects) $(classpath-object) $(jni-objects) $(driver-object) \
$(boot-object)
$(vm-objects) $(jni-objects) $(driver-object) $(vm-heapwalk-objects) \
$(boot-object) $(vm-classpath-object)
@echo "linking $(@)"
ifeq ($(platform),windows)
$(dlltool) -z $(@).def $(^)
@ -405,9 +450,21 @@ else
endif
$(strip) $(strip-all) $(@)
$(bootimage-generator): \
$(vm-objects) $(classpath-object) $(jni-objects) $(heapwalk-objects) \
$(bootimage-generator-objects)
@echo "linking $(@)"
ifeq ($(platform),windows)
$(dlltool) -z $(@).def $(^)
$(dlltool) -d $(@).def -e $(@).exp
$(cc) $(@).exp $(^) $(lflags) -o $(@)
else
$(cc) $(^) $(rdynamic) $(lflags) -o $(@)
endif
$(dynamic-library): \
$(vm-objects) $(classpath-object) $(dynamic-object) $(jni-objects) \
$(boot-object)
$(vm-objects) $(dynamic-object) $(jni-objects) $(vm-heapwalk-objects) \
$(boot-object) $(vm-classpath-object)
@echo "linking $(@)"
$(cc) $(^) $(shared) $(lflags) -o $(@)
$(strip) $(strip-all) $(@)

View File

@ -78,8 +78,16 @@ const int AnyRegister = -2;
class Promise {
public:
class Listener {
public:
virtual void* resolve(int64_t value) = 0;
Listener* next;
};
virtual int64_t value() = 0;
virtual bool resolved() = 0;
virtual Listener* listen(unsigned) { return 0; }
};
class ResolvedPromise: public Promise {
@ -97,6 +105,59 @@ class ResolvedPromise: public Promise {
int64_t value_;
};
class ListenPromise: public Promise {
public:
ListenPromise(System* s, Allocator* allocator):
s(s), allocator(allocator), listener(0)
{ }
virtual int64_t value() {
abort(s);
}
virtual bool resolved() {
return false;
}
virtual Listener* listen(unsigned sizeInBytes) {
Listener* l = static_cast<Listener*>(allocator->allocate(sizeInBytes));
l->next = listener;
listener = l;
return l;
}
System* s;
Allocator* allocator;
Listener* listener;
Promise* promise;
};
class DelayedPromise: public ListenPromise {
public:
DelayedPromise(System* s, Allocator* allocator, Promise* basis,
DelayedPromise* next):
ListenPromise(s, allocator), basis(basis), next(next)
{ }
virtual int64_t value() {
abort(s);
}
virtual bool resolved() {
return false;
}
virtual Listener* listen(unsigned sizeInBytes) {
Listener* l = static_cast<Listener*>(allocator->allocate(sizeInBytes));
l->next = listener;
listener = l;
return l;
}
Promise* basis;
DelayedPromise* next;
};
class TraceHandler {
public:
virtual void handleTrace(Promise* address) = 0;
@ -182,7 +243,8 @@ class Assembler {
virtual unsigned length() = 0;
virtual void updateCall(void* returnAddress, void* newTarget) = 0;
virtual void updateCall(UnaryOperation op, bool assertAlignment,
void* returnAddress, void* newTarget) = 0;
virtual void dispose() = 0;
};

View File

@ -15,6 +15,34 @@
// ourselves:
extern "C" void __cxa_pure_virtual(void) { abort(); }
#ifdef BOOT_IMAGE
#ifdef __MINGW32__
# define EXPORT __declspec(dllexport)
# define SYMBOL(x) binary_bootimage_bin_##x
#else
# define EXPORT __attribute__ ((visibility("default")))
# define SYMBOL(x) _binary_bootimage_bin_##x
#endif
extern "C" {
extern const uint8_t SYMBOL(start)[];
extern const uint8_t SYMBOL(end)[];
EXPORT const uint8_t*
bootimageBin(unsigned* size)
{
*size = SYMBOL(end) - SYMBOL(start);
return SYMBOL(start);
}
}
#endif//BOOT_IMAGE
#ifdef BOOT_CLASSPATH
#ifdef __MINGW32__
# define EXPORT __declspec(dllexport)
# define SYMBOL(x) binary_classpath_jar_##x
@ -36,3 +64,5 @@ extern "C" {
}
}
#endif//BOOT_CLASSPATH

369
src/bootimage.cpp Normal file
View File

@ -0,0 +1,369 @@
/* Copyright (c) 2008, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
#include "bootimage.h"
#include "heapwalk.h"
#include "common.h"
#include "machine.h"
#include "util.h"
#include "assembler.h"
// since we aren't linking against libstdc++, we must implement this
// ourselves:
extern "C" void __cxa_pure_virtual(void) { abort(); }
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;
}
object
makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
unsigned capacity, uintptr_t* codeMap)
{
unsigned size = 0;
t->m->processor->compileThunks(t, image, code, &size, capacity);
object constants = 0;
PROTECT(t, constants);
object calls = 0;
PROTECT(t, calls);
DelayedPromise* addresses = 0;
for (Finder::Iterator it(t->m->finder); it.hasMore();) {
unsigned nameSize;
const char* name = it.next(&nameSize);
if (endsWith(".class", name, nameSize)) {
//fprintf(stderr, "%.*s\n", nameSize - 6, name);
object c = resolveClass
(t, makeByteArray(t, "%.*s", nameSize - 6, name));
PROTECT(t, c);
if (classMethodTable(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) or (methodFlags(t, method) & ACC_NATIVE)) {
t->m->processor->compileMethod
(t, zone, code, &size, capacity, &constants, &calls, &addresses,
method);
}
}
}
}
}
for (; calls; calls = tripleThird(t, calls)) {
object method = tripleFirst(t, calls);
uintptr_t address;
if (methodFlags(t, method) & ACC_NATIVE) {
address = reinterpret_cast<uintptr_t>(code + image->nativeThunk);
} else {
address = methodCompiled(t, method);
}
static_cast<ListenPromise*>(pointerValue(t, tripleSecond(t, calls)))
->listener->resolve(address);
}
for (; addresses; addresses = addresses->next) {
uint8_t* value = reinterpret_cast<uint8_t*>(addresses->basis->value());
assert(t, value >= code);
void* dst = addresses->listener->resolve
((value - code) | (1 << BootShift));
assert(t, reinterpret_cast<intptr_t>(dst)
>= reinterpret_cast<intptr_t>(code));
markBit(codeMap, reinterpret_cast<intptr_t>(dst)
- reinterpret_cast<intptr_t>(code));
}
image->codeSize = size;
return constants;
}
unsigned
objectSize(Thread* t, object o)
{
assert(t, not objectExtended(t, o));
return baseSize(t, o, objectClass(t, o));
}
void
visitRoots(Thread* t, BootImage* image, HeapWalker* w, object constants)
{
Machine* m = t->m;
for (HashMapIterator it(t, m->classMap); it.hasMore();) {
w->visitRoot(tripleSecond(t, it.next()));
}
image->loader = w->visitRoot(m->loader);
image->types = w->visitRoot(m->types);
m->processor->visitRoots(image, w);
for (; constants; constants = tripleThird(t, constants)) {
w->visitRoot(tripleFirst(t, constants));
}
}
HeapWalker*
makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map,
unsigned capacity, object constants)
{
class Visitor: public HeapVisitor {
public:
Visitor(Thread* t, uintptr_t* heap, uintptr_t* map, unsigned capacity):
t(t), currentObject(0), currentNumber(0), currentOffset(0), heap(heap),
map(map), position(0), capacity(capacity)
{ }
void visit(unsigned number) {
if (currentObject) {
unsigned offset = currentNumber - 1 + currentOffset;
unsigned mark = heap[offset] & (~PointerMask);
unsigned value = number | (mark << BootShift);
if (value) markBit(map, offset);
heap[offset] = value;
}
}
virtual void root() {
currentObject = 0;
}
virtual unsigned visitNew(object p) {
if (p) {
unsigned size = objectSize(t, p);
unsigned number;
if (currentObject
and (currentOffset * BytesPerWord) == ClassStaticTable)
{
FixedAllocator allocator
(t, reinterpret_cast<uint8_t*>(heap + position),
(capacity - position) * BytesPerWord);
unsigned totalInBytes;
uintptr_t* dst = static_cast<uintptr_t*>
(t->m->heap->allocateImmortalFixed
(&allocator, size, true, &totalInBytes));
memcpy(dst, p, size * BytesPerWord);
dst[0] |= FixedMark;
number = (dst - heap) + 1;
position += ceiling(totalInBytes, BytesPerWord);
} else {
assert(t, position + size < capacity);
memcpy(heap + position, p, size * BytesPerWord);
number = position + 1;
position += size;
}
visit(number);
return number;
} else {
return 0;
}
}
virtual void visitOld(object, unsigned number) {
visit(number);
}
virtual void push(object object, unsigned number, unsigned offset) {
currentObject = object;
currentNumber = number;
currentOffset = offset;
}
virtual void pop() {
currentObject = 0;
}
Thread* t;
object currentObject;
unsigned currentNumber;
unsigned currentOffset;
uintptr_t* heap;
uintptr_t* map;
unsigned position;
unsigned capacity;
} visitor(t, heap, map, capacity / BytesPerWord);
HeapWalker* w = makeHeapWalker(t, &visitor);
visitRoots(t, image, w, constants);
image->heapSize = visitor.position * BytesPerWord;
return w;
}
void
updateConstants(Thread* t, object constants, uint8_t* code, uintptr_t* codeMap,
HeapMap* heapTable)
{
for (; constants; constants = tripleThird(t, constants)) {
unsigned target = heapTable->find(tripleFirst(t, constants));
assert(t, target > 0);
for (Promise::Listener* pl = static_cast<ListenPromise*>
(pointerValue(t, tripleSecond(t, constants)))->listener;
pl; pl = pl->next)
{
void* dst = pl->resolve(target);
assert(t, reinterpret_cast<intptr_t>(dst)
>= reinterpret_cast<intptr_t>(code));
markBit(codeMap, reinterpret_cast<intptr_t>(dst)
- reinterpret_cast<intptr_t>(code));
}
}
}
unsigned
offset(object a, uintptr_t* b)
{
return reinterpret_cast<uintptr_t>(b) - reinterpret_cast<uintptr_t>(a);
}
void
writeBootImage(Thread* t, FILE* out)
{
Zone zone(t->m->system, t->m->heap, 64 * 1024);
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 constants = makeCodeImage
(t, &zone, &image, code, CodeCapacity, codeMap);
PROTECT(t, constants);
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));
collect(t, Heap::MajorCollection);
HeapWalker* heapWalker = makeHeapImage
(t, &image, heap, heapMap, HeapCapacity, constants);
updateConstants(t, constants, code, codeMap, heapWalker->map());
image.classCount = hashMapSize(t, t->m->classMap);
unsigned* classTable = static_cast<unsigned*>
(t->m->heap->allocate(image.classCount * sizeof(unsigned)));
{ unsigned i = 0;
for (HashMapIterator it(t, t->m->classMap); it.hasMore();) {
classTable[i++] = heapWalker->map()->find(tripleSecond(t, it.next()));
}
}
image.stringCount = hashMapSize(t, t->m->stringMap);
unsigned* stringTable = static_cast<unsigned*>
(t->m->heap->allocate(image.stringCount * sizeof(unsigned)));
{ unsigned i = 0;
for (HashMapIterator it(t, t->m->stringMap); it.hasMore();) {
stringTable[i++] = heapWalker->map()->find
(jreferenceTarget(t, tripleFirst(t, it.next())));
}
}
unsigned* callTable = t->m->processor->makeCallTable
(t, &image, heapWalker, code);
heapWalker->dispose();
image.magic = BootImage::Magic;
image.codeBase = reinterpret_cast<uintptr_t>(code);
fprintf(stderr, "class count %d string count %d call count %d\n"
"heap size %d code size %d\n",
image.classCount, image.stringCount, image.callCount, image.heapSize,
image.codeSize);
if (true) {
fwrite(&image, sizeof(BootImage), 1, out);
fwrite(classTable, image.classCount * sizeof(unsigned), 1, out);
fwrite(stringTable, image.stringCount * sizeof(unsigned), 1, out);
fwrite(callTable, image.callCount * sizeof(unsigned) * 2, 1, out);
unsigned offset = (image.classCount * sizeof(unsigned))
+ (image.stringCount * sizeof(unsigned))
+ (image.callCount * sizeof(unsigned) * 2);
while (offset % BytesPerWord) {
uint8_t c = 0;
fwrite(&c, 1, 1, out);
++ offset;
}
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[1], 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;
}

82
src/bootimage.h Normal file
View File

@ -0,0 +1,82 @@
/* Copyright (c) 2008, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
#ifndef BOOTIMAGE_H
#define BOOTIMAGE_H
#include "common.h"
namespace vm {
const unsigned BootMask = (~static_cast<unsigned>(0)) / BytesPerWord;
const unsigned BootShift = 32 - log(BytesPerWord);
class BootImage {
public:
static const unsigned Magic = 0x22377322;
unsigned magic;
unsigned heapSize;
unsigned codeSize;
unsigned classCount;
unsigned stringCount;
unsigned callCount;
unsigned loader;
unsigned types;
unsigned methodTree;
unsigned methodTreeSentinal;
uintptr_t codeBase;
unsigned defaultThunk;
unsigned nativeThunk;
unsigned aioobThunk;
unsigned thunkTable;
unsigned thunkSize;
unsigned compileMethodCall;
unsigned invokeNativeCall;
unsigned throwArrayIndexOutOfBoundsCall;
#define THUNK(s) unsigned s##Call;
#include "thunks.cpp"
#undef THUNK
};
inline unsigned
codeMapSize(unsigned codeSize)
{
return ceiling(codeSize, BitsPerWord) * BytesPerWord;
}
inline unsigned
heapMapSize(unsigned heapSize)
{
return ceiling(heapSize, BitsPerWord * BytesPerWord) * BytesPerWord;
}
inline object
bootObject(uintptr_t* heap, unsigned offset)
{
if (offset) {
return reinterpret_cast<object>(heap + offset - 1);
} else {
return 0;
}
}
} // namespace vm
#endif//BOOTIMAGE_H

View File

@ -293,6 +293,15 @@ difference(void* a, void* b)
return reinterpret_cast<intptr_t>(a) - reinterpret_cast<intptr_t>(b);
}
template <class T>
inline void*
voidPointer(T function)
{
void* p;
memcpy(&p, &function, sizeof(void*));
return p;
}
class Machine;
class Thread;

File diff suppressed because it is too large Load Diff

View File

@ -3060,8 +3060,26 @@ class MyCompiler: public Compiler {
int i = 0;
for (ConstantPoolNode* n = c.firstConstant; n; n = n->next) {
*reinterpret_cast<intptr_t*>(dst + pad(c.assembler->length()) + i)
= n->promise->value();
intptr_t* target = reinterpret_cast<intptr_t*>
(dst + pad(c.assembler->length()) + i);
if (n->promise->resolved()) {
*target = n->promise->value();
} else {
class Listener: public Promise::Listener {
public:
Listener(intptr_t* target): target(target){ }
virtual void* resolve(int64_t value) {
*target = value;
return target;
}
intptr_t* target;
};
new (n->promise->listen(sizeof(Listener))) Listener(target);
}
i += BytesPerWord;
}
}

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,71 @@ class Element {
class DirectoryElement: public Element {
public:
class Iterator: public Element::Iterator {
public:
Iterator(System* s, const char* name, unsigned skip):
s(s), name(name), skip(skip), directory(0), last(0), it(0)
{
if (not s->success(s->open(&directory, name))) {
directory = 0;
}
}
virtual const char* next(unsigned* size) {
if (it) {
const char* v = it->next(size);
if (v) {
return v;
} else {
it->dispose();
it = 0;
}
}
if (last) {
s->free(last);
}
if (directory) {
for (const char* v = directory->next(); v; v = directory->next()) {
if (v[0] != '.') {
last = append(s, name, "/", v);
if (s->identify(last) == System::TypeDirectory) {
it = new (allocate(s, sizeof(Iterator))) Iterator(s, last, skip);
it->name = last;
}
const char* result = last + skip;
*size = strlen(result);
return result;
}
}
}
return 0;
}
virtual void dispose() {
directory->dispose();
s->free(this);
}
System* s;
const char* name;
unsigned skip;
System::Directory* directory;
const char* last;
Iterator* it;
};
DirectoryElement(System* s, const char* name):
s(s), name(name)
{ }
virtual Element::Iterator* iterator() {
return new (allocate(s, sizeof(Iterator)))
Iterator(s, name, strlen(name) + 1);
}
virtual System::Region* find(const char* name) {
const char* file = append(s, this->name, "/", name);
System::Region* region;
@ -91,7 +159,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 +447,39 @@ 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() {
init();
return new (allocate(s, sizeof(Iterator))) Iterator(s, index);
}
virtual void init() {
if (index == 0) {
System::Region* r;
@ -512,11 +609,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 +638,40 @@ 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;
} else {
it = 0;
}
}
}
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 +680,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,46 @@ 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() {
if (current) return true;
current = it->next(&currentSize);
return current != 0;
}
const char* next(unsigned* size) {
if (hasMore()) {
*size = currentSize;
const char* v = current;
current = 0;
return v;
} else {
return 0;
}
}
IteratorImp* it;
const char* current;
unsigned currentSize;
};
virtual IteratorImp* iterator() = 0;
virtual System::Region* find(const char* name) = 0;
virtual bool exists(const char* name) = 0;
virtual const char* path() = 0;

View File

@ -121,17 +121,17 @@ class Segment {
for (; word <= wordLimit and (word < wordLimit or bit < bitLimit);
++word)
{
uintptr_t* p = map->data() + word;
if (*p) {
uintptr_t w = map->data[word];
if (2) {
for (; bit < BitsPerWord and (word < wordLimit or bit < bitLimit);
++bit)
{
if (map->data()[word] & (static_cast<uintptr_t>(1) << bit)) {
if (w & (static_cast<uintptr_t>(1) << bit)) {
index = ::indexOf(word, bit);
// printf("hit at index %d\n", index);
// printf("hit at index %d\n", index);
return true;
} else {
// printf("miss at index %d\n", indexOf(word, bit));
// printf("miss at index %d\n", indexOf(word, bit));
}
}
}
@ -153,14 +153,26 @@ class Segment {
Segment* segment;
Map* child;
uintptr_t* data;
unsigned bitsPerRecord;
unsigned scale;
bool clearNewData;
Map(Segment* segment, unsigned bitsPerRecord, unsigned scale,
Map* child, bool clearNewData):
Map(Segment* segment, uintptr_t* data, unsigned bitsPerRecord,
unsigned scale, Map* child, bool clearNewData):
segment(segment),
child(child),
data(data),
bitsPerRecord(bitsPerRecord),
scale(scale),
clearNewData(clearNewData)
{ }
Map(Segment* segment, unsigned bitsPerRecord, unsigned scale, Map* child,
bool clearNewData):
segment(segment),
child(child),
data(0),
bitsPerRecord(bitsPerRecord),
scale(scale),
clearNewData(clearNewData)
@ -171,8 +183,13 @@ class Segment {
assert(segment->context, scale);
assert(segment->context, powerOfTwo(scale));
if (data == 0) {
data = segment->data + segment->capacity()
+ calculateOffset(segment->capacity());
}
if (clearNewData) {
memset(data(), 0, size() * BytesPerWord);
memset(data, 0, size() * BytesPerWord);
}
if (child) {
@ -180,40 +197,47 @@ class Segment {
}
}
unsigned calculateOffset(unsigned capacity) {
unsigned n = 0;
if (child) n += child->calculateFootprint(capacity);
return n;
}
static unsigned calculateSize(Context* c UNUSED, unsigned capacity,
unsigned scale, unsigned bitsPerRecord)
{
unsigned result
= ceiling(ceiling(capacity, scale) * bitsPerRecord, BitsPerWord);
assert(c, result);
return result;
}
unsigned calculateSize(unsigned capacity) {
return calculateSize(segment->context, capacity, scale, bitsPerRecord);
}
unsigned size() {
return calculateSize(segment->capacity());
}
unsigned calculateFootprint(unsigned capacity) {
unsigned n = calculateSize(capacity);
if (child) n += child->calculateFootprint(capacity);
return n;
}
void replaceWith(Map* m) {
assert(segment->context, bitsPerRecord == m->bitsPerRecord);
assert(segment->context, scale == m->scale);
data = m->data;
m->segment = 0;
m->data = 0;
if (child) child->replaceWith(m->child);
}
unsigned offset(unsigned capacity) {
unsigned n = 0;
if (child) n += child->footprint(capacity);
return n;
}
unsigned offset() {
return offset(segment->capacity());
}
uintptr_t* data() {
return segment->data + segment->capacity() + offset();
}
unsigned size(unsigned capacity) {
unsigned result
= ceiling(ceiling(capacity, scale) * bitsPerRecord, BitsPerWord);
assert(segment->context, result);
return result;
}
unsigned size() {
return size(max(segment->capacity(), 1));
}
unsigned indexOf(unsigned segmentIndex) {
return (segmentIndex / scale) * bitsPerRecord;
}
@ -224,33 +248,20 @@ class Segment {
return indexOf(segment->indexOf(p));
}
void update(uintptr_t* newData, unsigned capacity) {
assert(segment->context, capacity >= segment->capacity());
uintptr_t* p = newData + offset(capacity);
if (segment->position()) {
memcpy(p, data(), size(segment->position()) * BytesPerWord);
}
if (child) {
child->update(newData, capacity);
}
}
void clearBit(unsigned i) {
assert(segment->context, wordOf(i) < size());
vm::clearBit(data(), i);
vm::clearBit(data, i);
}
void setBit(unsigned i) {
assert(segment->context, wordOf(i) < size());
vm::markBit(data(), i);
vm::markBit(data, i);
}
void clearOnlyIndex(unsigned index) {
clearBits(data(), bitsPerRecord, index);
clearBits(data, bitsPerRecord, index);
}
void clearOnly(unsigned segmentIndex) {
@ -267,7 +278,7 @@ class Segment {
}
void setOnlyIndex(unsigned index, unsigned v = 1) {
setBits(data(), bitsPerRecord, index, v);
setBits(data, bitsPerRecord, index, v);
}
void setOnly(unsigned segmentIndex, unsigned v = 1) {
@ -285,13 +296,7 @@ class Segment {
}
unsigned get(void* p) {
return getBits(data(), bitsPerRecord, indexOf(p));
}
unsigned footprint(unsigned capacity) {
unsigned n = size(capacity);
if (child) n += child->footprint(capacity);
return n;
return getBits(data, bitsPerRecord, indexOf(p));
}
};
@ -334,8 +339,22 @@ class Segment {
}
}
Segment(Context* context, Map* map, uintptr_t* data, unsigned position,
unsigned capacity):
context(context),
data(data),
position_(position),
capacity_(capacity),
map(map)
{
if (map) {
map->init();
}
}
unsigned footprint(unsigned capacity) {
return capacity + (map and capacity ? map->footprint(capacity) : 0);
return capacity
+ (map and capacity ? map->calculateFootprint(capacity) : 0);
}
unsigned capacity() {
@ -411,15 +430,18 @@ class Segment {
class Fixie {
public:
Fixie(unsigned size, bool hasMask, Fixie** handle, bool immortal):
Fixie(Context* c, unsigned size, bool hasMask, Fixie** handle,
bool immortal):
age(immortal ? FixieTenureThreshold + 1 : 0),
hasMask(hasMask),
marked(false),
dirty(false),
size(size)
size(size),
next(0),
handle(0)
{
memset(mask(), 0, maskSize(size, hasMask));
add(handle);
add(c, handle);
if (DebugFixies) {
fprintf(stderr, "make fixie %p of size %d\n", this, totalSize());
}
@ -429,7 +451,10 @@ class Fixie {
return age == FixieTenureThreshold + 1;
}
void add(Fixie** handle) {
void add(Context* c UNUSED, Fixie** handle) {
assert(c, this->handle == 0);
assert(c, next == 0);
this->handle = handle;
if (handle) {
next = *handle;
@ -440,18 +465,25 @@ class Fixie {
}
}
void remove() {
if (handle) *handle = next;
if (next) next->handle = handle;
void remove(Context* c UNUSED) {
if (handle) {
assert(c, *handle == this);
*handle = next;
}
if (next) {
next->handle = handle;
}
next = 0;
handle = 0;
}
void move(Fixie** handle) {
void move(Context* c, Fixie** handle) {
if (DebugFixies) {
fprintf(stderr, "move fixie %p\n", this);
}
remove();
add(handle);
remove(c);
add(c, handle);
}
void** body() {
@ -502,6 +534,9 @@ class Context {
limit(limit),
lowMemoryThreshold(limit / 2),
lock(0),
immortalHeapStart(0),
immortalHeapEnd(0),
ageMap(&gen1, max(1, log(TenureThreshold)), 1, 0, false),
gen1(this, &ageMap, 0, 0),
@ -571,7 +606,10 @@ class Context {
unsigned lowMemoryThreshold;
System::Mutex* lock;
uintptr_t* immortalHeapStart;
uintptr_t* immortalHeapEnd;
Segment::Map ageMap;
Segment gen1;
@ -690,7 +728,7 @@ inline void
initNextGen1(Context* c)
{
new (&(c->nextAgeMap)) Segment::Map
(&(c->nextGen1), max(1, log(TenureThreshold)), 1, 0, false);
(&(c->nextGen1), max(1, log(TenureThreshold)), 1, 0, false);
unsigned minimum = minimumNextGen1Capacity(c);
unsigned desired = minimum;
@ -775,6 +813,7 @@ free(Context* c, Fixie** fixies)
{
for (Fixie** p = fixies; *p;) {
Fixie* f = *p;
if (f->immortal()) {
p = &(f->next);
} else {
@ -802,9 +841,9 @@ sweepFixies(Context* c)
c->untenuredFixieFootprint = 0;
for (Fixie** p = &(c->visitedFixies); *p;) {
Fixie* f = *p;
*p = f->next;
while (c->visitedFixies) {
Fixie* f = c->visitedFixies;
f->remove(c);
if (not f->immortal()) {
++ f->age;
@ -825,14 +864,14 @@ sweepFixies(Context* c)
}
if (f->dirty) {
f->move(&(c->dirtyTenuredFixies));
f->add(c, &(c->dirtyTenuredFixies));
} else {
f->move(&(c->tenuredFixies));
f->add(c, &(c->tenuredFixies));
}
} else {
c->untenuredFixieFootprint += f->totalSize();
f->move(&(c->fixies));
f->add(c, &(c->fixies));
}
f->marked = false;
@ -852,6 +891,12 @@ copyTo(Context* c, Segment* s, void* o, unsigned size)
return dst;
}
bool
immortalHeapContains(Context* c, void* p)
{
return p < c->immortalHeapEnd and p >= c->immortalHeapStart;
}
void*
copy2(Context* c, void* o)
{
@ -888,6 +933,7 @@ copy2(Context* c, void* o)
} else {
assert(c, not c->nextGen1.contains(o));
assert(c, not c->nextGen2.contains(o));
assert(c, not immortalHeapContains(c, o));
o = copyTo(c, &(c->nextGen1), o, size);
@ -926,10 +972,13 @@ update3(Context* c, void* o, bool* needsVisit)
fprintf(stderr, "mark fixie %p\n", f);
}
f->marked = true;
f->move(&(c->markedFixies));
f->move(c, &(c->markedFixies));
}
*needsVisit = false;
return o;
} else if (immortalHeapContains(c, o)) {
*needsVisit = false;
return o;
} else if (wasCollected(c, o)) {
*needsVisit = false;
return follow(c, o);
@ -950,23 +999,12 @@ update2(Context* c, void* o, bool* needsVisit)
return update3(c, o, needsVisit);
}
void*
update(Context* c, void** p, bool* needsVisit)
{
if (mask(*p) == 0) {
*needsVisit = false;
return 0;
}
return update2(c, mask(*p), needsVisit);
}
void
markDirty(Context* c, Fixie* f)
{
if (not f->dirty) {
f->dirty = true;
f->move(&(c->dirtyTenuredFixies));
f->move(c, &(c->dirtyTenuredFixies));
}
}
@ -975,7 +1013,11 @@ markClean(Context* c, Fixie* f)
{
if (f->dirty) {
f->dirty = false;
f->move(&(c->tenuredFixies));
if (f->immortal()) {
f->remove(c);
} else {
f->move(c, &(c->tenuredFixies));
}
}
}
@ -993,9 +1035,10 @@ updateHeapMap(Context* c, void* p, void* target, unsigned offset, void* result)
map = &(c->nextHeapMap);
}
if (not (c->client->isFixed(result)
and fixie(result)->age >= FixieTenureThreshold)
and not seg->contains(result))
if (not (immortalHeapContains(c, result)
or (c->client->isFixed(result)
and fixie(result)->age >= FixieTenureThreshold)
or seg->contains(result)))
{
if (target and c->client->isFixed(target)) {
Fixie* f = fixie(target);
@ -1003,11 +1046,11 @@ updateHeapMap(Context* c, void* p, void* target, unsigned offset, void* result)
if (static_cast<unsigned>(f->age + 1) >= FixieTenureThreshold) {
if (DebugFixies) {
fprintf(stderr, "dirty fixie %p at %d (%p)\n",
f, offset, f->body() + offset);
fprintf(stderr, "dirty fixie %p at %d (%p): %p\n",
f, offset, f->body() + offset, result);
}
markDirty(c, f);
f->dirty = true;
markBit(f->mask(), offset);
}
} else if (seg->contains(p)) {
@ -1399,7 +1442,6 @@ visitDirtyFixies(Context* c, Fixie** p)
assert(c, wasDirty);
if (clean) {
*p = f->next;
markClean(c, f);
} else {
p = &(f->next);
@ -1410,9 +1452,9 @@ visitDirtyFixies(Context* c, Fixie** p)
void
visitMarkedFixies(Context* c)
{
for (Fixie** p = &(c->markedFixies); *p;) {
Fixie* f = *p;
*p = f->next;
while (c->markedFixies) {
Fixie* f = c->markedFixies;
f->remove(c);
if (DebugFixies) {
fprintf(stderr, "visit fixie %p\n", f);
@ -1435,7 +1477,7 @@ visitMarkedFixies(Context* c)
c->client->walk(f->body(), &w);
f->move(&(c->visitedFixies));
f->move(c, &(c->visitedFixies));
}
}
@ -1664,6 +1706,11 @@ class MyHeap: public Heap {
c.client = client;
}
virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords) {
c.immortalHeapStart = start;
c.immortalHeapEnd = start + sizeInWords;
}
virtual void* tryAllocate(unsigned size) {
return ::tryAllocate(&c, size);
}
@ -1690,18 +1737,21 @@ class MyHeap: public Heap {
{
*totalInBytes = Fixie::totalSize(sizeInWords, objectMask);
return (new (allocator->allocate(*totalInBytes))
Fixie(sizeInWords, objectMask, &(c.fixies), false))->body();
Fixie(&c, sizeInWords, objectMask, &(c.fixies), false))->body();
}
virtual void* allocateImmortal(Allocator* allocator, unsigned sizeInWords,
bool objectMask, unsigned* totalInBytes)
virtual void* allocateImmortalFixed(Allocator* allocator,
unsigned sizeInWords, bool objectMask,
unsigned* totalInBytes)
{
*totalInBytes = Fixie::totalSize(sizeInWords, objectMask);
return (new (allocator->allocate(*totalInBytes))
Fixie(sizeInWords, objectMask, &(c.tenuredFixies), true))->body();
Fixie(&c, sizeInWords, objectMask, 0, true))->body();
}
virtual bool needsMark(void* p) {
assert(&c, c.client->isFixed(p) or (not immortalHeapContains(&c, p)));
if (c.client->isFixed(p)) {
return fixie(p)->age >= FixieTenureThreshold;
} else {
@ -1717,6 +1767,7 @@ class MyHeap: public Heap {
bool targetNeedsMark(void* target) {
return target
and not c.gen2.contains(target)
and not immortalHeapContains(&c, target)
and not (c.client->isFixed(target)
and fixie(target)->age >= FixieTenureThreshold);
}
@ -1731,8 +1782,8 @@ class MyHeap: public Heap {
void** target = static_cast<void**>(p) + offset + i;
if (targetNeedsMark(mask(*target))) {
if (DebugFixies) {
fprintf(stderr, "dirty fixie %p at %d (%p)\n",
f, offset, f->body() + offset);
fprintf(stderr, "dirty fixie %p at %d (%p): %p\n",
f, offset, f->body() + offset, mask(*target));
}
dirty = true;
@ -1789,6 +1840,7 @@ class MyHeap: public Heap {
} else if (c.nextGen1.contains(p)) {
return Reachable;
} else if (c.nextGen2.contains(p)
or immortalHeapContains(&c, p)
or (c.gen2.contains(p)
and (c.mode == Heap::MinorCollection
or c.gen2.indexOf(p) >= c.gen2Base)))

View File

@ -52,11 +52,13 @@ class Heap: public Allocator {
};
virtual void setClient(Client* client) = 0;
virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords) = 0;
virtual void collect(CollectionType type, unsigned footprint) = 0;
virtual void* allocateFixed(Allocator* allocator, unsigned sizeInWords,
bool objectMask, unsigned* totalInBytes) = 0;
virtual void* allocateImmortal(Allocator* allocator, unsigned sizeInWords,
bool objectMask, unsigned* totalInBytes) = 0;
virtual void* allocateImmortalFixed(Allocator* allocator,
unsigned sizeInWords, bool objectMask,
unsigned* totalInBytes) = 0;
virtual bool needsMark(void* p) = 0;
virtual bool needsMark(void* p, unsigned offset) = 0;
virtual void mark(void* p, unsigned offset, unsigned count) = 0;

View File

@ -9,194 +9,12 @@
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 +23,30 @@ enum {
Pop
};
inline object
get(object o, unsigned offsetInWords)
{
return static_cast<object>
(mask(cast<void*>(o, offsetInWords * BytesPerWord)));
}
void
write1(Context* c, uint8_t v)
write1(FILE* out, uint8_t v)
{
size_t n UNUSED = 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 };
size_t n UNUSED = fwrite(b, 4, 1, c->out);
size_t n UNUSED = 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);
size_t n UNUSED = fwrite(p, size, 1, c->out);
size_t n UNUSED = 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 +56,58 @@ namespace vm {
void
dumpHeap(Thread* t, FILE* out)
{
Context context(t, out);
class Visitor : public Heap::Visitor {
class Visitor: public HeapVisitor {
public:
Visitor(Context* c): c(c) { }
Visitor(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(object, unsigned, unsigned) {
write1(out, Push);
}
virtual void pop() {
write1(out, Pop);
}
Thread* t;
FILE* out;
unsigned nextNumber;
} visitor(t, out);
HeapWalker* w = makeHeapWalker(t, &visitor);
w->visitAllRoots();
w->dispose();
}
} // namespace vm

341
src/heapwalk.cpp Normal file
View File

@ -0,0 +1,341 @@
/* Copyright (c) 2008, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
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 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)
{ }
void dispose() {
if (objects) {
objects->dispose();
}
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;
}
unsigned
walk(Context* c, HeapVisitor* v, object p)
{
Thread* t = c->thread;
object root = p;
int nextChildOffset;
v->root();
visit: {
Set::Entry* e = find(c, p);
if (e) {
v->visitOld(p, e->number);
} else {
e = add(c, p);
e->number = v->visitNew(p);
nextChildOffset = walkNext(t, p, -1);
if (nextChildOffset != -1) {
goto children;
}
}
}
goto pop;
children: {
v->push(p, find(c, p)->number, nextChildOffset);
push(c, p, nextChildOffset);
p = get(p, nextChildOffset);
goto visit;
}
pop: {
if (pop(c, &p, &nextChildOffset)) {
v->pop();
nextChildOffset = walkNext(t, p, nextChildOffset);
if (nextChildOffset >= 0) {
goto children;
} else {
goto pop;
}
}
}
return find(c, root)->number;
}
class MyHeapWalker: public HeapWalker {
public:
MyHeapWalker(Thread* t, HeapVisitor* v):
context(t), visitor(v)
{
add(&context, 0)->number = v->visitNew(0);
}
virtual unsigned visitRoot(object root) {
return walk(&context, visitor, root);
}
virtual void visitAllRoots() {
class Visitor: public Heap::Visitor {
public:
Visitor(Context* c, HeapVisitor* v): c(c), v(v) { }
virtual void visit(void* p) {
walk(c, v, static_cast<object>(mask(*static_cast<void**>(p))));
}
Context* c;
HeapVisitor* v;
} v(&context, visitor);
visitRoots(context.thread->m, &v);
}
virtual HeapMap* map() {
return context.objects;
}
virtual void dispose() {
context.dispose();
context.thread->m->heap->free(this, sizeof(MyHeapWalker));
}
Context context;
HeapVisitor* visitor;
};
} // namespace
namespace vm {
HeapWalker*
makeHeapWalker(Thread* t, HeapVisitor* v)
{
return new (t->m->heap->allocate(sizeof(MyHeapWalker))) MyHeapWalker(t, v);
}
} // namespace vm

49
src/heapwalk.h Normal file
View File

@ -0,0 +1,49 @@
/* Copyright (c) 2008, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
#ifndef HEAPWALK_H
#define HEAPWALK_H
#include "common.h"
namespace vm {
class Thread;
class HeapMap {
public:
virtual int find(object value) = 0;
virtual void dispose() = 0;
};
class HeapVisitor {
public:
virtual void root() = 0;
virtual unsigned visitNew(object value) = 0;
virtual void visitOld(object value, unsigned number) = 0;
virtual void push(object parent, unsigned parentNumber,
unsigned childOffset) = 0;
virtual void pop() = 0;
};
class HeapWalker {
public:
virtual unsigned visitRoot(object root) = 0;
virtual void visitAllRoots() = 0;
virtual HeapMap* map() = 0;
virtual void dispose() = 0;
};
HeapWalker*
makeHeapWalker(Thread* t, HeapVisitor* v);
} // namespace vm
#endif//HEAPWALK_H

View File

@ -2876,7 +2876,7 @@ class MyProcessor: public Processor {
{
return vm::makeMethod
(t, vmFlags, returnCode, parameterCount, parameterFootprint, flags,
offset, name, spec, class_, code, 0);
offset, 0, name, spec, class_, code, 0);
}
virtual object
@ -3056,6 +3056,32 @@ class MyProcessor: public Processor {
return 0;
}
virtual void compileThunks(vm::Thread*, BootImage*, uint8_t*, unsigned*,
unsigned)
{
abort(s);
}
virtual void compileMethod(vm::Thread*, Zone*, uint8_t*, unsigned*, unsigned,
object*, object*, DelayedPromise**, object)
{
abort(s);
}
virtual void visitRoots(BootImage*, HeapWalker*) {
abort(s);
}
virtual unsigned* makeCallTable(vm::Thread*, BootImage*, HeapWalker*,
uint8_t*)
{
abort(s);
}
virtual void boot(vm::Thread*, BootImage* image) {
expect(s, image == 0);
}
virtual void dispose(vm::Thread* t) {
t->m->heap->free(t, sizeof(Thread));
}

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)
{
@ -1534,6 +1502,88 @@ bootJavaClass(Thread* t, Machine::Type type, int superType, const char* name,
hashMapInsert(t, t->m->bootstrapClassMap, n, class_, byteArrayHash);
}
void
boot(Thread* t)
{
Machine* m = t->m;
m->unsafe = true;
m->loader = allocate(t, sizeof(void*) * 3, true);
memset(m->loader, 0, sizeof(void*) * 2);
m->types = allocate(t, pad((TypeCount + 2) * BytesPerWord), true);
arrayLength(t, m->types) = TypeCount;
memset(&arrayBody(t, m->types, 0), 0, TypeCount * BytesPerWord);
#include "type-initializations.cpp"
object arrayClass = arrayBody(t, m->types, Machine::ArrayType);
set(t, m->types, 0, arrayClass);
object loaderClass = arrayBody
(t, m->types, Machine::SystemClassLoaderType);
set(t, m->loader, 0, loaderClass);
object objectClass = arrayBody(t, m->types, Machine::JobjectType);
object classClass = arrayBody(t, m->types, Machine::ClassType);
set(t, classClass, 0, classClass);
set(t, classClass, ClassSuper, objectClass);
object intArrayClass = arrayBody(t, m->types, Machine::IntArrayType);
set(t, intArrayClass, 0, classClass);
set(t, intArrayClass, ClassSuper, objectClass);
m->unsafe = false;
classVmFlags(t, arrayBody(t, m->types, Machine::SingletonType))
|= SingletonFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JreferenceType))
|= ReferenceFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::WeakReferenceType))
|= ReferenceFlag | WeakReferenceFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::PhantomReferenceType))
|= ReferenceFlag | WeakReferenceFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JbooleanType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JbyteType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JcharType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JshortType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JintType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JlongType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JfloatType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JdoubleType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JvoidType))
|= PrimitiveFlag;
m->bootstrapClassMap = makeHashMap(t, 0, 0);
m->classMap = makeHashMap(t, 0, 0);
m->stringMap = makeWeakHashMap(t, 0, 0);
m->processor->boot(t, 0);
{ object bootCode = makeCode(t, 0, 0, 0, 0, 0, 1, false);
codeBody(t, bootCode, 0) = impdep1;
object bootMethod = makeMethod
(t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode, 0);
PROTECT(t, bootMethod);
#include "type-java-initializations.cpp"
}
}
class HeapClient: public Heap::Client {
public:
HeapClient(Machine* m): m(m) { }
@ -1648,6 +1698,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
referenceLock(0),
libraries(0),
loader(0),
classMap(0),
bootstrapClassMap(0),
monitorMap(0),
stringMap(0),
@ -1748,86 +1799,32 @@ Thread::init()
abort(this);
}
Thread* t = this;
BootImage* image = 0;
const char* imageFunctionName = findProperty(m, "avian.bootimage");
if (imageFunctionName) {
void* p = m->libraries->resolve(imageFunctionName);
if (p) {
BootImage* (*function)(unsigned*);
memcpy(&function, &p, BytesPerWord);
t->m->loader = allocate(t, sizeof(void*) * 3, true);
memset(t->m->loader, 0, sizeof(void*) * 2);
t->m->types = allocate(t, pad((TypeCount + 2) * BytesPerWord), true);
arrayLength(t, t->m->types) = TypeCount;
memset(&arrayBody(t, t->m->types, 0), 0, TypeCount * BytesPerWord);
#include "type-initializations.cpp"
object arrayClass = arrayBody(t, t->m->types, Machine::ArrayType);
set(t, t->m->types, 0, arrayClass);
object loaderClass = arrayBody
(t, t->m->types, Machine::SystemClassLoaderType);
set(t, t->m->loader, 0, loaderClass);
object objectClass = arrayBody(t, m->types, Machine::JobjectType);
object classClass = arrayBody(t, m->types, Machine::ClassType);
set(t, classClass, 0, classClass);
set(t, classClass, ClassSuper, objectClass);
object intArrayClass = arrayBody(t, m->types, Machine::IntArrayType);
set(t, intArrayClass, 0, classClass);
set(t, intArrayClass, ClassSuper, objectClass);
unsigned size;
image = function(&size);
}
}
m->unsafe = false;
classVmFlags(t, arrayBody(t, m->types, Machine::SingletonType))
|= SingletonFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JreferenceType))
|= ReferenceFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::WeakReferenceType))
|= ReferenceFlag | WeakReferenceFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::PhantomReferenceType))
|= ReferenceFlag | WeakReferenceFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JbooleanType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JbyteType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JcharType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JshortType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JintType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JlongType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JfloatType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JdoubleType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JvoidType))
|= PrimitiveFlag;
m->bootstrapClassMap = makeHashMap(this, 0, 0);
{ object loaderMap = makeHashMap(this, 0, 0);
set(t, m->loader, SystemClassLoaderMap, loaderMap);
if (image) {
m->processor->boot(this, image);
} else {
boot(this);
}
m->monitorMap = makeWeakHashMap(this, 0, 0);
m->stringMap = makeWeakHashMap(this, 0, 0);
m->jniMethodTable = makeVector(this, 0, 0, false);
m->localThread->set(this);
{ object bootCode = makeCode(t, 0, 0, 0, 0, 0, 1, false);
codeBody(t, bootCode, 0) = impdep1;
object bootMethod = makeMethod
(t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode, 0);
PROTECT(t, bootMethod);
#include "type-java-initializations.cpp"
}
} else {
peer = parent->child;
parent->child = this;
@ -2108,7 +2105,7 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
case Machine::ImmortalAllocation: {
unsigned total;
object o = static_cast<object>
(t->m->heap->allocateImmortal
(t->m->heap->allocateImmortalFixed
(allocator, ceiling(sizeInBytes, BytesPerWord), objectMask, &total));
cast<uintptr_t>(o, 0) = FixedMark;
@ -2329,8 +2326,7 @@ findLoadedClass(Thread* t, object spec)
PROTECT(t, spec);
ACQUIRE(t, t->m->classLock);
return hashMapFind(t, systemClassLoaderMap(t, t->m->loader),
spec, byteArrayHash, byteArrayEqual);
return hashMapFind(t, t->m->classMap, spec, byteArrayHash, byteArrayEqual);
}
object
@ -2434,8 +2430,9 @@ resolveClass(Thread* t, object spec)
PROTECT(t, spec);
ACQUIRE(t, t->m->classLock);
object class_ = hashMapFind(t, systemClassLoaderMap(t, t->m->loader),
spec, byteArrayHash, byteArrayEqual);
object class_ = hashMapFind
(t, t->m->classMap, spec, byteArrayHash, byteArrayEqual);
if (class_ == 0) {
if (byteArrayBody(t, spec, 0) == '[') {
class_ = hashMapFind
@ -2487,8 +2484,7 @@ resolveClass(Thread* t, object spec)
if (class_) {
PROTECT(t, class_);
hashMapInsert(t, systemClassLoaderMap(t, t->m->loader),
spec, class_, byteArrayHash);
hashMapInsert(t, t->m->classMap, spec, class_, byteArrayHash);
} else if (t->exception == 0) {
object message = makeString(t, "%s", &byteArrayBody(t, spec, 0));
t->exception = makeClassNotFoundException(t, message);
@ -2770,6 +2766,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)
{
@ -2793,6 +2821,7 @@ void
visitRoots(Machine* m, Heap::Visitor* v)
{
v->visit(&(m->loader));
v->visit(&(m->classMap));
v->visit(&(m->bootstrapClassMap));
v->visit(&(m->monitorMap));
v->visit(&(m->stringMap));

View File

@ -1159,6 +1159,7 @@ class Machine {
System::Monitor* referenceLock;
System::Library* libraries;
object loader;
object classMap;
object bootstrapClassMap;
object monitorMap;
object stringMap;
@ -1433,6 +1434,35 @@ expect(Thread* t, bool v)
expect(t->m->system, v);
}
class FixedAllocator: public Allocator {
public:
FixedAllocator(Thread* t, uint8_t* base, unsigned capacity):
t(t), base(base), offset(0), capacity(capacity)
{ }
virtual void* tryAllocate(unsigned) {
abort(t);
}
virtual void* allocate(unsigned size) {
unsigned paddedSize = pad(size);
expect(t, offset + paddedSize < capacity);
void* p = base + offset;
offset += paddedSize;
return p;
}
virtual void free(const void*, unsigned) {
abort(t);
}
Thread* t;
uint8_t* base;
unsigned offset;
unsigned capacity;
};
inline void
ensure(Thread* t, unsigned sizeInBytes)
{
@ -2004,10 +2034,19 @@ resolveMethod(Thread* t, const char* className, const char* methodName,
object
resolveObjectArrayClass(Thread* t, object elementSpec);
inline bool
classNeedsInit(Thread* t, object c)
{
return classVmFlags(t, c) & NeedInitFlag
and (classVmFlags(t, c) & InitFlag) == 0;
}
inline void
initClass(Thread* t, object c)
{
t->m->processor->initClass(t, c);
if (classNeedsInit(t, c)) {
t->m->processor->initClass(t, c);
}
}
object
@ -2209,6 +2248,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

@ -79,11 +79,20 @@ main(int ac, const char** av)
++ vmArgs.nOptions;
#endif
#ifdef BOOT_IMAGE
++ vmArgs.nOptions;
#endif
JavaVMOption options[vmArgs.nOptions];
vmArgs.options = options;
unsigned optionIndex = 0;
#ifdef BOOT_IMAGE
options[optionIndex++].optionString
= const_cast<char*>("-Davian.bootimage=" BOOT_IMAGE);
#endif
#ifdef BOOT_CLASSPATH
options[optionIndex++].optionString
= const_cast<char*>("-Xbootclasspath:" BOOT_CLASSPATH);

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

@ -14,6 +14,10 @@
#include "common.h"
#include "system.h"
#include "heap.h"
#include "bootimage.h"
#include "heapwalk.h"
#include "zone.h"
#include "assembler.h"
namespace vm {
@ -112,6 +116,24 @@ class Processor {
virtual object
getStackTrace(Thread* t, Thread* target) = 0;
virtual void
compileThunks(Thread* t, BootImage* image, uint8_t* code, unsigned* size,
unsigned capacity) = 0;
virtual void
compileMethod(Thread* t, Zone* zone, uint8_t* code, unsigned* offset,
unsigned capacity, object* constants, object* calls,
DelayedPromise** addresses, object method) = 0;
virtual void
visitRoots(BootImage* image, HeapWalker* w) = 0;
virtual unsigned*
makeCallTable(Thread* t, BootImage* image, HeapWalker* w, uint8_t* code) = 0;
virtual void
boot(Thread* t, BootImage* image) = 0;
object
invoke(Thread* t, object method, object this_, ...)
{

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

@ -106,6 +106,25 @@ cloneTreeNode(Thread* t, object n)
return newNode;
}
object
treeFind(Thread* t, object tree, intptr_t key, object sentinal,
intptr_t (*compare)(Thread* t, intptr_t key, object b))
{
object node = tree;
while (node != sentinal) {
intptr_t difference = compare(t, key, getTreeNodeValue(t, node));
if (difference < 0) {
node = treeNodeLeft(t, node);
} else if (difference > 0) {
node = treeNodeRight(t, node);
} else {
return node;
}
}
return 0;
}
void
treeFind(Thread* t, TreeContext* c, object old, intptr_t key, object node,
object sentinal,
@ -531,29 +550,20 @@ object
treeQuery(Thread* t, object tree, intptr_t key, object sentinal,
intptr_t (*compare)(Thread* t, intptr_t key, object b))
{
object node = tree;
while (node != sentinal) {
intptr_t difference = compare(t, key, getTreeNodeValue(t, node));
if (difference < 0) {
node = treeNodeLeft(t, node);
} else if (difference > 0) {
node = treeNodeRight(t, node);
} else {
return getTreeNodeValue(t, node);
}
}
return 0;
object node = treeFind(t, tree, key, sentinal, compare);
return (node ? getTreeNodeValue(t, node) : 0);
}
object
treeInsertNode(Thread* t, Zone* zone, object tree, intptr_t key, object node,
object sentinal,
intptr_t (*compare)(Thread* t, intptr_t key, object b))
treeInsert(Thread* t, Zone* zone, object tree, intptr_t key, object value,
object sentinal,
intptr_t (*compare)(Thread* t, intptr_t key, object b))
{
PROTECT(t, tree);
PROTECT(t, sentinal);
object node = makeTreeNode(t, value, sentinal, sentinal);
TreeContext c(t, zone);
treeFind(t, &c, tree, key, node, sentinal, compare);
expect(t, c.fresh);
@ -561,4 +571,11 @@ treeInsertNode(Thread* t, Zone* zone, object tree, intptr_t key, object node,
return treeAdd(t, &c);
}
void
treeUpdate(Thread* t, object tree, intptr_t key, object value, object sentinal,
intptr_t (*compare)(Thread* t, intptr_t key, object b))
{
setTreeNodeValue(t, treeFind(t, tree, key, sentinal, compare), value);
}
} // namespace vm

View File

@ -89,9 +89,13 @@ treeQuery(Thread* t, object tree, intptr_t key, object sentinal,
intptr_t (*compare)(Thread* t, intptr_t key, object b));
object
treeInsertNode(Thread* t, Zone* zone, object tree, intptr_t key, object node,
object sentinal,
intptr_t (*compare)(Thread* t, intptr_t key, object b));
treeInsert(Thread* t, Zone* zone, object tree, intptr_t key, object value,
object sentinal,
intptr_t (*compare)(Thread* t, intptr_t key, object b));
void
treeUpdate(Thread* t, object tree, intptr_t key, object value, object sentinal,
intptr_t (*compare)(Thread* t, intptr_t key, object b));
class HashMapIterator: public Thread::Protector {
public:

View File

@ -11,6 +11,7 @@
#include "sys/stat.h"
#include "windows.h"
#include "sys/timeb.h"
#include "dirent.h"
#undef max
#undef min
@ -422,6 +423,31 @@ class MySystem: public System {
HANDLE file;
};
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, HMODULE handle, const char* name, bool mapName):
@ -630,19 +656,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

@ -135,6 +135,38 @@ class Task {
Task* next;
};
void*
resolveOffset(System* s, uint8_t* instruction, unsigned instructionSize,
int64_t value)
{
intptr_t v = reinterpret_cast<uint8_t*>(value)
- instruction - instructionSize;
expect(s, isInt32(v));
int32_t v4 = v;
memcpy(instruction + instructionSize - 4, &v4, 4);
return instruction + instructionSize;
}
class OffsetListener: public Promise::Listener {
public:
OffsetListener(System* s, uint8_t* instruction,
unsigned instructionSize):
s(s),
instruction(instruction),
instructionSize(instructionSize)
{ }
virtual void* resolve(int64_t value) {
return resolveOffset(s, instruction, instructionSize, value);
}
System* s;
uint8_t* instruction;
unsigned instructionSize;
};
class OffsetTask: public Task {
public:
OffsetTask(Task* next, Promise* promise, unsigned instructionOffset,
@ -146,14 +178,14 @@ class OffsetTask: public Task {
{ }
virtual void run(Context* c) {
uint8_t* instruction = c->result + instructionOffset;
intptr_t v = reinterpret_cast<uint8_t*>(promise->value())
- instruction - instructionSize;
expect(c, isInt32(v));
int32_t v4 = v;
memcpy(instruction + instructionSize - 4, &v4, 4);
if (promise->resolved()) {
resolveOffset
(c->s, c->result + instructionOffset, instructionSize,
promise->value());
} else {
new (promise->listen(sizeof(OffsetListener)))
OffsetListener(c->s, c->result + instructionOffset, instructionSize);
}
}
Promise* promise;
@ -169,28 +201,73 @@ appendOffsetTask(Context* c, Promise* promise, int instructionOffset,
(c->tasks, promise, instructionOffset, instructionSize);
}
void
copy(System* s, void* dst, int64_t src, unsigned size)
{
switch (size) {
case 4: {
int32_t v = src;
memcpy(dst, &v, 4);
} break;
case 8: {
int64_t v = src;
memcpy(dst, &v, 8);
} break;
default: abort(s);
}
}
class ImmediateListener: public Promise::Listener {
public:
ImmediateListener(System* s, void* dst, unsigned size, unsigned offset):
s(s), dst(dst), size(size), offset(offset)
{ }
virtual void* resolve(int64_t value) {
copy(s, dst, value, size);
return static_cast<uint8_t*>(dst) + offset;
}
System* s;
void* dst;
unsigned size;
unsigned offset;
};
class ImmediateTask: public Task {
public:
ImmediateTask(Task* next, Promise* promise, unsigned offset):
ImmediateTask(Task* next, Promise* promise, unsigned offset, unsigned size,
unsigned promiseOffset):
Task(next),
promise(promise),
offset(offset)
offset(offset),
size(size),
promiseOffset(promiseOffset)
{ }
virtual void run(Context* c) {
intptr_t v = promise->value();
memcpy(c->result + offset, &v, BytesPerWord);
if (promise->resolved()) {
copy(c->s, c->result + offset, promise->value(), size);
} else {
new (promise->listen(sizeof(ImmediateListener)))
ImmediateListener(c->s, c->result + offset, size, promiseOffset);
}
}
Promise* promise;
unsigned offset;
unsigned size;
unsigned promiseOffset;
};
void
appendImmediateTask(Context* c, Promise* promise, unsigned offset)
appendImmediateTask(Context* c, Promise* promise, unsigned offset,
unsigned size, unsigned promiseOffset = 0)
{
c->tasks = new (c->zone->allocate(sizeof(ImmediateTask))) ImmediateTask
(c->tasks, promise, offset);
(c->tasks, promise, offset, size, promiseOffset);
}
void
@ -305,6 +382,10 @@ conditional(Context* c, unsigned condition, Assembler::Constant* a)
void
moveCR(Context*, unsigned, Assembler::Constant*, Assembler::Register*);
void
moveCR2(Context*, unsigned, Assembler::Constant*, Assembler::Register*,
unsigned promiseOffset);
void
callR(Context*, unsigned, Assembler::Register*);
@ -323,7 +404,7 @@ longCallC(Context* c, unsigned size, Assembler::Constant* a)
if (BytesPerWord == 8) {
Assembler::Register r(r10);
moveCR(c, size, a, &r);
moveCR2(c, size, a, &r, 11);
callR(c, size, &r);
} else {
callC(c, size, a);
@ -382,7 +463,7 @@ longJumpC(Context* c, unsigned size, Assembler::Constant* a)
if (BytesPerWord == 8) {
Assembler::Register r(r10);
moveCR(c, size, a, &r);
moveCR2(c, size, a, &r, 11);
jumpR(c, size, &r);
} else {
jumpC(c, size, a);
@ -480,7 +561,7 @@ pushC(Context* c, unsigned size, Assembler::Constant* a)
} else {
if (BytesPerWord == 4) {
c->code.append(0x68);
appendImmediateTask(c, a->value, c->code.length());
appendImmediateTask(c, a->value, c->code.length(), BytesPerWord);
c->code.appendAddress(static_cast<uintptr_t>(0));
} else {
Assembler::Register tmp(c->client->acquireTemporary());
@ -627,8 +708,8 @@ leaMR(Context* c, unsigned size, Assembler::Memory* b, Assembler::Register* a)
}
void
moveCR(Context* c, unsigned size, Assembler::Constant* a,
Assembler::Register* b)
moveCR2(Context* c, unsigned size, Assembler::Constant* a,
Assembler::Register* b, unsigned promiseOffset)
{
if (BytesPerWord == 4 and size == 8) {
int64_t v = a->value->value();
@ -649,49 +730,18 @@ moveCR(Context* c, unsigned size, Assembler::Constant* a,
if (a->value->resolved()) {
c->code.appendAddress(a->value->value());
} else {
appendImmediateTask(c, a->value, c->code.length());
appendImmediateTask
(c, a->value, c->code.length(), BytesPerWord, promiseOffset);
c->code.appendAddress(static_cast<uintptr_t>(0));
}
}
}
void
moveCM(Context* c, unsigned size, Assembler::Constant* a,
Assembler::Memory* b)
moveCR(Context* c, unsigned size, Assembler::Constant* a,
Assembler::Register* b)
{
int64_t v = a->value->value();
switch (size) {
case 1:
encode(c, 0xc6, 0, b, false);
c->code.append(a->value->value());
break;
case 2:
encode2(c, 0x66c7, 0, b, false);
c->code.append2(a->value->value());
break;
case 4:
encode(c, 0xc7, 0, b, false);
c->code.append4(a->value->value());
break;
case 8: {
ResolvedPromise high((v >> 32) & 0xFFFFFFFF);
Assembler::Constant ah(&high);
ResolvedPromise low(v & 0xFFFFFFFF);
Assembler::Constant al(&low);
Assembler::Memory bh(b->base, b->offset + 4, b->index, b->scale);
moveCM(c, 4, &al, b);
moveCM(c, 4, &ah, &bh);
} break;
default: abort(c);
}
moveCR2(c, size, a, b, 0);
}
void
@ -779,6 +829,62 @@ moveRM(Context* c, unsigned size, Assembler::Register* a, Assembler::Memory* b)
}
}
void
moveCM(Context* c, unsigned size, Assembler::Constant* a,
Assembler::Memory* b)
{
switch (size) {
case 1:
encode(c, 0xc6, 0, b, false);
c->code.append(a->value->value());
break;
case 2:
encode2(c, 0x66c7, 0, b, false);
c->code.append2(a->value->value());
break;
case 4:
encode(c, 0xc7, 0, b, false);
if (a->value->resolved()) {
c->code.append4(a->value->value());
} else {
appendImmediateTask(c, a->value, c->code.length(), 4);
c->code.append4(0);
}
break;
case 8: {
if (BytesPerWord == 8) {
if(a->value->resolved() and isInt32(a->value->value())) {
encode(c, 0xc7, 0, b, true);
c->code.append4(a->value->value());
} else {
Assembler::Register tmp(c->client->acquireTemporary());
moveCR(c, 8, a, &tmp);
moveRM(c, 8, &tmp, b);
c->client->releaseTemporary(tmp.low);
}
} else {
int64_t v = a->value->value();
ResolvedPromise high((v >> 32) & 0xFFFFFFFF);
Assembler::Constant ah(&high);
ResolvedPromise low(v & 0xFFFFFFFF);
Assembler::Constant al(&low);
Assembler::Memory bh(b->base, b->offset + 4, b->index, b->scale);
moveCM(c, 4, &al, b);
moveCM(c, 4, &ah, &bh);
}
} break;
default: abort(c);
}
}
void
move4To8CR(Context* c, unsigned, Assembler::Constant* a,
Assembler::Register* b)
@ -1640,9 +1746,9 @@ compareCR(Context* c, unsigned size, Assembler::Constant* a,
{
assert(c, BytesPerWord == 8 or size == 4);
int64_t v = a->value->value();
if (a->value->resolved() and isInt32(a->value->value())) {
int64_t v = a->value->value();
if (isInt32(v)) {
if (size == 8) rex(c);
if (isInt8(v)) {
c->code.append(0x83);
@ -1661,25 +1767,6 @@ compareCR(Context* c, unsigned size, Assembler::Constant* a,
}
}
void
compareCM(Context* c, unsigned size UNUSED, Assembler::Constant* a,
Assembler::Memory* b)
{
assert(c, BytesPerWord == 8 or size == 4);
int64_t v = a->value->value();
encode(c, isInt8(v) ? 0x83 : 0x81, 7, b, true);
if (isInt8(v)) {
c->code.append(v);
} else if (isInt32(v)) {
c->code.append4(v);
} else {
abort(c);
}
}
void
compareRM(Context* c, unsigned size, Assembler::Register* a,
Assembler::Memory* b)
@ -1692,6 +1779,32 @@ compareRM(Context* c, unsigned size, Assembler::Register* a,
encode(c, 0x39, a->low, b, true);
}
void
compareCM(Context* c, unsigned size, Assembler::Constant* a,
Assembler::Memory* b)
{
assert(c, BytesPerWord == 8 or size == 4);
if (a->value->resolved()) {
int64_t v = a->value->value();
encode(c, isInt8(v) ? 0x83 : 0x81, 7, b, true);
if (isInt8(v)) {
c->code.append(v);
} else if (isInt32(v)) {
c->code.append4(v);
} else {
abort(c);
}
} else {
Assembler::Register tmp(c->client->acquireTemporary());
moveCR(c, size, a, &tmp);
compareRM(c, size, &tmp, b);
c->client->releaseTemporary(tmp.low);
}
}
void
compareAM(Context* c, unsigned size, Assembler::Address* a,
Assembler::Memory* b)
@ -2192,14 +2305,36 @@ class MyAssembler: public Assembler {
return c.code.length();
}
virtual void updateCall(void* returnAddress, void* newTarget) {
uint8_t* instruction = static_cast<uint8_t*>(returnAddress) - 5;
assert(&c, *instruction == 0xE8);
assert(&c, reinterpret_cast<uintptr_t>(instruction + 1) % 4 == 0);
virtual void updateCall(UnaryOperation op UNUSED,
bool assertAlignment UNUSED, void* returnAddress,
void* newTarget)
{
if (BytesPerWord == 4 or op == Call or op == Jump) {
uint8_t* instruction = static_cast<uint8_t*>(returnAddress) - 5;
int32_t v = static_cast<uint8_t*>(newTarget)
- static_cast<uint8_t*>(returnAddress);
memcpy(instruction + 1, &v, 4);
assert(&c, ((op == Call or op == LongCall) and *instruction == 0xE8)
or ((op == Jump or op == LongJump) and *instruction == 0xE9));
assert(&c, (not assertAlignment)
or reinterpret_cast<uintptr_t>(instruction + 1) % 4 == 0);
int32_t v = static_cast<uint8_t*>(newTarget)
- static_cast<uint8_t*>(returnAddress);
memcpy(instruction + 1, &v, 4);
} else {
uint8_t* instruction = static_cast<uint8_t*>(returnAddress) - 13;
assert(&c, instruction[0] == 0x49 and instruction[1] == 0xBA);
assert(&c, instruction[10] == 0x41 and instruction[11] == 0xFF);
assert(&c, (op == LongCall and instruction[12] == 0xD2)
or (op == LongJump and instruction[12] == 0xE2));
assert(&c, (not assertAlignment)
or reinterpret_cast<uintptr_t>(instruction + 2) % 8 == 0);
memcpy(instruction + 2, &newTarget, 8);
}
}
virtual void dispose() {