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;