From 6500f1eff62f2e949fe527345697dbf5a186f259 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 21 Nov 2008 16:20:35 -0700 Subject: [PATCH 01/39] initial work to support boot image creation and use --- makefile | 45 +++++-- src/bootimage.cpp | 240 ++++++++++++++++++++++++++++++++++ src/bootimage.h | 34 +++++ src/finder.cpp | 112 +++++++++++++++- src/finder.h | 38 ++++++ src/heapdump.cpp | 327 ++++++++-------------------------------------- src/heapwalk.cpp | 300 ++++++++++++++++++++++++++++++++++++++++++ src/heapwalk.h | 23 ++++ src/machine.cpp | 78 +++++------ src/machine.h | 5 +- src/posix.cpp | 48 ++++++- src/system.h | 15 ++- src/types.def | 5 - src/util.cpp | 34 ----- src/util.h | 46 +++++++ 15 files changed, 975 insertions(+), 375 deletions(-) create mode 100644 src/bootimage.cpp create mode 100644 src/bootimage.h create mode 100644 src/heapwalk.cpp create mode 100644 src/heapwalk.h diff --git a/makefile b/makefile index 3e4b0e989a..946c31e62f 100644 --- a/makefile +++ b/makefile @@ -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) $(@) diff --git a/src/bootimage.cpp b/src/bootimage.cpp new file mode 100644 index 0000000000..1936f9a65b --- /dev/null +++ b/src/bootimage.cpp @@ -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(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(b) - reinterpret_cast(a); +} + +void +writeBootImage(Thread* t, FILE* out) +{ + BootImage image; + + const unsigned CodeCapacity = 32 * 1024 * 1024; + uint8_t* code = static_cast(t->m->heap->allocate(CodeCapacity)); + uintptr_t* codeMap = static_cast + (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 + (t->m->heap->allocate(HeapCapacity)); + uintptr_t* heapMap = static_cast + (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 \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; +} diff --git a/src/bootimage.h b/src/bootimage.h new file mode 100644 index 0000000000..18c7e38012 --- /dev/null +++ b/src/bootimage.h @@ -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 diff --git a/src/finder.cpp b/src/finder.cpp index 091593d9ea..9867c01a13 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -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(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); diff --git a/src/finder.h b/src/finder.h index 64eb4c287b..37f6d3a9b7 100644 --- a/src/finder.h +++ b/src/finder.h @@ -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(¤tSize)) + { } + + ~Iterator() { + it->dispose(); + } + + bool hasMore() { + return current != 0; + } + + const char* next(unsigned* size) { + if (current) { + const char* v = current; + *size = currentSize; + current = it->next(¤tSize); + 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; diff --git a/src/heapdump.cpp b/src/heapdump.cpp index 617d1d2e74..504117bfbb 100644 --- a/src/heapdump.cpp +++ b/src/heapdump.cpp @@ -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 - (reinterpret_cast(this) - + sizeof(Set))), - entries(reinterpret_cast - (reinterpret_cast(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(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 - (mask(cast(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(mask(*static_cast(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 diff --git a/src/heapwalk.cpp b/src/heapwalk.cpp new file mode 100644 index 0000000000..4a240af4a2 --- /dev/null +++ b/src/heapwalk.cpp @@ -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 + (reinterpret_cast(this) + + sizeof(Set))), + entries(reinterpret_cast + (reinterpret_cast(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(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 + (mask(cast(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(mask(*static_cast(p)))); + } + + Context* c; + HeapWalker* w; + } v(&context, w); + + add(&context, 0)->number = w->visitNew(0); + + visitRoots(t->m, &v); + + return context.objects; +} + +} // namespace vm diff --git a/src/heapwalk.h b/src/heapwalk.h new file mode 100644 index 0000000000..f18cb021ea --- /dev/null +++ b/src/heapwalk.h @@ -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 diff --git a/src/machine.cpp b/src/machine.cpp index 713e4ac0e7..3935ed893a 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -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(t->m->heap->follow(objectClass(t, o))); - object objectMask = static_cast - (t->m->heap->follow(classObjectMask(t, class_))); - - if (objectMask) { - unsigned fixedSize = classFixedSize(t, class_); - unsigned arrayElementSize = classArrayElementSize(t, class_); - unsigned arrayLength - = (arrayElementSize ? - cast(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(t->m->heap->follow(objectClass(t, o))); + object objectMask = static_cast + (t->m->heap->follow(classObjectMask(t, class_))); + + if (objectMask) { + unsigned fixedSize = classFixedSize(t, class_); + unsigned arrayElementSize = classArrayElementSize(t, class_); + unsigned arrayLength + = (arrayElementSize ? + cast(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) { diff --git a/src/machine.h b/src/machine.h index 3c12722c21..1c18fa9770 100644 --- a/src/machine.h +++ b/src/machine.h @@ -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); diff --git a/src/posix.cpp b/src/posix.cpp index 8f480aee26..e92dd23e14 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -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; } } diff --git a/src/system.h b/src/system.h index 3a5cb3cf22..932a5ec4bc 100644 --- a/src/system.h +++ b/src/system.h @@ -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; diff --git a/src/types.def b/src/types.def index bfe450e16a..35fff05cd1 100644 --- a/src/types.def +++ b/src/types.def @@ -73,11 +73,6 @@ (type weakHashMap (extends hashMap)) -(type hashMapIterator - (object map) - (object node) - (unsigned index)) - (type list (uint32_t size) (object front) diff --git a/src/util.cpp b/src/util.cpp index 219695a536..720709fe8e 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -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) { diff --git a/src/util.h b/src/util.h index adf8487723..10279a69db 100644 --- a/src/util.h +++ b/src/util.h @@ -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 From 20cf42c5e40091be64682a7d5f17f9c1aea29013 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 23 Nov 2008 16:58:01 -0700 Subject: [PATCH 02/39] more work on boot image creation --- classpath/java/lang/reflect/Method.java | 2 +- src/assembler.h | 22 ++ src/bootimage.cpp | 85 +++-- src/bootimage.h | 32 +- src/common.h | 9 + src/compile.cpp | 479 +++++++++++++++--------- src/finder.h | 2 +- src/heapdump.cpp | 10 +- src/heapwalk.cpp | 99 +++-- src/heapwalk.h | 33 +- src/processor.h | 14 + src/x86.cpp | 8 +- 12 files changed, 544 insertions(+), 251 deletions(-) diff --git a/classpath/java/lang/reflect/Method.java b/classpath/java/lang/reflect/Method.java index b28b70c045..68058aedce 100644 --- a/classpath/java/lang/reflect/Method.java +++ b/classpath/java/lang/reflect/Method.java @@ -22,7 +22,7 @@ public class Method extends AccessibleObject implements Member { private byte[] spec; private Class class_; private Object code; - private Object compiled; + private long compiled; private Method() { } diff --git a/src/assembler.h b/src/assembler.h index eceedc5993..55b839ac8e 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -80,6 +80,7 @@ class Promise { public: virtual int64_t value() = 0; virtual bool resolved() = 0; + virtual bool offer(void*) { return false; } }; class ResolvedPromise: public Promise { @@ -97,6 +98,27 @@ class ResolvedPromise: public Promise { int64_t value_; }; +class OfferPromise: public Promise { + public: + OfferPromise(System* s): s(s), offset(0) { } + + virtual int64_t value() { + abort(s); + } + + virtual bool resolved() { + return false; + } + + virtual bool offer(void* offset) { + this->offset = offset; + return true; + } + + System* s; + void* offset; +}; + class TraceHandler { public: virtual void handleTrace(Promise* address) = 0; diff --git a/src/bootimage.cpp b/src/bootimage.cpp index 1936f9a65b..846c3f3f3e 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -1,8 +1,23 @@ +/* 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; @@ -26,11 +41,12 @@ object makeCodeImage(Thread* t, BootImage* image, uint8_t* code, unsigned capacity) { unsigned size; - compileThunks(t, code, &size, image); + t->m->processor->compileThunks(t, image, code, &size, capacity); - unsigned fixupCount = 0; - object table = makeHashMap(t, 0, 0); - PROTECT(t, table); + object objectTable = makeHashMap(t, 0, 0); + PROTECT(t, objectTable); + + Zone zone(t->m->system, t->m->heap, 64 * 1024); for (Finder::Iterator it(t->m->finder); it.hasMore();) { unsigned nameSize; @@ -44,8 +60,8 @@ makeCodeImage(Thread* t, BootImage* image, uint8_t* code, unsigned capacity) 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); + t->m->processor->compileMethod + (t, &zone, code, &size, capacity, objectTable, method); } } } @@ -53,7 +69,7 @@ makeCodeImage(Thread* t, BootImage* image, uint8_t* code, unsigned capacity) image->codeSize = size; - return table; + return objectTable; } unsigned @@ -69,13 +85,23 @@ objectSize(Thread* t, object o) return baseSize(t, o, objectClass(t, o)); } -HeapMap* +void +visitRoots(Machine* m, BootImage* image, HeapWalker* w) +{ + image->loader = w->visitRoot(m->loader); + image->stringMap = w->visitRoot(m->stringMap); + image->types = w->visitRoot(m->types); + + m->processor->visitRoots(image, w); +} + +HeapWalker* makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map, unsigned capacity) { - class Walker: public HeapWalker { + class Visitor: public HeapVisitor { public: - Walker(Thread* t, uintptr_t* heap, uintptr_t* map, unsigned capacity): + Visitor(Thread* t, uintptr_t* heap, uintptr_t* map, unsigned capacity): t(t), currentObject(0), currentOffset(0), heap(heap), map(map), position(0), capacity(capacity) { } @@ -130,13 +156,14 @@ makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map, uintptr_t* map; unsigned position; unsigned capacity; - } walker(t, heap, map, capacity / BytesPerWord); + } visitor(t, heap, map, capacity / BytesPerWord); - HeapMap* table = walk(t, &walker); + HeapWalker* w = makeHeapWalker(t, &visitor); + visitRoots(t->m, image, w); - image->heapSize = walker.position * BytesPerWord; + image->heapSize = visitor.position * BytesPerWord; - return table; + return w; } void @@ -153,9 +180,13 @@ updateCodeTable(Thread* t, object codeTable, uint8_t* code, uintptr_t* codeMap, fixup; fixup = pairSecond(t, fixup)) { - int32_t v = intValue(t, pairFirst(t, fixup)); - memcpy(code + v, &target, BytesPerWord); - markBit(codeMap, v); + OfferPromise* p = static_cast + (pointerValue(t, pairFirst(t, fixup))); + assert(t, p->offset); + + memcpy(p->offset, &target, BytesPerWord); + markBit(codeMap, reinterpret_cast(p->offset) + - reinterpret_cast(code)); } } } @@ -186,25 +217,15 @@ writeBootImage(Thread* t, FILE* out) (t->m->heap->allocate(heapMapSize(HeapCapacity))); memset(heapMap, 0, heapMapSize(HeapCapacity)); - HeapMap* heapTable = makeHeapImage(t, &image, heap, heapMap, HeapCapacity); + HeapWalker* heapWalker = makeHeapImage + (t, &image, heap, heapMap, HeapCapacity); - updateCodeTable(t, codeTable, code, codeMap, heapTable); + updateCodeTable(t, codeTable, code, codeMap, heapWalker->map()); + + heapWalker->dispose(); 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); diff --git a/src/bootimage.h b/src/bootimage.h index 18c7e38012..2e09e44d89 100644 --- a/src/bootimage.h +++ b/src/bootimage.h @@ -1,3 +1,18 @@ +/* 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 { class BootImage { @@ -9,18 +24,15 @@ class BootImage { 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; + + uintptr_t codeBase; + unsigned callTable; + unsigned methodTree; + unsigned methodTreeSentinal; + unsigned objectPools; unsigned defaultThunk; unsigned nativeThunk; @@ -32,3 +44,5 @@ class BootImage { }; } // namespace vm + +#endif//BOOTIMAGE_H diff --git a/src/common.h b/src/common.h index f0ac8f60cf..e2783c7ef9 100644 --- a/src/common.h +++ b/src/common.h @@ -293,6 +293,15 @@ difference(void* a, void* b) return reinterpret_cast(a) - reinterpret_cast(b); } +template +inline void* +voidPointer(T function) +{ + void* p; + memcpy(&p, &function, sizeof(void*)); + return p; +} + class Machine; class Thread; diff --git a/src/compile.cpp b/src/compile.cpp index 3fe7873a51..4f51986a38 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -113,23 +113,25 @@ methodTree(MyThread* t); object methodTreeSentinal(MyThread* t); +unsigned +compiledSize(intptr_t address) +{ + return reinterpret_cast(address)[-1]; +} + intptr_t compareIpToMethodBounds(Thread* t, intptr_t ip, object method) { - intptr_t start = reinterpret_cast - (&singletonValue(t, methodCompiled(t, method), 0)); + intptr_t start = methodCompiled(t, method); if (DebugMethodTree) { fprintf(stderr, "find 0x%"LX" in (0x%"LX",0x%"LX")\n", ip, start, - start + (singletonCount(t, methodCompiled(t, method)) - * BytesPerWord)); + start + compiledSize(start)); } if (ip < start) { return -1; - } else if (ip < start + static_cast - (singletonCount(t, methodCompiled(t, method)) - * BytesPerWord)) + } else if (ip < start + compiledSize(start)) { return 0; } else { @@ -284,8 +286,7 @@ class MyStackWalker: public Processor::StackWalker { virtual int ip() { switch (state) { case Method: - return reinterpret_cast(ip_) - reinterpret_cast - (&singletonValue(t, methodCompiled(t, method_), 0)); + return reinterpret_cast(ip_) - methodCompiled(t, method_); case NativeMethod: return 0; @@ -336,14 +337,24 @@ localObject(MyThread* t, void* base, object method, unsigned index) (static_cast(base) + localOffset(t, index, method)); } -class PoolElement { +class PoolElement: public Promise { public: - PoolElement(object value, Promise* address, PoolElement* next): - value(value), address(address), next(next) + PoolElement(Thread* t, object target, PoolElement* next): + t(t), target(target), address(0), next(next) { } - object value; - Promise* address; + virtual int64_t value() { + assert(t, resolved()); + return address; + } + + virtual bool resolved() { + return address != 0; + } + + Thread* t; + object target; + intptr_t address; PoolElement* next; }; @@ -440,6 +451,28 @@ const unsigned ThunkCount = gcIfNecessaryThunk + 1; intptr_t getThunk(MyThread* t, Thunk thunk); +class BootContext { + public: + class MyProtector: public Thread::Protector { + public: + MyProtector(Thread* t, BootContext* c): Protector(t), c(c) { } + + virtual void visit(Heap::Visitor* v) { + v->visit(&(c->objectTable)); + } + + BootContext* c; + }; + + BootContext(Thread* t, object objectTable, Zone* zone): + protector(t, this), objectTable(objectTable), zone(zone) + { } + + MyProtector protector; + object objectTable; + Zone* zone; +}; + class Context { public: class MyProtector: public Thread::Protector { @@ -450,7 +483,7 @@ class Context { v->visit(&(c->method)); for (PoolElement* p = c->objectPool; p; p = p->next) { - v->visit(&(p->value)); + v->visit(&(p->target)); } for (TraceElement* p = c->traceLog; p; p = p->next) { @@ -492,13 +525,14 @@ class Context { MyThread* t; }; - Context(MyThread* t, object method): + Context(MyThread* t, BootContext* bootContext, object method): thread(t), zone(t->m->system, t->m->heap, 16 * 1024), assembler(makeAssembler(t->m->system, t->m->heap, &zone)), client(t), compiler(makeCompiler(t->m->system, assembler, &zone, &client)), method(method), + bootContext(bootContext), objectPool(0), traceLog(0), traceLogCount(0), @@ -515,6 +549,7 @@ class Context { client(t), compiler(0), method(0), + bootContext(0), objectPool(0), traceLog(0), traceLogCount(0), @@ -535,6 +570,7 @@ class Context { MyClient client; Compiler* compiler; object method; + BootContext* bootContext; PoolElement* objectPool; TraceElement* traceLog; unsigned traceLogCount; @@ -599,11 +635,36 @@ class Frame { } Compiler::Operand* append(object o) { - Promise* p = c->poolAppend(0); - context->objectPool = new - (context->zone.allocate(sizeof(PoolElement))) - PoolElement(o, p, context->objectPool); - return c->address(p); + if (context->bootContext) { + BootContext* bc = context->bootContext; + + object node = hashMapFindNode + (t, bc->objectTable, o, objectHash, objectEqual); + PROTECT(t, node); + + Promise* p = new (bc->zone->allocate(sizeof(OfferPromise))) + OfferPromise(t->m->system); + + object pointer = makePointer(t, p); + + if (node) { + object fixup = makePair(t, pointer, tripleSecond(t, node)); + vm::set(t, node, TripleSecond, fixup); + } else { + PROTECT(t, o); + object fixup = makePair(t, pointer, 0); + // todo: use a hash function that compares by value + hashMapInsert(t, bc->objectTable, o, fixup, objectHash); + } + + return c->promiseConstant(p); + } else { + context->objectPool = new + (context->zone.allocate(sizeof(PoolElement))) + PoolElement(t, o, context->objectPool); + + return c->address(context->objectPool); + } } unsigned localSize() { @@ -1094,8 +1155,7 @@ findExceptionHandler(Thread* t, object method, void* ip) if (table) { object index = arrayBody(t, table, 0); - uint8_t* compiled = reinterpret_cast - (&singletonValue(t, methodCompiled(t, method), 0)); + uint8_t* compiled = reinterpret_cast(methodCompiled(t, method)); for (unsigned i = 0; i < arrayLength(t, table) - 1; ++i) { unsigned start = intArrayBody(t, index, i * 3); @@ -1192,9 +1252,9 @@ void* FORCE_ALIGN findInterfaceMethodFromInstance(MyThread* t, object method, object instance) { if (instance) { - return &singletonValue - (t, methodCompiled - (t, findInterfaceMethod(t, method, objectClass(t, instance))), 0); + return reinterpret_cast + (methodCompiled + (t, findInterfaceMethod(t, method, objectClass(t, instance)))); } else { t->exception = makeNullPointerException(t); unwind(t); @@ -1656,13 +1716,16 @@ emptyMethod(MyThread* t, object method) and (codeBody(t, methodCode(t, method), 0) == return_); } -object +object& +objectPools(MyThread* t); + +uintptr_t defaultThunk(MyThread* t); -object +uintptr_t nativeThunk(MyThread* t); -object +uintptr_t aioobThunk(MyThread* t); void @@ -1677,27 +1740,27 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target) if (not emptyMethod(t, target)) { if (methodFlags(t, target) & ACC_NATIVE) { result = c->call - (c->constant - (reinterpret_cast - (&singletonBody(t, nativeThunk(t), 0))), + (c->constant(nativeThunk(t)), 0, frame->trace(target, false), rSize, 0); - } else if (methodCompiled(t, target) == defaultThunk(t)) { + } else if (methodCompiled(t, target) == defaultThunk(t) + or (frame->context->bootContext + and methodClass(t, target) + != methodClass(t, frame->context->method))) + { + // todo: when creating a boot image, log intra-class calls for + // later fixup result = c->call - (c->constant - (reinterpret_cast - (&singletonBody(t, defaultThunk(t), 0))), + (c->constant(defaultThunk(t)), Compiler::Aligned, frame->trace(target, false), rSize, 0); } else { result = c->call - (c->constant - (reinterpret_cast - (&singletonBody(t, methodCompiled(t, target), 0))), + (c->constant(methodCompiled(t, target)), 0, frame->trace(0, false), rSize, @@ -1880,8 +1943,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* array = frame->popObject(); if (CheckArrayBounds) { - c->checkBounds(array, ArrayLength, index, reinterpret_cast - (&singletonValue(t, aioobThunk(t), 0))); + c->checkBounds(array, ArrayLength, index, aioobThunk(t)); } switch (instruction) { @@ -1936,8 +1998,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* array = frame->popObject(); if (CheckArrayBounds) { - c->checkBounds(array, ArrayLength, index, reinterpret_cast - (&singletonValue(t, aioobThunk(t), 0))); + c->checkBounds(array, ArrayLength, index, aioobThunk(t)); } switch (instruction) { @@ -3720,43 +3781,49 @@ codeSingletonSizeInBytes(MyThread*, unsigned codeSizeInBytes) return pad(SingletonBody + (size * BytesPerWord)); } -object -allocateCode(MyThread* t, unsigned codeSizeInBytes) +uint8_t* +finish(MyThread* t, Allocator* allocator, Assembler* a, const char* name) { - unsigned count = ceiling(codeSizeInBytes, BytesPerWord); - unsigned size = count + singletonMaskSize(count); - object result = allocate3 - (t, codeZone(t), Machine::ImmortalAllocation, - SingletonBody + (size * BytesPerWord), true); - initSingleton(t, result, size, true); - mark(t, result, 0); - singletonMask(t, result)[0] = 1; - return result; -} - -object -finish(MyThread* t, Assembler* a, const char* name) -{ - object result = allocateCode(t, a->length()); - uint8_t* start = reinterpret_cast(&singletonValue(t, result, 0)); + uint8_t* start = static_cast + (allocator->allocate(pad(a->length()))); a->writeTo(start); logCompile(t, start, a->length(), 0, name, 0); - return result; + return start; } -object -finish(MyThread* t, Context* context) +uint8_t* +finish(MyThread* t, Allocator* allocator, Context* context) { Compiler* c = context->compiler; unsigned codeSize = c->compile(); - object result = allocateCode(t, pad(codeSize) + c->poolSize()); - PROTECT(t, result); + uintptr_t* code = static_cast + (allocator->allocate(pad(codeSize) + BytesPerWord)); + code[0] = codeSize; + uint8_t* start = reinterpret_cast(code + 1); - uint8_t* start = reinterpret_cast(&singletonValue(t, result, 0)); + if (context->objectPool) { + object pool = allocate3 + (t, allocator, Machine::ImmortalAllocation, + FixedSizeOfArray + c->poolSize() + BytesPerWord, true); + + initArray(t, pool, (c->poolSize() / BytesPerWord) + 1, false); + + set(t, pool, ArrayBody, objectPools(t)); + objectPools(t) = pool; + + unsigned i = 1; + for (PoolElement* p = context->objectPool; p; p = p->next) { + unsigned offset = ArrayBody + ((i++) * BytesPerWord); + + p->address = reinterpret_cast(pool) + offset; + + set(t, pool, offset, p->target); + } + } c->writeTo(start); @@ -3828,14 +3895,6 @@ finish(MyThread* t, Context* context) set(t, methodCode(t, context->method), CodePool, map); } - for (PoolElement* p = context->objectPool; p; p = p->next) { - intptr_t offset = p->address->value() - reinterpret_cast(start); - - singletonMarkObject(t, result, offset / BytesPerWord); - - set(t, result, SingletonBody + offset, p->value); - } - logCompile (t, start, codeSize, reinterpret_cast @@ -3859,11 +3918,11 @@ finish(MyThread* t, Context* context) asm("int3"); } - return result; + return start; } -object -compile(MyThread* t, Context* context) +uint8_t* +compile(MyThread* t, Allocator* allocator, Context* context) { Compiler* c = context->compiler; @@ -3970,11 +4029,12 @@ compile(MyThread* t, Context* context) calculateFrameMaps(t, context, 0, 0); } - return finish(t, context); + return finish(t, allocator, context); } void -compile(MyThread* t, object method); +compile(MyThread* t, Allocator* allocator, BootContext* bootContext, + object method); void* compileMethod2(MyThread* t) @@ -3990,24 +4050,24 @@ compileMethod2(MyThread* t) } if (LIKELY(t->exception == 0)) { - compile(t, target); + compile(t, codeZone(t), 0, target); } if (UNLIKELY(t->exception)) { return 0; } else { + void* address = reinterpret_cast(methodCompiled(t, target)); if (callNodeVirtualCall(t, node)) { classVtable (t, objectClass (t, resolveThisPointer(t, t->stack, target)), methodOffset(t, target)) - = &singletonValue(t, methodCompiled(t, target), 0); + = address; } else { Context context(t); context.assembler->updateCall - (reinterpret_cast(callNodeAddress(t, node)), - &singletonValue(t, methodCompiled(t, target), 0)); + (reinterpret_cast(callNodeAddress(t, node)), address); } - return &singletonValue(t, methodCompiled(t, target), 0); + return address; } } @@ -4276,7 +4336,7 @@ visitStackAndLocals(MyThread* t, Heap::Visitor* v, void* base, object method, object map = codePool(t, methodCode(t, method)); int index = frameMapIndex (t, method, difference - (ip, &singletonValue(t, methodCompiled(t, method), 0))); + (ip, reinterpret_cast(methodCompiled(t, method)))); for (unsigned i = 0; i < count; ++i) { int j = index + i; @@ -4510,7 +4570,7 @@ invoke(Thread* thread, object method, ArgumentList* arguments) } result = vmInvoke - (t, &singletonValue(t, methodCompiled(t, method), 0), arguments->array, + (t, reinterpret_cast(methodCompiled(t, method)), arguments->array, arguments->position, returnType); } @@ -4593,8 +4653,41 @@ class SegFaultHandler: public System::SignalHandler { Machine* m; }; +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; +}; + class MyProcessor; +void +compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, + BootImage* image, uint8_t* imageBase); + MyProcessor* processor(MyThread* t); @@ -4690,8 +4783,8 @@ class MyProcessor: public Processor { virtual void initVtable(Thread* t, object c) { - void* compiled = &singletonBody - (t, ::defaultThunk(static_cast(t)), 0); + void* compiled = reinterpret_cast + (::defaultThunk(static_cast(t))); for (unsigned i = 0; i < classLength(t, c); ++i) { classVtable(t, c, i) = compiled; @@ -4722,13 +4815,10 @@ class MyProcessor: public Processor { MyThread* t = static_cast(vmt); if (t == t->m->rootThread) { - v->visit(&defaultThunk); - v->visit(&nativeThunk); - v->visit(&aioobThunk); - v->visit(&thunkTable); v->visit(&callTable); v->visit(&methodTree); v->visit(&methodTreeSentinal); + v->visit(&objectPools); } for (MyThread::CallTrace* trace = t->trace; trace; trace = trace->next) { @@ -4801,7 +4891,7 @@ class MyProcessor: public Processor { PROTECT(t, method); - compile(static_cast(t), method); + compile(static_cast(t), &codeZone, 0, method); if (LIKELY(t->exception == 0)) { return ::invoke(t, method, &list); @@ -4832,7 +4922,7 @@ class MyProcessor: public Processor { PROTECT(t, method); - compile(static_cast(t), method); + compile(static_cast(t), &codeZone, 0, method); if (LIKELY(t->exception == 0)) { return ::invoke(t, method, &list); @@ -4862,7 +4952,7 @@ class MyProcessor: public Processor { PROTECT(t, method); - compile(static_cast(t), method); + compile(static_cast(t), &codeZone, 0, method); if (LIKELY(t->exception == 0)) { return ::invoke(t, method, &list); @@ -4911,8 +5001,7 @@ class MyProcessor: public Processor { target->base = base; target->stack = stack; } else { - uint8_t* thunkStart = reinterpret_cast - (&singletonValue(t, p->thunkTable, 0)); + uint8_t* thunkStart = p->thunkTable; uint8_t* thunkEnd = thunkStart + (p->thunkSize * ThunkCount); if (static_cast(ip) >= thunkStart @@ -4951,18 +5040,50 @@ class MyProcessor: public Processor { return visitor.trace; } + + virtual void compileThunks(Thread* vmt, BootImage* image, uint8_t* code, + unsigned* offset, unsigned capacity) + { + MyThread* t = static_cast(vmt); + FixedAllocator allocator(t, code + *offset, capacity); + + ::compileThunks(t, &allocator, processor(t), image, code); + + *offset += allocator.offset; + } + + virtual void compileMethod(Thread* vmt, Zone* zone, uint8_t* code, + unsigned* offset, unsigned capacity, object table, + object method) + { + MyThread* t = static_cast(vmt); + FixedAllocator allocator(t, code + *offset, capacity); + BootContext bootContext(t, table, zone); + + compile(t, &allocator, &bootContext, method); + + *offset += allocator.offset; + } + + virtual void visitRoots(BootImage* image, HeapWalker* w) { + image->callTable = w->visitRoot(callTable); + image->methodTree = w->visitRoot(methodTree); + image->methodTreeSentinal = w->visitRoot(methodTreeSentinal); + image->objectPools = w->visitRoot(objectPools); + } System* s; Allocator* allocator; - object defaultThunk; - object nativeThunk; - object aioobThunk; - object thunkTable; + uint8_t* defaultThunk; + uint8_t* nativeThunk; + uint8_t* aioobThunk; + uint8_t* thunkTable; unsigned thunkSize; object callTable; unsigned callTableSize; object methodTree; object methodTreeSentinal; + object objectPools; SegFaultHandler segFaultHandler; CodeAllocator codeAllocator; Zone codeZone; @@ -4974,34 +5095,19 @@ getThunk(MyThread* t, Thunk thunk) MyProcessor* p = processor(t); return reinterpret_cast - (&singletonValue(t, p->thunkTable, (thunk * p->thunkSize) / BytesPerWord)); + (p->thunkTable + ((thunk * p->thunkSize) / BytesPerWord)); } void -compileThunks(MyThread* t, MyProcessor* p) +compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, + BootImage* image, uint8_t* imageBase) { class ThunkContext { public: - class MyPromise: public Promise { - public: - MyPromise(): resolved_(false) { } - - virtual int64_t value() { - return value_; - } - - virtual bool resolved() { - return resolved_; - } - - int64_t value_; - bool resolved_; - }; - - ThunkContext(MyThread* t): context(t) { } + ThunkContext(MyThread* t): context(t), promise(t->m->system) { } Context context; - MyPromise promise; + OfferPromise promise; }; ThunkContext defaultContext(t); @@ -5011,9 +5117,6 @@ compileThunks(MyThread* t, MyProcessor* p) saveStackAndBase(t, a); pushThread(t, a); - defaultContext.promise.resolved_ = true; - defaultContext.promise.value_ = reinterpret_cast(compileMethod); - Assembler::Constant proc(&(defaultContext.promise)); a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); @@ -5021,6 +5124,17 @@ compileThunks(MyThread* t, MyProcessor* p) Assembler::Register result(a->returnLow()); a->apply(Jump, BytesPerWord, RegisterOperand, &result); + + if (image) { + image->defaultThunk = static_cast + (defaultContext.promise.offset) - imageBase; + + memset(defaultContext.promise.offset, 0, BytesPerWord); + } else { + memcpy(defaultContext.promise.offset, + voidPointer(compileMethod), + BytesPerWord); + } } ThunkContext nativeContext(t); @@ -5029,16 +5143,23 @@ compileThunks(MyThread* t, MyProcessor* p) saveStackAndBase(t, a); pushThread(t, a); - - nativeContext.promise.resolved_ = true; - nativeContext.promise.value_ = reinterpret_cast(invokeNative); - Assembler::Constant proc(&(nativeContext.promise)); a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); popThread(t, a); a->apply(Return); + + if (image) { + image->nativeThunk = static_cast + (nativeContext.promise.offset) - imageBase; + + memset(nativeContext.promise.offset, 0, BytesPerWord); + } else { + memcpy(nativeContext.promise.offset, + voidPointer(invokeNative), + BytesPerWord); + } } ThunkContext aioobContext(t); @@ -5048,12 +5169,19 @@ compileThunks(MyThread* t, MyProcessor* p) saveStackAndBase(t, a); pushThread(t, a); - aioobContext.promise.resolved_ = true; - aioobContext.promise.value_ = reinterpret_cast - (throwArrayIndexOutOfBounds); - Assembler::Constant proc(&(aioobContext.promise)); a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); + + if (image) { + image->aioobThunk = static_cast + (aioobContext.promise.offset) - imageBase; + + memset(aioobContext.promise.offset, 0, BytesPerWord); + } else { + memcpy(aioobContext.promise.offset, + voidPointer(throwArrayIndexOutOfBounds), + BytesPerWord); + } } ThunkContext tableContext(t); @@ -5078,22 +5206,32 @@ compileThunks(MyThread* t, MyProcessor* p) + codeSingletonSizeInBytes (t, p->thunkSize * ThunkCount))); - p->defaultThunk = finish(t, defaultContext.context.assembler, "default"); - p->nativeThunk = finish(t, nativeContext.context.assembler, "native"); - p->aioobThunk = finish(t, aioobContext.context.assembler, "aioob"); + p->defaultThunk = finish + (t, allocator, defaultContext.context.assembler, "default"); - p->thunkTable = allocateCode(t, p->thunkSize * ThunkCount); - uint8_t* start = reinterpret_cast - (&singletonValue(t, p->thunkTable, 0)); + p->nativeThunk = finish + (t, allocator, nativeContext.context.assembler, "native"); - logCompile(t, start, p->thunkSize * ThunkCount, 0, "thunkTable", 0); + p->aioobThunk = finish + (t, allocator, aioobContext.context.assembler, "aioob"); - tableContext.promise.resolved_ = true; + p->thunkTable = static_cast + (allocator->allocate(p->thunkSize * ThunkCount)); -#define THUNK(s) \ - tableContext.promise.value_ = reinterpret_cast(s); \ - tableContext.context.assembler->writeTo(start); \ - start += p->thunkSize; + logCompile(t, p->thunkTable, p->thunkSize * ThunkCount, 0, "thunkTable", 0); + + uint8_t* start = p->thunkTable; + +#define THUNK(s) \ + tableContext.context.assembler->writeTo(start); \ + start += p->thunkSize; \ + if (image) { \ + image->s##Thunk = static_cast \ + (tableContext.promise.offset) - imageBase; \ + memset(tableContext.promise.offset, 0, BytesPerWord); \ + } else { \ + memcpy(tableContext.promise.offset, voidPointer(s), BytesPerWord); \ + } #include "thunks.cpp" @@ -5114,7 +5252,7 @@ processor(MyThread* t) set(t, p->methodTree, TreeNodeLeft, p->methodTreeSentinal); set(t, p->methodTree, TreeNodeRight, p->methodTreeSentinal); - compileThunks(t, p); + compileThunks(t, codeZone(t), p, 0, 0); p->segFaultHandler.m = t->m; expect(t, t->m->system->success @@ -5124,54 +5262,58 @@ processor(MyThread* t) return p; } -object +object& +objectPools(MyThread* t) +{ + return processor(t)->objectPools; +} + +uintptr_t defaultThunk(MyThread* t) { - return processor(t)->defaultThunk; + return reinterpret_cast(processor(t)->defaultThunk); } -object +uintptr_t nativeThunk(MyThread* t) { - return processor(t)->nativeThunk; + return reinterpret_cast(processor(t)->nativeThunk); } -object +uintptr_t aioobThunk(MyThread* t) { - return processor(t)->aioobThunk; + return reinterpret_cast(processor(t)->aioobThunk); } void -compile(MyThread* t, object method) +compile(MyThread* t, Allocator* allocator, BootContext* bootContext, + object method) { MyProcessor* p = processor(t); - if (methodCompiled(t, method) == p->defaultThunk) { + if (methodCompiled(t, method) == defaultThunk(t)) { PROTECT(t, method); ACQUIRE(t, t->m->classLock); - if (methodCompiled(t, method) == p->defaultThunk) { + if (methodCompiled(t, method) == defaultThunk(t)) { initClass(t, methodClass(t, method)); if (UNLIKELY(t->exception)) return; - if (methodCompiled(t, method) == p->defaultThunk) { + if (methodCompiled(t, method) == defaultThunk(t)) { object node; - object compiled; + uint8_t* compiled; if (methodFlags(t, method) & ACC_NATIVE) { node = 0; compiled = p->nativeThunk; } else { - Context context(t, method); - compiled = compile(t, &context); + Context context(t, bootContext, method); + compiled = compile(t, allocator, &context); if (UNLIKELY(t->exception)) return; - - PROTECT(t, compiled); if (DebugMethodTree) { - fprintf(stderr, "insert method at %p\n", - &singletonValue(t, compiled, 0)); + fprintf(stderr, "insert method at %p\n", compiled); } // We can't set the MethodCompiled field on the original @@ -5197,7 +5339,7 @@ compile(MyThread* t, object method) methodSpec(t, method), methodClass(t, method), methodCode(t, method), - compiled); + reinterpret_cast(compiled)); node = makeTreeNode (t, clone, methodTreeSentinal(t), methodTreeSentinal(t)); @@ -5205,16 +5347,15 @@ compile(MyThread* t, object method) PROTECT(t, node); methodTree(t) = treeInsertNode - (t, methodTree(t), reinterpret_cast - (&singletonValue(t, compiled, 0)), node, methodTreeSentinal(t), - compareIpToMethodBounds); + (t, methodTree(t), reinterpret_cast(compiled), node, + methodTreeSentinal(t), compareIpToMethodBounds); } - set(t, method, MethodCompiled, compiled); + methodCompiled(t, method) = reinterpret_cast(compiled); if (methodVirtual(t, method)) { classVtable(t, methodClass(t, method), methodOffset(t, method)) - = &singletonValue(t, compiled, 0); + = compiled; } if (node) { diff --git a/src/finder.h b/src/finder.h index 37f6d3a9b7..f7c392c2ab 100644 --- a/src/finder.h +++ b/src/finder.h @@ -56,7 +56,7 @@ class Finder { unsigned currentSize; }; - virtual IteratorImp* iterator(); + virtual IteratorImp* iterator() = 0; virtual System::Region* find(const char* name) = 0; virtual bool exists(const char* name) = 0; virtual const char* path() = 0; diff --git a/src/heapdump.cpp b/src/heapdump.cpp index 504117bfbb..b58fcceb56 100644 --- a/src/heapdump.cpp +++ b/src/heapdump.cpp @@ -55,9 +55,9 @@ namespace vm { void dumpHeap(Thread* t, FILE* out) { - class Walker: public HeapWalker { + class Visitor: public HeapVisitor { public: - Walker(Thread* t, FILE* out): t(t), out(out), nextNumber(1) { } + Visitor(Thread* t, FILE* out): t(t), out(out), nextNumber(1) { } virtual void root() { write1(out, Root); @@ -102,9 +102,11 @@ dumpHeap(Thread* t, FILE* out) Thread* t; FILE* out; unsigned nextNumber; - } walker(t, out); + } visitor(t, out); - walk(t, &walker)->dispose(); + HeapWalker* w = makeHeapWalker(t, &visitor); + w->visitAllRoots(); + w->dispose(); } } // namespace vm diff --git a/src/heapwalk.cpp b/src/heapwalk.cpp index 4a240af4a2..aa8e981e79 100644 --- a/src/heapwalk.cpp +++ b/src/heapwalk.cpp @@ -1,3 +1,14 @@ +/* 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; @@ -69,7 +80,11 @@ class Context { thread(thread), objects(0), stack(0) { } - ~Context() { + void dispose() { + if (objects) { + objects->dispose(); + } + while (stack) { Stack* dead = stack; stack = dead->next; @@ -224,21 +239,22 @@ objectSize(Thread* t, object o) return n; } -void -walk(Context* c, HeapWalker* w, object p) +unsigned +walk(Context* c, HeapVisitor* v, object p) { Thread* t = c->thread; + object root = p; int nextChildOffset; - w->root(); + v->root(); visit: { Set::Entry* e = find(c, p); if (e) { - w->visitOld(p, e->number); + v->visitOld(p, e->number); } else { e = add(c, p); - e->number = w->visitNew(p); + e->number = v->visitNew(p); nextChildOffset = walkNext(t, p, -1); if (nextChildOffset != -1) { @@ -250,7 +266,7 @@ walk(Context* c, HeapWalker* w, object p) goto pop; children: { - w->push(nextChildOffset); + v->push(nextChildOffset); push(c, p, nextChildOffset); p = get(p, nextChildOffset); goto visit; @@ -258,7 +274,7 @@ walk(Context* c, HeapWalker* w, object p) pop: { if (pop(c, &p, &nextChildOffset)) { - w->pop(); + v->pop(); nextChildOffset = walkNext(t, p, nextChildOffset); if (nextChildOffset >= 0) { goto children; @@ -267,34 +283,59 @@ walk(Context* c, HeapWalker* w, object p) } } } + + 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(mask(*static_cast(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 { -HeapMap* -walk(Thread* t, HeapWalker* w) +HeapWalker* +makeHeapWalker(Thread* t, HeapVisitor* v) { - 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(mask(*static_cast(p)))); - } - - Context* c; - HeapWalker* w; - } v(&context, w); - - add(&context, 0)->number = w->visitNew(0); - - visitRoots(t->m, &v); - - return context.objects; + return new (t->m->heap->allocate(sizeof(MyHeapWalker))) MyHeapWalker(t, v); } } // namespace vm diff --git a/src/heapwalk.h b/src/heapwalk.h index f18cb021ea..473856bea3 100644 --- a/src/heapwalk.h +++ b/src/heapwalk.h @@ -1,14 +1,29 @@ -#include "machine.h" +/* 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 HeapWalker { +class HeapVisitor { public: virtual void root() = 0; virtual unsigned visitNew(object value) = 0; @@ -17,7 +32,17 @@ class HeapWalker { virtual void pop() = 0; }; -HeapMap* -walk(Thread* t, HeapWalker* w); +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 diff --git a/src/processor.h b/src/processor.h index a0ef3491b2..7d9dacf224 100644 --- a/src/processor.h +++ b/src/processor.h @@ -14,6 +14,9 @@ #include "common.h" #include "system.h" #include "heap.h" +#include "bootimage.h" +#include "heapwalk.h" +#include "zone.h" namespace vm { @@ -112,6 +115,17 @@ 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 table, object method) = 0; + + virtual void + visitRoots(BootImage* image, HeapWalker* w) = 0; + object invoke(Thread* t, object method, object this_, ...) { diff --git a/src/x86.cpp b/src/x86.cpp index 8da31a0d8f..cd0ca302f5 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -178,8 +178,12 @@ class ImmediateTask: public Task { { } virtual void run(Context* c) { - intptr_t v = promise->value(); - memcpy(c->result + offset, &v, BytesPerWord); + if (promise->resolved()) { + intptr_t v = promise->value(); + memcpy(c->result + offset, &v, BytesPerWord); + } else if (not promise->offer(c->result + offset)) { + abort(c); + } } Promise* promise; From f698c24ea6d0aedc81a6013c83d444be6fbe54af Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 27 Nov 2008 13:59:40 -0700 Subject: [PATCH 03/39] delay resolving method call offsets until all methods have been compiled when creating a boot image --- src/assembler.h | 21 ++++--- src/bootimage.cpp | 48 ++++++++------- src/compile.cpp | 151 ++++++++++++++++++++++------------------------ src/processor.h | 3 +- src/x86.cpp | 75 +++++++++++++++++++---- 5 files changed, 176 insertions(+), 122 deletions(-) diff --git a/src/assembler.h b/src/assembler.h index 55b839ac8e..7b689123cd 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -78,9 +78,14 @@ const int AnyRegister = -2; class Promise { public: + class Listener { + public: + virtual void* resolve(int64_t value) = 0; + }; + virtual int64_t value() = 0; virtual bool resolved() = 0; - virtual bool offer(void*) { return false; } + virtual Listener* listen(unsigned) { return 0; } }; class ResolvedPromise: public Promise { @@ -98,9 +103,11 @@ class ResolvedPromise: public Promise { int64_t value_; }; -class OfferPromise: public Promise { +class ListenPromise: public Promise { public: - OfferPromise(System* s): s(s), offset(0) { } + ListenPromise(System* s, Allocator* allocator): + s(s), allocator(allocator), listener(0) + { } virtual int64_t value() { abort(s); @@ -110,13 +117,13 @@ class OfferPromise: public Promise { return false; } - virtual bool offer(void* offset) { - this->offset = offset; - return true; + virtual Listener* listen(unsigned sizeInBytes) { + return listener = static_cast(allocator->allocate(sizeInBytes)); } System* s; - void* offset; + Allocator* allocator; + Listener* listener; }; class TraceHandler { diff --git a/src/bootimage.cpp b/src/bootimage.cpp index 846c3f3f3e..ed8baa03bd 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -43,10 +43,13 @@ makeCodeImage(Thread* t, BootImage* image, uint8_t* code, unsigned capacity) unsigned size; t->m->processor->compileThunks(t, image, code, &size, capacity); - object objectTable = makeHashMap(t, 0, 0); - PROTECT(t, objectTable); - Zone zone(t->m->system, t->m->heap, 64 * 1024); + + object constants = 0; + PROTECT(t, constants); + + object calls = 0; + PROTECT(t, calls); for (Finder::Iterator it(t->m->finder); it.hasMore();) { unsigned nameSize; @@ -61,15 +64,20 @@ makeCodeImage(Thread* t, BootImage* image, uint8_t* code, unsigned capacity) object method = arrayBody(t, classMethodTable(t, c), i); if (methodCode(t, method)) { t->m->processor->compileMethod - (t, &zone, code, &size, capacity, objectTable, method); + (t, &zone, code, &size, capacity, &constants, &calls, method); } } } } + for (; calls; calls = tripleThird(t, calls)) { + static_cast(pointerValue(t, tripleSecond(t, calls))) + ->listener->resolve(methodCompiled(t, tripleFirst(t, calls))); + } + image->codeSize = size; - return objectTable; + return constants; } unsigned @@ -167,27 +175,21 @@ makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map, } void -updateCodeTable(Thread* t, object codeTable, uint8_t* code, uintptr_t* codeMap, +updateConstants(Thread* t, object constants, 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)); + for (; constants; constants = tripleThird(t, constants)) { + intptr_t target = heapTable->find(tripleFirst(t, constants)); assert(t, target >= 0); - for (object fixup = tripleSecond(t, mapEntry); - fixup; - fixup = pairSecond(t, fixup)) - { - OfferPromise* p = static_cast - (pointerValue(t, pairFirst(t, fixup))); - assert(t, p->offset); + void* dst = static_cast + (pointerValue(t, tripleSecond(t, constants)))->listener->resolve(target); - memcpy(p->offset, &target, BytesPerWord); - markBit(codeMap, reinterpret_cast(p->offset) - - reinterpret_cast(code)); - } + assert(t, reinterpret_cast(dst) + >= reinterpret_cast(code)); + + markBit(codeMap, reinterpret_cast(dst) + - reinterpret_cast(code)); } } @@ -208,7 +210,7 @@ writeBootImage(Thread* t, FILE* out) (t->m->heap->allocate(codeMapSize(CodeCapacity))); memset(codeMap, 0, codeMapSize(CodeCapacity)); - object codeTable = makeCodeImage(t, &image, code, CodeCapacity); + object constants = makeCodeImage(t, &image, code, CodeCapacity); const unsigned HeapCapacity = 32 * 1024 * 1024; uintptr_t* heap = static_cast @@ -220,7 +222,7 @@ writeBootImage(Thread* t, FILE* out) HeapWalker* heapWalker = makeHeapImage (t, &image, heap, heapMap, HeapCapacity); - updateCodeTable(t, codeTable, code, codeMap, heapWalker->map()); + updateConstants(t, constants, code, codeMap, heapWalker->map()); heapWalker->dispose(); diff --git a/src/compile.cpp b/src/compile.cpp index e8a19e4f85..a006622957 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -131,7 +131,7 @@ compareIpToMethodBounds(Thread* t, intptr_t ip, object method) if (ip < start) { return -1; - } else if (ip < start + compiledSize(start)) + } else if (ip < start + static_cast(compiledSize(start))) { return 0; } else { @@ -458,18 +458,20 @@ class BootContext { MyProtector(Thread* t, BootContext* c): Protector(t), c(c) { } virtual void visit(Heap::Visitor* v) { - v->visit(&(c->objectTable)); + v->visit(&(c->constants)); + v->visit(&(c->calls)); } BootContext* c; }; - BootContext(Thread* t, object objectTable, Zone* zone): - protector(t, this), objectTable(objectTable), zone(zone) + BootContext(Thread* t, object constants, object calls, Zone* zone): + protector(t, this), constants(constants), calls(calls), zone(zone) { } MyProtector protector; - object objectTable; + object constants; + object calls; Zone* zone; }; @@ -638,24 +640,12 @@ class Frame { if (context->bootContext) { BootContext* bc = context->bootContext; - object node = hashMapFindNode - (t, bc->objectTable, o, objectHash, objectEqual); - PROTECT(t, node); - - Promise* p = new (bc->zone->allocate(sizeof(OfferPromise))) - OfferPromise(t->m->system); + Promise* p = new (bc->zone->allocate(sizeof(ListenPromise))) + ListenPromise(t->m->system, bc->zone); + PROTECT(t, o); object pointer = makePointer(t, p); - - if (node) { - object fixup = makePair(t, pointer, tripleSecond(t, node)); - vm::set(t, node, TripleSecond, fixup); - } else { - PROTECT(t, o); - object fixup = makePair(t, pointer, 0); - // todo: use a hash function that compares by value - hashMapInsert(t, bc->objectTable, o, fixup, objectHash); - } + bc->constants = makeTriple(t, o, pointer, bc->constants); return c->promiseConstant(p); } else { @@ -1745,26 +1735,37 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target) frame->trace(target, false), rSize, 0); - } else if (methodCompiled(t, target) == defaultThunk(t) - or (frame->context->bootContext - and methodClass(t, target) - != methodClass(t, frame->context->method))) - { - // todo: when creating a boot image, log intra-class calls for - // later fixup - result = c->call - (c->constant(defaultThunk(t)), - Compiler::Aligned, - frame->trace(target, false), - rSize, - 0); } else { - result = c->call - (c->constant(methodCompiled(t, target)), - 0, - frame->trace(0, false), - rSize, - 0); + BootContext* bc = frame->context->bootContext; + if (bc) { + Promise* p = new (bc->zone->allocate(sizeof(ListenPromise))) + ListenPromise(t->m->system, bc->zone); + + PROTECT(t, target); + object pointer = makePointer(t, p); + bc->calls = makeTriple(t, target, pointer, bc->calls); + + result = c->call + (c->promiseConstant(p), + 0, + frame->trace(0, false), + rSize, + 0); + } else if (methodCompiled(t, target) == defaultThunk(t)) { + result = c->call + (c->constant(defaultThunk(t)), + Compiler::Aligned, + frame->trace(target, false), + rSize, + 0); + } else { + result = c->call + (c->constant(methodCompiled(t, target)), + 0, + frame->trace(0, false), + rSize, + 0); + } } } @@ -5053,15 +5054,17 @@ class MyProcessor: public Processor { } virtual void compileMethod(Thread* vmt, Zone* zone, uint8_t* code, - unsigned* offset, unsigned capacity, object table, - object method) + unsigned* offset, unsigned capacity, + object* constants, object* calls, object method) { MyThread* t = static_cast(vmt); FixedAllocator allocator(t, code + *offset, capacity); - BootContext bootContext(t, table, zone); + BootContext bootContext(t, *constants, *calls, zone); compile(t, &allocator, &bootContext, method); + *constants = bootContext.constants; + *calls = bootContext.calls; *offset += allocator.offset; } @@ -5104,13 +5107,16 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, { class ThunkContext { public: - ThunkContext(MyThread* t): context(t), promise(t->m->system) { } + ThunkContext(MyThread* t, Zone* zone): + context(t), promise(t->m->system, zone) + { } Context context; - OfferPromise promise; + ListenPromise promise; }; - ThunkContext defaultContext(t); + Zone zone(t->m->system, t->m->heap, 1024); + ThunkContext defaultContext(t, &zone); { Assembler* a = defaultContext.context.assembler; @@ -5125,19 +5131,15 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, Assembler::Register result(a->returnLow()); a->apply(Jump, BytesPerWord, RegisterOperand, &result); - if (image) { - image->defaultThunk = static_cast - (defaultContext.promise.offset) - imageBase; + void* p = defaultContext.promise.listener->resolve + (reinterpret_cast(voidPointer(compileMethod))); - memset(defaultContext.promise.offset, 0, BytesPerWord); - } else { - memcpy(defaultContext.promise.offset, - voidPointer(compileMethod), - BytesPerWord); + if (image) { + image->defaultThunk = static_cast(p) - imageBase; } } - ThunkContext nativeContext(t); + ThunkContext nativeContext(t, &zone); { Assembler* a = nativeContext.context.assembler; @@ -5150,19 +5152,15 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, a->apply(Return); - if (image) { - image->nativeThunk = static_cast - (nativeContext.promise.offset) - imageBase; + void* p = nativeContext.promise.listener->resolve + (reinterpret_cast(voidPointer(invokeNative))); - memset(nativeContext.promise.offset, 0, BytesPerWord); - } else { - memcpy(nativeContext.promise.offset, - voidPointer(invokeNative), - BytesPerWord); + if (image) { + image->nativeThunk = static_cast(p) - imageBase; } } - ThunkContext aioobContext(t); + ThunkContext aioobContext(t, &zone); { Assembler* a = aioobContext.context.assembler; @@ -5172,19 +5170,15 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, Assembler::Constant proc(&(aioobContext.promise)); a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); - if (image) { - image->aioobThunk = static_cast - (aioobContext.promise.offset) - imageBase; + void* p = aioobContext.promise.listener->resolve + (reinterpret_cast(voidPointer(throwArrayIndexOutOfBounds))); - memset(aioobContext.promise.offset, 0, BytesPerWord); - } else { - memcpy(aioobContext.promise.offset, - voidPointer(throwArrayIndexOutOfBounds), - BytesPerWord); + if (image) { + image->aioobThunk = static_cast(p) - imageBase; } } - ThunkContext tableContext(t); + ThunkContext tableContext(t, &zone); { Assembler* a = tableContext.context.assembler; @@ -5225,12 +5219,11 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, #define THUNK(s) \ tableContext.context.assembler->writeTo(start); \ start += p->thunkSize; \ - if (image) { \ - image->s##Thunk = static_cast \ - (tableContext.promise.offset) - imageBase; \ - memset(tableContext.promise.offset, 0, BytesPerWord); \ - } else { \ - memcpy(tableContext.promise.offset, voidPointer(s), BytesPerWord); \ + { void* p = tableContext.promise.listener->resolve \ + (reinterpret_cast(voidPointer(s))); \ + if (image) { \ + image->s##Thunk = static_cast(p) - imageBase; \ + } \ } #include "thunks.cpp" diff --git a/src/processor.h b/src/processor.h index 7d9dacf224..621bd5460a 100644 --- a/src/processor.h +++ b/src/processor.h @@ -121,7 +121,8 @@ class Processor { virtual void compileMethod(Thread* t, Zone* zone, uint8_t* code, unsigned* offset, - unsigned capacity, object table, object method) = 0; + unsigned capacity, object* constants, object* calls, + object method) = 0; virtual void visitRoots(BootImage* image, HeapWalker* w) = 0; diff --git a/src/x86.cpp b/src/x86.cpp index cd0ca302f5..54ca6ed816 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -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(value) + - instruction - instructionSize; + + expect(s, isInt32(v)); + + int32_t v4 = v; + memcpy(instruction + instructionSize - 4, &v4, 4); +} + +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) { + resolveOffset(s, instruction, instructionSize, value); + return 0; + } + + 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(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,6 +201,25 @@ appendOffsetTask(Context* c, Promise* promise, int instructionOffset, (c->tasks, promise, instructionOffset, instructionSize); } +void +copyWord(void* dst, int64_t src) +{ + intptr_t v = src; + memcpy(dst, &v, BytesPerWord); +} + +class ImmediateListener: public Promise::Listener { + public: + ImmediateListener(void* dst): dst(dst) { } + + virtual void* resolve(int64_t value) { + copyWord(dst, value); + return 0; + } + + void* dst; +}; + class ImmediateTask: public Task { public: ImmediateTask(Task* next, Promise* promise, unsigned offset): @@ -179,10 +230,10 @@ class ImmediateTask: public Task { virtual void run(Context* c) { if (promise->resolved()) { - intptr_t v = promise->value(); - memcpy(c->result + offset, &v, BytesPerWord); - } else if (not promise->offer(c->result + offset)) { - abort(c); + copyWord(c->result + offset, promise->value()); + } else { + new (promise->listen(sizeof(ImmediateListener))) + ImmediateListener(c->result + offset); } } From a8a030140ceeb0c2b9f2209931dab0d399bed8e9 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 27 Nov 2008 21:44:04 -0700 Subject: [PATCH 04/39] various bugfixes --- src/bootimage.cpp | 50 ++++++++++++++++++++++++++-------------------- src/compile.cpp | 51 ++++++++++++++++++++++++++--------------------- src/finder.cpp | 40 ++++++++++++++++++++++++++++++++----- src/finder.h | 8 +++++--- 4 files changed, 96 insertions(+), 53 deletions(-) diff --git a/src/bootimage.cpp b/src/bootimage.cpp index ed8baa03bd..99360d6dbe 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -40,7 +40,7 @@ codeMapSize(unsigned codeSize) object makeCodeImage(Thread* t, BootImage* image, uint8_t* code, unsigned capacity) { - unsigned size; + unsigned size = 0; t->m->processor->compileThunks(t, image, code, &size, capacity); Zone zone(t->m->system, t->m->heap, 64 * 1024); @@ -56,15 +56,18 @@ makeCodeImage(Thread* t, BootImage* image, uint8_t* code, unsigned capacity) 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 - 5, name)); + (t, makeByteArray(t, "%.*s", nameSize - 6, 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)) { - t->m->processor->compileMethod - (t, &zone, code, &size, capacity, &constants, &calls, method); + + 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)) { + t->m->processor->compileMethod + (t, &zone, code, &size, capacity, &constants, &calls, method); + } } } } @@ -114,13 +117,14 @@ makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map, position(0), capacity(capacity) { } - void visit(object p, unsigned number) { + void visit(unsigned number) { if (currentObject) { - markBit(map, (currentObject - heap) + currentOffset); - currentObject[currentOffset] = number; + unsigned index = currentObject - 1 + currentOffset; + markBit(map, index); + heap[index] = number; } - currentObject = reinterpret_cast(p); + currentObject = number; } virtual void root() { @@ -137,7 +141,7 @@ makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map, unsigned number = position + 1; position += size; - visit(p, number); + visit(number); return number; } else { @@ -146,7 +150,7 @@ makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map, } virtual void visitOld(object, unsigned number) { - visit(0, number); + visit(number); } virtual void push(unsigned offset) { @@ -158,7 +162,7 @@ makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map, } Thread* t; - uintptr_t* currentObject; + unsigned currentObject; unsigned currentOffset; uintptr_t* heap; uintptr_t* map; @@ -200,7 +204,7 @@ offset(object a, uintptr_t* b) } void -writeBootImage(Thread* t, FILE* out) +writeBootImage(Thread* t, FILE*) { BootImage image; @@ -228,13 +232,15 @@ writeBootImage(Thread* t, FILE* out) image.magic = BootImage::Magic; - fwrite(&image, sizeof(BootImage), 1, out); + fprintf(stderr, "heap size %d code size %d\n", + image.heapSize, image.codeSize); +// fwrite(&image, sizeof(BootImage), 1, out); - fwrite(heapMap, pad(heapMapSize(image.heapSize)), 1, out); - fwrite(heap, pad(image.heapSize), 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); +// fwrite(codeMap, pad(codeMapSize(image.codeSize)), 1, out); +// fwrite(code, pad(image.codeSize), 1, out); } } // namespace @@ -249,7 +255,7 @@ main(int ac, const char** av) System* s = makeSystem(0); Heap* h = makeHeap(s, 128 * 1024 * 1024); - Finder* f = makeFinder(s, av[0], 0); + 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); diff --git a/src/compile.cpp b/src/compile.cpp index a006622957..3441be0dae 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -4725,6 +4725,7 @@ class MyProcessor: public Processor { callTableSize(0), methodTree(0), methodTreeSentinal(0), + objectPools(0), codeAllocator(s), codeZone(s, &codeAllocator, 64 * 1024) { } @@ -5130,13 +5131,6 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, Assembler::Register result(a->returnLow()); a->apply(Jump, BytesPerWord, RegisterOperand, &result); - - void* p = defaultContext.promise.listener->resolve - (reinterpret_cast(voidPointer(compileMethod))); - - if (image) { - image->defaultThunk = static_cast(p) - imageBase; - } } ThunkContext nativeContext(t, &zone); @@ -5151,13 +5145,6 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, popThread(t, a); a->apply(Return); - - void* p = nativeContext.promise.listener->resolve - (reinterpret_cast(voidPointer(invokeNative))); - - if (image) { - image->nativeThunk = static_cast(p) - imageBase; - } } ThunkContext aioobContext(t, &zone); @@ -5169,13 +5156,6 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, Assembler::Constant proc(&(aioobContext.promise)); a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); - - void* p = aioobContext.promise.listener->resolve - (reinterpret_cast(voidPointer(throwArrayIndexOutOfBounds))); - - if (image) { - image->aioobThunk = static_cast(p) - imageBase; - } } ThunkContext tableContext(t, &zone); @@ -5203,12 +5183,35 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, p->defaultThunk = finish (t, allocator, defaultContext.context.assembler, "default"); + { void* p = defaultContext.promise.listener->resolve + (reinterpret_cast(voidPointer(compileMethod))); + if (image) { + image->defaultThunk = static_cast(p) - imageBase; + } + } + p->nativeThunk = finish (t, allocator, nativeContext.context.assembler, "native"); + { void* p = nativeContext.promise.listener->resolve + (reinterpret_cast(voidPointer(invokeNative))); + + if (image) { + image->nativeThunk = static_cast(p) - imageBase; + } + } + p->aioobThunk = finish (t, allocator, aioobContext.context.assembler, "aioob"); + { void* p = aioobContext.promise.listener->resolve + (reinterpret_cast(voidPointer(throwArrayIndexOutOfBounds))); + + if (image) { + image->aioobThunk = static_cast(p) - imageBase; + } + } + p->thunkTable = static_cast (allocator->allocate(p->thunkSize * ThunkCount)); @@ -5291,8 +5294,10 @@ compile(MyThread* t, Allocator* allocator, BootContext* bootContext, ACQUIRE(t, t->m->classLock); if (methodCompiled(t, method) == defaultThunk(t)) { - initClass(t, methodClass(t, method)); - if (UNLIKELY(t->exception)) return; + if (bootContext == 0) { + initClass(t, methodClass(t, method)); + if (UNLIKELY(t->exception)) return; + } if (methodCompiled(t, method) == defaultThunk(t)) { object node; diff --git a/src/finder.cpp b/src/finder.cpp index 9867c01a13..d017e4ec4b 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -79,8 +79,8 @@ class DirectoryElement: public Element { public: class Iterator: public Element::Iterator { public: - Iterator(System* s, const char* name): - s(s), directory(0) + 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; @@ -88,14 +88,35 @@ class DirectoryElement: public Element { } 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] != '.') { - *size = strlen(v); - return v; + 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; } @@ -105,7 +126,11 @@ class DirectoryElement: public Element { } System* s; + const char* name; + unsigned skip; System::Directory* directory; + const char* last; + Iterator* it; }; DirectoryElement(System* s, const char* name): @@ -113,7 +138,8 @@ class DirectoryElement: public Element { { } virtual Element::Iterator* iterator() { - return new (allocate(s, sizeof(Iterator))) Iterator(s, name); + return new (allocate(s, sizeof(Iterator))) + Iterator(s, name, strlen(name) + 1); } virtual System::Region* find(const char* name) { @@ -449,6 +475,8 @@ class JarElement: public Element { { } virtual Element::Iterator* iterator() { + init(); + return new (allocate(s, sizeof(Iterator))) Iterator(s, index); } @@ -626,6 +654,8 @@ class MyIterator: public Finder::IteratorImp { if (e) { it = e->iterator(); e = e->next; + } else { + it = 0; } } } diff --git a/src/finder.h b/src/finder.h index f7c392c2ab..4cd1256baf 100644 --- a/src/finder.h +++ b/src/finder.h @@ -37,14 +37,16 @@ class Finder { } bool hasMore() { + if (current) return true; + current = it->next(¤tSize); return current != 0; } const char* next(unsigned* size) { - if (current) { - const char* v = current; + if (hasMore()) { *size = currentSize; - current = it->next(¤tSize); + const char* v = current; + current = 0; return v; } else { return 0; From 6dc181fad5f782a319a60b631272f7630e6fd180 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 27 Nov 2008 21:58:04 -0700 Subject: [PATCH 05/39] move allocation zone from makeCodeImage to writeBootImage so it stays in scope until after updateConstants is called --- src/bootimage.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bootimage.cpp b/src/bootimage.cpp index 99360d6dbe..5bb0fcead3 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -38,12 +38,11 @@ codeMapSize(unsigned codeSize) } object -makeCodeImage(Thread* t, BootImage* image, uint8_t* code, unsigned capacity) +makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, + unsigned capacity) { unsigned size = 0; t->m->processor->compileThunks(t, image, code, &size, capacity); - - Zone zone(t->m->system, t->m->heap, 64 * 1024); object constants = 0; PROTECT(t, constants); @@ -66,7 +65,7 @@ makeCodeImage(Thread* t, BootImage* image, uint8_t* code, unsigned capacity) object method = arrayBody(t, classMethodTable(t, c), i); if (methodCode(t, method)) { t->m->processor->compileMethod - (t, &zone, code, &size, capacity, &constants, &calls, method); + (t, zone, code, &size, capacity, &constants, &calls, method); } } } @@ -206,6 +205,7 @@ offset(object a, uintptr_t* b) void writeBootImage(Thread* t, FILE*) { + Zone zone(t->m->system, t->m->heap, 64 * 1024); BootImage image; const unsigned CodeCapacity = 32 * 1024 * 1024; @@ -214,7 +214,7 @@ writeBootImage(Thread* t, FILE*) (t->m->heap->allocate(codeMapSize(CodeCapacity))); memset(codeMap, 0, codeMapSize(CodeCapacity)); - object constants = makeCodeImage(t, &image, code, CodeCapacity); + object constants = makeCodeImage(t, &zone, &image, code, CodeCapacity); const unsigned HeapCapacity = 32 * 1024 * 1024; uintptr_t* heap = static_cast From 02afbd1fa1d51ed7967c4d5cd2326f8e388a40d8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 27 Nov 2008 21:58:32 -0700 Subject: [PATCH 06/39] handle unresolved constants in moveCM --- src/x86.cpp | 57 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/src/x86.cpp b/src/x86.cpp index 54ca6ed816..e0956deb3b 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -202,50 +202,68 @@ appendOffsetTask(Context* c, Promise* promise, int instructionOffset, } void -copyWord(void* dst, int64_t src) +copy(System* s, void* dst, int64_t src, unsigned size) { - intptr_t v = src; - memcpy(dst, &v, BytesPerWord); + 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(void* dst): dst(dst) { } + ImmediateListener(System* s, void* dst, unsigned size): + s(s), dst(dst), size(size) + { } virtual void* resolve(int64_t value) { - copyWord(dst, value); - return 0; + copy(s, dst, value, size); + return dst; } + System* s; void* dst; + unsigned size; }; class ImmediateTask: public Task { public: - ImmediateTask(Task* next, Promise* promise, unsigned offset): + ImmediateTask(Task* next, Promise* promise, unsigned offset, unsigned size): Task(next), promise(promise), - offset(offset) + offset(offset), + size(size) { } virtual void run(Context* c) { if (promise->resolved()) { - copyWord(c->result + offset, promise->value()); + copy(c->s, c->result + offset, promise->value(), size); } else { new (promise->listen(sizeof(ImmediateListener))) - ImmediateListener(c->result + offset); + ImmediateListener(c->s, c->result + offset, size); } } Promise* promise; unsigned offset; + unsigned size; }; void -appendImmediateTask(Context* c, Promise* promise, unsigned offset) +appendImmediateTask(Context* c, Promise* promise, unsigned offset, + unsigned size) { c->tasks = new (c->zone->allocate(sizeof(ImmediateTask))) ImmediateTask - (c->tasks, promise, offset); + (c->tasks, promise, offset, size); } void @@ -535,7 +553,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(0)); } else { Assembler::Register tmp(c->client->acquireTemporary()); @@ -704,7 +722,7 @@ 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); c->code.appendAddress(static_cast(0)); } } @@ -714,8 +732,6 @@ void moveCM(Context* c, unsigned size, Assembler::Constant* a, Assembler::Memory* b) { - int64_t v = a->value->value(); - switch (size) { case 1: encode(c, 0xc6, 0, b, false); @@ -729,10 +745,17 @@ moveCM(Context* c, unsigned size, Assembler::Constant* a, case 4: encode(c, 0xc7, 0, b, false); - c->code.append4(a->value->value()); + 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: { + int64_t v = a->value->value(); + ResolvedPromise high((v >> 32) & 0xFFFFFFFF); Assembler::Constant ah(&high); From d22a9ab270d11f28be0d1976af5d2ec9bb47e9c5 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 28 Nov 2008 11:33:11 -0700 Subject: [PATCH 07/39] visit constants in visitRoots so they are included in the final heap image --- src/bootimage.cpp | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/bootimage.cpp b/src/bootimage.cpp index 5bb0fcead3..7179328580 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -55,7 +55,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, const char* name = it.next(&nameSize); if (endsWith(".class", name, nameSize)) { - fprintf(stderr, "%.*s\n", nameSize - 6, name); + //fprintf(stderr, "%.*s\n", nameSize - 6, name); object c = resolveClass (t, makeByteArray(t, "%.*s", nameSize - 6, name)); PROTECT(t, c); @@ -96,18 +96,24 @@ objectSize(Thread* t, object o) } void -visitRoots(Machine* m, BootImage* image, HeapWalker* w) +visitRoots(Thread* t, BootImage* image, HeapWalker* w, object constants) { + Machine* m = t->m; + image->loader = w->visitRoot(m->loader); image->stringMap = w->visitRoot(m->stringMap); 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) + unsigned capacity, object constants) { class Visitor: public HeapVisitor { public: @@ -170,7 +176,7 @@ makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map, } visitor(t, heap, map, capacity / BytesPerWord); HeapWalker* w = makeHeapWalker(t, &visitor); - visitRoots(t->m, image, w); + visitRoots(t, image, w, constants); image->heapSize = visitor.position * BytesPerWord; @@ -203,7 +209,7 @@ offset(object a, uintptr_t* b) } void -writeBootImage(Thread* t, FILE*) +writeBootImage(Thread* t, FILE* out) { Zone zone(t->m->system, t->m->heap, 64 * 1024); BootImage image; @@ -224,7 +230,7 @@ writeBootImage(Thread* t, FILE*) memset(heapMap, 0, heapMapSize(HeapCapacity)); HeapWalker* heapWalker = makeHeapImage - (t, &image, heap, heapMap, HeapCapacity); + (t, &image, heap, heapMap, HeapCapacity, constants); updateConstants(t, constants, code, codeMap, heapWalker->map()); @@ -232,15 +238,15 @@ writeBootImage(Thread* t, FILE*) image.magic = BootImage::Magic; - fprintf(stderr, "heap size %d code size %d\n", - image.heapSize, image.codeSize); -// fwrite(&image, sizeof(BootImage), 1, out); +// fprintf(stderr, "heap size %d code size %d\n", +// image.heapSize, image.codeSize); + fwrite(&image, sizeof(BootImage), 1, out); -// fwrite(heapMap, pad(heapMapSize(image.heapSize)), 1, out); -// fwrite(heap, pad(image.heapSize), 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); + fwrite(codeMap, pad(codeMapSize(image.codeSize)), 1, out); + fwrite(code, pad(image.codeSize), 1, out); } } // namespace From 4d1af63ed25e1bed15ccc3762a87ee5de1cdc7b6 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 28 Nov 2008 15:02:45 -0700 Subject: [PATCH 08/39] initial work on booting from boot image --- src/bootimage.cpp | 29 ++---- src/bootimage.h | 27 +++++- src/compile.cpp | 119 +++++++++++++++++++---- src/heap.cpp | 6 +- src/machine.cpp | 236 ++++++++++++++++++++++++++++++++-------------- src/processor.h | 3 + 6 files changed, 303 insertions(+), 117 deletions(-) diff --git a/src/bootimage.cpp b/src/bootimage.cpp index 7179328580..e57cfd0f3f 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -31,12 +31,6 @@ endsWith(const char* suffix, const char* s, unsigned length) and memcmp(suffix, s + (length - suffixLength), suffixLength) == 0; } -unsigned -codeMapSize(unsigned codeSize) -{ - return ceiling(codeSize, BitsPerWord) * BytesPerWord; -} - object makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, unsigned capacity) @@ -82,12 +76,6 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, return constants; } -unsigned -heapMapSize(unsigned heapSize) -{ - return ceiling(heapSize, BitsPerWord * 8) * BytesPerWord; -} - unsigned objectSize(Thread* t, object o) { @@ -238,15 +226,18 @@ writeBootImage(Thread* t, FILE* out) image.magic = BootImage::Magic; -// fprintf(stderr, "heap size %d code size %d\n", -// image.heapSize, image.codeSize); - fwrite(&image, sizeof(BootImage), 1, out); + if (true) { + fprintf(stderr, "heap size %d code size %d\n", + image.heapSize, image.codeSize); + } else { + fwrite(&image, sizeof(BootImage), 1, out); - fwrite(heapMap, pad(heapMapSize(image.heapSize)), 1, out); - fwrite(heap, pad(image.heapSize), 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); + fwrite(codeMap, pad(codeMapSize(image.codeSize)), 1, out); + fwrite(code, pad(image.codeSize), 1, out); + } } } // namespace diff --git a/src/bootimage.h b/src/bootimage.h index 2e09e44d89..cfd73171d1 100644 --- a/src/bootimage.h +++ b/src/bootimage.h @@ -28,21 +28,40 @@ class BootImage { unsigned stringMap; unsigned types; - uintptr_t codeBase; unsigned callTable; unsigned methodTree; unsigned methodTreeSentinal; - unsigned objectPools; + + uintptr_t codeBase; unsigned defaultThunk; unsigned nativeThunk; unsigned aioobThunk; - -#define THUNK(s) unsigned s##Thunk; + + 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 * 8) * BytesPerWord; +} + } // namespace vm #endif//BOOTIMAGE_H diff --git a/src/compile.cpp b/src/compile.cpp index 3441be0dae..4c68c5bf95 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -1738,19 +1738,28 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target) } else { BootContext* bc = frame->context->bootContext; if (bc) { - Promise* p = new (bc->zone->allocate(sizeof(ListenPromise))) - ListenPromise(t->m->system, bc->zone); + if (objectClass(t, target) == objectClass(t, frame->context->method)) { + Promise* p = new (bc->zone->allocate(sizeof(ListenPromise))) + ListenPromise(t->m->system, bc->zone); - PROTECT(t, target); - object pointer = makePointer(t, p); - bc->calls = makeTriple(t, target, pointer, bc->calls); + PROTECT(t, target); + object pointer = makePointer(t, p); + bc->calls = makeTriple(t, target, pointer, bc->calls); - result = c->call - (c->promiseConstant(p), - 0, - frame->trace(0, false), - rSize, - 0); + result = c->call + (c->promiseConstant(p), + 0, + frame->trace(0, false), + rSize, + 0); + } else { + result = c->call + (c->constant(defaultThunk(t)), + Compiler::Aligned, + frame->trace(target, false), + rSize, + 0); + } } else if (methodCompiled(t, target) == defaultThunk(t)) { result = c->call (c->constant(defaultThunk(t)), @@ -4654,6 +4663,31 @@ class SegFaultHandler: public System::SignalHandler { Machine* m; }; +object +fixupCallTable(MyThread* t, object oldTable, uintptr_t oldBase, + uintptr_t newBase) +{ + PROTECT(t, oldTable); + + object newTable = makeArray(t, arrayLength(t, oldTable), true); + + for (unsigned i = 0; i < arrayLength(t, oldTable); ++i) { + object next; + for (object p = arrayBody(t, oldTable, i); p; p = next) { + next = callNodeNext(t, p); + + intptr_t k = (callNodeAddress(t, p) - oldBase) + newBase; + + unsigned index = k & (arrayLength(t, newTable) - 1); + + set(t, p, CallNodeNext, arrayBody(t, newTable, index)); + set(t, newTable, ArrayBody + (index * BytesPerWord), p); + } + } + + return newTable; +} + class FixedAllocator: public Allocator { public: FixedAllocator(Thread* t, uint8_t* base, unsigned capacity): @@ -5073,7 +5107,43 @@ class MyProcessor: public Processor { image->callTable = w->visitRoot(callTable); image->methodTree = w->visitRoot(methodTree); image->methodTreeSentinal = w->visitRoot(methodTreeSentinal); - image->objectPools = w->visitRoot(objectPools); + } + + virtual void boot(Thread* t, BootImage* image, uintptr_t* heap, + uint8_t* code) + { + methodTree = reinterpret_cast(heap + image->methodTree); + methodTreeSentinal = reinterpret_cast + (heap + image->methodTreeSentinal); + + callTable = fixupCallTable + (static_cast(t), + reinterpret_cast(heap + image->callTable), + image->codeBase, + reinterpret_cast(code)); + + defaultThunk = code + image->defaultThunk; + { void* p = voidPointer(::compileMethod); + memcpy(code + image->compileMethodCall, &p, BytesPerWord); } + + nativeThunk = code + image->nativeThunk; + { void* p = voidPointer(invokeNative); + memcpy(code + image->invokeNativeCall, &p, BytesPerWord); } + + aioobThunk = code + image->aioobThunk; + { void* p = voidPointer(throwArrayIndexOutOfBounds); + memcpy(code + image->throwArrayIndexOutOfBoundsCall, &p, BytesPerWord); } + + thunkTable = code + image->thunkTable; + thunkSize = image->thunkSize; + +#define THUNK(s) \ + { void* p = voidPointer(s); \ + memcpy(code + image->s##Call, &p, BytesPerWord); } + +#include "thunks.cpp" + +#undef THUNK } System* s; @@ -5183,38 +5253,47 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, p->defaultThunk = finish (t, allocator, defaultContext.context.assembler, "default"); - { void* p = defaultContext.promise.listener->resolve + { void* call = defaultContext.promise.listener->resolve (reinterpret_cast(voidPointer(compileMethod))); if (image) { - image->defaultThunk = static_cast(p) - imageBase; + image->defaultThunk = p->defaultThunk - imageBase; + image->compileMethodCall = static_cast(call) - imageBase; } } p->nativeThunk = finish (t, allocator, nativeContext.context.assembler, "native"); - { void* p = nativeContext.promise.listener->resolve + { void* call = nativeContext.promise.listener->resolve (reinterpret_cast(voidPointer(invokeNative))); if (image) { - image->nativeThunk = static_cast(p) - imageBase; + image->nativeThunk = p->nativeThunk - imageBase; + image->invokeNativeCall = static_cast(call) - imageBase; } } p->aioobThunk = finish (t, allocator, aioobContext.context.assembler, "aioob"); - { void* p = aioobContext.promise.listener->resolve + { void* call = aioobContext.promise.listener->resolve (reinterpret_cast(voidPointer(throwArrayIndexOutOfBounds))); if (image) { - image->aioobThunk = static_cast(p) - imageBase; + image->aioobThunk = p->aioobThunk - imageBase; + image->throwArrayIndexOutOfBoundsCall + = static_cast(call) - imageBase; } } p->thunkTable = static_cast (allocator->allocate(p->thunkSize * ThunkCount)); + if (image) { + image->thunkTable = p->thunkTable - imageBase; + image->thunkSize = p->thunkSize; + } + logCompile(t, p->thunkTable, p->thunkSize * ThunkCount, 0, "thunkTable", 0); uint8_t* start = p->thunkTable; @@ -5222,10 +5301,10 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, #define THUNK(s) \ tableContext.context.assembler->writeTo(start); \ start += p->thunkSize; \ - { void* p = tableContext.promise.listener->resolve \ + { void* call = tableContext.promise.listener->resolve \ (reinterpret_cast(voidPointer(s))); \ if (image) { \ - image->s##Thunk = static_cast(p) - imageBase; \ + image->s##Call = static_cast(call) - imageBase; \ } \ } diff --git a/src/heap.cpp b/src/heap.cpp index a70f176b3e..93fb925b2d 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -121,12 +121,12 @@ 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(1) << bit)) { + if (w & (static_cast(1) << bit)) { index = ::indexOf(word, bit); // printf("hit at index %d\n", index); return true; diff --git a/src/machine.cpp b/src/machine.cpp index dd9b4cdd4f..78a0063995 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1502,6 +1502,156 @@ bootJavaClass(Thread* t, Machine::Type type, int superType, const char* name, hashMapInsert(t, t->m->bootstrapClassMap, n, class_, byteArrayHash); } +void +boot(Thread* t, BootImage* image) +{ + assert(t, image->magic == BootImage::Magic); + + uintptr_t* heapMap = reinterpret_cast(image + 1); + unsigned heapMapSizeInWords = ceiling + (heapMapSize(image->heapSize), BytesPerWord); + uintptr_t* heap = heapMap + heapMapSizeInWords; + + for (unsigned word = 0; word < heapMapSizeInWords; ++word) { + uintptr_t w = heapMap[word]; + if (w) { + for (unsigned bit = 0; bit < BitsPerWord; ++bit) { + if (w & (static_cast(1) << bit)) { + unsigned index = ::indexOf(word, bit); + uintptr_t* p = heap + index; + if (*p) { + *p = reinterpret_cast(heap + *p - 1); + } + } + } + } + } + + t->m->loader = reinterpret_cast(heap + image->loader); + t->m->stringMap = reinterpret_cast(heap + image->stringMap); + t->m->types = reinterpret_cast(heap + image->types); + + uintptr_t* codeMap = heap + ceiling(image->heapSize, BytesPerWord); + unsigned codeMapSizeInWords = ceiling + (codeMapSize(image->codeSize), BytesPerWord); + uint8_t* code = reinterpret_cast(codeMap + codeMapSizeInWords); + + for (unsigned word = 0; word < codeMapSizeInWords; ++word) { + uintptr_t w = codeMap[word]; + if (w) { + for (unsigned bit = 0; bit < BitsPerWord; ++bit) { + if (w & (static_cast(1) << bit)) { + unsigned index = ::indexOf(word, bit); + uintptr_t v; memcpy(&v, code + index, BytesPerWord); + if (v) { + v = reinterpret_cast(heap + v - 1); + memcpy(code + index, &v, BytesPerWord); + } + } + } + } + } + + t->m->processor->boot(t, image, heap, code); + + for (HashMapIterator it(t, systemClassLoaderMap(t, t->m->loader)); + it.hasMore();) + { + object c = tripleSecond(t, it.next()); + + if (classMethodTable(t, c)) { + for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { + object method = arrayBody(t, classMethodTable(t, c), i); + methodCompiled(t, method) + = (methodCompiled(t, method) - image->codeBase) + + reinterpret_cast(code); + } + } + + t->m->processor->initVtable(t, c); + } +} + +void +boot(Thread* t) +{ + Machine* m = t->m; + + 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); + + { object loaderMap = makeHashMap(t, 0, 0); + set(t, m->loader, SystemClassLoaderMap, loaderMap); + } + + m->stringMap = makeWeakHashMap(t, 0, 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) { } @@ -1716,86 +1866,30 @@ 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); + unsigned size; + image = function(&size); + } + } - 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); - - 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) { + 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; diff --git a/src/processor.h b/src/processor.h index 621bd5460a..ee5d728de3 100644 --- a/src/processor.h +++ b/src/processor.h @@ -127,6 +127,9 @@ class Processor { virtual void visitRoots(BootImage* image, HeapWalker* w) = 0; + virtual void + boot(Thread* t, BootImage* image, uintptr_t* heap, uint8_t* code) = 0; + object invoke(Thread* t, object method, object this_, ...) { From 80815d35f7f21e1b849a6a15e7a579a65015e374 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 28 Nov 2008 18:22:09 -0700 Subject: [PATCH 09/39] fix fixed object tracking in heap.cpp --- src/heap.cpp | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/heap.cpp b/src/heap.cpp index 93fb925b2d..b3f7eea200 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -440,17 +440,23 @@ class Fixie { } } - void remove() { - if (handle) *handle = next; - if (next) next->handle = handle; + void remove(Context* c) { + if (handle) { + assert(c, *handle == this); + *handle = next; + } + if (next) { + next->handle = handle; + } + handle = 0; } - void move(Fixie** handle) { + void move(Context* c, Fixie** handle) { if (DebugFixies) { fprintf(stderr, "move fixie %p\n", this); } - remove(); + remove(c); add(handle); } @@ -802,9 +808,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 +831,14 @@ sweepFixies(Context* c) } if (f->dirty) { - f->move(&(c->dirtyTenuredFixies)); + f->add(&(c->dirtyTenuredFixies)); } else { - f->move(&(c->tenuredFixies)); + f->add(&(c->tenuredFixies)); } } else { c->untenuredFixieFootprint += f->totalSize(); - f->move(&(c->fixies)); + f->add(&(c->fixies)); } f->marked = false; @@ -926,7 +932,7 @@ 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; @@ -966,7 +972,7 @@ markDirty(Context* c, Fixie* f) { if (not f->dirty) { f->dirty = true; - f->move(&(c->dirtyTenuredFixies)); + f->move(c, &(c->dirtyTenuredFixies)); } } @@ -975,7 +981,7 @@ markClean(Context* c, Fixie* f) { if (f->dirty) { f->dirty = false; - f->move(&(c->tenuredFixies)); + f->move(c, &(c->tenuredFixies)); } } @@ -1007,7 +1013,7 @@ updateHeapMap(Context* c, void* p, void* target, unsigned offset, void* result) f, offset, f->body() + offset); } - markDirty(c, f); + f->dirty = true; markBit(f->mask(), offset); } } else if (seg->contains(p)) { @@ -1399,7 +1405,6 @@ visitDirtyFixies(Context* c, Fixie** p) assert(c, wasDirty); if (clean) { - *p = f->next; markClean(c, f); } else { p = &(f->next); @@ -1410,9 +1415,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 +1440,7 @@ visitMarkedFixies(Context* c) c->client->walk(f->body(), &w); - f->move(&(c->visitedFixies)); + f->add(&(c->visitedFixies)); } } From b8056d905c5f60a433b21953ec5017754eb24fb2 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 28 Nov 2008 18:23:01 -0700 Subject: [PATCH 10/39] fix bugs in allocating and populating method object pools --- src/compile.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 4c68c5bf95..3bfb70e480 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -131,7 +131,8 @@ compareIpToMethodBounds(Thread* t, intptr_t ip, object method) if (ip < start) { return -1; - } else if (ip < start + static_cast(compiledSize(start))) + } else if (ip < start + static_cast + (compiledSize(start) + BytesPerWord)) { return 0; } else { @@ -536,6 +537,7 @@ class Context { method(method), bootContext(bootContext), objectPool(0), + objectPoolCount(0), traceLog(0), traceLogCount(0), visitTable(makeVisitTable(t, &zone, method)), @@ -553,6 +555,7 @@ class Context { method(0), bootContext(0), objectPool(0), + objectPoolCount(0), traceLog(0), traceLogCount(0), visitTable(0), @@ -574,6 +577,7 @@ class Context { object method; BootContext* bootContext; PoolElement* objectPool; + unsigned objectPoolCount; TraceElement* traceLog; unsigned traceLogCount; uint16_t* visitTable; @@ -653,6 +657,8 @@ class Frame { (context->zone.allocate(sizeof(PoolElement))) PoolElement(t, o, context->objectPool); + ++ context->objectPoolCount; + return c->address(context->objectPool); } } @@ -3811,16 +3817,18 @@ finish(MyThread* t, Allocator* allocator, Context* context) unsigned codeSize = c->compile(); uintptr_t* code = static_cast - (allocator->allocate(pad(codeSize) + BytesPerWord)); + (allocator->allocate(pad(codeSize) + pad(c->poolSize()) + BytesPerWord)); code[0] = codeSize; uint8_t* start = reinterpret_cast(code + 1); if (context->objectPool) { object pool = allocate3 (t, allocator, Machine::ImmortalAllocation, - FixedSizeOfArray + c->poolSize() + BytesPerWord, true); + FixedSizeOfArray + ((context->objectPoolCount + 1) * BytesPerWord), + true); - initArray(t, pool, (c->poolSize() / BytesPerWord) + 1, false); + initArray(t, pool, context->objectPoolCount + 1, false); + mark(t, pool, 0); set(t, pool, ArrayBody, objectPools(t)); objectPools(t) = pool; @@ -5169,7 +5177,7 @@ getThunk(MyThread* t, Thunk thunk) MyProcessor* p = processor(t); return reinterpret_cast - (p->thunkTable + ((thunk * p->thunkSize) / BytesPerWord)); + (p->thunkTable + (thunk * p->thunkSize)); } void From 702525fd32db709ffcea42c78356c0b4ec577384 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 28 Nov 2008 19:31:06 -0700 Subject: [PATCH 11/39] support immortal heap area in heap.cpp --- src/heap.cpp | 20 +++++++++++++++++--- src/heap.h | 6 ++++-- src/machine.cpp | 4 +++- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/heap.cpp b/src/heap.cpp index b3f7eea200..4b7703aacc 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -509,6 +509,9 @@ class Context { lowMemoryThreshold(limit / 2), lock(0), + immortalHeapStart(0), + immortalHeapEnd(0), + ageMap(&gen1, max(1, log(TenureThreshold)), 1, 0, false), gen1(this, &ageMap, 0, 0), @@ -577,6 +580,9 @@ class Context { unsigned lowMemoryThreshold; System::Mutex* lock; + + void* immortalHeapStart; + void* immortalHeapEnd; Segment::Map ageMap; Segment gen1; @@ -948,7 +954,9 @@ update3(Context* c, void* o, bool* needsVisit) void* update2(Context* c, void* o, bool* needsVisit) { - if (c->mode == Heap::MinorCollection and c->gen2.contains(o)) { + if ((o < c->immortalHeapEnd and o > c->immortalHeapStart) + or (c->mode == Heap::MinorCollection and c->gen2.contains(o))) + { *needsVisit = false; return o; } @@ -1669,6 +1677,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); } @@ -1698,8 +1711,9 @@ class MyHeap: public Heap { Fixie(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)) diff --git a/src/heap.h b/src/heap.h index bc8f9a5a1c..28f1533d8f 100644 --- a/src/heap.h +++ b/src/heap.h @@ -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; diff --git a/src/machine.cpp b/src/machine.cpp index 78a0063995..4d0df1861f 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1512,6 +1512,8 @@ boot(Thread* t, BootImage* image) (heapMapSize(image->heapSize), BytesPerWord); uintptr_t* heap = heapMap + heapMapSizeInWords; + t->m->heap->setImmortalHeap(heap, image->heapSize); + for (unsigned word = 0; word < heapMapSizeInWords; ++word) { uintptr_t w = heapMap[word]; if (w) { @@ -2170,7 +2172,7 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, case Machine::ImmortalAllocation: { unsigned total; object o = static_cast - (t->m->heap->allocateImmortal + (t->m->heap->allocateImmortalFixed (allocator, ceiling(sizeInBytes, BytesPerWord), objectMask, &total)); cast(o, 0) = FixedMark; From 0ef2ee1d02c598530ec0b07878005d47a231ef11 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 29 Nov 2008 13:37:03 -0700 Subject: [PATCH 12/39] refactor Segment::Map to support map data which is not allocated as part of the segment data --- src/heap.cpp | 193 +++++++++++++++++++++++++++++++----------------- src/heap.h | 3 +- src/machine.cpp | 5 +- 3 files changed, 131 insertions(+), 70 deletions(-) diff --git a/src/heap.cpp b/src/heap.cpp index 4b7703aacc..46c4f7526c 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -121,17 +121,17 @@ class Segment { for (; word <= wordLimit and (word < wordLimit or bit < bitLimit); ++word) { - uintptr_t w = map->data()[word]; + uintptr_t w = map->data[word]; if (2) { for (; bit < BitsPerWord and (word < wordLimit or bit < bitLimit); ++bit) { if (w & (static_cast(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, 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() { @@ -508,9 +527,13 @@ class Context { limit(limit), lowMemoryThreshold(limit / 2), lock(0), - - immortalHeapStart(0), - immortalHeapEnd(0), + + immortalPointerMap(&immortalHeap, 1, 1, 0, true), + immortalPageMap(&immortalHeap, 1, LikelyPageSizeInBytes / BytesPerWord, + &immortalPointerMap, true), + immortalHeapMap(&immortalHeap, 1, immortalPageMap.scale * 1024, + &immortalPageMap, true), + immortalHeap(this, &immortalHeapMap, 0, 0), ageMap(&gen1, max(1, log(TenureThreshold)), 1, 0, false), gen1(this, &ageMap, 0, 0), @@ -563,6 +586,15 @@ class Context { nextGen1.dispose(); gen2.dispose(); nextGen2.dispose(); + + if (immortalHeapMap.data) { + free(this, immortalHeapMap.data, immortalHeapMap.size() * BytesPerWord); + } + + if (immortalPageMap.data) { + free(this, immortalPageMap.data, immortalPageMap.size() * BytesPerWord); + } + lock->dispose(); } @@ -581,9 +613,11 @@ class Context { System::Mutex* lock; - void* immortalHeapStart; - void* immortalHeapEnd; - + Segment::Map immortalPointerMap; + Segment::Map immortalPageMap; + Segment::Map immortalHeapMap; + Segment immortalHeap; + Segment::Map ageMap; Segment gen1; @@ -702,7 +736,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; @@ -954,7 +988,7 @@ update3(Context* c, void* o, bool* needsVisit) void* update2(Context* c, void* o, bool* needsVisit) { - if ((o < c->immortalHeapEnd and o > c->immortalHeapStart) + if (c->immortalHeap.contains(o) or (c->mode == Heap::MinorCollection and c->gen2.contains(o))) { *needsVisit = false; @@ -1677,9 +1711,34 @@ class MyHeap: public Heap { c.client = client; } - virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords) { - c.immortalHeapStart = start; - c.immortalHeapEnd = start + sizeInWords; + virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords, + uintptr_t* map) + { + new (&(c.immortalPointerMap)) Segment::Map + (&(c.immortalHeap), map, 1, 1, 0, false); + + unsigned pageMapScale = LikelyPageSizeInBytes / BytesPerWord; + unsigned pageMapSize = Segment::Map::calculateSize + (&c, sizeInWords, pageMapScale, 1); + uintptr_t* pageMap = static_cast + (allocate(pageMapSize * BytesPerWord)); + + new (&(c.immortalPageMap)) Segment::Map + (&(c.immortalHeap), pageMap, 1, pageMapScale, &(c.immortalPointerMap), + true); + + unsigned heapMapScale = pageMapScale * 1024; + unsigned heapMapSize = Segment::Map::calculateSize + (&c, sizeInWords, heapMapScale, 1); + uintptr_t* heapMap = static_cast + (allocate(heapMapSize * BytesPerWord)); + + new (&(c.immortalHeapMap)) Segment::Map + (&(c.immortalHeap), heapMap, 1, heapMapScale, &(c.immortalPageMap), + true); + + new (&(c.immortalHeap)) Segment + (&c, &(c.immortalHeapMap), start, sizeInWords, sizeInWords); } virtual void* tryAllocate(unsigned size) { diff --git a/src/heap.h b/src/heap.h index 28f1533d8f..4e213654c1 100644 --- a/src/heap.h +++ b/src/heap.h @@ -52,7 +52,8 @@ class Heap: public Allocator { }; virtual void setClient(Client* client) = 0; - virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords) = 0; + virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords, + uintptr_t* map) = 0; virtual void collect(CollectionType type, unsigned footprint) = 0; virtual void* allocateFixed(Allocator* allocator, unsigned sizeInWords, bool objectMask, unsigned* totalInBytes) = 0; diff --git a/src/machine.cpp b/src/machine.cpp index 4d0df1861f..e64e892ebc 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1512,8 +1512,6 @@ boot(Thread* t, BootImage* image) (heapMapSize(image->heapSize), BytesPerWord); uintptr_t* heap = heapMap + heapMapSizeInWords; - t->m->heap->setImmortalHeap(heap, image->heapSize); - for (unsigned word = 0; word < heapMapSizeInWords; ++word) { uintptr_t w = heapMap[word]; if (w) { @@ -1526,9 +1524,12 @@ boot(Thread* t, BootImage* image) } } } + heapMap[word] = 0; } } + t->m->heap->setImmortalHeap(heap, image->heapSize, heapMap); + t->m->loader = reinterpret_cast(heap + image->loader); t->m->stringMap = reinterpret_cast(heap + image->stringMap); t->m->types = reinterpret_cast(heap + image->types); From 0ec5ad3701683ccc433722503de6c6f361ea1392 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 29 Nov 2008 16:08:14 -0700 Subject: [PATCH 13/39] update makefile to optionally build and use a boot image; various bugfixes --- makefile | 55 ++++++++++++++++++++++++--------- src/assembler.h | 3 +- src/boot.cpp | 30 ++++++++++++++++++ src/bootimage.cpp | 29 ++++++++---------- src/bootimage.h | 12 +++++++- src/compile.cpp | 78 ++++++++++++++++++++++++++++------------------- src/heapwalk.cpp | 2 +- src/heapwalk.h | 3 +- src/machine.cpp | 25 ++++++++------- src/main.cpp | 9 ++++++ src/x86.cpp | 17 +++++++---- 11 files changed, 178 insertions(+), 85 deletions(-) diff --git a/makefile b/makefile index 946c31e62f..dca8d638a6 100644 --- a/makefile +++ b/makefile @@ -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 @@ -187,7 +186,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 \ @@ -227,10 +228,21 @@ ifeq ($(heapdump),true) cflags += -DAVIAN_HEAPDUMP endif -bootimage-sources = $(src)/bootimage.cpp -bootimage-objects = \ - $(call cpp-objects,$(bootimage-sources),$(src),$(native-build)) -bootimage = $(native-build)/bootimage +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 @@ -269,7 +281,7 @@ args = $(flags) $(input) .PHONY: build build: $(static-library) $(executable) $(dynamic-library) \ - $(executable-dynamic) $(classpath-dep) $(test-dep) $(bootimage) + $(executable-dynamic) $(classpath-dep) $(test-dep) $(test-classes): $(classpath-dep) @@ -356,7 +368,7 @@ $(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) +$(bootimage-generator-objects): $(native-build)/%.o: $(src)/%.cpp $(vm-depends) $(compile-object) $(heapwalk-objects): $(native-build)/%.o: $(src)/%.cpp $(vm-depends) @@ -409,9 +421,24 @@ $(static-library): $(vm-objects) $(jni-objects) $(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) -I binary bootimage.bin \ + -O $(object-format) -B $(object-arch) "$${wd}/$(@)") +endif + $(executable): \ - $(vm-objects) $(classpath-object) $(jni-objects) $(driver-object) \ - $(vm-heapwalk-objects) $(boot-object) + $(vm-objects) $(jni-objects) $(driver-object) $(vm-heapwalk-objects) \ + $(boot-object) $(vm-classpath-object) @echo "linking $(@)" ifeq ($(platform),windows) $(dlltool) -z $(@).def $(^) @@ -422,9 +449,9 @@ else endif $(strip) $(strip-all) $(@) -$(bootimage): \ +$(bootimage-generator): \ $(vm-objects) $(classpath-object) $(jni-objects) $(heapwalk-objects) \ - $(bootimage-objects) + $(bootimage-generator-objects) @echo "linking $(@)" ifeq ($(platform),windows) $(dlltool) -z $(@).def $(^) @@ -436,8 +463,8 @@ endif $(strip) $(strip-all) $(@) $(dynamic-library): \ - $(vm-objects) $(classpath-object) $(dynamic-object) $(jni-objects) \ - $(vm-heapwalk-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) $(@) diff --git a/src/assembler.h b/src/assembler.h index 7b689123cd..126a3c21dc 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -211,7 +211,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; }; diff --git a/src/boot.cpp b/src/boot.cpp index 9f4c96a612..9fca36f7f5 100644 --- a/src/boot.cpp +++ b/src/boot.cpp @@ -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 diff --git a/src/bootimage.cpp b/src/bootimage.cpp index e57cfd0f3f..85737f0922 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -106,22 +106,18 @@ makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map, class Visitor: public HeapVisitor { public: Visitor(Thread* t, uintptr_t* heap, uintptr_t* map, unsigned capacity): - t(t), currentObject(0), currentOffset(0), heap(heap), map(map), - position(0), capacity(capacity) + t(t), current(0), heap(heap), map(map), position(0), capacity(capacity) { } void visit(unsigned number) { - if (currentObject) { - unsigned index = currentObject - 1 + currentOffset; - markBit(map, index); - heap[index] = number; + if (current) { + if (number) markBit(map, current - 1); + heap[current - 1] = number; } - - currentObject = number; } virtual void root() { - currentObject = 0; + current = 0; } virtual unsigned visitNew(object p) { @@ -146,17 +142,16 @@ makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map, visit(number); } - virtual void push(unsigned offset) { - currentOffset = offset; + virtual void push(object, unsigned number, unsigned offset) { + current = number + offset; } virtual void pop() { - currentObject = 0; + current = 0; } Thread* t; - unsigned currentObject; - unsigned currentOffset; + unsigned current; uintptr_t* heap; uintptr_t* map; unsigned position; @@ -176,8 +171,8 @@ updateConstants(Thread* t, object constants, uint8_t* code, uintptr_t* codeMap, HeapMap* heapTable) { for (; constants; constants = tripleThird(t, constants)) { - intptr_t target = heapTable->find(tripleFirst(t, constants)); - assert(t, target >= 0); + unsigned target = heapTable->find(tripleFirst(t, constants)); + assert(t, target > 0); void* dst = static_cast (pointerValue(t, tripleSecond(t, constants)))->listener->resolve(target); @@ -226,7 +221,7 @@ writeBootImage(Thread* t, FILE* out) image.magic = BootImage::Magic; - if (true) { + if (false) { fprintf(stderr, "heap size %d code size %d\n", image.heapSize, image.codeSize); } else { diff --git a/src/bootimage.h b/src/bootimage.h index cfd73171d1..a868d02d74 100644 --- a/src/bootimage.h +++ b/src/bootimage.h @@ -59,7 +59,17 @@ codeMapSize(unsigned codeSize) inline unsigned heapMapSize(unsigned heapSize) { - return ceiling(heapSize, BitsPerWord * 8) * BytesPerWord; + return ceiling(heapSize, BitsPerWord * BytesPerWord) * BytesPerWord; +} + +inline object +bootObject(uintptr_t* heap, unsigned offset) +{ + if (offset) { + return reinterpret_cast(heap + offset - 1); + } else { + return 0; + } } } // namespace vm diff --git a/src/compile.cpp b/src/compile.cpp index 3bfb70e480..9088f5c25c 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -4050,6 +4050,14 @@ compile(MyThread* t, Allocator* allocator, Context* context) return finish(t, allocator, context); } +void +updateCall(MyThread* t, UnaryOperation op, bool assertAlignment, + void* returnAddress, void* target) +{ + Context context(t); + context.assembler->updateCall(op, assertAlignment, returnAddress, target); +} + void compile(MyThread* t, Allocator* allocator, BootContext* bootContext, object method); @@ -4081,9 +4089,9 @@ compileMethod2(MyThread* t) (t, resolveThisPointer(t, t->stack, target)), methodOffset(t, target)) = address; } else { - Context context(t); - context.assembler->updateCall - (reinterpret_cast(callNodeAddress(t, node)), address); + updateCall + (t, LongCall, true, reinterpret_cast(callNodeAddress(t, node)), + address); } return address; } @@ -5117,37 +5125,38 @@ class MyProcessor: public Processor { image->methodTreeSentinal = w->visitRoot(methodTreeSentinal); } - virtual void boot(Thread* t, BootImage* image, uintptr_t* heap, + virtual void boot(Thread* vmt, BootImage* image, uintptr_t* heap, uint8_t* code) { - methodTree = reinterpret_cast(heap + image->methodTree); - methodTreeSentinal = reinterpret_cast - (heap + image->methodTreeSentinal); + MyThread* t = static_cast(vmt); + methodTree = bootObject(heap, image->methodTree); + methodTreeSentinal = bootObject(heap, image->methodTreeSentinal); callTable = fixupCallTable - (static_cast(t), - reinterpret_cast(heap + image->callTable), - image->codeBase, + (t, bootObject(heap, image->callTable), image->codeBase, reinterpret_cast(code)); defaultThunk = code + image->defaultThunk; - { void* p = voidPointer(::compileMethod); - memcpy(code + image->compileMethodCall, &p, BytesPerWord); } + + updateCall(t, LongCall, false, code + image->compileMethodCall, + voidPointer(::compileMethod)); nativeThunk = code + image->nativeThunk; - { void* p = voidPointer(invokeNative); - memcpy(code + image->invokeNativeCall, &p, BytesPerWord); } + + updateCall(t, LongCall, false, code + image->invokeNativeCall, + voidPointer(invokeNative)); aioobThunk = code + image->aioobThunk; - { void* p = voidPointer(throwArrayIndexOutOfBounds); - memcpy(code + image->throwArrayIndexOutOfBoundsCall, &p, BytesPerWord); } + + updateCall(t, LongCall, false, + code + image->throwArrayIndexOutOfBoundsCall, + voidPointer(throwArrayIndexOutOfBounds)); thunkTable = code + image->thunkTable; thunkSize = image->thunkSize; #define THUNK(s) \ - { void* p = voidPointer(s); \ - memcpy(code + image->s##Call, &p, BytesPerWord); } + updateCall(t, LongJump, false, code + image->s##Call, voidPointer(s)); #include "thunks.cpp" @@ -5261,36 +5270,42 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, p->defaultThunk = finish (t, allocator, defaultContext.context.assembler, "default"); - { void* call = defaultContext.promise.listener->resolve - (reinterpret_cast(voidPointer(compileMethod))); + { uint8_t* call = static_cast + (defaultContext.promise.listener->resolve + (reinterpret_cast(voidPointer(compileMethod)))) + + BytesPerWord; + if (image) { image->defaultThunk = p->defaultThunk - imageBase; - image->compileMethodCall = static_cast(call) - imageBase; + image->compileMethodCall = call - imageBase; } } p->nativeThunk = finish (t, allocator, nativeContext.context.assembler, "native"); - { void* call = nativeContext.promise.listener->resolve - (reinterpret_cast(voidPointer(invokeNative))); + { uint8_t* call = static_cast + (nativeContext.promise.listener->resolve + (reinterpret_cast(voidPointer(invokeNative)))) + + BytesPerWord; if (image) { image->nativeThunk = p->nativeThunk - imageBase; - image->invokeNativeCall = static_cast(call) - imageBase; + image->invokeNativeCall = call - imageBase; } } p->aioobThunk = finish (t, allocator, aioobContext.context.assembler, "aioob"); - { void* call = aioobContext.promise.listener->resolve - (reinterpret_cast(voidPointer(throwArrayIndexOutOfBounds))); + { uint8_t* call = static_cast + (aioobContext.promise.listener->resolve + (reinterpret_cast(voidPointer(throwArrayIndexOutOfBounds)))) + + BytesPerWord; if (image) { image->aioobThunk = p->aioobThunk - imageBase; - image->throwArrayIndexOutOfBoundsCall - = static_cast(call) - imageBase; + image->throwArrayIndexOutOfBoundsCall = call - imageBase; } } @@ -5309,10 +5324,11 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, #define THUNK(s) \ tableContext.context.assembler->writeTo(start); \ start += p->thunkSize; \ - { void* call = tableContext.promise.listener->resolve \ - (reinterpret_cast(voidPointer(s))); \ + { uint8_t* call = static_cast \ + (tableContext.promise.listener->resolve \ + (reinterpret_cast(voidPointer(s)))) + BytesPerWord; \ if (image) { \ - image->s##Call = static_cast(call) - imageBase; \ + image->s##Call = call - imageBase; \ } \ } diff --git a/src/heapwalk.cpp b/src/heapwalk.cpp index aa8e981e79..f6e2b746fe 100644 --- a/src/heapwalk.cpp +++ b/src/heapwalk.cpp @@ -266,7 +266,7 @@ walk(Context* c, HeapVisitor* v, object p) goto pop; children: { - v->push(nextChildOffset); + v->push(p, find(c, p)->number, nextChildOffset); push(c, p, nextChildOffset); p = get(p, nextChildOffset); goto visit; diff --git a/src/heapwalk.h b/src/heapwalk.h index 473856bea3..25c681d6a3 100644 --- a/src/heapwalk.h +++ b/src/heapwalk.h @@ -28,7 +28,8 @@ class HeapVisitor { 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 push(object parent, unsigned parentNumber, + unsigned childOffset) = 0; virtual void pop() = 0; }; diff --git a/src/machine.cpp b/src/machine.cpp index e64e892ebc..9c75036e97 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1517,11 +1517,8 @@ boot(Thread* t, BootImage* image) if (w) { for (unsigned bit = 0; bit < BitsPerWord; ++bit) { if (w & (static_cast(1) << bit)) { - unsigned index = ::indexOf(word, bit); - uintptr_t* p = heap + index; - if (*p) { - *p = reinterpret_cast(heap + *p - 1); - } + uintptr_t* p = heap + indexOf(word, bit); + *p = reinterpret_cast(heap + (*p - 1)); } } heapMap[word] = 0; @@ -1530,9 +1527,9 @@ boot(Thread* t, BootImage* image) t->m->heap->setImmortalHeap(heap, image->heapSize, heapMap); - t->m->loader = reinterpret_cast(heap + image->loader); - t->m->stringMap = reinterpret_cast(heap + image->stringMap); - t->m->types = reinterpret_cast(heap + image->types); + t->m->loader = bootObject(heap, image->loader); + t->m->stringMap = bootObject(heap, image->stringMap); + t->m->types = bootObject(heap, image->types); uintptr_t* codeMap = heap + ceiling(image->heapSize, BytesPerWord); unsigned codeMapSizeInWords = ceiling @@ -1544,12 +1541,10 @@ boot(Thread* t, BootImage* image) if (w) { for (unsigned bit = 0; bit < BitsPerWord; ++bit) { if (w & (static_cast(1) << bit)) { - unsigned index = ::indexOf(word, bit); + unsigned index = indexOf(word, bit); uintptr_t v; memcpy(&v, code + index, BytesPerWord); - if (v) { - v = reinterpret_cast(heap + v - 1); - memcpy(code + index, &v, BytesPerWord); - } + v = reinterpret_cast(heap + v - 1); + memcpy(code + index, &v, BytesPerWord); } } } @@ -1580,6 +1575,8 @@ 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); @@ -1882,6 +1879,8 @@ Thread::init() } } + m->unsafe = false; + if (image) { boot(this, image); } else { diff --git a/src/main.cpp b/src/main.cpp index b784314579..5e412c0bae 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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("-Davian.bootimage=" BOOT_IMAGE); +#endif + #ifdef BOOT_CLASSPATH options[optionIndex++].optionString = const_cast("-Xbootclasspath:" BOOT_CLASSPATH); diff --git a/src/x86.cpp b/src/x86.cpp index e0956deb3b..cb7d778612 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -135,7 +135,7 @@ class Task { Task* next; }; -void +void* resolveOffset(System* s, uint8_t* instruction, unsigned instructionSize, int64_t value) { @@ -146,6 +146,7 @@ resolveOffset(System* s, uint8_t* instruction, unsigned instructionSize, int32_t v4 = v; memcpy(instruction + instructionSize - 4, &v4, 4); + return instruction + instructionSize - 4; } class OffsetListener: public Promise::Listener { @@ -158,8 +159,7 @@ class OffsetListener: public Promise::Listener { { } virtual void* resolve(int64_t value) { - resolveOffset(s, instruction, instructionSize, value); - return 0; + return resolveOffset(s, instruction, instructionSize, value); } System* s; @@ -2270,10 +2270,15 @@ class MyAssembler: public Assembler { return c.code.length(); } - virtual void updateCall(void* returnAddress, void* newTarget) { + virtual void updateCall(UnaryOperation op UNUSED, + bool assertAlignment UNUSED, void* returnAddress, + void* newTarget) + { uint8_t* instruction = static_cast(returnAddress) - 5; - assert(&c, *instruction == 0xE8); - assert(&c, reinterpret_cast(instruction + 1) % 4 == 0); + assert(&c, (op == LongCall and *instruction == 0xE8) + or (op == LongJump and *instruction == 0xE9)); + assert(&c, (not assertAlignment) + or reinterpret_cast(instruction + 1) % 4 == 0); int32_t v = static_cast(newTarget) - static_cast(returnAddress); From e44f326377d104b8d38cb9f8ffb79bb54d340f94 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 29 Nov 2008 18:39:42 -0700 Subject: [PATCH 14/39] various bugfixes --- src/bootimage.cpp | 35 +++++++++++++++++--- src/compile.cpp | 81 +++++++++++++++++++++++------------------------ src/machine.cpp | 21 ++++++++++-- 3 files changed, 89 insertions(+), 48 deletions(-) diff --git a/src/bootimage.cpp b/src/bootimage.cpp index 85737f0922..20abcc07d4 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -99,6 +99,21 @@ visitRoots(Thread* t, BootImage* image, HeapWalker* w, object constants) } } +void +visitReference(Thread* t, HeapWalker* w, uintptr_t* heap, uintptr_t* map, + object r) +{ + int target = w->map()->find(jreferenceTarget(t, r)); + assert(t, target > 0); + + int reference = w->map()->find(r); + assert(t, reference > 0); + + unsigned index = reference - 1 + (JreferenceTarget / BytesPerWord); + markBit(map, index); + heap[index] = target; +} + HeapWalker* makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map, unsigned capacity, object constants) @@ -161,6 +176,14 @@ makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map, HeapWalker* w = makeHeapWalker(t, &visitor); visitRoots(t, image, w, constants); + for (object r = t->m->weakReferences; r; r = jreferenceVmNext(t, r)) { + visitReference(t, w, heap, map, r); + } + + for (object r = t->m->tenuredWeakReferences; r; r = jreferenceVmNext(t, r)) { + visitReference(t, w, heap, map, r); + } + image->heapSize = visitor.position * BytesPerWord; return w; @@ -212,6 +235,9 @@ writeBootImage(Thread* t, FILE* out) (t->m->heap->allocate(heapMapSize(HeapCapacity))); memset(heapMap, 0, heapMapSize(HeapCapacity)); + PROTECT(t, constants); + collect(t, Heap::MajorCollection); + HeapWalker* heapWalker = makeHeapImage (t, &image, heap, heapMap, HeapCapacity, constants); @@ -220,11 +246,12 @@ writeBootImage(Thread* t, FILE* out) heapWalker->dispose(); image.magic = BootImage::Magic; + image.codeBase = reinterpret_cast(code); - if (false) { - fprintf(stderr, "heap size %d code size %d\n", - image.heapSize, image.codeSize); - } else { + fprintf(stderr, "heap size %d code size %d\n", + image.heapSize, image.codeSize); + + if (true) { fwrite(&image, sizeof(BootImage), 1, out); fwrite(heapMap, pad(heapMapSize(image.heapSize)), 1, out); diff --git a/src/compile.cpp b/src/compile.cpp index 9088f5c25c..02ae365d45 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -1482,10 +1482,46 @@ makeBlankObjectArray(MyThread* t, object class_, int32_t length) } object FORCE_ALIGN -makeBlankArray(MyThread* t, object (*constructor)(Thread*, uintptr_t, bool), - int32_t length) +makeBlankArray(MyThread* t, unsigned type, int32_t length) { if (length >= 0) { + object (*constructor)(Thread*, uintptr_t, bool); + switch (type) { + case T_BOOLEAN: + constructor = makeBooleanArray; + break; + + case T_CHAR: + constructor = makeCharArray; + break; + + case T_FLOAT: + constructor = makeFloatArray; + break; + + case T_DOUBLE: + constructor = makeDoubleArray; + break; + + case T_BYTE: + constructor = makeByteArray; + break; + + case T_SHORT: + constructor = makeShortArray; + break; + + case T_INT: + constructor = makeIntArray; + break; + + case T_LONG: + constructor = makeLongArray; + break; + + default: abort(t); + } + return constructor(t, length, true); } else { object message = makeString(t, "%d", length); @@ -3272,51 +3308,13 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* length = frame->popInt(); - object (*constructor)(Thread*, uintptr_t, bool); - switch (type) { - case T_BOOLEAN: - constructor = makeBooleanArray; - break; - - case T_CHAR: - constructor = makeCharArray; - break; - - case T_FLOAT: - constructor = makeFloatArray; - break; - - case T_DOUBLE: - constructor = makeDoubleArray; - break; - - case T_BYTE: - constructor = makeByteArray; - break; - - case T_SHORT: - constructor = makeShortArray; - break; - - case T_INT: - constructor = makeIntArray; - break; - - case T_LONG: - constructor = makeLongArray; - break; - - default: abort(t); - } - frame->pushObject (c->call (c->constant(getThunk(t, makeBlankArrayThunk)), 0, frame->trace(0, false), BytesPerWord, - 3, c->thread(), c->constant(reinterpret_cast(constructor)), - length)); + 3, c->thread(), c->constant(type), length)); } break; case nop: break; @@ -4693,6 +4691,7 @@ fixupCallTable(MyThread* t, object oldTable, uintptr_t oldBase, next = callNodeNext(t, p); intptr_t k = (callNodeAddress(t, p) - oldBase) + newBase; + callNodeAddress(t, p) = k; unsigned index = k & (arrayLength(t, newTable) - 1); diff --git a/src/machine.cpp b/src/machine.cpp index 9c75036e97..f57e070b33 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1560,14 +1560,29 @@ boot(Thread* t, BootImage* image) if (classMethodTable(t, c)) { for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { object method = arrayBody(t, classMethodTable(t, c), i); - methodCompiled(t, method) - = (methodCompiled(t, method) - image->codeBase) - + reinterpret_cast(code); + if (methodCode(t, method)) { + assert(t, (methodCompiled(t, method) - image->codeBase) + <= image->codeSize); + + methodCompiled(t, method) + = (methodCompiled(t, method) - image->codeBase) + + reinterpret_cast(code); + +// fprintf(stderr, "%p %p %s.%s%s\n", +// reinterpret_cast(methodCompiled(t, method)), +// reinterpret_cast(methodCompiled(t, method)) + +// reinterpret_cast(methodCompiled(t, method))[-1], +// &byteArrayBody(t, className(t, methodClass(t, method)), 0), +// &byteArrayBody(t, methodName(t, method), 0), +// &byteArrayBody(t, methodSpec(t, method), 0)); + } } } t->m->processor->initVtable(t, c); } + + t->m->bootstrapClassMap = makeHashMap(t, 0, 0); } void From eaf30eb909ee9ce1c448c1e7dcdec6733fc1a6b4 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 29 Nov 2008 21:58:09 -0700 Subject: [PATCH 15/39] fix static class initialization when using a boot image --- src/bootimage.cpp | 2 +- src/compile.cpp | 104 +++++++++++++++++++++++----------------------- src/machine.cpp | 20 +++++---- src/machine.h | 11 ++++- 4 files changed, 75 insertions(+), 62 deletions(-) diff --git a/src/bootimage.cpp b/src/bootimage.cpp index 20abcc07d4..c4d68ac9ac 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -57,7 +57,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, 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)) { + if (methodCode(t, method) or (methodFlags(t, method) & ACC_NATIVE)) { t->m->processor->compileMethod (t, zone, code, &size, capacity, &constants, &calls, method); } diff --git a/src/compile.cpp b/src/compile.cpp index 02ae365d45..44806d71a4 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -1770,53 +1770,55 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target) Compiler::Operand* result = 0; if (not emptyMethod(t, target)) { - if (methodFlags(t, target) & ACC_NATIVE) { - result = c->call - (c->constant(nativeThunk(t)), - 0, - frame->trace(target, false), - rSize, - 0); - } else { - BootContext* bc = frame->context->bootContext; - if (bc) { - if (objectClass(t, target) == objectClass(t, frame->context->method)) { - Promise* p = new (bc->zone->allocate(sizeof(ListenPromise))) - ListenPromise(t->m->system, bc->zone); + BootContext* bc = frame->context->bootContext; + if (bc) { + if (methodClass(t, target) == methodClass(t, frame->context->method) + or (not classNeedsInit(t, methodClass(t, target)))) + { + Promise* p = new (bc->zone->allocate(sizeof(ListenPromise))) + ListenPromise(t->m->system, bc->zone); - PROTECT(t, target); - object pointer = makePointer(t, p); - bc->calls = makeTriple(t, target, pointer, bc->calls); + PROTECT(t, target); + object pointer = makePointer(t, p); + bc->calls = makeTriple(t, target, pointer, bc->calls); - result = c->call - (c->promiseConstant(p), - 0, - frame->trace(0, false), - rSize, - 0); - } else { - result = c->call - (c->constant(defaultThunk(t)), - Compiler::Aligned, - frame->trace(target, false), - rSize, - 0); - } - } else if (methodCompiled(t, target) == defaultThunk(t)) { + result = c->call + (c->promiseConstant(p), + 0, + frame->trace(0, false), + rSize, + 0); + } else { result = c->call (c->constant(defaultThunk(t)), Compiler::Aligned, frame->trace(target, false), rSize, 0); - } else { - result = c->call - (c->constant(methodCompiled(t, target)), - 0, - frame->trace(0, false), - rSize, - 0); } + } else if (methodFlags(t, target) & ACC_NATIVE) { + result = c->call + (c->constant(nativeThunk(t)), + 0, + frame->trace(target, false), + rSize, + 0); + } else if (methodCompiled(t, target) == defaultThunk(t) + or classNeedsInit(t, methodClass(t, target))) + { + result = c->call + (c->constant(defaultThunk(t)), + Compiler::Aligned, + frame->trace(target, false), + rSize, + 0); + } else { + result = c->call + (c->constant(methodCompiled(t, target)), + 0, + frame->trace(0, false), + rSize, + 0); } } @@ -2457,8 +2459,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* table; if (instruction == getstatic) { - if ((classVmFlags(t, fieldClass(t, field)) & NeedInitFlag) - and (classVmFlags(t, fieldClass(t, field)) & InitFlag) == 0) + if (fieldClass(t, field) != methodClass(t, context->method) + and classNeedsInit(t, fieldClass(t, field))); { c->call (c->constant(getThunk(t, tryInitClassThunk)), @@ -3337,8 +3339,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, object staticTable = 0; if (instruction == putstatic) { - if ((classVmFlags(t, fieldClass(t, field)) & NeedInitFlag) - and (classVmFlags(t, fieldClass(t, field)) & InitFlag) == 0) + if (fieldClass(t, field) != methodClass(t, context->method) + and classNeedsInit(t, fieldClass(t, field))) { c->call (c->constant(getThunk(t, tryInitClassThunk)), @@ -4848,9 +4850,7 @@ class MyProcessor: public Processor { PROTECT(t, c); ACQUIRE(t, t->m->classLock); - if (classVmFlags(t, c) & NeedInitFlag - and (classVmFlags(t, c) & InitFlag) == 0) - { + if (classNeedsInit(t, c)) { classVmFlags(t, c) |= InitFlag; invoke(t, classInitializer(t, c), 0); if (t->exception) { @@ -5388,19 +5388,19 @@ void compile(MyThread* t, Allocator* allocator, BootContext* bootContext, object method) { + PROTECT(t, method); + + if (bootContext == 0) { + initClass(t, methodClass(t, method)); + if (UNLIKELY(t->exception)) return; + } + MyProcessor* p = processor(t); if (methodCompiled(t, method) == defaultThunk(t)) { - PROTECT(t, method); - ACQUIRE(t, t->m->classLock); if (methodCompiled(t, method) == defaultThunk(t)) { - if (bootContext == 0) { - initClass(t, methodClass(t, method)); - if (UNLIKELY(t->exception)) return; - } - if (methodCompiled(t, method) == defaultThunk(t)) { object node; uint8_t* compiled; diff --git a/src/machine.cpp b/src/machine.cpp index f57e070b33..ed9e6b8ec6 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1560,7 +1560,7 @@ boot(Thread* t, BootImage* image) 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)) { + if (methodCode(t, method) or (methodFlags(t, method) & ACC_NATIVE)) { assert(t, (methodCompiled(t, method) - image->codeBase) <= image->codeSize); @@ -1568,13 +1568,17 @@ boot(Thread* t, BootImage* image) = (methodCompiled(t, method) - image->codeBase) + reinterpret_cast(code); -// fprintf(stderr, "%p %p %s.%s%s\n", -// reinterpret_cast(methodCompiled(t, method)), -// reinterpret_cast(methodCompiled(t, method)) + -// reinterpret_cast(methodCompiled(t, method))[-1], -// &byteArrayBody(t, className(t, methodClass(t, method)), 0), -// &byteArrayBody(t, methodName(t, method), 0), -// &byteArrayBody(t, methodSpec(t, method), 0)); + if (false and (methodFlags(t, method) & ACC_NATIVE) == 0) { + fprintf(stderr, "%p %p %s.%s%s\n", + reinterpret_cast(methodCompiled(t, method)), + reinterpret_cast(methodCompiled(t, method)) + + reinterpret_cast + (methodCompiled(t, method))[-1], + &byteArrayBody + (t, className(t, methodClass(t, method)), 0), + &byteArrayBody(t, methodName(t, method), 0), + &byteArrayBody(t, methodSpec(t, method), 0)); + } } } } diff --git a/src/machine.h b/src/machine.h index 0e84fae7dd..becfd81e5c 100644 --- a/src/machine.h +++ b/src/machine.h @@ -2004,10 +2004,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 From f13bf44e87573bde9fd8f609eddaec804257596f Mon Sep 17 00:00:00 2001 From: Rich Scott Date: Mon, 1 Dec 2008 16:53:34 -0700 Subject: [PATCH 16/39] Check return value of fwrite() calls. This is to satisfy GCC 4.3.2 (on Ubuntu 8.10), which requires it. --- src/heapdump.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/heapdump.cpp b/src/heapdump.cpp index 617d1d2e74..e8105c974a 100644 --- a/src/heapdump.cpp +++ b/src/heapdump.cpp @@ -215,21 +215,21 @@ get(object o, unsigned offsetInWords) void write1(Context* c, uint8_t v) { - fwrite(&v, 1, 1, c->out); + size_t n UNUSED = fwrite(&v, 1, 1, c->out); } void write4(Context* c, uint32_t v) { uint8_t b[] = { v >> 24, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF }; - fwrite(b, 4, 1, c->out); + size_t n UNUSED = fwrite(b, 4, 1, c->out); } void writeString(Context* c, int8_t* p, unsigned size) { write4(c, size); - fwrite(p, size, 1, c->out); + size_t n UNUSED = fwrite(p, size, 1, c->out); } unsigned From 4a1dd3a8f73ecff1b98b38a132749a28cc5c1e3c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 1 Dec 2008 19:35:52 -0700 Subject: [PATCH 17/39] specify writable and executable section for boot image --- makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index dca8d638a6..341cf6e1c9 100644 --- a/makefile +++ b/makefile @@ -432,8 +432,10 @@ ifeq ($(platform),darwin) else (wd=$$(pwd); \ cd $(native-build); \ - $(objcopy) -I binary bootimage.bin \ - -O $(object-format) -B $(object-arch) "$${wd}/$(@)") + $(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): \ From 25ade1484a3509e7ea0502496a2310545105a88c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 1 Dec 2008 19:38:00 -0700 Subject: [PATCH 18/39] lots of bugfixes and refactoring --- classpath/java/lang/SystemClassLoader.java | 2 - src/assembler.h | 7 +- src/bootimage.cpp | 158 +++-- src/bootimage.h | 13 +- src/compile.cpp | 756 +++++++++++++-------- src/heap.cpp | 104 +-- src/heap.h | 3 +- src/machine.cpp | 107 +-- src/machine.h | 30 + src/processor.h | 5 +- src/util.cpp | 49 +- src/util.h | 10 +- src/x86.cpp | 169 +++-- 13 files changed, 814 insertions(+), 599 deletions(-) diff --git a/classpath/java/lang/SystemClassLoader.java b/classpath/java/lang/SystemClassLoader.java index 3e936fa040..723651ca10 100644 --- a/classpath/java/lang/SystemClassLoader.java +++ b/classpath/java/lang/SystemClassLoader.java @@ -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); diff --git a/src/assembler.h b/src/assembler.h index 126a3c21dc..7d3946274c 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -81,6 +81,8 @@ class Promise { class Listener { public: virtual void* resolve(int64_t value) = 0; + + Listener* next; }; virtual int64_t value() = 0; @@ -118,7 +120,10 @@ class ListenPromise: public Promise { } virtual Listener* listen(unsigned sizeInBytes) { - return listener = static_cast(allocator->allocate(sizeInBytes)); + Listener* l = static_cast(allocator->allocate(sizeInBytes)); + l->next = listener; + listener = l; + return l; } System* s; diff --git a/src/bootimage.cpp b/src/bootimage.cpp index c4d68ac9ac..aa368258e0 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -67,8 +67,16 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, } for (; calls; calls = tripleThird(t, calls)) { + object method = tripleFirst(t, calls); + uintptr_t address; + if (methodFlags(t, method) & ACC_NATIVE) { + address = reinterpret_cast(code + image->nativeThunk); + } else { + address = methodCompiled(t, method); + } + static_cast(pointerValue(t, tripleSecond(t, calls))) - ->listener->resolve(methodCompiled(t, tripleFirst(t, calls))); + ->listener->resolve(address); } image->codeSize = size; @@ -80,6 +88,7 @@ unsigned objectSize(Thread* t, object o) { assert(t, not objectExtended(t, o)); + return baseSize(t, o, objectClass(t, o)); } @@ -88,8 +97,11 @@ 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->stringMap = w->visitRoot(m->stringMap); image->types = w->visitRoot(m->types); m->processor->visitRoots(image, w); @@ -99,21 +111,6 @@ visitRoots(Thread* t, BootImage* image, HeapWalker* w, object constants) } } -void -visitReference(Thread* t, HeapWalker* w, uintptr_t* heap, uintptr_t* map, - object r) -{ - int target = w->map()->find(jreferenceTarget(t, r)); - assert(t, target > 0); - - int reference = w->map()->find(r); - assert(t, reference > 0); - - unsigned index = reference - 1 + (JreferenceTarget / BytesPerWord); - markBit(map, index); - heap[index] = target; -} - HeapWalker* makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map, unsigned capacity, object constants) @@ -121,29 +118,56 @@ makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map, class Visitor: public HeapVisitor { public: Visitor(Thread* t, uintptr_t* heap, uintptr_t* map, unsigned capacity): - t(t), current(0), heap(heap), map(map), position(0), capacity(capacity) + t(t), currentObject(0), currentNumber(0), currentOffset(0), heap(heap), + map(map), position(0), capacity(capacity) { } void visit(unsigned number) { - if (current) { - if (number) markBit(map, current - 1); - heap[current - 1] = 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() { - current = 0; + 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; + if (currentObject + and (currentOffset * BytesPerWord) == ClassStaticTable) + { + FixedAllocator allocator + (t, reinterpret_cast(heap + position), + (capacity - position) * BytesPerWord); - unsigned number = position + 1; - position += size; + unsigned totalInBytes; + uintptr_t* dst = static_cast + (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); @@ -157,16 +181,20 @@ makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map, visit(number); } - virtual void push(object, unsigned number, unsigned offset) { - current = number + offset; + virtual void push(object object, unsigned number, unsigned offset) { + currentObject = object; + currentNumber = number; + currentOffset = offset; } virtual void pop() { - current = 0; + currentObject = 0; } Thread* t; - unsigned current; + object currentObject; + unsigned currentNumber; + unsigned currentOffset; uintptr_t* heap; uintptr_t* map; unsigned position; @@ -176,14 +204,6 @@ makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map, HeapWalker* w = makeHeapWalker(t, &visitor); visitRoots(t, image, w, constants); - for (object r = t->m->weakReferences; r; r = jreferenceVmNext(t, r)) { - visitReference(t, w, heap, map, r); - } - - for (object r = t->m->tenuredWeakReferences; r; r = jreferenceVmNext(t, r)) { - visitReference(t, w, heap, map, r); - } - image->heapSize = visitor.position * BytesPerWord; return w; @@ -197,14 +217,18 @@ updateConstants(Thread* t, object constants, uint8_t* code, uintptr_t* codeMap, unsigned target = heapTable->find(tripleFirst(t, constants)); assert(t, target > 0); - void* dst = static_cast - (pointerValue(t, tripleSecond(t, constants)))->listener->resolve(target); + for (Promise::Listener* pl = static_cast + (pointerValue(t, tripleSecond(t, constants)))->listener; + pl; pl = pl->next) + { + void* dst = pl->resolve(target); - assert(t, reinterpret_cast(dst) - >= reinterpret_cast(code)); + assert(t, reinterpret_cast(dst) + >= reinterpret_cast(code)); - markBit(codeMap, reinterpret_cast(dst) - - reinterpret_cast(code)); + markBit(codeMap, reinterpret_cast(dst) + - reinterpret_cast(code)); + } } } @@ -227,6 +251,7 @@ writeBootImage(Thread* t, FILE* out) memset(codeMap, 0, codeMapSize(CodeCapacity)); object constants = makeCodeImage(t, &zone, &image, code, CodeCapacity); + PROTECT(t, constants); const unsigned HeapCapacity = 32 * 1024 * 1024; uintptr_t* heap = static_cast @@ -235,7 +260,6 @@ writeBootImage(Thread* t, FILE* out) (t->m->heap->allocate(heapMapSize(HeapCapacity))); memset(heapMap, 0, heapMapSize(HeapCapacity)); - PROTECT(t, constants); collect(t, Heap::MajorCollection); HeapWalker* heapWalker = makeHeapImage @@ -243,17 +267,57 @@ writeBootImage(Thread* t, FILE* out) updateConstants(t, constants, code, codeMap, heapWalker->map()); + image.classCount = hashMapSize(t, t->m->classMap); + unsigned* classTable = static_cast + (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 + (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(code); - fprintf(stderr, "heap size %d code size %d\n", - image.heapSize, image.codeSize); + 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); diff --git a/src/bootimage.h b/src/bootimage.h index a868d02d74..4b2ee7d458 100644 --- a/src/bootimage.h +++ b/src/bootimage.h @@ -15,6 +15,10 @@ namespace vm { +const unsigned BootMask = (~static_cast(0)) / BytesPerWord; + +const unsigned BootShift = 32 - log(BytesPerWord); + class BootImage { public: static const unsigned Magic = 0x22377322; @@ -24,11 +28,12 @@ class BootImage { unsigned heapSize; unsigned codeSize; - unsigned loader; - unsigned stringMap; - unsigned types; + unsigned classCount; + unsigned stringCount; + unsigned callCount; - unsigned callTable; + unsigned loader; + unsigned types; unsigned methodTree; unsigned methodTreeSentinal; diff --git a/src/compile.cpp b/src/compile.cpp index 44806d71a4..18c670a74f 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -1244,12 +1244,34 @@ tryInitClass(MyThread* t, object class_) if (UNLIKELY(t->exception)) unwind(t); } +object& +objectPools(MyThread* t); + +uintptr_t +defaultThunk(MyThread* t); + +uintptr_t +nativeThunk(MyThread* t); + +uintptr_t +aioobThunk(MyThread* t); + +uintptr_t +methodAddress(Thread* t, object method) +{ + if (methodFlags(t, method) & ACC_NATIVE) { + return nativeThunk(static_cast(t)); + } else { + return methodCompiled(t, method); + } +} + void* FORCE_ALIGN findInterfaceMethodFromInstance(MyThread* t, object method, object instance) { if (instance) { return reinterpret_cast - (methodCompiled + (methodAddress (t, findInterfaceMethod(t, method, objectClass(t, instance)))); } else { t->exception = makeNullPointerException(t); @@ -1748,18 +1770,6 @@ emptyMethod(MyThread* t, object method) and (codeBody(t, methodCode(t, method), 0) == return_); } -object& -objectPools(MyThread* t); - -uintptr_t -defaultThunk(MyThread* t); - -uintptr_t -nativeThunk(MyThread* t); - -uintptr_t -aioobThunk(MyThread* t); - void compileDirectInvoke(MyThread* t, Frame* frame, object target) { @@ -1782,10 +1792,13 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target) object pointer = makePointer(t, p); bc->calls = makeTriple(t, target, pointer, bc->calls); + object traceTarget + = (methodFlags(t, target) & ACC_NATIVE) ? target : 0; + result = c->call (c->promiseConstant(p), 0, - frame->trace(0, false), + frame->trace(traceTarget, false), rSize, 0); } else { @@ -1796,14 +1809,7 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target) rSize, 0); } - } else if (methodFlags(t, target) & ACC_NATIVE) { - result = c->call - (c->constant(nativeThunk(t)), - 0, - frame->trace(target, false), - rSize, - 0); - } else if (methodCompiled(t, target) == defaultThunk(t) + } else if (methodAddress(t, target) == defaultThunk(t) or classNeedsInit(t, methodClass(t, target))) { result = c->call @@ -1813,10 +1819,13 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target) rSize, 0); } else { + object traceTarget + = (methodFlags(t, target) & ACC_NATIVE) ? target : 0; + result = c->call - (c->constant(methodCompiled(t, target)), + (c->constant(methodAddress(t, target)), 0, - frame->trace(0, false), + frame->trace(traceTarget, false), rSize, 0); } @@ -2460,7 +2469,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (instruction == getstatic) { if (fieldClass(t, field) != methodClass(t, context->method) - and classNeedsInit(t, fieldClass(t, field))); + and classNeedsInit(t, fieldClass(t, field))) { c->call (c->constant(getThunk(t, tryInitClassThunk)), @@ -4082,7 +4091,7 @@ compileMethod2(MyThread* t) if (UNLIKELY(t->exception)) { return 0; } else { - void* address = reinterpret_cast(methodCompiled(t, target)); + void* address = reinterpret_cast(methodAddress(t, target)); if (callNodeVirtualCall(t, node)) { classVtable (t, objectClass @@ -4090,7 +4099,7 @@ compileMethod2(MyThread* t) = address; } else { updateCall - (t, LongCall, true, reinterpret_cast(callNodeAddress(t, node)), + (t, Call, true, reinterpret_cast(callNodeAddress(t, node)), address); } return address; @@ -4119,7 +4128,7 @@ invokeNative2(MyThread* t, object method) initClass(t, methodClass(t, method)); if (UNLIKELY(t->exception)) return 0; - if (methodCode(t, method) == 0) { + if (methodCompiled(t, method) == defaultThunk(t)) { void* function = resolveNativeMethod(t, method); if (UNLIKELY(function == 0)) { object message = makeString @@ -4131,8 +4140,7 @@ invokeNative2(MyThread* t, object method) return 0; } - object p = makePointer(t, function); - set(t, method, MethodCode, p); + methodCompiled(t, method) = reinterpret_cast(function); } object class_ = methodClass(t, method); @@ -4198,7 +4206,7 @@ invokeNative2(MyThread* t, object method) } } - void* function = pointerValue(t, methodCode(t, method)); + void* function = reinterpret_cast(methodCompiled(t, method)); unsigned returnCode = methodReturnCode(t, method); unsigned returnType = fieldType(t, returnCode); uint64_t result; @@ -4362,7 +4370,7 @@ visitStackAndLocals(MyThread* t, Heap::Visitor* v, void* base, object method, object map = codePool(t, methodCode(t, method)); int index = frameMapIndex (t, method, difference - (ip, reinterpret_cast(methodCompiled(t, method)))); + (ip, reinterpret_cast(methodAddress(t, method)))); for (unsigned i = 0; i < count; ++i) { int j = index + i; @@ -4596,8 +4604,8 @@ invoke(Thread* thread, object method, ArgumentList* arguments) } result = vmInvoke - (t, reinterpret_cast(methodCompiled(t, method)), arguments->array, - arguments->position, returnType); + (t, reinterpret_cast(methodAddress(t, method)), + arguments->array, arguments->position, returnType); } if (t->exception) { @@ -4679,60 +4687,8 @@ class SegFaultHandler: public System::SignalHandler { Machine* m; }; -object -fixupCallTable(MyThread* t, object oldTable, uintptr_t oldBase, - uintptr_t newBase) -{ - PROTECT(t, oldTable); - - object newTable = makeArray(t, arrayLength(t, oldTable), true); - - for (unsigned i = 0; i < arrayLength(t, oldTable); ++i) { - object next; - for (object p = arrayBody(t, oldTable, i); p; p = next) { - next = callNodeNext(t, p); - - intptr_t k = (callNodeAddress(t, p) - oldBase) + newBase; - callNodeAddress(t, p) = k; - - unsigned index = k & (arrayLength(t, newTable) - 1); - - set(t, p, CallNodeNext, arrayBody(t, newTable, index)); - set(t, newTable, ArrayBody + (index * BytesPerWord), p); - } - } - - return newTable; -} - -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; -}; +void +boot(MyThread* t, BootImage* image); class MyProcessor; @@ -4777,6 +4733,7 @@ class MyProcessor: public Processor { methodTree(0), methodTreeSentinal(0), objectPools(0), + staticTableArray(0), codeAllocator(s), codeZone(s, &codeAllocator, 64 * 1024) { } @@ -4870,6 +4827,7 @@ class MyProcessor: public Processor { v->visit(&methodTree); v->visit(&methodTreeSentinal); v->visit(&objectPools); + v->visit(&staticTableArray); } for (MyThread::CallTrace* trace = t->trace; trace; trace = trace->next) { @@ -5034,7 +4992,7 @@ class MyProcessor: public Processor { virtual object getStackTrace(Thread* vmt, Thread* vmTarget) { MyThread* t = static_cast(vmt); MyThread* target = static_cast(vmTarget); - MyProcessor* p = processor(t); + MyProcessor* p = this; class Visitor: public System::ThreadVisitor { public: @@ -5098,7 +5056,7 @@ class MyProcessor: public Processor { MyThread* t = static_cast(vmt); FixedAllocator allocator(t, code + *offset, capacity); - ::compileThunks(t, &allocator, processor(t), image, code); + ::compileThunks(t, &allocator, this, image, code); *offset += allocator.offset; } @@ -5119,47 +5077,47 @@ class MyProcessor: public Processor { } virtual void visitRoots(BootImage* image, HeapWalker* w) { - image->callTable = w->visitRoot(callTable); image->methodTree = w->visitRoot(methodTree); image->methodTreeSentinal = w->visitRoot(methodTreeSentinal); } - virtual void boot(Thread* vmt, BootImage* image, uintptr_t* heap, - uint8_t* code) + virtual unsigned* makeCallTable(Thread* t, BootImage* image, HeapWalker* w, + uint8_t* code) { - MyThread* t = static_cast(vmt); - methodTree = bootObject(heap, image->methodTree); - methodTreeSentinal = bootObject(heap, image->methodTreeSentinal); + image->callCount = callTableSize; - callTable = fixupCallTable - (t, bootObject(heap, image->callTable), image->codeBase, - reinterpret_cast(code)); + unsigned* table = static_cast + (t->m->heap->allocate(callTableSize * sizeof(unsigned) * 2)); - defaultThunk = code + image->defaultThunk; + unsigned index = 0; + for (unsigned i = 0; i < arrayLength(t, callTable); ++i) { + for (object p = arrayBody(t, callTable, i); p; p = callNodeNext(t, p)) { + table[index++] = callNodeAddress(t, p) + - reinterpret_cast(code); + table[index++] = w->map()->find(callNodeTarget(t, p)) + | (static_cast(callNodeVirtualCall(t, p)) << BootShift); + } + } - updateCall(t, LongCall, false, code + image->compileMethodCall, - voidPointer(::compileMethod)); + return table; + } - nativeThunk = code + image->nativeThunk; + virtual void boot(Thread* t, BootImage* image) { + if (image) { + ::boot(static_cast(t), image); + } else { + callTable = makeArray(t, 128, true); - updateCall(t, LongCall, false, code + image->invokeNativeCall, - voidPointer(invokeNative)); + methodTree = methodTreeSentinal = makeTreeNode(t, 0, 0, 0); + set(t, methodTree, TreeNodeLeft, methodTreeSentinal); + set(t, methodTree, TreeNodeRight, methodTreeSentinal); - aioobThunk = code + image->aioobThunk; + ::compileThunks(static_cast(t), &codeZone, this, 0, 0); + } - updateCall(t, LongCall, false, - code + image->throwArrayIndexOutOfBoundsCall, - voidPointer(throwArrayIndexOutOfBounds)); - - thunkTable = code + image->thunkTable; - thunkSize = image->thunkSize; - -#define THUNK(s) \ - updateCall(t, LongJump, false, code + image->s##Call, voidPointer(s)); - -#include "thunks.cpp" - -#undef THUNK + segFaultHandler.m = t->m; + expect(t, t->m->system->success + (t->m->system->handleSegFault(&segFaultHandler))); } System* s; @@ -5174,11 +5132,344 @@ class MyProcessor: public Processor { object methodTree; object methodTreeSentinal; object objectPools; + object staticTableArray; SegFaultHandler segFaultHandler; CodeAllocator codeAllocator; Zone codeZone; }; +object +findCallNode(MyThread* t, void* address) +{ + if (DebugCallTable) { + fprintf(stderr, "find call node %p\n", address); + } + + MyProcessor* p = processor(t); + object table = p->callTable; + + intptr_t key = reinterpret_cast(address); + unsigned index = static_cast(key) + & (arrayLength(t, table) - 1); + + for (object n = arrayBody(t, table, index); + n; n = callNodeNext(t, n)) + { + intptr_t k = callNodeAddress(t, n); + + if (k == key) { + return n; + } + } + + return 0; +} + +object +resizeTable(MyThread* t, object oldTable, unsigned newLength) +{ + PROTECT(t, oldTable); + + object oldNode = 0; + PROTECT(t, oldNode); + + object newTable = makeArray(t, newLength, true); + PROTECT(t, newTable); + + for (unsigned i = 0; i < arrayLength(t, oldTable); ++i) { + for (oldNode = arrayBody(t, oldTable, i); + oldNode; + oldNode = callNodeNext(t, oldNode)) + { + intptr_t k = callNodeAddress(t, oldNode); + + unsigned index = k & (newLength - 1); + + object newNode = makeCallNode + (t, callNodeAddress(t, oldNode), + callNodeTarget(t, oldNode), + callNodeVirtualCall(t, oldNode), + arrayBody(t, newTable, index)); + + set(t, newTable, ArrayBody + (index * BytesPerWord), newNode); + } + } + + return newTable; +} + +object +insertCallNode(MyThread* t, object table, unsigned* size, object node) +{ + if (DebugCallTable) { + fprintf(stderr, "insert call node %p\n", + reinterpret_cast(callNodeAddress(t, node))); + } + + PROTECT(t, table); + PROTECT(t, node); + + ++ (*size); + + if (*size >= arrayLength(t, table) * 2) { + table = resizeTable(t, table, arrayLength(t, table) * 2); + } + + intptr_t key = callNodeAddress(t, node); + unsigned index = static_cast(key) & (arrayLength(t, table) - 1); + + set(t, node, CallNodeNext, arrayBody(t, table, index)); + set(t, table, ArrayBody + (index * BytesPerWord), node); + + return table; +} + +void +insertCallNode(MyThread* t, object node) +{ + MyProcessor* p = processor(t); + p->callTable = insertCallNode(t, p->callTable, &(p->callTableSize), node); +} + +object +makeClassMap(Thread* t, unsigned* table, unsigned count, uintptr_t* heap) +{ + object array = makeArray(t, nextPowerOfTwo(count), true); + object map = makeHashMap(t, 0, array); + PROTECT(t, map); + + for (unsigned i = 0; i < count; ++i) { + object c = bootObject(heap, table[i]); + hashMapInsert(t, map, className(t, c), c, byteArrayHash); + } + + return map; +} + +object +makeStaticTableArray(Thread* t, unsigned* table, unsigned count, + uintptr_t* heap) +{ + object array = makeArray(t, count, false); + + for (unsigned i = 0; i < count; ++i) { + set(t, array, ArrayBody + (i * BytesPerWord), + classStaticTable(t, bootObject(heap, table[i]))); + } + + return array; +} + +object +makeStringMap(Thread* t, unsigned* table, unsigned count, uintptr_t* heap) +{ + object array = makeArray(t, nextPowerOfTwo(count), true); + object map = makeWeakHashMap(t, 0, array); + PROTECT(t, map); + + for (unsigned i = 0; i < count; ++i) { + object s = bootObject(heap, table[i]); + hashMapInsert(t, map, s, 0, stringHash); + } + + return map; +} + +object +makeCallTable(MyThread* t, uintptr_t* heap, unsigned* calls, unsigned count, + uintptr_t base) +{ + object table = makeArray(t, nextPowerOfTwo(count), true); + PROTECT(t, table); + + unsigned size = 0; + for (unsigned i = 0; i < count; ++i) { + unsigned address = calls[i * 2]; + unsigned target = calls[(i * 2) + 1]; + + object node = makeCallNode + (t, base + address, bootObject(heap, target & BootMask), + target >> BootShift, 0); + + table = insertCallNode(t, table, &size, node); + } + + return table; +} + +void +fixupHeap(MyThread* t, uintptr_t* map, unsigned size, uintptr_t* heap) +{ + for (unsigned word = 0; word < size; ++word) { + uintptr_t w = map[word]; + if (w) { + for (unsigned bit = 0; bit < BitsPerWord; ++bit) { + if (w & (static_cast(1) << bit)) { + unsigned index = indexOf(word, bit); + uintptr_t* p = heap + index; + assert(t, *p); + + uintptr_t number = *p & BootMask; + uintptr_t mark = *p >> BootShift; + + if (number) { + *p = reinterpret_cast(heap + (number - 1)) | mark; + } else { + *p = mark; + } + } + } + } + } +} + +void +fixupCode(Thread*, uintptr_t* map, unsigned size, uint8_t* code, + uintptr_t* heap) +{ + for (unsigned word = 0; word < size; ++word) { + uintptr_t w = map[word]; + if (w) { + for (unsigned bit = 0; bit < BitsPerWord; ++bit) { + if (w & (static_cast(1) << bit)) { + unsigned index = indexOf(word, bit); + uintptr_t v; memcpy(&v, code + index, BytesPerWord); + v = reinterpret_cast(heap + v - 1); + memcpy(code + index, &v, BytesPerWord); + } + } + } + } +} + +void +fixupMethods(Thread* t, BootImage* image, uint8_t* code) +{ + for (HashMapIterator it(t, t->m->classMap); it.hasMore();) { + object c = tripleSecond(t, it.next()); + + 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)) { + assert(t, (methodCompiled(t, method) - image->codeBase) + <= image->codeSize); + + methodCompiled(t, method) + = (methodCompiled(t, method) - image->codeBase) + + reinterpret_cast(code); + + if (DebugCompile and (methodFlags(t, method) & ACC_NATIVE) == 0) { + logCompile + (static_cast(t), + reinterpret_cast(methodCompiled(t, method)), + reinterpret_cast + (methodCompiled(t, method))[-1], + reinterpret_cast + (&byteArrayBody(t, className(t, methodClass(t, method)), 0)), + reinterpret_cast + (&byteArrayBody(t, methodName(t, method), 0)), + reinterpret_cast + (&byteArrayBody(t, methodSpec(t, method), 0))); + } + } + } + } + + t->m->processor->initVtable(t, c); + } +} + +void +fixupThunks(MyThread* t, BootImage* image, uint8_t* code) +{ + MyProcessor* p = processor(t); + + p->defaultThunk = code + image->defaultThunk; + + updateCall(t, LongCall, false, code + image->compileMethodCall, + voidPointer(::compileMethod)); + + p->nativeThunk = code + image->nativeThunk; + + updateCall(t, LongCall, false, code + image->invokeNativeCall, + voidPointer(invokeNative)); + + p->aioobThunk = code + image->aioobThunk; + + updateCall(t, LongCall, false, + code + image->throwArrayIndexOutOfBoundsCall, + voidPointer(throwArrayIndexOutOfBounds)); + + p->thunkTable = code + image->thunkTable; + p->thunkSize = image->thunkSize; + +#define THUNK(s) \ + updateCall(t, LongJump, false, code + image->s##Call, voidPointer(s)); + +#include "thunks.cpp" + +#undef THUNK +} + +void +boot(MyThread* t, BootImage* image) +{ + assert(t, image->magic == BootImage::Magic); + + unsigned* classTable = reinterpret_cast(image + 1); + unsigned* stringTable = classTable + image->classCount; + unsigned* callTable = stringTable + image->stringCount; + + uintptr_t* heapMap = reinterpret_cast + (pad(reinterpret_cast(callTable + (image->callCount * 2)))); + unsigned heapMapSizeInWords = ceiling + (heapMapSize(image->heapSize), BytesPerWord); + uintptr_t* heap = heapMap + heapMapSizeInWords; + +// fprintf(stderr, "heap from %p to %p\n", +// heap, heap + ceiling(image->heapSize, BytesPerWord)); + + uintptr_t* codeMap = heap + ceiling(image->heapSize, BytesPerWord); + unsigned codeMapSizeInWords = ceiling + (codeMapSize(image->codeSize), BytesPerWord); + uint8_t* code = reinterpret_cast(codeMap + codeMapSizeInWords); + + fprintf(stderr, "code from %p to %p\n", + code, code + image->codeSize); + + fixupHeap(t, heapMap, heapMapSizeInWords, heap); + + t->m->heap->setImmortalHeap(heap, image->heapSize / BytesPerWord); + + t->m->loader = bootObject(heap, image->loader); + t->m->types = bootObject(heap, image->types); + + MyProcessor* p = static_cast(t->m->processor); + + p->methodTree = bootObject(heap, image->methodTree); + p->methodTreeSentinal = bootObject(heap, image->methodTreeSentinal); + + fixupCode(t, codeMap, codeMapSizeInWords, code, heap); + + t->m->classMap = makeClassMap(t, classTable, image->classCount, heap); + t->m->stringMap = makeStringMap(t, stringTable, image->stringCount, heap); + + p->callTableSize = image->callCount; + p->callTable = makeCallTable + (t, heap, callTable, image->callCount, + reinterpret_cast(code)); + + p->staticTableArray = makeStaticTableArray + (t, classTable, image->classCount, heap); + + fixupThunks(t, image, code); + + fixupMethods(t, image, code); + + t->m->bootstrapClassMap = makeHashMap(t, 0, 0); +} + intptr_t getThunk(MyThread* t, Thunk thunk) { @@ -5271,8 +5562,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, { uint8_t* call = static_cast (defaultContext.promise.listener->resolve - (reinterpret_cast(voidPointer(compileMethod)))) - + BytesPerWord; + (reinterpret_cast(voidPointer(compileMethod)))); if (image) { image->defaultThunk = p->defaultThunk - imageBase; @@ -5285,8 +5575,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, { uint8_t* call = static_cast (nativeContext.promise.listener->resolve - (reinterpret_cast(voidPointer(invokeNative)))) - + BytesPerWord; + (reinterpret_cast(voidPointer(invokeNative)))); if (image) { image->nativeThunk = p->nativeThunk - imageBase; @@ -5299,8 +5588,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, { uint8_t* call = static_cast (aioobContext.promise.listener->resolve - (reinterpret_cast(voidPointer(throwArrayIndexOutOfBounds)))) - + BytesPerWord; + (reinterpret_cast(voidPointer(throwArrayIndexOutOfBounds)))); if (image) { image->aioobThunk = p->aioobThunk - imageBase; @@ -5325,7 +5613,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, start += p->thunkSize; \ { uint8_t* call = static_cast \ (tableContext.promise.listener->resolve \ - (reinterpret_cast(voidPointer(s)))) + BytesPerWord; \ + (reinterpret_cast(voidPointer(s)))); \ if (image) { \ image->s##Call = call - imageBase; \ } \ @@ -5339,25 +5627,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, MyProcessor* processor(MyThread* t) { - MyProcessor* p = static_cast(t->m->processor); - if (p->callTable == 0) { - ACQUIRE(t, t->m->classLock); - - if (p->callTable == 0) { - p->callTable = makeArray(t, 128, true); - - p->methodTree = p->methodTreeSentinal = makeTreeNode(t, 0, 0, 0); - set(t, p->methodTree, TreeNodeLeft, p->methodTreeSentinal); - set(t, p->methodTree, TreeNodeRight, p->methodTreeSentinal); - - compileThunks(t, codeZone(t), p, 0, 0); - - p->segFaultHandler.m = t->m; - expect(t, t->m->system->success - (t->m->system->handleSegFault(&(p->segFaultHandler)))); - } - } - return p; + return static_cast(t->m->processor); } object& @@ -5395,164 +5665,62 @@ compile(MyThread* t, Allocator* allocator, BootContext* bootContext, if (UNLIKELY(t->exception)) return; } - MyProcessor* p = processor(t); - - if (methodCompiled(t, method) == defaultThunk(t)) { + if (methodAddress(t, method) == defaultThunk(t)) { ACQUIRE(t, t->m->classLock); - if (methodCompiled(t, method) == defaultThunk(t)) { - if (methodCompiled(t, method) == defaultThunk(t)) { - object node; - uint8_t* compiled; - if (methodFlags(t, method) & ACC_NATIVE) { - node = 0; - compiled = p->nativeThunk; - } else { - Context context(t, bootContext, method); - compiled = compile(t, allocator, &context); - if (UNLIKELY(t->exception)) return; + if (methodAddress(t, method) == defaultThunk(t)) { + assert(t, (methodFlags(t, method) & ACC_NATIVE) == 0); - if (DebugMethodTree) { - fprintf(stderr, "insert method at %p\n", compiled); - } + Context context(t, bootContext, method); + uint8_t* compiled = compile(t, allocator, &context); + if (UNLIKELY(t->exception)) return; - // We can't set the MethodCompiled field on the original - // method before it is placed into the method tree, since - // another thread might call the method, from which stack - // unwinding would fail (since there is not yet an entry in - // the method tree). However, we can't insert the original - // method into the tree before setting the MethodCompiled - // field on it since we rely on that field to determine its - // position in the tree. Therefore, we insert a clone in - // its place. Later, we'll replace the clone with the - // original to save memory. - - object clone = makeMethod - (t, methodVmFlags(t, method), - methodReturnCode(t, method), - methodParameterCount(t, method), - methodParameterFootprint(t, method), - methodFlags(t, method), - methodOffset(t, method), - methodNativeID(t, method), - methodName(t, method), - methodSpec(t, method), - methodClass(t, method), - methodCode(t, method), - reinterpret_cast(compiled)); - - node = makeTreeNode - (t, clone, methodTreeSentinal(t), methodTreeSentinal(t)); - - PROTECT(t, node); - - methodTree(t) = treeInsertNode - (t, &(context.zone), methodTree(t), - reinterpret_cast(compiled), node, methodTreeSentinal(t), - compareIpToMethodBounds); - } - - methodCompiled(t, method) = reinterpret_cast(compiled); - - if (methodVirtual(t, method)) { - classVtable(t, methodClass(t, method), methodOffset(t, method)) - = compiled; - } - - if (node) { - set(t, node, TreeNodeValue, method); - } + if (DebugMethodTree) { + fprintf(stderr, "insert method at %p\n", compiled); } + + // We can't set the MethodCompiled field on the original method + // before it is placed into the method tree, since another + // thread might call the method, from which stack unwinding + // would fail (since there is not yet an entry in the method + // tree). However, we can't insert the original method into the + // tree before setting the MethodCompiled field on it since we + // rely on that field to determine its position in the tree. + // Therefore, we insert a clone in its place. Later, we'll + // replace the clone with the original to save memory. + + object clone = makeMethod + (t, methodVmFlags(t, method), + methodReturnCode(t, method), + methodParameterCount(t, method), + methodParameterFootprint(t, method), + methodFlags(t, method), + methodOffset(t, method), + methodNativeID(t, method), + methodName(t, method), + methodSpec(t, method), + methodClass(t, method), + methodCode(t, method), + reinterpret_cast(compiled)); + + methodTree(t) = treeInsert + (t, &(context.zone), methodTree(t), + reinterpret_cast(compiled), clone, methodTreeSentinal(t), + compareIpToMethodBounds); + + methodCompiled(t, method) = reinterpret_cast(compiled); + + if (methodVirtual(t, method)) { + classVtable(t, methodClass(t, method), methodOffset(t, method)) + = compiled; + } + + treeUpdate(t, methodTree(t), reinterpret_cast(compiled), + method, methodTreeSentinal(t), compareIpToMethodBounds); } } } -object -findCallNode(MyThread* t, void* address) -{ - if (DebugCallTable) { - fprintf(stderr, "find call node %p\n", address); - } - - MyProcessor* p = processor(t); - object table = p->callTable; - - intptr_t key = reinterpret_cast(address); - unsigned index = static_cast(key) - & (arrayLength(t, table) - 1); - - for (object n = arrayBody(t, table, index); - n; n = callNodeNext(t, n)) - { - intptr_t k = callNodeAddress(t, n); - - if (k == key) { - return n; - } - } - - return 0; -} - -object -resizeTable(MyThread* t, object oldTable, unsigned newLength) -{ - PROTECT(t, oldTable); - - object oldNode = 0; - PROTECT(t, oldNode); - - object newTable = makeArray(t, newLength, true); - PROTECT(t, newTable); - - for (unsigned i = 0; i < arrayLength(t, oldTable); ++i) { - for (oldNode = arrayBody(t, oldTable, i); - oldNode; - oldNode = callNodeNext(t, oldNode)) - { - intptr_t k = callNodeAddress(t, oldNode); - - unsigned index = k & (newLength - 1); - - object newNode = makeCallNode - (t, callNodeAddress(t, oldNode), - callNodeTarget(t, oldNode), - callNodeVirtualCall(t, oldNode), - arrayBody(t, newTable, index)); - - set(t, newTable, ArrayBody + (index * BytesPerWord), newNode); - } - } - - return newTable; -} - -void -insertCallNode(MyThread* t, object node) -{ - if (DebugCallTable) { - fprintf(stderr, "insert call node %p\n", - reinterpret_cast(callNodeAddress(t, node))); - } - - MyProcessor* p = processor(t); - PROTECT(t, node); - - ++ p->callTableSize; - - if (p->callTableSize >= arrayLength(t, p->callTable) * 2) { - p->callTable = resizeTable - (t, p->callTable, arrayLength(t, p->callTable) * 2); - } - - intptr_t key = callNodeAddress(t, node); - unsigned index = static_cast(key) - & (arrayLength(t, p->callTable) - 1); - - set(t, node, CallNodeNext, arrayBody(t, p->callTable, index)); - set(t, p->callTable, ArrayBody + (index * BytesPerWord), node); -} - object& methodTree(MyThread* t) { diff --git a/src/heap.cpp b/src/heap.cpp index 46c4f7526c..09f49f4bf8 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -528,12 +528,8 @@ class Context { lowMemoryThreshold(limit / 2), lock(0), - immortalPointerMap(&immortalHeap, 1, 1, 0, true), - immortalPageMap(&immortalHeap, 1, LikelyPageSizeInBytes / BytesPerWord, - &immortalPointerMap, true), - immortalHeapMap(&immortalHeap, 1, immortalPageMap.scale * 1024, - &immortalPageMap, true), - immortalHeap(this, &immortalHeapMap, 0, 0), + immortalHeapStart(0), + immortalHeapEnd(0), ageMap(&gen1, max(1, log(TenureThreshold)), 1, 0, false), gen1(this, &ageMap, 0, 0), @@ -586,15 +582,6 @@ class Context { nextGen1.dispose(); gen2.dispose(); nextGen2.dispose(); - - if (immortalHeapMap.data) { - free(this, immortalHeapMap.data, immortalHeapMap.size() * BytesPerWord); - } - - if (immortalPageMap.data) { - free(this, immortalPageMap.data, immortalPageMap.size() * BytesPerWord); - } - lock->dispose(); } @@ -613,10 +600,8 @@ class Context { System::Mutex* lock; - Segment::Map immortalPointerMap; - Segment::Map immortalPageMap; - Segment::Map immortalHeapMap; - Segment immortalHeap; + uintptr_t* immortalHeapStart; + uintptr_t* immortalHeapEnd; Segment::Map ageMap; Segment gen1; @@ -821,6 +806,7 @@ free(Context* c, Fixie** fixies) { for (Fixie** p = fixies; *p;) { Fixie* f = *p; + if (f->immortal()) { p = &(f->next); } else { @@ -959,6 +945,12 @@ copy(Context* c, void* o) return r; } +bool +immortalHeapContains(Context* c, void* p) +{ + return p < c->immortalHeapEnd and p >= c->immortalHeapStart; +} + void* update3(Context* c, void* o, bool* needsVisit) { @@ -976,6 +968,9 @@ update3(Context* c, void* o, bool* needsVisit) } *needsVisit = false; return o; + } else if (immortalHeapContains(c, o)) { + *needsVisit = false; + return o; } else if (wasCollected(c, o)) { *needsVisit = false; return follow(c, o); @@ -988,9 +983,7 @@ update3(Context* c, void* o, bool* needsVisit) void* update2(Context* c, void* o, bool* needsVisit) { - if (c->immortalHeap.contains(o) - or (c->mode == Heap::MinorCollection and c->gen2.contains(o))) - { + if (c->mode == Heap::MinorCollection and c->gen2.contains(o)) { *needsVisit = false; return o; } @@ -998,17 +991,6 @@ 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) { @@ -1023,7 +1005,11 @@ markClean(Context* c, Fixie* f) { if (f->dirty) { f->dirty = false; - f->move(c, &(c->tenuredFixies)); + if (f->immortal()) { + f->remove(c); + } else { + f->move(c, &(c->tenuredFixies)); + } } } @@ -1041,9 +1027,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); @@ -1051,8 +1038,8 @@ updateHeapMap(Context* c, void* p, void* target, unsigned offset, void* result) if (static_cast(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); } f->dirty = true; @@ -1711,34 +1698,9 @@ class MyHeap: public Heap { c.client = client; } - virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords, - uintptr_t* map) - { - new (&(c.immortalPointerMap)) Segment::Map - (&(c.immortalHeap), map, 1, 1, 0, false); - - unsigned pageMapScale = LikelyPageSizeInBytes / BytesPerWord; - unsigned pageMapSize = Segment::Map::calculateSize - (&c, sizeInWords, pageMapScale, 1); - uintptr_t* pageMap = static_cast - (allocate(pageMapSize * BytesPerWord)); - - new (&(c.immortalPageMap)) Segment::Map - (&(c.immortalHeap), pageMap, 1, pageMapScale, &(c.immortalPointerMap), - true); - - unsigned heapMapScale = pageMapScale * 1024; - unsigned heapMapSize = Segment::Map::calculateSize - (&c, sizeInWords, heapMapScale, 1); - uintptr_t* heapMap = static_cast - (allocate(heapMapSize * BytesPerWord)); - - new (&(c.immortalHeapMap)) Segment::Map - (&(c.immortalHeap), heapMap, 1, heapMapScale, &(c.immortalPageMap), - true); - - new (&(c.immortalHeap)) Segment - (&c, &(c.immortalHeapMap), start, sizeInWords, sizeInWords); + virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords) { + c.immortalHeapStart = start; + c.immortalHeapEnd = start + sizeInWords; } virtual void* tryAllocate(unsigned size) { @@ -1776,10 +1738,12 @@ class MyHeap: public Heap { { *totalInBytes = Fixie::totalSize(sizeInWords, objectMask); return (new (allocator->allocate(*totalInBytes)) - Fixie(sizeInWords, objectMask, &(c.tenuredFixies), true))->body(); + Fixie(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 { @@ -1809,8 +1773,8 @@ class MyHeap: public Heap { void** target = static_cast(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; diff --git a/src/heap.h b/src/heap.h index 4e213654c1..28f1533d8f 100644 --- a/src/heap.h +++ b/src/heap.h @@ -52,8 +52,7 @@ class Heap: public Allocator { }; virtual void setClient(Client* client) = 0; - virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords, - uintptr_t* map) = 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; diff --git a/src/machine.cpp b/src/machine.cpp index ed9e6b8ec6..309b5381e5 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1502,93 +1502,6 @@ bootJavaClass(Thread* t, Machine::Type type, int superType, const char* name, hashMapInsert(t, t->m->bootstrapClassMap, n, class_, byteArrayHash); } -void -boot(Thread* t, BootImage* image) -{ - assert(t, image->magic == BootImage::Magic); - - uintptr_t* heapMap = reinterpret_cast(image + 1); - unsigned heapMapSizeInWords = ceiling - (heapMapSize(image->heapSize), BytesPerWord); - uintptr_t* heap = heapMap + heapMapSizeInWords; - - for (unsigned word = 0; word < heapMapSizeInWords; ++word) { - uintptr_t w = heapMap[word]; - if (w) { - for (unsigned bit = 0; bit < BitsPerWord; ++bit) { - if (w & (static_cast(1) << bit)) { - uintptr_t* p = heap + indexOf(word, bit); - *p = reinterpret_cast(heap + (*p - 1)); - } - } - heapMap[word] = 0; - } - } - - t->m->heap->setImmortalHeap(heap, image->heapSize, heapMap); - - t->m->loader = bootObject(heap, image->loader); - t->m->stringMap = bootObject(heap, image->stringMap); - t->m->types = bootObject(heap, image->types); - - uintptr_t* codeMap = heap + ceiling(image->heapSize, BytesPerWord); - unsigned codeMapSizeInWords = ceiling - (codeMapSize(image->codeSize), BytesPerWord); - uint8_t* code = reinterpret_cast(codeMap + codeMapSizeInWords); - - for (unsigned word = 0; word < codeMapSizeInWords; ++word) { - uintptr_t w = codeMap[word]; - if (w) { - for (unsigned bit = 0; bit < BitsPerWord; ++bit) { - if (w & (static_cast(1) << bit)) { - unsigned index = indexOf(word, bit); - uintptr_t v; memcpy(&v, code + index, BytesPerWord); - v = reinterpret_cast(heap + v - 1); - memcpy(code + index, &v, BytesPerWord); - } - } - } - } - - t->m->processor->boot(t, image, heap, code); - - for (HashMapIterator it(t, systemClassLoaderMap(t, t->m->loader)); - it.hasMore();) - { - object c = tripleSecond(t, it.next()); - - 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)) { - assert(t, (methodCompiled(t, method) - image->codeBase) - <= image->codeSize); - - methodCompiled(t, method) - = (methodCompiled(t, method) - image->codeBase) - + reinterpret_cast(code); - - if (false and (methodFlags(t, method) & ACC_NATIVE) == 0) { - fprintf(stderr, "%p %p %s.%s%s\n", - reinterpret_cast(methodCompiled(t, method)), - reinterpret_cast(methodCompiled(t, method)) + - reinterpret_cast - (methodCompiled(t, method))[-1], - &byteArrayBody - (t, className(t, methodClass(t, method)), 0), - &byteArrayBody(t, methodName(t, method), 0), - &byteArrayBody(t, methodSpec(t, method), 0)); - } - } - } - } - - t->m->processor->initVtable(t, c); - } - - t->m->bootstrapClassMap = makeHashMap(t, 0, 0); -} - void boot(Thread* t) { @@ -1655,9 +1568,7 @@ boot(Thread* t) m->bootstrapClassMap = makeHashMap(t, 0, 0); - { object loaderMap = makeHashMap(t, 0, 0); - set(t, m->loader, SystemClassLoaderMap, loaderMap); - } + m->classMap = makeHashMap(t, 0, 0); m->stringMap = makeWeakHashMap(t, 0, 0); @@ -1785,6 +1696,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder, referenceLock(0), libraries(0), loader(0), + classMap(0), bootstrapClassMap(0), monitorMap(0), stringMap(0), @@ -1901,9 +1813,10 @@ Thread::init() m->unsafe = false; if (image) { - boot(this, image); + m->processor->boot(this, image); } else { boot(this); + m->processor->boot(this, 0); } m->monitorMap = makeWeakHashMap(this, 0, 0); @@ -2412,8 +2325,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 @@ -2517,8 +2429,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 @@ -2570,8 +2483,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); @@ -2908,6 +2820,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)); diff --git a/src/machine.h b/src/machine.h index becfd81e5c..25ac00d351 100644 --- a/src/machine.h +++ b/src/machine.h @@ -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) { diff --git a/src/processor.h b/src/processor.h index ee5d728de3..b4ada313b0 100644 --- a/src/processor.h +++ b/src/processor.h @@ -127,8 +127,11 @@ class Processor { 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, uintptr_t* heap, uint8_t* code) = 0; + boot(Thread* t, BootImage* image) = 0; object invoke(Thread* t, object method, object this_, ...) diff --git a/src/util.cpp b/src/util.cpp index f149e9c2e2..2fa3e4ae56 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -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 diff --git a/src/util.h b/src/util.h index ea8fc8b09c..9dcdd5730e 100644 --- a/src/util.h +++ b/src/util.h @@ -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: diff --git a/src/x86.cpp b/src/x86.cpp index cb7d778612..1722c2553d 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -146,7 +146,7 @@ resolveOffset(System* s, uint8_t* instruction, unsigned instructionSize, int32_t v4 = v; memcpy(instruction + instructionSize - 4, &v4, 4); - return instruction + instructionSize - 4; + return instruction + instructionSize; } class OffsetListener: public Promise::Listener { @@ -221,27 +221,30 @@ copy(System* s, void* dst, int64_t src, unsigned size) class ImmediateListener: public Promise::Listener { public: - ImmediateListener(System* s, void* dst, unsigned size): - s(s), dst(dst), size(size) + 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 dst; + return static_cast(dst) + offset; } System* s; void* dst; unsigned size; + unsigned offset; }; class ImmediateTask: public Task { public: - ImmediateTask(Task* next, Promise* promise, unsigned offset, unsigned size): + ImmediateTask(Task* next, Promise* promise, unsigned offset, unsigned size, + unsigned promiseOffset): Task(next), promise(promise), offset(offset), - size(size) + size(size), + promiseOffset(promiseOffset) { } virtual void run(Context* c) { @@ -249,21 +252,22 @@ class ImmediateTask: public Task { copy(c->s, c->result + offset, promise->value(), size); } else { new (promise->listen(sizeof(ImmediateListener))) - ImmediateListener(c->s, c->result + offset, size); + ImmediateListener(c->s, c->result + offset, size, promiseOffset); } } Promise* promise; unsigned offset; unsigned size; + unsigned promiseOffset; }; void appendImmediateTask(Context* c, Promise* promise, unsigned offset, - unsigned size) + unsigned size, unsigned promiseOffset = 0) { c->tasks = new (c->zone->allocate(sizeof(ImmediateTask))) ImmediateTask - (c->tasks, promise, offset, size); + (c->tasks, promise, offset, size, promiseOffset); } void @@ -378,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*); @@ -396,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); @@ -455,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); @@ -700,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(); @@ -722,54 +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(), BytesPerWord); + appendImmediateTask + (c, a->value, c->code.length(), BytesPerWord, promiseOffset); c->code.appendAddress(static_cast(0)); } } } void -moveCM(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Memory* b) +moveCR(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* 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: { - 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); - } + moveCR2(c, size, a, b, 0); } void @@ -857,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) @@ -2274,15 +2302,32 @@ class MyAssembler: public Assembler { bool assertAlignment UNUSED, void* returnAddress, void* newTarget) { - uint8_t* instruction = static_cast(returnAddress) - 5; - assert(&c, (op == LongCall and *instruction == 0xE8) - or (op == LongJump and *instruction == 0xE9)); - assert(&c, (not assertAlignment) - or reinterpret_cast(instruction + 1) % 4 == 0); + if (BytesPerWord == 4 or op == Call or op == Jump) { + uint8_t* instruction = static_cast(returnAddress) - 5; - int32_t v = static_cast(newTarget) - - static_cast(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(instruction + 1) % 4 == 0); + + int32_t v = static_cast(newTarget) + - static_cast(returnAddress); + memcpy(instruction + 1, &v, 4); + } else { + uint8_t* instruction = static_cast(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(instruction + 2) % 8 == 0); + + memcpy(instruction + 2, &newTarget, 8); + } } virtual void dispose() { From d4363d250a8a22a787d25ce51c4f4bb9fc0376da Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 2 Dec 2008 09:45:20 -0700 Subject: [PATCH 19/39] mark and fix up absolute addresses in boot image code --- src/assembler.h | 27 +++++++++++++++++++ src/bootimage.cpp | 23 +++++++++++++--- src/compile.cpp | 69 ++++++++++++++++++++++++++++++++++++----------- src/compiler.cpp | 22 +++++++++++++-- src/heap.cpp | 1 + src/processor.h | 3 ++- 6 files changed, 124 insertions(+), 21 deletions(-) diff --git a/src/assembler.h b/src/assembler.h index 7d3946274c..0677178e68 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -129,6 +129,33 @@ class ListenPromise: public Promise { 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(allocator->allocate(sizeInBytes)); + l->next = listener; + listener = l; + return l; + } + + Promise* basis; + DelayedPromise* next; }; class TraceHandler { diff --git a/src/bootimage.cpp b/src/bootimage.cpp index aa368258e0..7f7d12fc8f 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -33,7 +33,7 @@ endsWith(const char* suffix, const char* s, unsigned length) object makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, - unsigned capacity) + unsigned capacity, uintptr_t* codeMap) { unsigned size = 0; t->m->processor->compileThunks(t, image, code, &size, capacity); @@ -44,6 +44,8 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, 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); @@ -59,7 +61,8 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, 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, method); + (t, zone, code, &size, capacity, &constants, &calls, &addresses, + method); } } } @@ -79,6 +82,19 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, ->listener->resolve(address); } + for (; addresses; addresses = addresses->next) { + uint8_t* value = reinterpret_cast(addresses->basis->value()); + assert(t, value >= code); + + void* dst = addresses->listener->resolve + ((value - code) | (1 << BootShift)); + assert(t, reinterpret_cast(dst) + >= reinterpret_cast(code)); + + markBit(codeMap, reinterpret_cast(dst) + - reinterpret_cast(code)); + } + image->codeSize = size; return constants; @@ -250,7 +266,8 @@ writeBootImage(Thread* t, FILE* out) (t->m->heap->allocate(codeMapSize(CodeCapacity))); memset(codeMap, 0, codeMapSize(CodeCapacity)); - object constants = makeCodeImage(t, &zone, &image, code, CodeCapacity); + object constants = makeCodeImage + (t, &zone, &image, code, CodeCapacity, codeMap); PROTECT(t, constants); const unsigned HeapCapacity = 32 * 1024 * 1024; diff --git a/src/compile.cpp b/src/compile.cpp index 18c670a74f..bf84652cb0 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -466,13 +466,17 @@ class BootContext { BootContext* c; }; - BootContext(Thread* t, object constants, object calls, Zone* zone): - protector(t, this), constants(constants), calls(calls), zone(zone) + BootContext(Thread* t, object constants, object calls, + DelayedPromise* addresses, Zone* zone): + protector(t, this), constants(constants), calls(calls), + addresses(addresses), addressSentinal(addresses), zone(zone) { } MyProtector protector; object constants; object calls; + DelayedPromise* addresses; + DelayedPromise* addressSentinal; Zone* zone; }; @@ -856,6 +860,21 @@ class Frame { set(sp - 2, saved); } + Promise* addressPromise(Promise* p) { + BootContext* bc = context->bootContext; + if (bc) { + bc->addresses = new (bc->zone->allocate(sizeof(DelayedPromise))) + DelayedPromise(t->m->system, bc->zone, p, bc->addresses); + return bc->addresses; + } else { + return p; + } + } + + Compiler::Operand* addressOperand(Promise* p) { + return c->promiseConstant(addressPromise(p)); + } + Compiler::Operand* machineIp(unsigned logicalIp) { return c->promiseConstant(c->machineIp(logicalIp)); } @@ -2997,7 +3016,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, c->saveStack(); - frame->pushAddress(frame->machineIp(ip)); + frame->pushAddress(frame->addressOperand(c->machineIp(ip))); c->jmp(frame->machineIp(newIp)); // NB: we assume that the stack will look the same on return @@ -3145,8 +3164,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint32_t defaultIp = base + codeReadInt32(t, code, ip); assert(t, defaultIp < codeLength(t, code)); - Compiler::Operand* default_ = c->address - (c->poolAppendPromise(c->machineIp(defaultIp))); + Compiler::Operand* default_ = frame->addressOperand + (c->machineIp(defaultIp)); int32_t pairCount = codeReadInt32(t, code, ip); @@ -3162,9 +3181,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Promise* p = c->poolAppend(key); if (i == 0) { - start = c->promiseConstant(p); + start = frame->addressOperand(p); } - c->poolAppendPromise(c->machineIp(newIp)); + c->poolAppendPromise(frame->addressPromise(c->machineIp(newIp))); } assert(t, start); @@ -3475,9 +3494,10 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, ipTable[i] = newIp; - Promise* p = c->poolAppendPromise(c->machineIp(newIp)); + Promise* p = c->poolAppendPromise + (frame->addressPromise(c->machineIp(newIp))); if (i == 0) { - start = c->promiseConstant(p); + start = frame->addressOperand(p); } } assert(t, start); @@ -3854,6 +3874,17 @@ finish(MyThread* t, Allocator* allocator, Context* context) c->writeTo(start); + BootContext* bc = context->bootContext; + if (bc) { + for (DelayedPromise* p = bc->addresses; + p != bc->addressSentinal; + p = p->next) + { + p->basis = new (bc->zone->allocate(sizeof(ResolvedPromise))) + ResolvedPromise(p->basis->value()); + } + } + translateExceptionHandlerTable(t, c, methodCode(t, context->method), reinterpret_cast(start)); if (UNLIKELY(t->exception)) return 0; @@ -5063,16 +5094,18 @@ class MyProcessor: public Processor { virtual void compileMethod(Thread* vmt, Zone* zone, uint8_t* code, unsigned* offset, unsigned capacity, - object* constants, object* calls, object method) + object* constants, object* calls, + DelayedPromise** addresses, object method) { MyThread* t = static_cast(vmt); FixedAllocator allocator(t, code + *offset, capacity); - BootContext bootContext(t, *constants, *calls, zone); + BootContext bootContext(t, *constants, *calls, *addresses, zone); compile(t, &allocator, &bootContext, method); *constants = bootContext.constants; *calls = bootContext.calls; + *addresses = bootContext.addresses; *offset += allocator.offset; } @@ -5334,8 +5367,14 @@ fixupCode(Thread*, uintptr_t* map, unsigned size, uint8_t* code, if (w & (static_cast(1) << bit)) { unsigned index = indexOf(word, bit); uintptr_t v; memcpy(&v, code + index, BytesPerWord); - v = reinterpret_cast(heap + v - 1); - memcpy(code + index, &v, BytesPerWord); + uintptr_t mark = v >> BootShift; + if (mark) { + v = reinterpret_cast(code + (v & BootMask)); + memcpy(code + index, &v, BytesPerWord); + } else { + v = reinterpret_cast(heap + v - 1); + memcpy(code + index, &v, BytesPerWord); + } } } } @@ -5435,8 +5474,8 @@ boot(MyThread* t, BootImage* image) (codeMapSize(image->codeSize), BytesPerWord); uint8_t* code = reinterpret_cast(codeMap + codeMapSizeInWords); - fprintf(stderr, "code from %p to %p\n", - code, code + image->codeSize); +// fprintf(stderr, "code from %p to %p\n", +// code, code + image->codeSize); fixupHeap(t, heapMap, heapMapSizeInWords, heap); diff --git a/src/compiler.cpp b/src/compiler.cpp index 1ef9659829..7e80a91d2e 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -3060,8 +3060,26 @@ class MyCompiler: public Compiler { int i = 0; for (ConstantPoolNode* n = c.firstConstant; n; n = n->next) { - *reinterpret_cast(dst + pad(c.assembler->length()) + i) - = n->promise->value(); + intptr_t* target = reinterpret_cast + (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; } } diff --git a/src/heap.cpp b/src/heap.cpp index 09f49f4bf8..bea641e8e2 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -1759,6 +1759,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); } diff --git a/src/processor.h b/src/processor.h index b4ada313b0..94177a9abd 100644 --- a/src/processor.h +++ b/src/processor.h @@ -17,6 +17,7 @@ #include "bootimage.h" #include "heapwalk.h" #include "zone.h" +#include "assembler.h" namespace vm { @@ -122,7 +123,7 @@ class Processor { virtual void compileMethod(Thread* t, Zone* zone, uint8_t* code, unsigned* offset, unsigned capacity, object* constants, object* calls, - object method) = 0; + DelayedPromise** addresses, object method) = 0; virtual void visitRoots(BootImage* image, HeapWalker* w) = 0; From 4ec853d1bcec492e277a54347a4f9f6c7849c9b4 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 2 Dec 2008 19:37:16 -0700 Subject: [PATCH 20/39] include heapwalk.o in libavian.a if bootimage=true --- makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/makefile b/makefile index 341cf6e1c9..fdb7d60924 100644 --- a/makefile +++ b/makefile @@ -415,7 +415,7 @@ $(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 $(@) $(^) @@ -462,7 +462,6 @@ ifeq ($(platform),windows) else $(cc) $(^) $(rdynamic) $(lflags) -o $(@) endif - $(strip) $(strip-all) $(@) $(dynamic-library): \ $(vm-objects) $(dynamic-object) $(jni-objects) $(vm-heapwalk-objects) \ From bcfdc03631211c83d54027cb9804f8e1c095c8c6 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 2 Dec 2008 19:38:32 -0700 Subject: [PATCH 21/39] fix build breakage in heapdump.cpp --- src/heapdump.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/heapdump.cpp b/src/heapdump.cpp index b58fcceb56..8d4654fc55 100644 --- a/src/heapdump.cpp +++ b/src/heapdump.cpp @@ -8,6 +8,7 @@ There is NO WARRANTY for this software. See license.txt for details. */ +#include "machine.h" #include "heapwalk.h" using namespace vm; @@ -91,7 +92,7 @@ dumpHeap(Thread* t, FILE* out) write4(out, number); } - virtual void push(unsigned) { + virtual void push(object, unsigned, unsigned) { write1(out, Push); } From 851efc8d1011b6745d4e663dae67ce0e019bfa6d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 2 Dec 2008 19:39:09 -0700 Subject: [PATCH 22/39] handle case of unresolved promise in compareCR and compareCM --- src/x86.cpp | 49 ++++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/src/x86.cpp b/src/x86.cpp index 1722c2553d..baa9b23ba5 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -1746,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); @@ -1767,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) @@ -1798,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) From 4098368cb9eb9bbcfdf59cbcfac62833bffb34fd Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 2 Dec 2008 19:39:56 -0700 Subject: [PATCH 23/39] fix non-debug build of compile.cpp --- src/compile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compile.cpp b/src/compile.cpp index bf84652cb0..d9367bfd4c 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -5331,7 +5331,7 @@ makeCallTable(MyThread* t, uintptr_t* heap, unsigned* calls, unsigned count, } void -fixupHeap(MyThread* t, uintptr_t* map, unsigned size, uintptr_t* heap) +fixupHeap(MyThread* t UNUSED, uintptr_t* map, unsigned size, uintptr_t* heap) { for (unsigned word = 0; word < size; ++word) { uintptr_t w = map[word]; From 457c3d135ed3c81910079ef24864b29e84a6f1e8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 2 Dec 2008 19:41:22 -0700 Subject: [PATCH 24/39] return Tenured from MyHeap::status if the object resides in the immortal heap --- src/heap.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/heap.cpp b/src/heap.cpp index bea641e8e2..2ab6838343 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -203,7 +203,7 @@ class Segment { return n; } - static unsigned calculateSize(Context* c, unsigned capacity, + static unsigned calculateSize(Context* c UNUSED, unsigned capacity, unsigned scale, unsigned bitsPerRecord) { unsigned result @@ -459,7 +459,7 @@ class Fixie { } } - void remove(Context* c) { + void remove(Context* c UNUSED) { if (handle) { assert(c, *handle == this); *handle = next; @@ -884,6 +884,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) { @@ -920,6 +926,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); @@ -945,12 +952,6 @@ copy(Context* c, void* o) return r; } -bool -immortalHeapContains(Context* c, void* p) -{ - return p < c->immortalHeapEnd and p >= c->immortalHeapStart; -} - void* update3(Context* c, void* o, bool* needsVisit) { @@ -1832,6 +1833,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))) From 93d4fbc43ddaf5cd05a47b7f2bd1620c76af0d88 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 3 Dec 2008 08:44:07 -0700 Subject: [PATCH 25/39] fix platform=windows and process=interpret builds --- src/interpret.cpp | 28 +++++++++++++++++++++++++++- src/windows.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/src/interpret.cpp b/src/interpret.cpp index 604a97d43f..db55168865 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -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)); } diff --git a/src/windows.cpp b/src/windows.cpp index de295d90b0..59c6bbacce 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -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; } } From db3434001ff88fa9ed2092ad59e61ba464ef6606 Mon Sep 17 00:00:00 2001 From: Rich Scott Date: Wed, 3 Dec 2008 13:12:49 -0700 Subject: [PATCH 26/39] Use mingw32 'strip' when compiling for Windows. This fixes the error when using /usr/bin/strip on Ubuntu 8.10 when it believes the target file is of an "ambiguous format". --- makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/makefile b/makefile index 3e4b0e989a..b195da9efb 100644 --- a/makefile +++ b/makefile @@ -123,6 +123,7 @@ ifeq ($(platform),windows) ar = i586-mingw32msvc-ar ranlib = i586-mingw32msvc-ranlib objcopy = i586-mingw32msvc-objcopy + strip = i586-mingw32msvc-strip else build-cflags = $(common-cflags) \ "-I$(JAVA_HOME)/include/win32" -I$(src) -mthreads @@ -150,11 +151,9 @@ ifeq ($(mode),stress-major) endif ifeq ($(mode),fast) cflags += -O3 -g3 -DNDEBUG - strip = strip endif ifeq ($(mode),small) cflags += -Os -g3 -DNDEBUG - strip = strip endif cpp-objects = $(foreach x,$(1),$(patsubst $(2)/%.cpp,$(3)/%.o,$(x))) From 58a90f2b84a4d7624d6debdcbc728b66e1f7fb65 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 3 Dec 2008 19:09:57 -0700 Subject: [PATCH 27/39] fix regressions for non-bootimage case --- src/heap.cpp | 29 ++++++++++++++++++----------- src/machine.cpp | 3 ++- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/heap.cpp b/src/heap.cpp index 2ab6838343..f04d5de2c3 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -430,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()); } @@ -448,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; @@ -467,6 +473,7 @@ class Fixie { if (next) { next->handle = handle; } + next = 0; handle = 0; } @@ -476,7 +483,7 @@ class Fixie { } remove(c); - add(handle); + add(c, handle); } void** body() { @@ -857,14 +864,14 @@ sweepFixies(Context* c) } if (f->dirty) { - f->add(&(c->dirtyTenuredFixies)); + f->add(c, &(c->dirtyTenuredFixies)); } else { - f->add(&(c->tenuredFixies)); + f->add(c, &(c->tenuredFixies)); } } else { c->untenuredFixieFootprint += f->totalSize(); - f->add(&(c->fixies)); + f->add(c, &(c->fixies)); } f->marked = false; @@ -1470,7 +1477,7 @@ visitMarkedFixies(Context* c) c->client->walk(f->body(), &w); - f->add(&(c->visitedFixies)); + f->move(c, &(c->visitedFixies)); } } @@ -1730,7 +1737,7 @@ 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* allocateImmortalFixed(Allocator* allocator, @@ -1739,7 +1746,7 @@ class MyHeap: public Heap { { *totalInBytes = Fixie::totalSize(sizeInWords, objectMask); return (new (allocator->allocate(*totalInBytes)) - Fixie(sizeInWords, objectMask, 0, true))->body(); + Fixie(&c, sizeInWords, objectMask, 0, true))->body(); } virtual bool needsMark(void* p) { diff --git a/src/machine.cpp b/src/machine.cpp index 309b5381e5..dfa94cd66b 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1572,6 +1572,8 @@ boot(Thread* t) 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 @@ -1816,7 +1818,6 @@ Thread::init() m->processor->boot(this, image); } else { boot(this); - m->processor->boot(this, 0); } m->monitorMap = makeWeakHashMap(this, 0, 0); From aa7b47eec4f2a0b51ae1d966216f528071c7cd0e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 4 Dec 2008 14:35:25 -0700 Subject: [PATCH 28/39] fix merge confict fallout in heapdump.cpp --- src/heapdump.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/heapdump.cpp b/src/heapdump.cpp index 9ab8496448..f45c225aaf 100644 --- a/src/heapdump.cpp +++ b/src/heapdump.cpp @@ -26,7 +26,7 @@ enum { void write1(FILE* out, uint8_t v) { - size_t n UNUSED = fwrite(&v, 1, 1, c->out); + size_t n UNUSED = fwrite(&v, 1, 1, out); } void @@ -39,7 +39,7 @@ write4(FILE* out, uint32_t v) void writeString(FILE* out, int8_t* p, unsigned size) { - write4(c, size); + write4(out, size); size_t n UNUSED = fwrite(p, size, 1, out); } From c479bccdb431e7ee4954828e938776ddc17c9b04 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 4 Dec 2008 17:24:38 -0700 Subject: [PATCH 29/39] support cross-platform bootimage build (as long as the build arch matches the target arch --- makefile | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index c7b6f30991..42b29c807e 100644 --- a/makefile +++ b/makefile @@ -230,12 +230,17 @@ 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-generator = \ + $(build)/$(build-platform)-$(build-arch)-compile-fast/bootimage-generator bootimage-bin = $(native-build)/bootimage.bin bootimage-object = $(native-build)/bootimage-bin.o ifeq ($(bootimage),true) + ifneq ($(build-arch),$(arch)) + error "can't cross-build a bootimage" + endif + vm-classpath-object = $(bootimage-object) cflags += -DBOOT_IMAGE=\"bootimageBin\" else @@ -450,7 +455,16 @@ else endif $(strip) $(strip-all) $(@) -$(bootimage-generator): \ +$(bootimage-generator): + (unset MAKEFLAGS && \ + make mode=fast process=compile \ + arch=$(build-arch) \ + platform=$(build-platform) \ + bootimage-generator= \ + build-bootimage-generator=$(bootimage-generator) \ + $(bootimage-generator)) + +$(build-bootimage-generator): \ $(vm-objects) $(classpath-object) $(jni-objects) $(heapwalk-objects) \ $(bootimage-generator-objects) @echo "linking $(@)" From 7ce35b212f9d68905f70d2df18c054410a6a747c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 18 Dec 2008 10:10:19 -0700 Subject: [PATCH 30/39] fix GCC 4.0.1 uninitialized value warning --- src/bootimage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootimage.cpp b/src/bootimage.cpp index 7f7d12fc8f..9291acdfd0 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -47,7 +47,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, DelayedPromise* addresses = 0; for (Finder::Iterator it(t->m->finder); it.hasMore();) { - unsigned nameSize; + unsigned nameSize = 0; const char* name = it.next(&nameSize); if (endsWith(".class", name, nameSize)) { From 5e727c8c5dced9c39530ef05ffc21deba4125752 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 18 Dec 2008 16:32:18 -0700 Subject: [PATCH 31/39] throw an error if a volatile field is encountered, since we don't yet support them properly --- src/compile.cpp | 2 ++ src/interpret.cpp | 6 ++++++ src/process.h | 15 +++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/src/compile.cpp b/src/compile.cpp index d9367bfd4c..44e27ed088 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -2483,6 +2483,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, object field = resolveField(t, codePool(t, code), index - 1); if (UNLIKELY(t->exception)) return; + if (throwIfVolatileField(t, field)) return; Compiler::Operand* table; @@ -3363,6 +3364,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, object field = resolveField(t, codePool(t, code), index - 1); if (UNLIKELY(t->exception)) return; + if (throwIfVolatileField(t, field)) return; object staticTable = 0; diff --git a/src/interpret.cpp b/src/interpret.cpp index db55168865..72421baf6a 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -1452,6 +1452,7 @@ interpret(Thread* t) object field = resolveField(t, codePool(t, code), index - 1); if (UNLIKELY(exception)) goto throw_; + if (throwIfVolatileField(t, field)) goto throw_; pushField(t, popObject(t), field); } else { @@ -1465,6 +1466,8 @@ interpret(Thread* t) object field = resolveField(t, codePool(t, code), index - 1); if (UNLIKELY(exception)) goto throw_; + if (throwIfVolatileField(t, field)) goto throw_; + PROTECT(t, field); if (UNLIKELY(classInit(t, fieldClass(t, field), 3))) goto invoke; @@ -2396,6 +2399,7 @@ interpret(Thread* t) object field = resolveField(t, codePool(t, code), index - 1); if (UNLIKELY(exception)) goto throw_; + if (throwIfVolatileField(t, field)) goto throw_; switch (fieldCode(t, field)) { case ByteField: @@ -2461,6 +2465,8 @@ interpret(Thread* t) object field = resolveField(t, codePool(t, code), index - 1); if (UNLIKELY(exception)) goto throw_; + if (throwIfVolatileField(t, field)) goto throw_; + PROTECT(t, field); if (UNLIKELY(classInit(t, fieldClass(t, field), 3))) goto invoke; diff --git a/src/process.h b/src/process.h index 78c231b307..8be25c0bd0 100644 --- a/src/process.h +++ b/src/process.h @@ -188,6 +188,21 @@ populateMultiArray(Thread* t, object array, int32_t* counts, int findLineNumber(Thread* t, object method, unsigned ip); +inline bool +throwIfVolatileField(Thread* t, object field) +{ + if (fieldFlags(t, field) & ACC_VOLATILE) { + object message = makeString + (t, "volatile fields are not yet supported: %s.%s", + &byteArrayBody(t, className(t, fieldClass(t, field)), 0), + &byteArrayBody(t, fieldName(t, field), 0)); + t->exception = makeNoSuchFieldError(t, message); + return true; + } else { + return false; + } +} + } // namespace vm #endif//PROCESS_H From 2622773eb42976dd2ae998135e2c11d387ebf901 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 18 Dec 2008 19:52:03 -0700 Subject: [PATCH 32/39] support bootimage build on OS X --- makefile | 11 +++++++---- src/binaryToMacho.cpp | 21 ++++++++++++++------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/makefile b/makefile index 42b29c807e..157cc9bb9c 100644 --- a/makefile +++ b/makefile @@ -94,6 +94,9 @@ endif ifeq ($(platform),darwin) build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src) lflags = $(common-lflags) -ldl -framework CoreFoundation + ifeq ($(bootimage),true) + bootimage-lflags = -Wl,-segprot,__BOOT,rwx,rwx + endif rdynamic = strip-all = -S -x binaryToMacho = $(native-build)/binaryToMacho @@ -401,7 +404,7 @@ $(binaryToMacho): $(src)/binaryToMacho.cpp $(classpath-object): $(build)/classpath.jar $(binaryToMacho) @echo "creating $(@)" ifeq ($(platform),darwin) - $(binaryToMacho) $(build)/classpath.jar \ + $(binaryToMacho) $(build)/classpath.jar __TEXT __text \ __binary_classpath_jar_start __binary_classpath_jar_end > $(@) else (wd=$$(pwd); \ @@ -431,7 +434,7 @@ $(bootimage-bin): $(bootimage-generator) $(bootimage-object): $(bootimage-bin) @echo "creating $(@)" ifeq ($(platform),darwin) - $(binaryToMacho) $(<) \ + $(binaryToMacho) $(<) __BOOT __boot \ __binary_bootimage_bin_start __binary_bootimage_bin_end > $(@) else (wd=$$(pwd); \ @@ -451,7 +454,7 @@ ifeq ($(platform),windows) $(dlltool) -d $(@).def -e $(@).exp $(cc) $(@).exp $(^) $(lflags) -o $(@) else - $(cc) $(^) $(rdynamic) $(lflags) -o $(@) + $(cc) $(^) $(rdynamic) $(lflags) $(bootimage-lflags) -o $(@) endif $(strip) $(strip-all) $(@) @@ -480,7 +483,7 @@ $(dynamic-library): \ $(vm-objects) $(dynamic-object) $(jni-objects) $(vm-heapwalk-objects) \ $(boot-object) $(vm-classpath-object) @echo "linking $(@)" - $(cc) $(^) $(shared) $(lflags) -o $(@) + $(cc) $(^) $(shared) $(lflags) $(bootimage-lflags) -o $(@) $(strip) $(strip-all) $(@) $(executable-dynamic): $(driver-dynamic-object) $(dynamic-library) diff --git a/src/binaryToMacho.cpp b/src/binaryToMacho.cpp index 013b9bfc7f..88259b81cb 100644 --- a/src/binaryToMacho.cpp +++ b/src/binaryToMacho.cpp @@ -30,6 +30,7 @@ pad(unsigned n) void writeObject(FILE* out, const uint8_t* data, unsigned size, + const char* segmentName, const char* sectionName, const char* startName, const char* endName) { unsigned startNameLength = strlen(startName) + 1; @@ -39,7 +40,7 @@ writeObject(FILE* out, const uint8_t* data, unsigned size, MH_MAGIC, // magic CPU_TYPE_I386, // cputype CPU_SUBTYPE_I386_ALL, // cpusubtype - MH_OBJECT, // filetype, + MH_OBJECT, // filetype 2, // ncmds sizeof(segment_command) + sizeof(section) @@ -50,7 +51,7 @@ writeObject(FILE* out, const uint8_t* data, unsigned size, segment_command segment = { LC_SEGMENT, // cmd sizeof(segment_command) + sizeof(section), // cmdsize - "__TEXT", // segname + "", // segname 0, // vmaddr pad(size), // vmsize sizeof(mach_header) @@ -64,9 +65,11 @@ writeObject(FILE* out, const uint8_t* data, unsigned size, 0 // flags }; + strncpy(segment.segname, segmentName, sizeof(segment.segname)); + section sect = { - "__const", // sectname - "__TEXT", // segname + "", // sectname + "", // segname 0, // addr pad(size), // size sizeof(mach_header) @@ -81,6 +84,9 @@ writeObject(FILE* out, const uint8_t* data, unsigned size, 0, // reserved2 }; + strncpy(sect.segname, segmentName, sizeof(sect.segname)); + strncpy(sect.sectname, sectionName, sizeof(sect.sectname)); + symtab_command symbolTable = { LC_SYMTAB, // cmd sizeof(symtab_command), // cmdsize @@ -136,9 +142,10 @@ writeObject(FILE* out, const uint8_t* data, unsigned size, int main(int argc, const char** argv) { - if (argc != 4) { + if (argc != 6) { fprintf(stderr, - "usage: %s \n", + "usage: %s
" + " \n", argv[0]); return -1; } @@ -158,7 +165,7 @@ main(int argc, const char** argv) } if (data) { - writeObject(stdout, data, size, argv[2], argv[3]); + writeObject(stdout, data, size, argv[2], argv[3], argv[4], argv[5]); munmap(data, size); return 0; } else { From 21df2e915326e7f58275661e68da4a09306c8d08 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 18 Dec 2008 20:01:18 -0700 Subject: [PATCH 33/39] update readme.txt to indicate new binaryToMacho arguments --- readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index c4e80a3cfd..81ebc28d86 100644 --- a/readme.txt +++ b/readme.txt @@ -174,7 +174,7 @@ for darwin-i386: (objcopy is not currently supported on this platform, so we use the binaryToMacho utility instead) $ ../build/darwin-i386-compile-fast/binaryToMacho boot.jar \ - __binary_boot_jar_start __binary_boot_jar_end > boot-jar.o + __TEXT __text __binary_boot_jar_start __binary_boot_jar_end > boot-jar.o Step 4: Write a driver which starts the VM and runs the desired main From 368c804bb736c189970d489511817605b4693183 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 18 Dec 2008 20:10:25 -0700 Subject: [PATCH 34/39] bootimage-object should depend on binaryToMacho --- makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile b/makefile index 157cc9bb9c..87fc2329f1 100644 --- a/makefile +++ b/makefile @@ -431,7 +431,7 @@ $(static-library): $(vm-objects) $(jni-objects) $(vm-heapwalk-objects) $(bootimage-bin): $(bootimage-generator) $(<) $(classpath-build) > $(@) -$(bootimage-object): $(bootimage-bin) +$(bootimage-object): $(bootimage-bin) $(binaryToMacho) @echo "creating $(@)" ifeq ($(platform),darwin) $(binaryToMacho) $(<) __BOOT __boot \ From bd89b8e00a7beb5c7ef0784a50019de104ab364f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 18 Dec 2008 20:23:08 -0700 Subject: [PATCH 35/39] check for null array in HashMapIterator::find --- src/util.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/util.h b/src/util.h index 9dcdd5730e..bf895f6bae 100644 --- a/src/util.h +++ b/src/util.h @@ -107,11 +107,13 @@ class HashMapIterator: public Thread::Protector { 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; - return; + if (array) { + for (unsigned i = index; i < arrayLength(t, array); ++i) { + if (arrayBody(t, array, i)) { + node = arrayBody(t, array, i); + index = i + 1; + return; + } } } node = 0; From e86acf45431d4d4a5837ac14576cef4025299c31 Mon Sep 17 00:00:00 2001 From: JET Date: Fri, 2 Jan 2009 13:25:05 -0700 Subject: [PATCH 36/39] added separator to String and added IOException to vm.pro --- classpath/java/io/File.java | 2 ++ vm.pro | 1 + 2 files changed, 3 insertions(+) diff --git a/classpath/java/io/File.java b/classpath/java/io/File.java index 0f91ebb746..96697c9af2 100644 --- a/classpath/java/io/File.java +++ b/classpath/java/io/File.java @@ -14,6 +14,8 @@ public class File { private static final String FileSeparator = System.getProperty("file.separator"); + public static final String separator = FileSeparator; + // static { // System.loadLibrary("natives"); // } diff --git a/vm.pro b/vm.pro index 7e024896ce..ad77a5eb57 100644 --- a/vm.pro +++ b/vm.pro @@ -50,6 +50,7 @@ -keep public class java.lang.ExceptionInInitializerError -keep public class java.lang.OutOfMemoryError -keep public class java.lang.reflect.InvocationTargetException +-keep public class java.io.IOException # ClassLoader.getSystemClassloader() depends on the existence of this class: From 54ad7c4e98558f4e423a104cc473997330589d07 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 10 Jan 2009 12:25:52 -0700 Subject: [PATCH 37/39] tolerate ConstantValue attributes on non-static fields, since the compiler ensures that they are initialized in any constructors for that class (i.e., the VM does not need to do anything special to initialize them) --- src/compile.cpp | 8 ++++++++ src/interpret.cpp | 10 +++++++++- src/machine.cpp | 4 ---- test/Misc.java | 4 ++++ 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 44e27ed088..89e1b6d658 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -2488,6 +2488,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* table; if (instruction == getstatic) { + assert(t, fieldFlags(t, field) & ACC_STATIC); + if (fieldClass(t, field) != methodClass(t, context->method) and classNeedsInit(t, fieldClass(t, field))) { @@ -2501,6 +2503,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, table = frame->append(classStaticTable(t, fieldClass(t, field))); } else { + assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); + table = frame->popObject(); } @@ -3369,6 +3373,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, object staticTable = 0; if (instruction == putstatic) { + assert(t, fieldFlags(t, field) & ACC_STATIC); + if (fieldClass(t, field) != methodClass(t, context->method) and classNeedsInit(t, fieldClass(t, field))) { @@ -3381,6 +3387,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } staticTable = classStaticTable(t, fieldClass(t, field)); + } else { + assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); } Compiler::Operand* value; diff --git a/src/interpret.cpp b/src/interpret.cpp index 72421baf6a..d3919f7117 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -1453,7 +1453,9 @@ interpret(Thread* t) object field = resolveField(t, codePool(t, code), index - 1); if (UNLIKELY(exception)) goto throw_; if (throwIfVolatileField(t, field)) goto throw_; - + + assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); + pushField(t, popObject(t), field); } else { exception = makeNullPointerException(t); @@ -1468,6 +1470,8 @@ interpret(Thread* t) if (UNLIKELY(exception)) goto throw_; if (throwIfVolatileField(t, field)) goto throw_; + assert(t, fieldFlags(t, field) & ACC_STATIC); + PROTECT(t, field); if (UNLIKELY(classInit(t, fieldClass(t, field), 3))) goto invoke; @@ -2401,6 +2405,8 @@ interpret(Thread* t) if (UNLIKELY(exception)) goto throw_; if (throwIfVolatileField(t, field)) goto throw_; + assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); + switch (fieldCode(t, field)) { case ByteField: case BooleanField: @@ -2467,6 +2473,8 @@ interpret(Thread* t) if (UNLIKELY(exception)) goto throw_; if (throwIfVolatileField(t, field)) goto throw_; + assert(t, fieldFlags(t, field) & ACC_STATIC); + PROTECT(t, field); if (UNLIKELY(classInit(t, fieldClass(t, field), 3))) goto invoke; diff --git a/src/machine.cpp b/src/machine.cpp index dfa94cd66b..cd5c552487 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -835,10 +835,6 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) staticTypes[staticCount++] = code; } else { - if (value) { - abort(t); // todo: handle non-static field initializers - } - unsigned excess = (memberOffset % fieldSize(t, code)) % BytesPerWord; if (excess) { memberOffset += BytesPerWord - excess; diff --git a/test/Misc.java b/test/Misc.java index be83804e78..80c6bd7535 100644 --- a/test/Misc.java +++ b/test/Misc.java @@ -3,6 +3,8 @@ public class Misc { private static int beta; private static byte byte1, byte2, byte3; + private final int NonStaticConstant = 42; + private int gamma; private int pajama; private boolean boolean1; @@ -338,6 +340,8 @@ public class Misc { { Misc m = new Misc(); m.toString(); + expect(m.NonStaticConstant == 42); + expect(m.time == 0xffffffffffffffffL); long t = m.time; expect(t == 0xffffffffffffffffL); From 277278b33187ee069563258b2553b6d8a818ee66 Mon Sep 17 00:00:00 2001 From: Ryan Forbes Date: Tue, 3 Feb 2009 15:28:39 -0700 Subject: [PATCH 38/39] Fixed off by one in list method. --- classpath/java/io/File.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classpath/java/io/File.java b/classpath/java/io/File.java index 96697c9af2..7e961ce138 100644 --- a/classpath/java/io/File.java +++ b/classpath/java/io/File.java @@ -159,7 +159,7 @@ public class File { } String[] result = new String[count]; - for (int i = count; i >= 0; --i) { + for (int i = count - 1; i >= 0; --i) { result[i] = list.value; list = list.next; } From 46e19f9c80e6fd24b7d20e05dced4e76193ddd81 Mon Sep 17 00:00:00 2001 From: Ryan Forbes Date: Tue, 3 Feb 2009 15:30:03 -0700 Subject: [PATCH 39/39] Fixed bug where seconds were always zero because % was misspelled as / --- classpath/java/util/Calendar.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classpath/java/util/Calendar.java b/classpath/java/util/Calendar.java index d39b8a1438..629eaced15 100644 --- a/classpath/java/util/Calendar.java +++ b/classpath/java/util/Calendar.java @@ -126,7 +126,7 @@ public abstract class Calendar { int hour = remainder / MILLIS_PER_HOUR; remainder = remainder % MILLIS_PER_HOUR; int minute = remainder / MILLIS_PER_MINUTE; - remainder = remainder / MILLIS_PER_MINUTE; + remainder = remainder % MILLIS_PER_MINUTE; int second = remainder / MILLIS_PER_SECOND; fields[YEAR] = year; fields[MONTH] = month;