generate read-only code image in bootimage build

This avoids the requirement of putting the code image in a
section/segment which is both writable and executable, which is good
for security and avoids trouble with systems like iOS which disallow
such things.

The implementation relies on relative addressing such that the offset
of the desired address is fixed as a compile-time constant relative to
the start of the memory area of interest (e.g. the code image, heap
image, or thunk table).  At runtime, the base pointer to the memory
area is retrieved from the thread structure and added to the offset to
compute the final address.  Using the thread pointer allows us to
generate read-only, position-independent code while avoiding the use
of IP-relative addressing, which is not available on all
architectures.
This commit is contained in:
Joel Dice 2011-09-20 16:30:30 -06:00
parent 349d381d95
commit c537dcfd34
15 changed files with 478 additions and 416 deletions

View File

@ -564,11 +564,14 @@ bootimage-generator = $(build)/bootimage-generator
bootimage-bin = $(build)/bootimage.bin bootimage-bin = $(build)/bootimage.bin
bootimage-object = $(build)/bootimage-bin.o bootimage-object = $(build)/bootimage-bin.o
codeimage-bin = $(build)/codeimage.bin
codeimage-object = $(build)/codeimage-bin.o
ifeq ($(bootimage),true) ifeq ($(bootimage),true)
vm-classpath-object = $(bootimage-object) vm-classpath-objects = $(bootimage-object) $(codeimage-object)
cflags += -DBOOT_IMAGE=\"bootimageBin\" -DAVIAN_CLASSPATH=\"\" cflags += -DBOOT_IMAGE -DAVIAN_CLASSPATH=\"\"
else else
vm-classpath-object = $(classpath-object) vm-classpath-objects = $(classpath-object)
cflags += -DBOOT_CLASSPATH=\"[classpathJar]\" \ cflags += -DBOOT_CLASSPATH=\"[classpathJar]\" \
-DAVIAN_CLASSPATH=\"[classpathJar]\" -DAVIAN_CLASSPATH=\"[classpathJar]\"
endif endif
@ -870,16 +873,22 @@ $(static-library): $(vm-objects) $(classpath-objects) $(vm-heapwalk-objects) \
$(ranlib) $(@) $(ranlib) $(@)
$(bootimage-bin): $(bootimage-generator) $(bootimage-bin): $(bootimage-generator)
$(<) $(classpath-build) $(@) $(<) $(classpath-build) $(@) $(codeimage-bin)
$(bootimage-object): $(bootimage-bin) $(converter) $(bootimage-object): $(bootimage-bin) $(converter)
@echo "creating $(@)" @echo "creating $(@)"
$(converter) $(<) $(@) _binary_bootimage_bin_start \ $(converter) $(<) $(@) _binary_bootimage_bin_start \
_binary_bootimage_bin_end $(platform) $(arch) $(pointer-size) \ _binary_bootimage_bin_end $(platform) $(arch) $(pointer-size) \
writable executable writable
$(codeimage-object): $(bootimage-bin) $(converter)
@echo "creating $(@)"
$(converter) $(codeimage-bin) $(@) _binary_codeimage_bin_start \
_binary_codeimage_bin_end $(platform) $(arch) $(pointer-size) \
executable
executable-objects = $(vm-objects) $(classpath-objects) $(driver-object) \ executable-objects = $(vm-objects) $(classpath-objects) $(driver-object) \
$(vm-heapwalk-objects) $(boot-object) $(vm-classpath-object) \ $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-objects) \
$(javahome-object) $(boot-javahome-object) $(javahome-object) $(boot-javahome-object)
$(executable): $(executable-objects) $(executable): $(executable-objects)
@ -930,7 +939,7 @@ else
endif endif
$(dynamic-library): $(vm-objects) $(dynamic-object) $(classpath-objects) \ $(dynamic-library): $(vm-objects) $(dynamic-object) $(classpath-objects) \
$(vm-heapwalk-objects) $(boot-object) $(vm-classpath-object) \ $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-objects) \
$(classpath-libraries) $(javahome-object) $(boot-javahome-object) $(classpath-libraries) $(javahome-object) $(boot-javahome-object)
@echo "linking $(@)" @echo "linking $(@)"
ifdef msvc ifdef msvc

View File

