From f698c24ea6d0aedc81a6013c83d444be6fbe54af Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 27 Nov 2008 13:59:40 -0700 Subject: [PATCH] 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); } }