mirror of
https://github.com/corda/corda.git
synced 2025-01-17 02:09:50 +00:00
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:
parent
349d381d95
commit
c537dcfd34
23
makefile
23
makefile
@ -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
|
||||||
|
@ -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):
|
||||||
|
@ -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;
|
||||||
|
@ -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";
|
||||||
|
@ -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,
|
||||||
|
24
src/boot.cpp
24
src/boot.cpp
@ -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
43
src/bootimage-fields.cpp
Normal 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
|
@ -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);
|
||||||
|
554
src/compile.cpp
554
src/compile.cpp
@ -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*
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
18
src/target.h
18
src/target.h
@ -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;
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user