mirror of
https://github.com/corda/corda.git
synced 2025-06-14 05:08:18 +00:00
delay resolving method call offsets until all methods have been compiled when creating a boot image
This commit is contained in:
@ -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 {
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
151
src/compile.cpp
151
src/compile.cpp
@ -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"
|
||||||
|
@ -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;
|
||||||
|
75
src/x86.cpp
75
src/x86.cpp
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user