@ -199,6 +199,24 @@ class CombinedPromise: public Promise {
Promise* high; Promise* high;
}; };
class OffsetPromise: public Promise {
public:
OffsetPromise(Promise* base, int64_t offset):
base(base), offset(offset)
{ }
virtual int64_t value() {
return base->value() + offset;
}
virtual bool resolved() {
return base->resolved();
}
Promise* base;
int64_t offset;
};
class ListenPromise: public Promise { class ListenPromise: public Promise {
public: public:
ListenPromise(System* s, Allocator* allocator): ListenPromise(System* s, Allocator* allocator):

View File

@ -381,12 +381,14 @@ MAKE_NAME(writeElf, BITS_PER_WORD, Object)
const char* sectionName; const char* sectionName;
unsigned sectionFlags = SHF_ALLOC; unsigned sectionFlags = SHF_ALLOC;
if (writable and executable) { if (writable) {
sectionName = ".rwx"; if (executable) {
sectionFlags |= SHF_WRITE | SHF_EXECINSTR; sectionName = ".rwx";
} else if (writable) { sectionFlags |= SHF_WRITE | SHF_EXECINSTR;
sectionName = ".data"; } else {
sectionFlags |= SHF_WRITE; sectionName = ".data";
sectionFlags |= SHF_WRITE;
}
} else if (executable) { } else if (executable) {
sectionName = ".text"; sectionName = ".text";
sectionFlags |= SHF_EXECINSTR; sectionFlags |= SHF_EXECINSTR;

View File

@ -306,7 +306,7 @@ bool
MAKE_NAME(writeMachO, BITS_PER_WORD, Object) MAKE_NAME(writeMachO, BITS_PER_WORD, Object)
(uint8_t* data, unsigned size, FILE* out, const char* startName, (uint8_t* data, unsigned size, FILE* out, const char* startName,
const char* endName, const char* architecture, unsigned alignment, const char* endName, const char* architecture, unsigned alignment,
bool writable, bool) bool writable, bool executable)
{ {
cpu_type_t cpuType; cpu_type_t cpuType;
cpu_subtype_t cpuSubType; cpu_subtype_t cpuSubType;
@ -330,8 +330,13 @@ MAKE_NAME(writeMachO, BITS_PER_WORD, Object)
const char* segmentName; const char* segmentName;
const char* sectionName; const char* sectionName;
if (writable) { if (writable) {
segmentName = "__RWX"; if (executable) {
sectionName = "__rwx"; segmentName = "__RWX";
sectionName = "__rwx";
} else {
segmentName = "__DATA";
sectionName = "__data";
}
} else { } else {
segmentName = "__TEXT"; segmentName = "__TEXT";
sectionName = "__text"; sectionName = "__text";

View File

@ -207,17 +207,19 @@ writePEObject
sectionMask |= IMAGE_SCN_MEM_READ; sectionMask |= IMAGE_SCN_MEM_READ;
const char* sectionName; const char* sectionName;
if (writable and executable) { if (writable) {
sectionName = ".rwx"; if (executable) {
sectionMask |= IMAGE_SCN_MEM_WRITE sectionName = ".rwx";
| IMAGE_SCN_MEM_EXECUTE sectionMask |= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_CNT_CODE; | IMAGE_SCN_MEM_EXECUTE
} else if (executable) { | IMAGE_SCN_CNT_CODE;
} else {
sectionName = ".data";
sectionMask |= IMAGE_SCN_MEM_WRITE;
}
} else {
sectionName = ".text"; sectionName = ".text";
sectionMask |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE; sectionMask |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE;
} else {
sectionName = ".data";
sectionMask |= IMAGE_SCN_MEM_WRITE;
} }
writeObject(data, size, out, startName, endName, sectionName, machine, writeObject(data, size, out, startName, endName, sectionName, machine,

View File

@ -33,21 +33,33 @@ extern "C" void __cxa_pure_virtual(void) { abort(); }
#ifdef BOOT_IMAGE #ifdef BOOT_IMAGE
#if (! defined __x86_64__) && ((defined __MINGW32__) || (defined _MSC_VER)) #if (! defined __x86_64__) && ((defined __MINGW32__) || (defined _MSC_VER))
# define SYMBOL(x) binary_bootimage_bin_##x # define BOOTIMAGE_SYMBOL(x) binary_bootimage_bin_##x
# define CODEIMAGE_SYMBOL(x) binary_codeimage_bin_##x
#else #else
# define SYMBOL(x) _binary_bootimage_bin_##x # define BOOTIMAGE_SYMBOL(x) _binary_bootimage_bin_##x
# define CODEIMAGE_SYMBOL(x) _binary_codeimage_bin_##x
#endif #endif
extern "C" { extern "C" {
extern const uint8_t SYMBOL(start)[]; extern const uint8_t BOOTIMAGE_SYMBOL(start)[];
extern const uint8_t SYMBOL(end)[]; extern const uint8_t BOOTIMAGE_SYMBOL(end)[];
EXPORT const uint8_t* EXPORT const uint8_t*
bootimageBin(unsigned* size) bootimageBin(unsigned* size)
{ {
*size = SYMBOL(end) - SYMBOL(start); *size = BOOTIMAGE_SYMBOL(end) - BOOTIMAGE_SYMBOL(start);
return SYMBOL(start); return BOOTIMAGE_SYMBOL(start);
}
extern const uint8_t CODEIMAGE_SYMBOL(start)[];
extern const uint8_t CODEIMAGE_SYMBOL(end)[];
EXPORT const uint8_t*
codeimageBin(unsigned* size)
{
*size = CODEIMAGE_SYMBOL(end) - CODEIMAGE_SYMBOL(start);
return CODEIMAGE_SYMBOL(start);
} }
} }

43
src/bootimage-fields.cpp Normal file
View File

@ -0,0 +1,43 @@
#ifndef FIELD
# define FIELD(name)
# define FIELD_DEFINED
#endif
FIELD(magic)
FIELD(heapSize)
FIELD(codeSize)
FIELD(bootClassCount)
FIELD(appClassCount)
FIELD(stringCount)
FIELD(callCount)
FIELD(bootLoader)
FIELD(appLoader)
FIELD(types)
FIELD(methodTree)
FIELD(methodTreeSentinal)
FIELD(virtualThunks)
#ifdef FIELD_DEFINED
# undef FIELD
# undef FIELD_DEFINED
#endif
#ifndef THUNK_FIELD
# define THUNK_FIELD(name)
# define THUNK_FIELD_DEFINED
#endif
THUNK_FIELD(default_);
THUNK_FIELD(defaultVirtual);
THUNK_FIELD(native);
THUNK_FIELD(aioob);
THUNK_FIELD(stackOverflow);
THUNK_FIELD(table);
#ifdef THUNK_FIELD_DEFINED
# undef THUNK_FIELD
# undef THUNK_FIELD_DEFINED
#endif

View File

@ -265,8 +265,8 @@ targetFieldOffset(Thread* t, object typeMaps, object field)
object object
makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
target_uintptr_t* codeMap, const char* className, const char* className, const char* methodName,
const char* methodName, const char* methodSpec, object typeMaps) const char* methodSpec, object typeMaps)
{ {
PROTECT(t, typeMaps); PROTECT(t, typeMaps);
@ -671,21 +671,8 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
uint8_t* value = reinterpret_cast<uint8_t*>(addresses->basis->value()); uint8_t* value = reinterpret_cast<uint8_t*>(addresses->basis->value());
expect(t, value >= code); expect(t, value >= code);
void* location; addresses->listener->resolve
bool flat = addresses->listener->resolve (targetVW(static_cast<target_intptr_t>(value - code)), 0);
(reinterpret_cast<int64_t>(code), &location);
target_uintptr_t offset = value - code;
if (flat) {
offset |= TargetBootFlatConstant;
}
offset = targetVW(offset);
memcpy(location, &offset, TargetBytesPerWord);
expect(t, reinterpret_cast<intptr_t>(location)
>= reinterpret_cast<intptr_t>(code));
targetMarkBit(codeMap, reinterpret_cast<intptr_t>(location)
- reinterpret_cast<intptr_t>(code));
} }
for (; methods; methods = pairSecond(t, methods)) { for (; methods; methods = pairSecond(t, methods)) {
@ -1260,8 +1247,7 @@ makeHeapImage(Thread* t, BootImage* image, target_uintptr_t* heap,
} }
void void
updateConstants(Thread* t, object constants, uint8_t* code, updateConstants(Thread* t, object constants, HeapMap* heapTable)
target_uintptr_t* codeMap, HeapMap* heapTable)
{ {
for (; constants; constants = tripleThird(t, constants)) { for (; constants; constants = tripleThird(t, constants)) {
unsigned target = heapTable->find(tripleFirst(t, constants)); unsigned target = heapTable->find(tripleFirst(t, constants));
@ -1271,26 +1257,7 @@ updateConstants(Thread* t, object constants, uint8_t* code,
(pointerValue(t, tripleSecond(t, constants)))->listener; (pointerValue(t, tripleSecond(t, constants)))->listener;
pl; pl = pl->next) pl; pl = pl->next)
{ {
void* location; pl->resolve((target - 1) * TargetBytesPerWord, 0);
bool flat = pl->resolve(0, &location);
target_uintptr_t offset = target | TargetBootHeapOffset;
if (flat) {
offset |= TargetBootFlatConstant;
}
offset = targetVW(offset);
memcpy(location, &offset, TargetBytesPerWord);
expect(t, reinterpret_cast<intptr_t>(location)
>= reinterpret_cast<intptr_t>(code));
// fprintf(stderr, "mark constant %d %d\n",
// static_cast<unsigned>
// (reinterpret_cast<intptr_t>(location)
// - reinterpret_cast<intptr_t>(code)),
// static_cast<unsigned>(offset));
targetMarkBit(codeMap, reinterpret_cast<intptr_t>(location)
- reinterpret_cast<intptr_t>(code));
} }
} }
} }
@ -1309,16 +1276,12 @@ targetThunk(BootImage::Thunk t)
} }
void void
writeBootImage2(Thread* t, FILE* out, BootImage* image, uint8_t* code, writeBootImage2(Thread* t, FILE* bootimageOutput, FILE* codeOutput,
unsigned codeCapacity, const char* className, BootImage* image, uint8_t* code, const char* className,
const char* methodName, const char* methodSpec) const char* methodName, const char* methodSpec)
{ {
Zone zone(t->m->system, t->m->heap, 64 * 1024); Zone zone(t->m->system, t->m->heap, 64 * 1024);
target_uintptr_t* codeMap = static_cast<target_uintptr_t*>
(t->m->heap->allocate(codeMapSize(codeCapacity)));
memset(codeMap, 0, codeMapSize(codeCapacity));
object classPoolMap; object classPoolMap;
object typeMaps; object typeMaps;
object constants; object constants;
@ -1471,8 +1434,7 @@ writeBootImage2(Thread* t, FILE* out, BootImage* image, uint8_t* code,
} }
constants = makeCodeImage constants = makeCodeImage
(t, &zone, image, code, codeMap, className, methodName, methodSpec, (t, &zone, image, code, className, methodName, methodSpec, typeMaps);
typeMaps);
PROTECT(t, constants); PROTECT(t, constants);
@ -1549,7 +1511,7 @@ writeBootImage2(Thread* t, FILE* out, BootImage* image, uint8_t* code,
HeapWalker* heapWalker = makeHeapImage HeapWalker* heapWalker = makeHeapImage
(t, image, heap, heapMap, HeapCapacity, constants, typeMaps); (t, image, heap, heapMap, HeapCapacity, constants, typeMaps);
updateConstants(t, constants, code, codeMap, heapWalker->map()); updateConstants(t, constants, heapWalker->map());
image->bootClassCount = hashMapSize image->bootClassCount = hashMapSize
(t, classLoaderMap(t, root(t, Machine::BootLoader))); (t, classLoaderMap(t, root(t, Machine::BootLoader)));
@ -1618,50 +1580,53 @@ writeBootImage2(Thread* t, FILE* out, BootImage* image, uint8_t* code,
#include "bootimage-fields.cpp" #include "bootimage-fields.cpp"
#undef THUNK_FIELD #undef THUNK_FIELD
fwrite(&targetImage, sizeof(BootImage), 1, out); fwrite(&targetImage, sizeof(BootImage), 1, bootimageOutput);
} }
fwrite(bootClassTable, image->bootClassCount * sizeof(unsigned), 1, out); fwrite(bootClassTable, image->bootClassCount * sizeof(unsigned), 1,
fwrite(appClassTable, image->appClassCount * sizeof(unsigned), 1, out); bootimageOutput);
fwrite(stringTable, image->stringCount * sizeof(unsigned), 1, out); fwrite(appClassTable, image->appClassCount * sizeof(unsigned), 1,
fwrite(callTable, image->callCount * sizeof(unsigned) * 2, 1, out); bootimageOutput);
fwrite(stringTable, image->stringCount * sizeof(unsigned), 1,
bootimageOutput);
fwrite(callTable, image->callCount * sizeof(unsigned) * 2, 1,
bootimageOutput);
unsigned offset = (image->bootClassCount * sizeof(unsigned)) unsigned offset = sizeof(BootImage)
+ (image->bootClassCount * sizeof(unsigned))
+ (image->appClassCount * sizeof(unsigned)) + (image->appClassCount * sizeof(unsigned))
+ (image->stringCount * sizeof(unsigned)) + (image->stringCount * sizeof(unsigned))
+ (image->callCount * sizeof(unsigned) * 2); + (image->callCount * sizeof(unsigned) * 2);
while (offset % TargetBytesPerWord) { while (offset % TargetBytesPerWord) {
uint8_t c = 0; uint8_t c = 0;
fwrite(&c, 1, 1, out); fwrite(&c, 1, 1, bootimageOutput);
++ offset; ++ offset;
} }
fwrite fwrite(heapMap, pad(heapMapSize(image->heapSize), TargetBytesPerWord), 1,
(heapMap, pad(heapMapSize(image->heapSize), TargetBytesPerWord), 1, out); bootimageOutput);
fwrite(heap, pad(image->heapSize, TargetBytesPerWord), 1, out); fwrite(heap, pad(image->heapSize, TargetBytesPerWord), 1, bootimageOutput);
fwrite fwrite(code, pad(image->codeSize, TargetBytesPerWord), 1, codeOutput);
(codeMap, pad(codeMapSize(image->codeSize), TargetBytesPerWord), 1, out);
fwrite(code, pad(image->codeSize, TargetBytesPerWord), 1, out);
} }
} }
uint64_t uint64_t
writeBootImage(Thread* t, uintptr_t* arguments) writeBootImage(Thread* t, uintptr_t* arguments)
{ {
FILE* out = reinterpret_cast<FILE*>(arguments[0]); FILE* bootimageOutput = reinterpret_cast<FILE*>(arguments[0]);
BootImage* image = reinterpret_cast<BootImage*>(arguments[1]); FILE* codeOutput = reinterpret_cast<FILE*>(arguments[1]);
uint8_t* code = reinterpret_cast<uint8_t*>(arguments[2]); BootImage* image = reinterpret_cast<BootImage*>(arguments[2]);
unsigned codeCapacity = arguments[3]; uint8_t* code = reinterpret_cast<uint8_t*>(arguments[3]);
const char* className = reinterpret_cast<const char*>(arguments[4]); const char* className = reinterpret_cast<const char*>(arguments[4]);
const char* methodName = reinterpret_cast<const char*>(arguments[5]); const char* methodName = reinterpret_cast<const char*>(arguments[5]);
const char* methodSpec = reinterpret_cast<const char*>(arguments[6]); const char* methodSpec = reinterpret_cast<const char*>(arguments[6]);
writeBootImage2 writeBootImage2
(t, out, image, code, codeCapacity, className, methodName, methodSpec); (t, bootimageOutput, codeOutput, image, code, className, methodName,
methodSpec);
return 1; return 1;
} }
@ -1671,8 +1636,8 @@ writeBootImage(Thread* t, uintptr_t* arguments)
int int
main(int ac, const char** av) main(int ac, const char** av)
{ {
if (ac < 3 or ac > 6) { if (ac < 4 or ac > 7) {
fprintf(stderr, "usage: %s <classpath> <output file> " fprintf(stderr, "usage: %s <classpath> <bootimage file> <code file>"
"[<class name> [<method name> [<method spec>]]]\n", av[0]); "[<class name> [<method name> [<method spec>]]]\n", av[0]);
return -1; return -1;
} }
@ -1701,23 +1666,30 @@ main(int ac, const char** av)
enter(t, Thread::ActiveState); enter(t, Thread::ActiveState);
enter(t, Thread::IdleState); enter(t, Thread::IdleState);
FILE* output = vm::fopen(av[2], "wb"); FILE* bootimageOutput = vm::fopen(av[2], "wb");
if (output == 0) { if (bootimageOutput == 0) {
fprintf(stderr, "unable to open %s\n", av[2]); fprintf(stderr, "unable to open %s\n", av[2]);
return -1; return -1;
} }
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(output), FILE* codeOutput = vm::fopen(av[3], "wb");
if (codeOutput == 0) {
fprintf(stderr, "unable to open %s\n", av[3]);
return -1;
}
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(bootimageOutput),
reinterpret_cast<uintptr_t>(codeOutput),
reinterpret_cast<uintptr_t>(&image), reinterpret_cast<uintptr_t>(&image),
reinterpret_cast<uintptr_t>(code), reinterpret_cast<uintptr_t>(code),
CodeCapacity,
reinterpret_cast<uintptr_t>(ac > 3 ? av[3] : 0),
reinterpret_cast<uintptr_t>(ac > 4 ? av[4] : 0), reinterpret_cast<uintptr_t>(ac > 4 ? av[4] : 0),
reinterpret_cast<uintptr_t>(ac > 5 ? av[5] : 0) }; reinterpret_cast<uintptr_t>(ac > 5 ? av[5] : 0),
reinterpret_cast<uintptr_t>(ac > 6 ? av[6] : 0) };
run(t, writeBootImage, arguments); run(t, writeBootImage, arguments);
fclose(output); fclose(codeOutput);
fclose(bootimageOutput);
if (t->exception) { if (t->exception) {
printTrace(t, t->exception); printTrace(t, t->exception);

View File

@ -71,6 +71,20 @@ enum Root {
RewindMethod RewindMethod
}; };
enum ThunkIndex {
compileMethodIndex,
compileVirtualMethodIndex,
invokeNativeIndex,
throwArrayIndexOutOfBoundsIndex,
throwStackOverflowIndex,
#define THUNK(s) s##Index,
#include "thunks.cpp"
#undef THUNK
dummyIndex
};
const unsigned RootCount = RewindMethod + 1; const unsigned RootCount = RewindMethod + 1;
inline bool inline bool
@ -229,6 +243,9 @@ class MyThread: public Thread {
tailAddress(0), tailAddress(0),
virtualCallTarget(0), virtualCallTarget(0),
virtualCallIndex(0), virtualCallIndex(0),
heapImage(0),
codeImage(0),
thunkTable(0),
trace(0), trace(0),
reference(0), reference(0),
arch(parent arch(parent
@ -252,6 +269,9 @@ class MyThread: public Thread {
void* tailAddress; void* tailAddress;
void* virtualCallTarget; void* virtualCallTarget;
uintptr_t virtualCallIndex; uintptr_t virtualCallIndex;
uintptr_t* heapImage;
uint8_t* codeImage;
void** thunkTable;
CallTrace* trace; CallTrace* trace;
Reference* reference; Reference* reference;
Assembler::Architecture* arch; Assembler::Architecture* arch;
@ -1310,6 +1330,9 @@ storeLocal(Context* context, unsigned footprint, Compiler::Operand* value,
(footprint, value, translateLocalIndex(context, footprint, index)); (footprint, value, translateLocalIndex(context, footprint, index));
} }
FixedAllocator*
codeAllocator(MyThread* t);
class Frame { class Frame {
public: public:
enum StackType { enum StackType {
@ -1356,9 +1379,8 @@ class Frame {
} }
Compiler::Operand* append(object o) { Compiler::Operand* append(object o) {
if (context->bootContext) { BootContext* bc = context->bootContext;
BootContext* bc = context->bootContext; if (bc) {
Promise* p = new (bc->zone->allocate(sizeof(ListenPromise))) Promise* p = new (bc->zone->allocate(sizeof(ListenPromise)))
ListenPromise(t->m->system, bc->zone); ListenPromise(t->m->system, bc->zone);
@ -1366,7 +1388,11 @@ class Frame {
object pointer = makePointer(t, p); object pointer = makePointer(t, p);
bc->constants = makeTriple(t, o, pointer, bc->constants); bc->constants = makeTriple(t, o, pointer, bc->constants);
return c->promiseConstant(p, Compiler::ObjectType); return c->add
(TargetBytesPerWord, c->memory
(c->register_(t->arch->thread()), Compiler::AddressType,
TargetThreadHeapImage), c->promiseConstant
(p, Compiler::AddressType));
} else { } else {
for (PoolElement* e = context->objectPool; e; e = e->next) { for (PoolElement* e = context->objectPool; e; e = e->next) {
if (o == e->target) { if (o == e->target) {
@ -1590,7 +1616,20 @@ class Frame {
} }
Compiler::Operand* addressOperand(Promise* p) { Compiler::Operand* addressOperand(Promise* p) {
return c->promiseConstant(addressPromise(p), Compiler::AddressType); return c->promiseConstant(p, Compiler::AddressType);
}
Compiler::Operand* absoluteAddressOperand(Promise* p) {
return context->bootContext
? c->add
(TargetBytesPerWord, c->memory
(c->register_(t->arch->thread()), Compiler::AddressType,
TargetThreadCodeImage), c->promiseConstant
(new (context->zone.allocate(sizeof(OffsetPromise)))
OffsetPromise
(p, - reinterpret_cast<intptr_t>(codeAllocator(t)->base)),
Compiler::AddressType))
: addressOperand(p);
} }
Compiler::Operand* machineIp(unsigned logicalIp) { Compiler::Operand* machineIp(unsigned logicalIp) {
@ -1865,7 +1904,7 @@ class Frame {
} }
unsigned startSubroutine(unsigned ip, Promise* returnAddress) { unsigned startSubroutine(unsigned ip, Promise* returnAddress) {
pushAddress(addressOperand(returnAddress)); pushAddress(absoluteAddressOperand(returnAddress));
Subroutine* subroutine = 0; Subroutine* subroutine = 0;
for (Subroutine* s = context->subroutines; s; s = s->listNext) { for (Subroutine* s = context->subroutines; s; s = s->listNext) {
@ -2247,9 +2286,6 @@ tryInitClass(MyThread* t, object class_)
initClass(t, class_); initClass(t, class_);
} }
FixedAllocator*
codeAllocator(MyThread* t);
void void
compile(MyThread* t, FixedAllocator* allocator, BootContext* bootContext, compile(MyThread* t, FixedAllocator* allocator, BootContext* bootContext,
object method); object method);
@ -3288,7 +3324,9 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall,
if (useThunk if (useThunk
or (TailCalls and tailCall and (methodFlags(t, target) & ACC_NATIVE))) or (TailCalls and tailCall and (methodFlags(t, target) & ACC_NATIVE)))
{ {
flags |= Compiler::Aligned; if (frame->context->bootContext == 0) {
flags |= Compiler::Aligned;
}
if (TailCalls and tailCall) { if (TailCalls and tailCall) {
traceFlags |= TraceElement::TailCall; traceFlags |= TraceElement::TailCall;
@ -3308,7 +3346,8 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall,
methodParameterFootprint(t, target)); methodParameterFootprint(t, target));
c->store c->store
(TargetBytesPerWord, frame->addressOperand(returnAddressPromise), (TargetBytesPerWord,
frame->absoluteAddressOperand(returnAddressPromise),
TargetBytesPerWord, c->memory TargetBytesPerWord, c->memory
(c->register_(t->arch->thread()), Compiler::AddressType, (c->register_(t->arch->thread()), Compiler::AddressType,
TargetThreadTailAddress)); TargetThreadTailAddress));
@ -5327,12 +5366,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
assert(t, defaultIp < codeLength(t, code)); assert(t, defaultIp < codeLength(t, code));
Compiler::Operand* default_ = frame->addressOperand Compiler::Operand* default_ = frame->addressOperand
(c->machineIp(defaultIp)); (frame->addressPromise(c->machineIp(defaultIp)));
int32_t pairCount = codeReadInt32(t, code, ip); int32_t pairCount = codeReadInt32(t, code, ip);
if (pairCount) { if (pairCount) {
Compiler::Operand* start = 0; Promise* start = 0;
THREAD_RUNTIME_ARRAY(t, uint32_t, ipTable, pairCount); THREAD_RUNTIME_ARRAY(t, uint32_t, ipTable, pairCount);
for (int32_t i = 0; i < pairCount; ++i) { for (int32_t i = 0; i < pairCount; ++i) {
unsigned index = ip + (i * 8); unsigned index = ip + (i * 8);
@ -5344,19 +5383,25 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
Promise* p = c->poolAppend(key); Promise* p = c->poolAppend(key);
if (i == 0) { if (i == 0) {
start = frame->addressOperand(p); start = p;
} }
c->poolAppendPromise(frame->addressPromise(c->machineIp(newIp))); c->poolAppendPromise
(frame->addressPromise(c->machineIp(newIp)));
} }
assert(t, start); assert(t, start);
Compiler::Operand* address = c->call
(c->constant(getThunk(t, lookUpAddressThunk), Compiler::AddressType),
0, 0, TargetBytesPerWord, Compiler::AddressType,
4, key, frame->absoluteAddressOperand(start),
c->constant(pairCount, Compiler::IntegerType), default_);
c->jmp c->jmp
(c->call (context->bootContext ? c->add
(c->constant (TargetBytesPerWord, c->memory
(getThunk(t, lookUpAddressThunk), Compiler::AddressType), (c->register_(t->arch->thread()), Compiler::AddressType,
0, 0, TargetBytesPerWord, Compiler::AddressType, TargetThreadCodeImage), address)
4, key, start, c->constant(pairCount, Compiler::IntegerType), : address);
default_));
Compiler::State* state = c->saveState(); Compiler::State* state = c->saveState();
@ -5855,7 +5900,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
int32_t bottom = codeReadInt32(t, code, ip); int32_t bottom = codeReadInt32(t, code, ip);
int32_t top = codeReadInt32(t, code, ip); int32_t top = codeReadInt32(t, code, ip);
Compiler::Operand* start = 0; Promise* start = 0;
THREAD_RUNTIME_ARRAY(t, uint32_t, ipTable, top - bottom + 1); THREAD_RUNTIME_ARRAY(t, uint32_t, ipTable, top - bottom + 1);
for (int32_t i = 0; i < top - bottom + 1; ++i) { for (int32_t i = 0; i < top - bottom + 1; ++i) {
unsigned index = ip + (i * 4); unsigned index = ip + (i * 4);
@ -5867,7 +5912,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
Promise* p = c->poolAppendPromise Promise* p = c->poolAppendPromise
(frame->addressPromise(c->machineIp(newIp))); (frame->addressPromise(c->machineIp(newIp)));
if (i == 0) { if (i == 0) {
start = frame->addressOperand(p); start = p;
} }
} }
assert(t, start); assert(t, start);
@ -5892,10 +5937,18 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
= (bottom = (bottom
? c->sub(4, c->constant(bottom, Compiler::IntegerType), key) : key); ? c->sub(4, c->constant(bottom, Compiler::IntegerType), key) : key);
Compiler::Operand* entry = c->memory
(frame->absoluteAddressOperand(start), Compiler::AddressType, 0,
normalizedKey, TargetBytesPerWord);
c->jmp c->jmp
(c->load (c->load
(TargetBytesPerWord, TargetBytesPerWord, c->memory (TargetBytesPerWord, TargetBytesPerWord, context->bootContext
(start, Compiler::AddressType, 0, normalizedKey, TargetBytesPerWord), ? c->add
(TargetBytesPerWord, c->memory
(c->register_(t->arch->thread()), Compiler::AddressType,
TargetThreadCodeImage), entry)
: entry,
TargetBytesPerWord)); TargetBytesPerWord));
Compiler::State* state = c->saveState(); Compiler::State* state = c->saveState();
@ -7105,47 +7158,7 @@ updateCall(MyThread* t, UnaryOperation op, void* returnAddress, void* target)
} }
void* void*
compileMethod2(MyThread* t, void* ip) compileMethod2(MyThread* t, void* ip);
{
object node = findCallNode(t, ip);
object target = callNodeTarget(t, node);
PROTECT(t, node);
PROTECT(t, target);
t->trace->targetMethod = target;
THREAD_RESOURCE0(t, static_cast<MyThread*>(t)->trace->targetMethod = 0);
compile(t, codeAllocator(t), 0, target);
uintptr_t address;
if ((methodFlags(t, target) & ACC_NATIVE)
and useLongJump(t, reinterpret_cast<uintptr_t>(ip)))
{
address = bootNativeThunk(t);
} else {
address = methodAddress(t, target);
}
uint8_t* updateIp = static_cast<uint8_t*>(ip);
UnaryOperation op;
if (callNodeFlags(t, node) & TraceElement::LongCall) {
if (callNodeFlags(t, node) & TraceElement::TailCall) {
op = AlignedLongJump;
} else {
op = AlignedLongCall;
}
} else if (callNodeFlags(t, node) & TraceElement::TailCall) {
op = AlignedJump;
} else {
op = AlignedCall;
}
updateCall(t, op, updateIp, reinterpret_cast<void*>(address));
return reinterpret_cast<void*>(address);
}
uint64_t uint64_t
compileMethod(MyThread* t) compileMethod(MyThread* t)
@ -8270,7 +8283,7 @@ bool
isThunkUnsafeStack(MyThread* t, void* ip); isThunkUnsafeStack(MyThread* t, void* ip);
void void
boot(MyThread* t, BootImage* image); boot(MyThread* t, BootImage* image, uint8_t* code);
class MyProcessor; class MyProcessor;
@ -8278,7 +8291,7 @@ MyProcessor*
processor(MyThread* t); processor(MyThread* t);
void void
compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p); compileThunks(MyThread* t, Allocator* allocator);
class MyProcessor: public Processor { class MyProcessor: public Processor {
public: public:
@ -8312,6 +8325,9 @@ class MyProcessor: public Processor {
allocator(allocator), allocator(allocator),
roots(0), roots(0),
bootImage(0), bootImage(0),
heapImage(0),
codeImage(0),
codeImageSize(0),
segFaultHandler(Machine::NullPointerExceptionType, segFaultHandler(Machine::NullPointerExceptionType,
Machine::NullPointerException, Machine::NullPointerException,
FixedSizeOfNullPointerException), FixedSizeOfNullPointerException),
@ -8321,7 +8337,18 @@ class MyProcessor: public Processor {
codeAllocator(s, 0, 0), codeAllocator(s, 0, 0),
callTableSize(0), callTableSize(0),
useNativeFeatures(useNativeFeatures) useNativeFeatures(useNativeFeatures)
{ } {
thunkTable[compileMethodIndex] = voidPointer(local::compileMethod);
thunkTable[compileVirtualMethodIndex] = voidPointer(compileVirtualMethod);
thunkTable[invokeNativeIndex] = voidPointer(invokeNative);
thunkTable[throwArrayIndexOutOfBoundsIndex] = voidPointer
(throwArrayIndexOutOfBounds);
thunkTable[throwStackOverflowIndex] = voidPointer(throwStackOverflow);
#define THUNK(s) thunkTable[s##Index] = voidPointer(s);
#include "thunks.cpp"
#undef THUNK
thunkTable[dummyIndex] = 0;
}
virtual Thread* virtual Thread*
makeThread(Machine* m, object javaThread, Thread* parent) makeThread(Machine* m, object javaThread, Thread* parent)
@ -8329,7 +8356,10 @@ class MyProcessor: public Processor {
MyThread* t = new (m->heap->allocate(sizeof(MyThread))) MyThread* t = new (m->heap->allocate(sizeof(MyThread)))
MyThread(m, javaThread, static_cast<MyThread*>(parent), MyThread(m, javaThread, static_cast<MyThread*>(parent),
useNativeFeatures); useNativeFeatures);
t->init();
t->heapImage = heapImage;
t->codeImage = codeImage;
t->thunkTable = thunkTable;
if (false) { if (false) {
fprintf(stderr, "stack %d\n", fprintf(stderr, "stack %d\n",
@ -8359,6 +8389,8 @@ class MyProcessor: public Processor {
exit(0); exit(0);
} }
t->init();
return t; return t;
} }
@ -8755,15 +8787,15 @@ class MyProcessor: public Processor {
return table; return table;
} }
virtual void boot(Thread* t, BootImage* image) { virtual void boot(Thread* t, BootImage* image, uint8_t* code) {
if (codeAllocator.base == 0) { if (codeAllocator.base == 0) {
codeAllocator.base = static_cast<uint8_t*> codeAllocator.base = static_cast<uint8_t*>
(s->tryAllocateExecutable(ExecutableAreaSizeInBytes)); (s->tryAllocateExecutable(ExecutableAreaSizeInBytes));
codeAllocator.capacity = ExecutableAreaSizeInBytes; codeAllocator.capacity = ExecutableAreaSizeInBytes;
} }
if (image) { if (image and code) {
local::boot(static_cast<MyThread*>(t), image); local::boot(static_cast<MyThread*>(t), image, code);
} else { } else {
roots = makeArray(t, RootCount); roots = makeArray(t, RootCount);
@ -8777,7 +8809,7 @@ class MyProcessor: public Processor {
root(t, MethodTreeSentinal)); root(t, MethodTreeSentinal));
} }
local::compileThunks(static_cast<MyThread*>(t), &codeAllocator, this); local::compileThunks(static_cast<MyThread*>(t), &codeAllocator);
segFaultHandler.m = t->m; segFaultHandler.m = t->m;
expect(t, t->m->system->success expect(t, t->m->system->success
@ -8840,6 +8872,9 @@ class MyProcessor: public Processor {
Allocator* allocator; Allocator* allocator;
object roots; object roots;
BootImage* bootImage; BootImage* bootImage;
uintptr_t* heapImage;
uint8_t* codeImage;
unsigned codeImageSize;
SignalHandler segFaultHandler; SignalHandler segFaultHandler;
SignalHandler divideByZeroHandler; SignalHandler divideByZeroHandler;
FixedAllocator codeAllocator; FixedAllocator codeAllocator;
@ -8847,8 +8882,57 @@ class MyProcessor: public Processor {
ThunkCollection bootThunks; ThunkCollection bootThunks;
unsigned callTableSize; unsigned callTableSize;
bool useNativeFeatures; bool useNativeFeatures;
void* thunkTable[dummyIndex + 1];
}; };
void*
compileMethod2(MyThread* t, void* ip)
{
object node = findCallNode(t, ip);
object target = callNodeTarget(t, node);
PROTECT(t, node);
PROTECT(t, target);
t->trace->targetMethod = target;
THREAD_RESOURCE0(t, static_cast<MyThread*>(t)->trace->targetMethod = 0);
compile(t, codeAllocator(t), 0, target);
uintptr_t address;
if ((methodFlags(t, target) & ACC_NATIVE)
and useLongJump(t, reinterpret_cast<uintptr_t>(ip)))
{
address = bootNativeThunk(t);
} else {
address = methodAddress(t, target);
}
uint8_t* updateIp = static_cast<uint8_t*>(ip);
MyProcessor* p = processor(t);
if (updateIp < p->codeImage or updateIp >= p->codeImage + p->codeImageSize) {
UnaryOperation op;
if (callNodeFlags(t, node) & TraceElement::LongCall) {
if (callNodeFlags(t, node) & TraceElement::TailCall) {
op = AlignedLongJump;
} else {
op = AlignedLongCall;
}
} else if (callNodeFlags(t, node) & TraceElement::TailCall) {
op = AlignedJump;
} else {
op = AlignedCall;
}
updateCall(t, op, updateIp, reinterpret_cast<void*>(address));
}
return reinterpret_cast<void*>(address);
}
bool bool
isThunk(MyProcessor::ThunkCollection* thunks, void* ip) isThunk(MyProcessor::ThunkCollection* thunks, void* ip)
{ {
@ -9132,45 +9216,6 @@ fixupHeap(MyThread* t UNUSED, uintptr_t* map, unsigned size, uintptr_t* heap)
} }
} }
void
fixupCode(Thread* t, uintptr_t* map, unsigned size, uint8_t* code,
uintptr_t* heap)
{
Assembler::Architecture* arch = makeArchitecture(t->m->system, false);
arch->acquire();
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<uintptr_t>(1) << bit)) {
unsigned index = indexOf(word, bit);
uintptr_t oldValue; memcpy(&oldValue, code + index, BytesPerWord);
uintptr_t newValue;
if (oldValue & BootHeapOffset) {
newValue = reinterpret_cast<uintptr_t>
(heap + (oldValue & BootMask) - 1);
// fprintf(stderr, "constant marked %d %d\n",
// index, static_cast<unsigned>(oldValue));
} else {
newValue = reinterpret_cast<uintptr_t>
(code + (oldValue & BootMask));
}
if (oldValue & BootFlatConstant) {
memcpy(code + index, &newValue, BytesPerWord);
} else {
arch->setConstant(code + index, newValue);
}
}
}
}
}
arch->release();
}
void void
fixupMethods(Thread* t, object map, BootImage* image UNUSED, uint8_t* code) fixupMethods(Thread* t, object map, BootImage* image UNUSED, uint8_t* code)
{ {
@ -9216,7 +9261,7 @@ thunkToThunk(const BootImage::Thunk& thunk, uint8_t* base)
} }
void void
fixupThunks(MyThread* t, BootImage* image, uint8_t* code) findThunks(MyThread* t, BootImage* image, uint8_t* code)
{ {
MyProcessor* p = processor(t); MyProcessor* p = processor(t);
@ -9228,28 +9273,6 @@ fixupThunks(MyThread* t, BootImage* image, uint8_t* code)
p->bootThunks.stackOverflow p->bootThunks.stackOverflow
= thunkToThunk(image->thunks.stackOverflow, code); = thunkToThunk(image->thunks.stackOverflow, code);
p->bootThunks.table = thunkToThunk(image->thunks.table, code); p->bootThunks.table = thunkToThunk(image->thunks.table, code);
updateCall(t, LongCall, code + image->compileMethodCall,
voidPointer(local::compileMethod));
updateCall(t, LongCall, code + image->compileVirtualMethodCall,
voidPointer(local::compileVirtualMethod));
updateCall(t, LongCall, code + image->invokeNativeCall,
voidPointer(invokeNative));
updateCall(t, LongCall, code + image->throwArrayIndexOutOfBoundsCall,
voidPointer(throwArrayIndexOutOfBounds));
updateCall(t, LongCall, code + image->throwStackOverflowCall,
voidPointer(throwStackOverflow));
#define THUNK(s) \
updateCall(t, LongJump, code + image->s##Call, voidPointer(s));
#include "thunks.cpp"
#undef THUNK
} }
void void
@ -9266,7 +9289,7 @@ fixupVirtualThunks(MyThread* t, uint8_t* code)
} }
void void
boot(MyThread* t, BootImage* image) boot(MyThread* t, BootImage* image, uint8_t* code)
{ {
assert(t, image->magic == BootImage::Magic); assert(t, image->magic == BootImage::Magic);
@ -9277,17 +9300,20 @@ boot(MyThread* t, BootImage* image)
uintptr_t* heapMap = reinterpret_cast<uintptr_t*> uintptr_t* heapMap = reinterpret_cast<uintptr_t*>
(padWord(reinterpret_cast<uintptr_t>(callTable + (image->callCount * 2)))); (padWord(reinterpret_cast<uintptr_t>(callTable + (image->callCount * 2))));
unsigned heapMapSizeInWords = ceiling unsigned heapMapSizeInWords = ceiling
(heapMapSize(image->heapSize), BytesPerWord); (heapMapSize(image->heapSize), BytesPerWord);
uintptr_t* heap = heapMap + heapMapSizeInWords; uintptr_t* heap = heapMap + heapMapSizeInWords;
MyProcessor* p = static_cast<MyProcessor*>(t->m->processor);
t->heapImage = p->heapImage = heap;
// fprintf(stderr, "heap from %p to %p\n", // fprintf(stderr, "heap from %p to %p\n",
// heap, heap + ceiling(image->heapSize, BytesPerWord)); // heap, heap + ceiling(image->heapSize, BytesPerWord));
uintptr_t* codeMap = heap + ceiling(image->heapSize, BytesPerWord); t->codeImage = p->codeImage = code;
unsigned codeMapSizeInWords = ceiling p->codeImageSize = image->codeSize;
(codeMapSize(image->codeSize), BytesPerWord);
uint8_t* code = reinterpret_cast<uint8_t*>(codeMap + codeMapSizeInWords);
// fprintf(stderr, "code from %p to %p\n", // fprintf(stderr, "code from %p to %p\n",
// code, code + image->codeSize); // code, code + image->codeSize);
@ -9303,8 +9329,6 @@ boot(MyThread* t, BootImage* image)
setRoot(t, Machine::BootLoader, bootObject(heap, image->bootLoader)); setRoot(t, Machine::BootLoader, bootObject(heap, image->bootLoader));
setRoot(t, Machine::AppLoader, bootObject(heap, image->appLoader)); setRoot(t, Machine::AppLoader, bootObject(heap, image->appLoader));
MyProcessor* p = static_cast<MyProcessor*>(t->m->processor);
p->roots = makeArray(t, RootCount); p->roots = makeArray(t, RootCount);
setRoot(t, MethodTree, bootObject(heap, image->methodTree)); setRoot(t, MethodTree, bootObject(heap, image->methodTree));
@ -9312,8 +9336,6 @@ boot(MyThread* t, BootImage* image)
setRoot(t, VirtualThunks, bootObject(heap, image->virtualThunks)); setRoot(t, VirtualThunks, bootObject(heap, image->virtualThunks));
fixupCode(t, codeMap, codeMapSizeInWords, code, heap);
syncInstructionCache(code, image->codeSize); syncInstructionCache(code, image->codeSize);
{ object map = makeClassMap(t, bootClassTable, image->bootClassCount, heap); { object map = makeClassMap(t, bootClassTable, image->bootClassCount, heap);
@ -9341,7 +9363,7 @@ boot(MyThread* t, BootImage* image)
(t, bootClassTable, image->bootClassCount, (t, bootClassTable, image->bootClassCount,
appClassTable, image->appClassCount, heap)); appClassTable, image->appClassCount, heap));
fixupThunks(t, image, code); findThunks(t, image, code);
fixupVirtualThunks(t, code); fixupVirtualThunks(t, code);
@ -9369,23 +9391,37 @@ thunkToThunk(const MyProcessor::Thunk& thunk, uint8_t* base)
} }
void void
compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) compileCall(MyThread* t, Context* c, ThunkIndex index, bool call = true)
{ {
class ThunkContext { Assembler* a = c->assembler;
public:
ThunkContext(MyThread* t, Zone* zone):
context(t), promise(t->m->system, zone)
{ }
Context context; if (processor(t)->bootImage) {
ListenPromise promise; Assembler::Memory table(t->arch->thread(), TargetThreadThunkTable);
}; // use Architecture::virtualCallTarget register here as a scratch
// register; any register that isn't used to pass arguments would
// be acceptable:
Assembler::Register tableRegister(t->arch->virtualCallTarget());
a->apply(Move, TargetBytesPerWord, MemoryOperand, &table,
TargetBytesPerWord, RegisterOperand, &tableRegister);
Assembler::Memory proc(tableRegister.low, index * TargetBytesPerWord);
a->apply(call ? Call : Jump, TargetBytesPerWord, MemoryOperand, &proc);
} else {
Assembler::Constant proc
(new (c->zone.allocate(sizeof(ResolvedPromise)))
ResolvedPromise(reinterpret_cast<intptr_t>(t->thunkTable[index])));
Zone zone(t->m->system, t->m->heap, 1024); a->apply
(call ? LongCall : LongJump, TargetBytesPerWord, ConstantOperand, &proc);
}
}
ThunkContext defaultContext(t, &zone); void
compileThunks(MyThread* t, Allocator* allocator)
{
MyProcessor* p = processor(t);
{ Assembler* a = defaultContext.context.assembler; { Context context(t);
Assembler* a = context.assembler;
a->saveFrame(TargetThreadStack, TargetThreadIp); a->saveFrame(TargetThreadStack, TargetThreadIp);
@ -9394,8 +9430,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p)
Assembler::Register thread(t->arch->thread()); Assembler::Register thread(t->arch->thread());
a->pushFrame(1, TargetBytesPerWord, RegisterOperand, &thread); a->pushFrame(1, TargetBytesPerWord, RegisterOperand, &thread);
Assembler::Constant proc(&(defaultContext.promise)); compileCall(t, &context, compileMethodIndex);
a->apply(LongCall, TargetBytesPerWord, ConstantOperand, &proc);
a->popFrame(t->arch->alignFrameSize(1)); a->popFrame(t->arch->alignFrameSize(1));
@ -9403,12 +9438,14 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p)
a->apply(Jump, TargetBytesPerWord, RegisterOperand, &result); a->apply(Jump, TargetBytesPerWord, RegisterOperand, &result);
p->thunks.default_.length = a->endBlock(false)->resolve(0, 0); p->thunks.default_.length = a->endBlock(false)->resolve(0, 0);
p->thunks.default_.start = finish
(t, allocator, a, "default", p->thunks.default_.length);
} }
ThunkContext defaultVirtualContext(t, &zone); { Context context(t);
Assembler* a = context.assembler;
{ Assembler* a = defaultVirtualContext.context.assembler;
Assembler::Register class_(t->arch->virtualCallTarget()); Assembler::Register class_(t->arch->virtualCallTarget());
Assembler::Memory virtualCallTargetSrc Assembler::Memory virtualCallTargetSrc
(t->arch->stack(), (t->arch->stack(),
@ -9437,21 +9474,22 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p)
Assembler::Register thread(t->arch->thread()); Assembler::Register thread(t->arch->thread());
a->pushFrame(1, TargetBytesPerWord, RegisterOperand, &thread); a->pushFrame(1, TargetBytesPerWord, RegisterOperand, &thread);
Assembler::Constant proc(&(defaultVirtualContext.promise));
a->apply(LongCall, TargetBytesPerWord, ConstantOperand, &proc);
compileCall(t, &context, compileVirtualMethodIndex);
a->popFrame(t->arch->alignFrameSize(1)); a->popFrame(t->arch->alignFrameSize(1));
Assembler::Register result(t->arch->returnLow()); Assembler::Register result(t->arch->returnLow());
a->apply(Jump, TargetBytesPerWord, RegisterOperand, &result); a->apply(Jump, TargetBytesPerWord, RegisterOperand, &result);
p->thunks.defaultVirtual.length = a->endBlock(false)->resolve(0, 0); p->thunks.defaultVirtual.length = a->endBlock(false)->resolve(0, 0);
p->thunks.defaultVirtual.start = finish
(t, allocator, a, "defaultVirtual", p->thunks.defaultVirtual.length);
} }
ThunkContext nativeContext(t, &zone); { Context context(t);
Assembler* a = context.assembler;
{ Assembler* a = nativeContext.context.assembler;
a->saveFrame(TargetThreadStack, TargetThreadIp); a->saveFrame(TargetThreadStack, TargetThreadIp);
@ -9460,19 +9498,20 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p)
Assembler::Register thread(t->arch->thread()); Assembler::Register thread(t->arch->thread());
a->pushFrame(1, TargetBytesPerWord, RegisterOperand, &thread); a->pushFrame(1, TargetBytesPerWord, RegisterOperand, &thread);
Assembler::Constant proc(&(nativeContext.promise)); compileCall(t, &context, invokeNativeIndex);
a->apply(LongCall, TargetBytesPerWord, ConstantOperand, &proc);
a->popFrameAndUpdateStackAndReturn a->popFrameAndUpdateStackAndReturn
(t->arch->alignFrameSize(1), TargetThreadStack); (t->arch->alignFrameSize(1), TargetThreadStack);
p->thunks.native.length = a->endBlock(false)->resolve(0, 0); p->thunks.native.length = a->endBlock(false)->resolve(0, 0);
p->thunks.native.start = finish
(t, allocator, a, "native", p->thunks.native.length);
} }
ThunkContext aioobContext(t, &zone); { Context context(t);
Assembler* a = context.assembler;
{ Assembler* a = aioobContext.context.assembler;
a->saveFrame(TargetThreadStack, TargetThreadIp); a->saveFrame(TargetThreadStack, TargetThreadIp);
p->thunks.aioob.frameSavedOffset = a->length(); p->thunks.aioob.frameSavedOffset = a->length();
@ -9480,15 +9519,16 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p)
Assembler::Register thread(t->arch->thread()); Assembler::Register thread(t->arch->thread());
a->pushFrame(1, TargetBytesPerWord, RegisterOperand, &thread); a->pushFrame(1, TargetBytesPerWord, RegisterOperand, &thread);
Assembler::Constant proc(&(aioobContext.promise)); compileCall(t, &context, throwArrayIndexOutOfBoundsIndex);
a->apply(LongCall, TargetBytesPerWord, ConstantOperand, &proc);
p->thunks.aioob.length = a->endBlock(false)->resolve(0, 0); p->thunks.aioob.length = a->endBlock(false)->resolve(0, 0);
p->thunks.aioob.start = finish
(t, allocator, a, "aioob", p->thunks.aioob.length);
} }
ThunkContext stackOverflowContext(t, &zone); { Context context(t);
Assembler* a = context.assembler;
{ Assembler* a = stackOverflowContext.context.assembler;
a->saveFrame(TargetThreadStack, TargetThreadIp); a->saveFrame(TargetThreadStack, TargetThreadIp);
@ -9497,133 +9537,69 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p)
Assembler::Register thread(t->arch->thread()); Assembler::Register thread(t->arch->thread());
a->pushFrame(1, TargetBytesPerWord, RegisterOperand, &thread); a->pushFrame(1, TargetBytesPerWord, RegisterOperand, &thread);
Assembler::Constant proc(&(stackOverflowContext.promise)); compileCall(t, &context, throwStackOverflowIndex);
a->apply(LongCall, TargetBytesPerWord, ConstantOperand, &proc);
p->thunks.stackOverflow.length = a->endBlock(false)->resolve(0, 0); p->thunks.stackOverflow.length = a->endBlock(false)->resolve(0, 0);
p->thunks.stackOverflow.start = finish
(t, allocator, a, "stackOverflow", p->thunks.stackOverflow.length);
} }
ThunkContext tableContext(t, &zone); { { Context context(t);
Assembler* a = context.assembler;
{ Assembler* a = tableContext.context.assembler; a->saveFrame(TargetThreadStack, TargetThreadIp);
a->saveFrame(TargetThreadStack, TargetThreadIp);
p->thunks.table.frameSavedOffset = a->length(); p->thunks.table.frameSavedOffset = a->length();
Assembler::Constant proc(&(tableContext.promise)); compileCall(t, &context, dummyIndex, false);
a->apply(LongJump, TargetBytesPerWord, ConstantOperand, &proc);
p->thunks.table.length = a->endBlock(false)->resolve(0, 0); p->thunks.table.length = a->endBlock(false)->resolve(0, 0);
}
p->thunks.default_.start = finish p->thunks.table.start = static_cast<uint8_t*>
(t, allocator, defaultContext.context.assembler, "default", (allocator->allocate(p->thunks.table.length * ThunkCount));
p->thunks.default_.length); }
uint8_t* start = p->thunks.table.start;
#define THUNK(s) { \
Context context(t); \
Assembler* a = context.assembler; \
\
a->saveFrame(TargetThreadStack, TargetThreadIp); \
\
p->thunks.table.frameSavedOffset = a->length(); \
\
compileCall(t, &context, s##Index, false); \
\
expect(t, a->endBlock(false)->resolve(0, 0) \
<= p->thunks.table.length); \
\
a->setDestination(start); \
a->write(); \
\
logCompile(t, start, p->thunks.table.length, 0, #s, 0); \
\
start += p->thunks.table.length; \
}
#include "thunks.cpp"
#undef THUNK
}
BootImage* image = p->bootImage; BootImage* image = p->bootImage;
uint8_t* imageBase = p->codeAllocator.base;
{ void* call;
defaultContext.promise.listener->resolve
(reinterpret_cast<intptr_t>(voidPointer(compileMethod)), &call);
if (image) {
image->compileMethodCall = static_cast<uint8_t*>(call) - imageBase;
}
}
p->thunks.defaultVirtual.start = finish
(t, allocator, defaultVirtualContext.context.assembler, "defaultVirtual",
p->thunks.defaultVirtual.length);
{ void* call;
defaultVirtualContext.promise.listener->resolve
(reinterpret_cast<intptr_t>(voidPointer(compileVirtualMethod)), &call);
if (image) {
image->compileVirtualMethodCall
= static_cast<uint8_t*>(call) - imageBase;
}
}
p->thunks.native.start = finish
(t, allocator, nativeContext.context.assembler, "native",
p->thunks.native.length);
{ void* call;
nativeContext.promise.listener->resolve
(reinterpret_cast<intptr_t>(voidPointer(invokeNative)), &call);
if (image) {
image->invokeNativeCall = static_cast<uint8_t*>(call) - imageBase;
}
}
p->thunks.aioob.start = finish
(t, allocator, aioobContext.context.assembler, "aioob",
p->thunks.aioob.length);
{ void* call;
aioobContext.promise.listener->resolve
(reinterpret_cast<intptr_t>(voidPointer(throwArrayIndexOutOfBounds)),
&call);
if (image) {
image->throwArrayIndexOutOfBoundsCall
= static_cast<uint8_t*>(call) - imageBase;
}
}
p->thunks.stackOverflow.start = finish
(t, allocator, stackOverflowContext.context.assembler, "stackOverflow",
p->thunks.stackOverflow.length);
{ void* call;
stackOverflowContext.promise.listener->resolve
(reinterpret_cast<intptr_t>(voidPointer(throwStackOverflow)),
&call);
if (image) {
image->throwStackOverflowCall
= static_cast<uint8_t*>(call) - imageBase;
}
}
p->thunks.table.start = static_cast<uint8_t*>
(allocator->allocate(p->thunks.table.length * ThunkCount));
if (image) { if (image) {
uint8_t* imageBase = p->codeAllocator.base;
image->thunks.default_ = thunkToThunk(p->thunks.default_, imageBase); image->thunks.default_ = thunkToThunk(p->thunks.default_, imageBase);
image->thunks.defaultVirtual image->thunks.defaultVirtual = thunkToThunk
= thunkToThunk(p->thunks.defaultVirtual, imageBase); (p->thunks.defaultVirtual, imageBase);
image->thunks.native = thunkToThunk(p->thunks.native, imageBase); image->thunks.native = thunkToThunk(p->thunks.native, imageBase);
image->thunks.aioob = thunkToThunk(p->thunks.aioob, imageBase); image->thunks.aioob = thunkToThunk(p->thunks.aioob, imageBase);
image->thunks.stackOverflow image->thunks.stackOverflow = thunkToThunk
= thunkToThunk(p->thunks.stackOverflow, imageBase); (p->thunks.stackOverflow, imageBase);
image->thunks.table = thunkToThunk(p->thunks.table, imageBase); image->thunks.table = thunkToThunk(p->thunks.table, imageBase);
} }
logCompile(t, p->thunks.table.start, p->thunks.table.length * ThunkCount, 0,
"thunkTable", 0);
uint8_t* start = p->thunks.table.start;
#define THUNK(s) \
tableContext.context.assembler->setDestination(start); \
tableContext.context.assembler->write(); \
start += p->thunks.table.length; \
{ void* call; \
tableContext.promise.listener->resolve \
(reinterpret_cast<intptr_t>(voidPointer(s)), &call); \
if (image) { \
image->s##Call = static_cast<uint8_t*>(call) - imageBase; \
} \
}
#include "thunks.cpp"
#undef THUNK
} }
MyProcessor* MyProcessor*

View File

@ -3083,8 +3083,8 @@ class MyProcessor: public Processor {
abort(s); abort(s);
} }
virtual void boot(vm::Thread*, BootImage* image) { virtual void boot(vm::Thread*, BootImage* image, uint8_t* code) {
expect(s, image == 0); expect(s, image == 0 and code == 0);
} }

View File

@ -2208,7 +2208,7 @@ boot(Thread* t)
setRoot(t, Machine::StringMap, makeWeakHashMap(t, 0, 0)); setRoot(t, Machine::StringMap, makeWeakHashMap(t, 0, 0));
m->processor->boot(t, 0); m->processor->boot(t, 0, 0);
{ object bootCode = makeCode(t, 0, 0, 0, 0, 0, 0, 1); { object bootCode = makeCode(t, 0, 0, 0, 0, 0, 0, 1);
codeBody(t, bootCode, 0) = impdep1; codeBody(t, bootCode, 0) = impdep1;
@ -2537,15 +2537,27 @@ Thread::init()
} }
BootImage* image = 0; BootImage* image = 0;
uint8_t* code = 0;
const char* imageFunctionName = findProperty(m, "avian.bootimage"); const char* imageFunctionName = findProperty(m, "avian.bootimage");
if (imageFunctionName) { if (imageFunctionName) {
void* p = m->libraries->resolve(imageFunctionName); void* imagep = m->libraries->resolve(imageFunctionName);
if (p) { if (imagep) {
BootImage* (*function)(unsigned*); BootImage* (*imageFunction)(unsigned*);
memcpy(&function, &p, BytesPerWord); memcpy(&imageFunction, &imagep, BytesPerWord);
unsigned size; unsigned size;
image = function(&size); image = imageFunction(&size);
const char* codeFunctionName = findProperty(m, "avian.codeimage");
if (codeFunctionName) {
void* codep = m->libraries->resolve(codeFunctionName);
if (codep) {
uint8_t* (*codeFunction)(unsigned*);
memcpy(&codeFunction, &codep, BytesPerWord);
code = codeFunction(&size);
}
}
} }
} }
@ -2553,8 +2565,8 @@ Thread::init()
enter(this, ActiveState); enter(this, ActiveState);
if (image) { if (image and image) {
m->processor->boot(this, image); m->processor->boot(this, image, code);
} else { } else {
boot(this); boot(this);
} }

View File

@ -211,7 +211,7 @@ main(int ac, const char** av)
#endif #endif
#ifdef BOOT_IMAGE #ifdef BOOT_IMAGE
++ vmArgs.nOptions; vmArgs.nOptions += 2;
#endif #endif
#ifdef BOOT_BUILTINS #ifdef BOOT_BUILTINS
@ -225,7 +225,10 @@ main(int ac, const char** av)
#ifdef BOOT_IMAGE #ifdef BOOT_IMAGE
vmArgs.options[optionIndex++].optionString vmArgs.options[optionIndex++].optionString
= const_cast<char*>("-Davian.bootimage=" BOOT_IMAGE); = const_cast<char*>("-Davian.bootimage=bootimageBin");
vmArgs.options[optionIndex++].optionString
= const_cast<char*>("-Davian.codeimage=codeimageBin");
#endif #endif
#ifdef BOOT_LIBRARY #ifdef BOOT_LIBRARY

View File

@ -135,7 +135,7 @@ class Processor {
makeCallTable(Thread* t, HeapWalker* w) = 0; makeCallTable(Thread* t, HeapWalker* w) = 0;
virtual void virtual void
boot(Thread* t, BootImage* image) = 0; boot(Thread* t, BootImage* image, uint8_t* code) = 0;
virtual void virtual void
callWithCurrentContinuation(Thread* t, object receiver) = 0; callWithCurrentContinuation(Thread* t, object receiver) = 0;

View File

@ -92,12 +92,15 @@ typedef int64_t target_intptr_t;
const unsigned TargetBytesPerWord = 8; const unsigned TargetBytesPerWord = 8;
const unsigned TargetThreadTailAddress = 2272;
const unsigned TargetThreadStackLimit = 2336;
const unsigned TargetThreadStack = 2224;
const unsigned TargetThreadIp = 2216; const unsigned TargetThreadIp = 2216;
const unsigned TargetThreadStack = 2224;
const unsigned TargetThreadTailAddress = 2272;
const unsigned TargetThreadVirtualCallTarget = 2280; const unsigned TargetThreadVirtualCallTarget = 2280;
const unsigned TargetThreadVirtualCallIndex = 2288; const unsigned TargetThreadVirtualCallIndex = 2288;
const unsigned TargetThreadHeapImage = 2296;
const unsigned TargetThreadCodeImage = 2304;
const unsigned TargetThreadThunkTable = 2312;
const unsigned TargetThreadStackLimit = 2360;
const unsigned TargetClassFixedSize = 12; const unsigned TargetClassFixedSize = 12;
const unsigned TargetClassArrayElementSize = 14; const unsigned TargetClassArrayElementSize = 14;
@ -119,12 +122,15 @@ typedef int32_t target_intptr_t;
const unsigned TargetBytesPerWord = 4; const unsigned TargetBytesPerWord = 4;
const unsigned TargetThreadTailAddress = 2172;
const unsigned TargetThreadStackLimit = 2204;
const unsigned TargetThreadStack = 2148;
const unsigned TargetThreadIp = 2144; const unsigned TargetThreadIp = 2144;
const unsigned TargetThreadStack = 2148;
const unsigned TargetThreadTailAddress = 2172;
const unsigned TargetThreadVirtualCallTarget = 2176; const unsigned TargetThreadVirtualCallTarget = 2176;
const unsigned TargetThreadVirtualCallIndex = 2180; const unsigned TargetThreadVirtualCallIndex = 2180;
const unsigned TargetThreadHeapImage = 2184;
const unsigned TargetThreadCodeImage = 2188;
const unsigned TargetThreadThunkTable = 2192;
const unsigned TargetThreadStackLimit = 2216;
const unsigned TargetClassFixedSize = 8; const unsigned TargetClassFixedSize = 8;
const unsigned TargetClassArrayElementSize = 10; const unsigned TargetClassArrayElementSize = 10;

View File

@ -345,8 +345,10 @@ void
appendOffsetTask(Context* c, Promise* promise, Promise* instructionOffset, appendOffsetTask(Context* c, Promise* promise, Promise* instructionOffset,
unsigned instructionSize) unsigned instructionSize)
{ {
c->tasks = new (c->zone->allocate(sizeof(OffsetTask))) OffsetTask OffsetTask* task = new (c->zone->allocate(sizeof(OffsetTask))) OffsetTask
(c->tasks, promise, instructionOffset, instructionSize); (c->tasks, promise, instructionOffset, instructionSize);
c->tasks = task;
} }
void void