delay resolving method call offsets until all methods have been compiled when creating a boot image

This commit is contained in:
Joel Dice
2008-11-27 13:59:40 -07:00
parent 035aa0ecd4
commit f698c24ea6
5 changed files with 176 additions and 122 deletions

View File

@ -78,9 +78,14 @@ const int AnyRegister = -2;
class Promise { class Promise {
public: public:
class Listener {
public:
virtual void* resolve(int64_t value) = 0;
};
virtual int64_t value() = 0; virtual int64_t value() = 0;
virtual bool resolved() = 0; virtual bool resolved() = 0;
virtual bool offer(void*) { return false; } virtual Listener* listen(unsigned) { return 0; }
}; };
class ResolvedPromise: public Promise { class ResolvedPromise: public Promise {
@ -98,9 +103,11 @@ class ResolvedPromise: public Promise {
int64_t value_; int64_t value_;
}; };
class OfferPromise: public Promise { class ListenPromise: public Promise {
public: public:
OfferPromise(System* s): s(s), offset(0) { } ListenPromise(System* s, Allocator* allocator):
s(s), allocator(allocator), listener(0)
{ }
virtual int64_t value() { virtual int64_t value() {
abort(s); abort(s);
@ -110,13 +117,13 @@ class OfferPromise: public Promise {
return false; return false;
} }
virtual bool offer(void* offset) { virtual Listener* listen(unsigned sizeInBytes) {
this->offset = offset; return listener = static_cast<Listener*>(allocator->allocate(sizeInBytes));
return true;
} }
System* s; System* s;
void* offset; Allocator* allocator;
Listener* listener;
}; };
class TraceHandler { class TraceHandler {

View File

@ -43,10 +43,13 @@ makeCodeImage(Thread* t, BootImage* image, uint8_t* code, unsigned capacity)
unsigned size; unsigned size;
t->m->processor->compileThunks(t, image, code, &size, capacity); 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); 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();) { for (Finder::Iterator it(t->m->finder); it.hasMore();) {
unsigned nameSize; unsigned nameSize;
@ -61,15 +64,20 @@ makeCodeImage(Thread* t, BootImage* image, uint8_t* code, unsigned capacity)
object method = arrayBody(t, classMethodTable(t, c), i); object method = arrayBody(t, classMethodTable(t, c), i);
if (methodCode(t, method)) { if (methodCode(t, method)) {
t->m->processor->compileMethod 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<ListenPromise*>(pointerValue(t, tripleSecond(t, calls)))
->listener->resolve(methodCompiled(t, tripleFirst(t, calls)));
}
image->codeSize = size; image->codeSize = size;
return objectTable; return constants;
} }
unsigned unsigned
@ -167,27 +175,21 @@ makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map,
} }
void 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) HeapMap* heapTable)
{ {
intptr_t i = 0; for (; constants; constants = tripleThird(t, constants)) {
for (HashMapIterator it(t, codeTable); it.hasMore(); ++i) { intptr_t target = heapTable->find(tripleFirst(t, constants));
object mapEntry = it.next();
intptr_t target = heapTable->find(tripleFirst(t, mapEntry));
assert(t, target >= 0); assert(t, target >= 0);
for (object fixup = tripleSecond(t, mapEntry); void* dst = static_cast<ListenPromise*>
fixup; (pointerValue(t, tripleSecond(t, constants)))->listener->resolve(target);
fixup = pairSecond(t, fixup))
{
OfferPromise* p = static_cast<OfferPromise*>
(pointerValue(t, pairFirst(t, fixup)));
assert(t, p->offset);
memcpy(p->offset, &target, BytesPerWord); assert(t, reinterpret_cast<intptr_t>(dst)
markBit(codeMap, reinterpret_cast<intptr_t>(p->offset) >= reinterpret_cast<intptr_t>(code));
- reinterpret_cast<intptr_t>(code));
} markBit(codeMap, reinterpret_cast<intptr_t>(dst)
- reinterpret_cast<intptr_t>(code));
} }
} }
@ -208,7 +210,7 @@ writeBootImage(Thread* t, FILE* out)
(t->m->heap->allocate(codeMapSize(CodeCapacity))); (t->m->heap->allocate(codeMapSize(CodeCapacity)));
memset(codeMap, 0, 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; const unsigned HeapCapacity = 32 * 1024 * 1024;
uintptr_t* heap = static_cast<uintptr_t*> uintptr_t* heap = static_cast<uintptr_t*>
@ -220,7 +222,7 @@ writeBootImage(Thread* t, FILE* out)
HeapWalker* heapWalker = makeHeapImage HeapWalker* heapWalker = makeHeapImage
(t, &image, heap, heapMap, HeapCapacity); (t, &image, heap, heapMap, HeapCapacity);
updateCodeTable(t, codeTable, code, codeMap, heapWalker->map()); updateConstants(t, constants, code, codeMap, heapWalker->map());
heapWalker->dispose(); heapWalker->dispose();

View File

@ -131,7 +131,7 @@ compareIpToMethodBounds(Thread* t, intptr_t ip, object method)
if (ip < start) { if (ip < start) {
return -1; return -1;
} else if (ip < start + compiledSize(start)) } else if (ip < start + static_cast<intptr_t>(compiledSize(start)))
{ {
return 0; return 0;
} else { } else {
@ -458,18 +458,20 @@ class BootContext {
MyProtector(Thread* t, BootContext* c): Protector(t), c(c) { } MyProtector(Thread* t, BootContext* c): Protector(t), c(c) { }
virtual void visit(Heap::Visitor* v) { virtual void visit(Heap::Visitor* v) {
v->visit(&(c->objectTable)); v->visit(&(c->constants));
v->visit(&(c->calls));
} }
BootContext* c; BootContext* c;
}; };
BootContext(Thread* t, object objectTable, Zone* zone): BootContext(Thread* t, object constants, object calls, Zone* zone):
protector(t, this), objectTable(objectTable), zone(zone) protector(t, this), constants(constants), calls(calls), zone(zone)
{ } { }
MyProtector protector; MyProtector protector;
object objectTable; object constants;
object calls;
Zone* zone; Zone* zone;
}; };
@ -638,24 +640,12 @@ class Frame {
if (context->bootContext) { if (context->bootContext) {
BootContext* bc = context->bootContext; BootContext* bc = context->bootContext;
object node = hashMapFindNode Promise* p = new (bc->zone->allocate(sizeof(ListenPromise)))
(t, bc->objectTable, o, objectHash, objectEqual); ListenPromise(t->m->system, bc->zone);
PROTECT(t, node);
Promise* p = new (bc->zone->allocate(sizeof(OfferPromise)))
OfferPromise(t->m->system);
PROTECT(t, o);
object pointer = makePointer(t, p); object pointer = makePointer(t, p);
bc->constants = makeTriple(t, o, pointer, bc->constants);
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); return c->promiseConstant(p);
} else { } else {
@ -1745,26 +1735,37 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target)
frame->trace(target, false), frame->trace(target, false),
rSize, rSize,
0); 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 { } else {
result = c->call BootContext* bc = frame->context->bootContext;
(c->constant(methodCompiled(t, target)), if (bc) {
0, Promise* p = new (bc->zone->allocate(sizeof(ListenPromise)))
frame->trace(0, false), ListenPromise(t->m->system, bc->zone);
rSize,
0); 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, virtual void compileMethod(Thread* vmt, Zone* zone, uint8_t* code,
unsigned* offset, unsigned capacity, object table, unsigned* offset, unsigned capacity,
object method) object* constants, object* calls, object method)
{ {
MyThread* t = static_cast<MyThread*>(vmt); MyThread* t = static_cast<MyThread*>(vmt);
FixedAllocator allocator(t, code + *offset, capacity); FixedAllocator allocator(t, code + *offset, capacity);
BootContext bootContext(t, table, zone); BootContext bootContext(t, *constants, *calls, zone);
compile(t, &allocator, &bootContext, method); compile(t, &allocator, &bootContext, method);
*constants = bootContext.constants;
*calls = bootContext.calls;
*offset += allocator.offset; *offset += allocator.offset;
} }
@ -5104,13 +5107,16 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p,
{ {
class ThunkContext { class ThunkContext {
public: public:
ThunkContext(MyThread* t): context(t), promise(t->m->system) { } ThunkContext(MyThread* t, Zone* zone):
context(t), promise(t->m->system, zone)
{ }
Context context; 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; { Assembler* a = defaultContext.context.assembler;
@ -5125,19 +5131,15 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p,
Assembler::Register result(a->returnLow()); Assembler::Register result(a->returnLow());
a->apply(Jump, BytesPerWord, RegisterOperand, &result); a->apply(Jump, BytesPerWord, RegisterOperand, &result);
if (image) { void* p = defaultContext.promise.listener->resolve
image->defaultThunk = static_cast<uint8_t*> (reinterpret_cast<intptr_t>(voidPointer(compileMethod)));
(defaultContext.promise.offset) - imageBase;
memset(defaultContext.promise.offset, 0, BytesPerWord); if (image) {
} else { image->defaultThunk = static_cast<uint8_t*>(p) - imageBase;
memcpy(defaultContext.promise.offset,
voidPointer(compileMethod),
BytesPerWord);
} }
} }
ThunkContext nativeContext(t); ThunkContext nativeContext(t, &zone);
{ Assembler* a = nativeContext.context.assembler; { Assembler* a = nativeContext.context.assembler;
@ -5150,19 +5152,15 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p,
a->apply(Return); a->apply(Return);
if (image) { void* p = nativeContext.promise.listener->resolve
image->nativeThunk = static_cast<uint8_t*> (reinterpret_cast<intptr_t>(voidPointer(invokeNative)));
(nativeContext.promise.offset) - imageBase;
memset(nativeContext.promise.offset, 0, BytesPerWord); if (image) {
} else { image->nativeThunk = static_cast<uint8_t*>(p) - imageBase;
memcpy(nativeContext.promise.offset,
voidPointer(invokeNative),
BytesPerWord);
} }
} }
ThunkContext aioobContext(t); ThunkContext aioobContext(t, &zone);
{ Assembler* a = aioobContext.context.assembler; { Assembler* a = aioobContext.context.assembler;
@ -5172,19 +5170,15 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p,
Assembler::Constant proc(&(aioobContext.promise)); Assembler::Constant proc(&(aioobContext.promise));
a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); a->apply(LongCall, BytesPerWord, ConstantOperand, &proc);
if (image) { void* p = aioobContext.promise.listener->resolve
image->aioobThunk = static_cast<uint8_t*> (reinterpret_cast<intptr_t>(voidPointer(throwArrayIndexOutOfBounds)));
(aioobContext.promise.offset) - imageBase;
memset(aioobContext.promise.offset, 0, BytesPerWord); if (image) {
} else { image->aioobThunk = static_cast<uint8_t*>(p) - imageBase;
memcpy(aioobContext.promise.offset,
voidPointer(throwArrayIndexOutOfBounds),
BytesPerWord);
} }
} }
ThunkContext tableContext(t); ThunkContext tableContext(t, &zone);
{ Assembler* a = tableContext.context.assembler; { Assembler* a = tableContext.context.assembler;
@ -5225,12 +5219,11 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p,
#define THUNK(s) \ #define THUNK(s) \
tableContext.context.assembler->writeTo(start); \ tableContext.context.assembler->writeTo(start); \
start += p->thunkSize; \ start += p->thunkSize; \
if (image) { \ { void* p = tableContext.promise.listener->resolve \
image->s##Thunk = static_cast<uint8_t*> \ (reinterpret_cast<intptr_t>(voidPointer(s))); \
(tableContext.promise.offset) - imageBase; \ if (image) { \
memset(tableContext.promise.offset, 0, BytesPerWord); \ image->s##Thunk = static_cast<uint8_t*>(p) - imageBase; \
} else { \ } \
memcpy(tableContext.promise.offset, voidPointer(s), BytesPerWord); \
} }
#include "thunks.cpp" #include "thunks.cpp"

View File

@ -121,7 +121,8 @@ class Processor {
virtual void virtual void
compileMethod(Thread* t, Zone* zone, uint8_t* code, unsigned* offset, 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 virtual void
visitRoots(BootImage* image, HeapWalker* w) = 0; visitRoots(BootImage* image, HeapWalker* w) = 0;

View File

@ -135,6 +135,38 @@ class Task {
Task* next; Task* next;
}; };
void
resolveOffset(System* s, uint8_t* instruction, unsigned instructionSize,
int64_t value)
{
intptr_t v = reinterpret_cast<uint8_t*>(value)
- instruction - instructionSize;
expect(s, isInt32(v));
int32_t v4 = v;
memcpy(instruction + instructionSize - 4, &v4, 4);
}
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 { class OffsetTask: public Task {
public: public:
OffsetTask(Task* next, Promise* promise, unsigned instructionOffset, OffsetTask(Task* next, Promise* promise, unsigned instructionOffset,
@ -146,14 +178,14 @@ class OffsetTask: public Task {
{ } { }
virtual void run(Context* c) { virtual void run(Context* c) {
uint8_t* instruction = c->result + instructionOffset; if (promise->resolved()) {
intptr_t v = reinterpret_cast<uint8_t*>(promise->value()) resolveOffset
- instruction - instructionSize; (c->s, c->result + instructionOffset, instructionSize,
promise->value());
expect(c, isInt32(v)); } else {
new (promise->listen(sizeof(OffsetListener)))
int32_t v4 = v; OffsetListener(c->s, c->result + instructionOffset, instructionSize);
memcpy(instruction + instructionSize - 4, &v4, 4); }
} }
Promise* promise; Promise* promise;
@ -169,6 +201,25 @@ appendOffsetTask(Context* c, Promise* promise, int instructionOffset,
(c->tasks, promise, instructionOffset, instructionSize); (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 { class ImmediateTask: public Task {
public: public:
ImmediateTask(Task* next, Promise* promise, unsigned offset): ImmediateTask(Task* next, Promise* promise, unsigned offset):
@ -179,10 +230,10 @@ class ImmediateTask: public Task {
virtual void run(Context* c) { virtual void run(Context* c) {
if (promise->resolved()) { if (promise->resolved()) {
intptr_t v = promise->value(); copyWord(c->result + offset, promise->value());
memcpy(c->result + offset, &v, BytesPerWord); } else {
} else if (not promise->offer(c->result + offset)) { new (promise->listen(sizeof(ImmediateListener)))
abort(c); ImmediateListener(c->result + offset);
} }
} }