corda/src/compile.cpp

3988 lines
88 KiB
C++
Raw Normal View History

#include "common.h"
#include "system.h"
#include "constants.h"
#include "machine.h"
#include "processor.h"
#include "process.h"
using namespace vm;
extern "C" uint64_t
vmInvoke(void* function, void* stack, unsigned stackSize,
unsigned returnType);
2007-10-04 03:19:39 +00:00
extern "C" void
vmCall();
2007-10-02 00:08:17 +00:00
extern "C" void NO_RETURN
2007-10-04 22:41:19 +00:00
vmJump(void* address, void* base, void* stack);
2007-10-02 00:08:17 +00:00
namespace {
2007-10-04 00:41:54 +00:00
const bool Verbose = true;
2007-09-30 15:52:21 +00:00
const unsigned FrameThread = BytesPerWord * 2;
const unsigned FrameMethod = FrameThread + BytesPerWord;
2007-10-04 00:41:54 +00:00
const unsigned FrameNext = FrameMethod + BytesPerWord;
const unsigned FrameFootprint = BytesPerWord * 3;
2007-09-25 23:53:11 +00:00
class ArgumentList;
2007-10-03 00:22:48 +00:00
class Buffer {
public:
Buffer(System* s, unsigned minimumCapacity):
s(s),
data(0),
position(0),
capacity(0),
minimumCapacity(minimumCapacity)
{ }
~Buffer() {
if (data) {
s->free(data);
}
}
void ensure(unsigned space) {
if (position + space > capacity) {
unsigned newCapacity = max
(position + space, max(minimumCapacity, capacity * 2));
uint8_t* newData = static_cast<uint8_t*>(s->allocate(newCapacity));
if (data) {
memcpy(newData, data, position);
s->free(data);
}
data = newData;
}
}
void append(uint8_t v) {
ensure(1);
data[position++] = v;
}
void append2(uint16_t v) {
ensure(2);
memcpy(data + position, &v, 2);
position += 2;
}
void append4(uint32_t v) {
ensure(4);
memcpy(data + position, &v, 4);
position += 4;
}
void set2(unsigned offset, uint32_t v) {
assert(s, offset + 2 <= position);
memcpy(data + offset, &v, 2);
}
void set4(unsigned offset, uint32_t v) {
assert(s, offset + 4 <= position);
memcpy(data + offset, &v, 4);
}
uint16_t get(unsigned offset) {
assert(s, offset + 1 <= position);
return data[offset];
}
2007-10-03 00:22:48 +00:00
uint16_t get2(unsigned offset) {
assert(s, offset + 2 <= position);
uint16_t v; memcpy(&v, data + offset, 2);
return v;
}
uint32_t get4(unsigned offset) {
assert(s, offset + 4 <= position);
uint32_t v; memcpy(&v, data + offset, 4);
return v;
}
void appendAddress(uintptr_t v) {
append4(v);
if (BytesPerWord == 8) {
// we have to use the preprocessor here to avoid a warning on
// 32-bit systems
#ifdef __x86_64__
append4(v >> 32);
#endif
}
}
unsigned length() {
return position;
}
void copyTo(void* b) {
if (data) {
memcpy(b, data, position);
}
}
System* s;
uint8_t* data;
unsigned position;
unsigned capacity;
unsigned minimumCapacity;
};
2007-10-10 22:39:40 +00:00
class StackMapper {
public:
static const uint32_t Infinity = ~static_cast<uint32_t>(0);
enum {
Call,
2007-10-10 22:39:40 +00:00
PushLong,
PushInt,
PushObject,
Duplicate,
2007-10-12 00:30:46 +00:00
Pop,
2007-10-10 22:39:40 +00:00
PopLong,
PopInt,
PopObject,
PopIntOrObject,
StoreObject,
Return,
2007-10-10 22:39:40 +00:00
Jump,
Branch,
End
2007-10-10 22:39:40 +00:00
};
StackMapper(Thread* t, object method):
t(t),
method(method),
ip(-1),
2007-10-10 22:39:40 +00:00
index(codeSize() ? static_cast<uint32_t*>
(t->m->system->allocate(codeSize() * 4)) : 0),
log(t->m->system, 1024),
callCount(0)
2007-10-10 22:39:40 +00:00
{ }
~StackMapper() {
if (index) {
t->m->system->free(index);
}
}
unsigned codeSize() {
return codeLength(t, methodCode(t, method));
}
void end(unsigned nextIp) {
if (ip >= 0) {
log.append(End);
log.append2(nextIp);
}
ip = nextIp;
}
2007-10-10 22:39:40 +00:00
void newIp(unsigned javaIp) {
assert(t, javaIp < codeSize());
end(javaIp);
2007-10-10 22:39:40 +00:00
index[javaIp] = log.length();
}
void finish() {
end(codeSize());
}
void called(unsigned nextMachineIp) {
log.append(Call);
log.append4(nextMachineIp);
++ callCount;
2007-10-10 22:39:40 +00:00
}
void pushedLong() {
log.append(PushLong);
}
void pushedInt() {
log.append(PushInt);
}
void pushedObject() {
log.append(PushObject);
}
void dupped() {
log.append(Duplicate);
}
2007-10-12 00:30:46 +00:00
void popped(unsigned count) {
log.append(Pop);
log.append(count);
}
2007-10-10 22:39:40 +00:00
void poppedLong() {
log.append(PopLong);
}
void poppedInt() {
log.append(PopInt);
}
void poppedObject() {
log.append(PopObject);
}
void poppedIntOrObject() {
log.append(PopIntOrObject);
}
void storedObject(unsigned index) {
log.append(StoreObject);
log.append2(index - parameterFootprint());
2007-10-10 22:39:40 +00:00
}
2007-10-12 00:30:46 +00:00
void exited() {
log.append(Return);
2007-10-10 22:39:40 +00:00
}
void jumped(unsigned targetJavaIp) {
2007-10-10 22:39:40 +00:00
log.append(Jump);
log.append2(targetJavaIp);
2007-10-10 22:39:40 +00:00
}
void branched(unsigned targetJavaIp) {
2007-10-10 22:39:40 +00:00
log.append(Branch);
log.append2(targetJavaIp);
}
unsigned parameterFootprint() {
return methodParameterFootprint(t, method);
}
unsigned localSize() {
return codeMaxLocals(t, methodCode(t, method))
- parameterFootprint();
}
unsigned stackSize() {
return codeMaxStack(t, methodCode(t, method));
}
unsigned mapSize() {
return stackSize() + localSize();
}
unsigned mapSizeInWords() {
return ceiling(mapSize(), BytesPerWord);
}
unsigned mapSizeInBytes() {
return mapSizeInWords() * BytesPerWord;
}
unsigned callTableSize() {
return callCount * (mapSizeInBytes() + BytesPerWord);
}
void populateCalls(uintptr_t* calls, unsigned& callIndex, uintptr_t* table,
uintptr_t* mask, uintptr_t* initialMap,
unsigned initialSp, unsigned ip)
{
uintptr_t map[mapSizeInWords()];
memcpy(map, initialMap, mapSizeInBytes());
unsigned sp = initialSp;
while (ip < codeSize()) {
if (getBit(mask, ip)) {
return;
}
markBit(mask, ip);
memcpy(table + (ip * mapSizeInWords()), map, mapSizeInBytes());
unsigned i = index[ip];
while (true) {
switch (log.get(i++)) {
case Call: {
assert(t, callIndex < callCount);
unsigned machineIp = log.get4(i); i += 4;
calls[callIndex * (mapSizeInWords() + 1)] = machineIp;
memcpy(calls + (callIndex * (mapSizeInWords() + 1)) + 1,
map, mapSizeInBytes());
++ callIndex;
} break;
case PushLong:
assert(t, sp + 2 <= mapSize());
2007-10-12 00:30:46 +00:00
assert(t, getBit(map, sp) == 0);
assert(t, getBit(map, sp + 1) == 0);
sp += 2;
break;
case PushInt:
assert(t, sp + 1 <= mapSize());
2007-10-12 00:30:46 +00:00
assert(t, getBit(map, sp) == 0);
++ sp;
break;
case PushObject:
assert(t, sp + 1 <= mapSize());
markBit(map, sp++);
break;
case Duplicate:
assert(t, sp + 1 <= mapSize());
assert(t, sp - 1 >= localSize());
if (getBit(map, sp - 1)) {
markBit(map, sp);
}
++ sp;
break;
2007-10-12 00:30:46 +00:00
case Pop: {
unsigned count = log.get(i++);
assert(t, sp >= count);
assert(t, sp - count >= localSize());
while (count) {
clearBit(map, -- sp);
-- count;
}
} break;
case PopLong:
2007-10-12 00:30:46 +00:00
assert(t, sp >= 2);
assert(t, sp - 2 >= localSize());
assert(t, getBit(map, sp - 1) == 0);
assert(t, getBit(map, sp - 2) == 0);
sp -= 2;
break;
case PopInt:
2007-10-12 00:30:46 +00:00
assert(t, sp >= 1);
assert(t, sp - 1 >= localSize());
assert(t, getBit(map, sp - 1) == 0);
-- sp;
break;
case PopObject:
2007-10-12 00:30:46 +00:00
assert(t, sp >= 1);
assert(t, sp - 1 >= localSize());
assert(t, getBit(map, sp - 1) != 0);
clearBit(map, -- sp);
break;
case PopIntOrObject:
2007-10-12 00:30:46 +00:00
assert(t, sp >= 1);
assert(t, sp - 1 >= localSize());
clearBit(map, -- sp);
break;
case StoreObject: {
unsigned index = log.get2(i); i += 2;
assert(t, index < localSize());
markBit(map, index);
} break;
case Return:
ip = codeSize();
goto loop;
case Jump:
ip = log.get2(i); i += 2;
assert(t, ip < codeSize());
goto loop;
case Branch: {
unsigned target = log.get2(i); i += 2;
assert(t, target < codeSize());
populateCalls(calls, callIndex, table, mask, map, sp, target);
} break;
case End:
goto next;
default:
abort(t);
}
}
next:
ip = log.get2(i);
loop:;
}
}
static int compareCalls(const void* a, const void* b) {
return (*static_cast<const uintptr_t*>(a) >
*static_cast<const uintptr_t*>(b) ? 1 : -1);
2007-10-10 22:39:40 +00:00
}
void writeCallTableTo(uintptr_t* calls) {
uintptr_t* table = static_cast<uintptr_t*>
(t->m->system->allocate(codeSize() * mapSizeInBytes()));
uintptr_t* mask = static_cast<uintptr_t*>
(t->m->system->allocate
(ceiling(codeSize(), BytesPerWord) * BytesPerWord));
memset(mask, 0, ceiling(codeSize(), BytesPerWord) * BytesPerWord);
uintptr_t map[mapSizeInWords()];
memset(map, 0, mapSizeInWords());
unsigned callIndex = 0;
populateCalls(calls, callIndex, table, mask, map, localSize(), 0);
object eht = codeExceptionHandlerTable(t, methodCode(t, method));
if (eht) {
PROTECT(t, eht);
for (unsigned i = 0; i < exceptionHandlerTableLength(t, eht); ++i) {
ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i);
assert(t, getBit(mask, exceptionHandlerStart(eh)));
memcpy(map,
2007-10-12 14:26:36 +00:00
table + (exceptionHandlerStart(eh) * mapSizeInWords()),
mapSizeInBytes());
for (unsigned j = localSize() + 1; j < mapSize(); ++j) {
clearBit(map, j);
}
markBit(map, localSize());
populateCalls(calls, callIndex, table, mask, map, localSize() + 1,
exceptionHandlerIp(eh));
}
}
t->m->system->free(mask);
2007-10-12 14:26:36 +00:00
t->m->system->free(table);
assert(t, callIndex == callCount);
qsort(calls, callCount, mapSizeInBytes() + BytesPerWord, compareCalls);
2007-10-10 22:39:40 +00:00
}
Thread* t;
object method;
int ip;
2007-10-10 22:39:40 +00:00
uint32_t* index;
Buffer log;
unsigned callCount;
2007-10-10 22:39:40 +00:00
};
class MyThread: public Thread {
public:
MyThread(Machine* m, object javaThread, vm::Thread* parent):
vm::Thread(m, javaThread, parent),
argumentList(0),
frame(0),
reference(0)
{ }
ArgumentList* argumentList;
void* frame;
Reference* reference;
};
2007-10-04 00:41:54 +00:00
inline void*
frameBase(void* frame)
2007-10-02 00:08:17 +00:00
{
2007-10-04 22:41:19 +00:00
return static_cast<void**>(frame)
[static_cast<int>(- (FrameFootprint / BytesPerWord) - 2)];
2007-10-02 00:08:17 +00:00
}
2007-10-04 00:41:54 +00:00
inline bool
frameValid(void* frame)
2007-10-02 00:08:17 +00:00
{
2007-10-04 03:19:39 +00:00
return frame != 0;
2007-10-02 00:08:17 +00:00
}
inline void*
frameNext(void* frame)
{
2007-10-04 03:19:39 +00:00
return static_cast<void**>(frameBase(frame))[FrameNext / BytesPerWord];
2007-10-02 00:08:17 +00:00
}
inline object
frameMethod(void* frame)
{
return static_cast<object*>(frameBase(frame))[FrameMethod / BytesPerWord];
}
2007-10-03 00:22:48 +00:00
inline void*
2007-10-02 00:08:17 +00:00
frameAddress(void* frame)
{
2007-10-04 22:41:19 +00:00
return static_cast<void**>(frame)
[static_cast<int>(- (FrameFootprint / BytesPerWord) - 1)];
2007-10-02 00:08:17 +00:00
}
inline void*
frameReturnAddress(void* frame)
{
return static_cast<void**>(frameBase(frame))[1];
}
2007-10-04 00:41:54 +00:00
inline uint8_t*
compiledCode(Compiled* code)
{
return compiledBody(code);
}
2007-10-04 22:41:19 +00:00
inline unsigned
compiledLineNumberCount(Thread*, Compiled* code)
{
return compiledLineNumberTableLength(code) / sizeof(NativeLineNumber);
}
2007-10-04 00:41:54 +00:00
inline NativeLineNumber*
compiledLineNumber(Thread* t, Compiled* code, unsigned index)
{
2007-10-04 22:41:19 +00:00
assert(t, index < compiledLineNumberCount(t, code));
2007-10-04 00:41:54 +00:00
return reinterpret_cast<NativeLineNumber*>
2007-10-04 22:41:19 +00:00
(compiledBody(code) + pad(compiledCodeLength(code))) + index;
}
inline unsigned
compiledExceptionHandlerCount(Thread*, Compiled* code)
{
return compiledExceptionHandlerTableLength(code)
/ sizeof(NativeExceptionHandler);
2007-10-04 00:41:54 +00:00
}
inline NativeExceptionHandler*
compiledExceptionHandler(Thread* t, Compiled* code, unsigned index)
{
2007-10-04 22:41:19 +00:00
assert(t, index < compiledExceptionHandlerCount(t, code));
2007-10-04 00:41:54 +00:00
return reinterpret_cast<NativeExceptionHandler*>
2007-10-10 22:39:40 +00:00
(compiledBody(code)
+ pad(compiledCodeLength(code))
2007-10-04 22:41:19 +00:00
+ pad(compiledLineNumberTableLength(code))) + index;
2007-10-04 00:41:54 +00:00
}
2007-10-10 22:39:40 +00:00
inline unsigned
compiledStackMapSize(Thread*, Compiled* code)
{
return ceiling(compiledMaxStack(code)
+ compiledMaxLocals(code)
- compiledParameterFootprint(code),
BytesPerWord) + 1;
2007-10-10 22:39:40 +00:00
}
inline unsigned
compiledStackMapCount(Thread* t, Compiled* code)
{
return compiledStackMapTableLength(code)
/ (compiledStackMapSize(t, code) * BytesPerWord);
}
inline uintptr_t*
compiledStackMap(Thread* t, Compiled* code, unsigned index)
{
assert(t, index < compiledStackMapCount(t, code));
return reinterpret_cast<uintptr_t*>
(compiledBody(code)
+ pad(compiledCodeLength(code))
+ pad(compiledLineNumberTableLength(code))
+ pad(compiledExceptionHandlerTableLength(code)))
+ (index * compiledStackMapSize(t, code));
}
inline Compiled*
makeCompiled(Thread* t, Buffer* code)
{
Compiled* c = static_cast<Compiled*>
(t->m->system->allocate(sizeof(Compiled) + pad(code->length())));
compiledMaxLocals(c) = 0;
compiledMaxStack(c) = 0;
compiledParameterFootprint(c) = 0;
compiledCodeLength(c) = code->length();
compiledLineNumberTableLength(c) = 0;
compiledExceptionHandlerTableLength(c) = 0;
compiledStackMapTableLength(c) = 0;
if (code->length()) {
code->copyTo(compiledCode(c));
}
return c;
}
2007-10-04 00:41:54 +00:00
inline Compiled*
makeCompiled(Thread* t, object method, Buffer* code,
NativeLineNumber* lineNumbers,
2007-10-10 22:39:40 +00:00
NativeExceptionHandler* exceptionHandlers,
StackMapper* stackMapper)
2007-10-04 00:41:54 +00:00
{
unsigned lineNumberCount
2007-10-10 22:39:40 +00:00
= codeLineNumberTable(t, methodCode(t, method)) ?
lineNumberTableLength
(t, codeLineNumberTable(t, methodCode(t, method))) : 0;
2007-10-10 22:39:40 +00:00
unsigned exceptionHandlerCount
2007-10-10 22:39:40 +00:00
= codeExceptionHandlerTable(t, methodCode(t, method)) ?
exceptionHandlerTableLength
(t, codeExceptionHandlerTable(t, methodCode(t, method))) : 0;
2007-10-10 22:39:40 +00:00
unsigned maxStack = codeMaxStack(t, methodCode(t, method));
unsigned maxLocals = codeMaxLocals(t, methodCode(t, method));
unsigned parameterFootprint = methodParameterFootprint(t, method);
2007-10-04 00:41:54 +00:00
Compiled* c = static_cast<Compiled*>
(t->m->system->allocate(sizeof(Compiled)
+ pad(code->length())
2007-10-10 22:39:40 +00:00
+ pad(lineNumberCount
* sizeof(NativeLineNumber))
+ pad(exceptionHandlerCount
2007-10-10 22:39:40 +00:00
* sizeof(NativeExceptionHandler))
+ pad(stackMapper->callTableSize())));
2007-10-10 22:39:40 +00:00
compiledMaxLocals(c) = maxStack;
compiledMaxStack(c) = maxLocals;
compiledParameterFootprint(c) = parameterFootprint;
2007-10-04 00:41:54 +00:00
compiledCodeLength(c) = code->length();
2007-10-10 22:39:40 +00:00
compiledLineNumberTableLength(c)
= lineNumberCount * sizeof(NativeLineNumber);
2007-10-10 22:39:40 +00:00
compiledExceptionHandlerTableLength(c)
= exceptionHandlerCount * sizeof(NativeExceptionHandler);
2007-10-04 00:41:54 +00:00
compiledStackMapTableLength(c) = stackMapper->callTableSize();
2007-10-10 22:39:40 +00:00
2007-10-04 00:41:54 +00:00
if (code->length()) {
code->copyTo(compiledCode(c));
}
2007-10-10 22:39:40 +00:00
if (lineNumberCount) {
memcpy(compiledLineNumber(t, c, 0),
lineNumbers,
lineNumberCount * sizeof(NativeLineNumber));
2007-10-04 00:41:54 +00:00
}
2007-10-10 22:39:40 +00:00
if (exceptionHandlerCount) {
memcpy(compiledExceptionHandler(t, c, 0),
exceptionHandlers,
exceptionHandlerCount * sizeof(NativeExceptionHandler));
2007-10-04 00:41:54 +00:00
}
2007-10-12 00:30:46 +00:00
if (stackMapper->callTableSize()) {
stackMapper->writeCallTableTo(compiledStackMap(t, c, 0));
2007-10-10 22:39:40 +00:00
}
2007-10-04 00:41:54 +00:00
return c;
}
2007-10-03 00:22:48 +00:00
inline unsigned
addressOffset(Thread* t, object method, void* address)
2007-10-02 00:08:17 +00:00
{
2007-10-04 00:41:54 +00:00
Compiled* code = reinterpret_cast<Compiled*>(methodCompiled(t, method));
return static_cast<uint8_t*>(address) - compiledCode(code);
2007-10-02 00:08:17 +00:00
}
2007-10-03 01:54:21 +00:00
NativeExceptionHandler*
2007-10-03 00:22:48 +00:00
findExceptionHandler(Thread* t, void* frame)
2007-10-02 00:08:17 +00:00
{
2007-10-03 00:22:48 +00:00
object method = frameMethod(frame);
2007-10-04 00:41:54 +00:00
Compiled* code = reinterpret_cast<Compiled*>(methodCompiled(t, method));
2007-10-03 00:22:48 +00:00
2007-10-04 22:41:19 +00:00
for (unsigned i = 0; i < compiledExceptionHandlerCount(t, code); ++i) {
2007-10-04 00:41:54 +00:00
NativeExceptionHandler* handler = compiledExceptionHandler(t, code, i);
2007-10-03 00:22:48 +00:00
unsigned offset = addressOffset(t, method, frameAddress(frame));
2007-10-03 01:54:21 +00:00
if (offset - 1 >= nativeExceptionHandlerStart(handler)
and offset - 1 < nativeExceptionHandlerEnd(handler))
2007-10-03 00:22:48 +00:00
{
object catchType;
2007-10-03 01:54:21 +00:00
if (nativeExceptionHandlerCatchType(handler)) {
2007-10-03 00:22:48 +00:00
catchType = arrayBody
2007-10-03 01:54:21 +00:00
(t, methodCode(t, method),
nativeExceptionHandlerCatchType(handler) - 1);
2007-10-03 00:22:48 +00:00
} else {
catchType = 0;
}
if (catchType == 0 or instanceOf(t, catchType, t->exception)) {
2007-10-04 22:41:19 +00:00
fprintf(stderr, "exception handler match for %d in %s: "
"start: %d; end: %d; ip: %d\n",
offset,
&byteArrayBody(t, methodName(t, frameMethod(frame)), 0),
nativeExceptionHandlerStart(handler),
nativeExceptionHandlerEnd(handler),
nativeExceptionHandlerIp(handler));
2007-10-03 00:22:48 +00:00
return handler;
}
2007-10-02 00:08:17 +00:00
}
}
2007-10-03 00:22:48 +00:00
return 0;
2007-10-02 00:08:17 +00:00
}
void NO_RETURN
2007-10-03 00:22:48 +00:00
unwind(MyThread* t)
2007-09-29 21:08:29 +00:00
{
2007-10-02 00:08:17 +00:00
for (void* frame = t->frame; frameValid(frame); frame = frameNext(frame)) {
2007-10-04 22:41:19 +00:00
if ((methodFlags(t, frameMethod(frame)) & ACC_NATIVE) == 0) {
2007-10-03 01:54:21 +00:00
NativeExceptionHandler* eh = findExceptionHandler(t, frame);
2007-10-02 00:08:17 +00:00
if (eh) {
2007-10-04 22:41:19 +00:00
object method = frameMethod(frame);
2007-10-04 00:41:54 +00:00
Compiled* code = reinterpret_cast<Compiled*>
2007-10-04 22:41:19 +00:00
(methodCompiled(t, method));
2007-10-02 00:08:17 +00:00
t->frame = frame;
2007-10-04 22:41:19 +00:00
void** stack = static_cast<void**>(frameBase(frame));
unsigned parameterFootprint = methodParameterFootprint(t, method);
unsigned localFootprint = compiledMaxLocals(code);
if (localFootprint > parameterFootprint) {
stack -= (localFootprint - parameterFootprint);
}
*(--stack) = t->exception;
t->exception = 0;
2007-10-04 00:41:54 +00:00
vmJump(compiledCode(code) + nativeExceptionHandlerIp(eh),
2007-10-04 22:41:19 +00:00
frameBase(frame),
stack);
2007-10-02 00:08:17 +00:00
}
}
2007-10-04 22:41:19 +00:00
void* next = frameNext(frame);
if (not frameValid(next)
or methodFlags(t, frameMethod(next)) & ACC_NATIVE)
{
t->frame = next;
vmJump(frameReturnAddress(frame),
*static_cast<void**>(frameBase(frame)),
static_cast<void**>(frameBase(frame)) + 2);
}
2007-10-02 00:08:17 +00:00
}
2007-09-29 21:08:29 +00:00
abort(t);
}
void NO_RETURN
2007-10-03 00:22:48 +00:00
throwNew(MyThread* t, object class_)
2007-09-29 21:08:29 +00:00
{
t->exception = makeNew(t, class_);
2007-10-09 19:30:01 +00:00
object trace = makeTrace(t);
set(t, cast<object>(t->exception, ThrowableTrace), trace);
2007-09-29 21:08:29 +00:00
unwind(t);
}
void NO_RETURN
2007-10-03 00:22:48 +00:00
throw_(MyThread* t, object o)
2007-09-30 02:48:27 +00:00
{
if (o) {
t->exception = o;
2007-10-04 00:41:54 +00:00
} else {
t->exception = makeNullPointerException(t);
2007-09-30 02:48:27 +00:00
}
unwind(t);
}
int64_t
divideLong(MyThread*, int64_t a, int64_t b)
{
return a / b;
}
int64_t
moduloLong(MyThread*, int64_t a, int64_t b)
{
return a % b;
}
2007-09-30 02:48:27 +00:00
object
makeBlankObjectArray(Thread* t, object class_, int32_t length)
{
return makeObjectArray(t, class_, length, true);
}
object
makeBlankArray(Thread* t, object (*constructor)(Thread*, uintptr_t, bool),
int32_t length)
{
return constructor(t, length, true);
}
uint64_t
invokeNative2(MyThread* t, object method)
{
PROTECT(t, method);
if (objectClass(t, methodCode(t, method))
== arrayBody(t, t->m->types, Machine::ByteArrayType))
{
void* function = resolveNativeMethod(t, method);
if (UNLIKELY(function == 0)) {
object message = makeString
(t, "%s", &byteArrayBody(t, methodCode(t, method), 0));
t->exception = makeUnsatisfiedLinkError(t, message);
return 0;
}
object p = makePointer(t, function);
set(t, methodCode(t, method), p);
}
object class_ = methodClass(t, method);
PROTECT(t, class_);
unsigned footprint = methodParameterFootprint(t, method) + 1;
unsigned count = methodParameterCount(t, method) + 1;
if (methodFlags(t, method) & ACC_STATIC) {
++ footprint;
++ count;
}
uintptr_t args[footprint];
unsigned argOffset = 0;
uint8_t types[count];
unsigned typeOffset = 0;
args[argOffset++] = reinterpret_cast<uintptr_t>(t);
types[typeOffset++] = POINTER_TYPE;
2007-10-04 03:19:39 +00:00
uintptr_t* sp = static_cast<uintptr_t*>(frameBase(t->frame))
+ (methodParameterFootprint(t, method) + 1)
+ (FrameFootprint / BytesPerWord);
if (methodFlags(t, method) & ACC_STATIC) {
args[argOffset++] = reinterpret_cast<uintptr_t>(&class_);
} else {
args[argOffset++] = reinterpret_cast<uintptr_t>(sp--);
}
types[typeOffset++] = POINTER_TYPE;
MethodSpecIterator it
(t, reinterpret_cast<const char*>
(&byteArrayBody(t, methodSpec(t, method), 0)));
while (it.hasNext()) {
unsigned type = types[typeOffset++]
= fieldType(t, fieldCode(t, *it.next()));
switch (type) {
case INT8_TYPE:
case INT16_TYPE:
case INT32_TYPE:
case FLOAT_TYPE:
args[argOffset++] = *(sp--);
break;
case INT64_TYPE:
case DOUBLE_TYPE: {
if (BytesPerWord == 8) {
uint64_t a = *(sp--);
uint64_t b = *(sp--);
args[argOffset++] = (a << 32) | b;
} else {
memcpy(args + argOffset, sp, 8);
argOffset += 2;
sp -= 2;
}
} break;
case POINTER_TYPE: {
args[argOffset++] = reinterpret_cast<uintptr_t>(sp--);
} break;
default: abort(t);
}
}
void* function = pointerValue(t, methodCode(t, method));
unsigned returnType = fieldType(t, methodReturnCode(t, method));
uint64_t result;
if (Verbose) {
fprintf(stderr, "invoke native method %s.%s\n",
&byteArrayBody(t, className(t, methodClass(t, method)), 0),
&byteArrayBody(t, methodName(t, method), 0));
}
{ ENTER(t, Thread::IdleState);
result = t->m->system->call
(function,
args,
types,
count + 1,
2007-10-04 03:19:39 +00:00
footprint * BytesPerWord,
returnType);
}
if (Verbose) {
fprintf(stderr, "return from native method %s.%s\n",
&byteArrayBody(t, className(t, methodClass(t, method)), 0),
&byteArrayBody(t, methodName(t, method), 0));
}
if (LIKELY(t->exception == 0) and returnType == POINTER_TYPE) {
2007-10-09 19:30:01 +00:00
return result ? *reinterpret_cast<uintptr_t*>(result) : 0;
} else {
return result;
}
}
uint64_t
invokeNative(MyThread* t, object method)
{
uint64_t result = invokeNative2(t, method);
if (UNLIKELY(t->exception)) {
unwind(t);
} else {
return result;
}
}
void
compileMethod(MyThread* t, object method);
inline bool
isByte(int32_t v)
{
return v == static_cast<int8_t>(v);
}
2007-10-09 17:15:40 +00:00
inline bool
isInt32(uintptr_t v)
{
return v == static_cast<uintptr_t>(static_cast<int32_t>(v));
}
enum Register {
rax = 0,
rcx = 1,
rdx = 2,
rbx = 3,
rsp = 4,
rbp = 5,
rsi = 6,
rdi = 7,
r8 = 8,
r9 = 9,
r10 = 10,
r11 = 11,
r12 = 12,
r13 = 13,
r14 = 14,
r15 = 15,
};
enum SSERegister {
xmm0 = 0,
xmm1 = 1,
xmm2 = 2,
xmm3 = 3,
xmm4 = 4,
xmm5 = 5,
xmm6 = 6,
xmm7 = 7
};
class Assembler {
public:
2007-09-25 23:53:11 +00:00
class Label {
public:
static const unsigned Capacity = 8;
Label(Assembler* a):
code(&(a->code)),
2007-09-25 23:53:11 +00:00
unresolvedCount(0),
mark_(-1)
{ }
void reference() {
2007-09-25 23:53:11 +00:00
if (mark_ == -1) {
expect(code->s, unresolvedCount < Capacity);
unresolved[unresolvedCount] = code->length();
2007-09-25 23:53:11 +00:00
++ unresolvedCount;
code->append4(0);
2007-09-25 23:53:11 +00:00
} else {
code->append4(mark_ - (code->length() + 4));
2007-09-25 23:53:11 +00:00
}
}
void mark() {
mark_ = code->length();
2007-09-25 23:53:11 +00:00
for (unsigned i = 0; i < unresolvedCount; ++i) {
code->set4(unresolved[i], mark_ - (unresolved[i] + 4));
2007-09-25 23:53:11 +00:00
}
}
Buffer* code;
unsigned unresolved[Capacity];
2007-09-25 23:53:11 +00:00
unsigned unresolvedCount;
int mark_;
};
Assembler(System* s):
code(s, 1024),
2007-10-10 21:34:04 +00:00
jumps(s, 256)
{ }
void rex() {
if (BytesPerWord == 8) {
code.append(0x48);
}
}
2007-09-25 23:53:11 +00:00
void mov(Register src, Register dst) {
rex();
code.append(0x89);
code.append(0xc0 | (src << 3) | dst);
2007-09-25 23:53:11 +00:00
}
void offsetInstruction(uint8_t instruction, uint8_t zeroPrefix,
uint8_t bytePrefix, uint8_t wordPrefix,
unsigned a, unsigned b, int32_t offset)
{
code.append(instruction);
uint8_t prefix;
if (offset == 0 and b != rbp) {
prefix = zeroPrefix;
} else if (isByte(offset)) {
prefix = bytePrefix;
2007-09-25 23:53:11 +00:00
} else {
prefix = wordPrefix;
2007-09-25 23:53:11 +00:00
}
code.append(prefix | (a << 3) | b);
if (b == rsp) {
code.append(0x24);
}
if (offset == 0 and b != rbp) {
// do nothing
} else if (isByte(offset)) {
code.append(offset);
} else {
code.append4(offset);
}
}
2007-09-30 15:52:21 +00:00
void movz1(Register src, Register dst) {
code.append(0x0f);
code.append(0xb6);
code.append(0xc0 | (dst << 3) | src);
}
void movz1(Register src, int32_t srcOffset, Register dst) {
code.append(0x0f);
2007-09-30 15:52:21 +00:00
offsetInstruction(0xb6, 0, 0x40, 0x80, dst, src, srcOffset);
}
void movs1(Register src, Register dst) {
code.append(0x0f);
code.append(0xbe);
code.append(0xc0 | (dst << 3) | src);
}
void movs1(Register src, int32_t srcOffset, Register dst) {
code.append(0x0f);
2007-09-30 15:52:21 +00:00
offsetInstruction(0xbe, 0, 0x40, 0x80, dst, src, srcOffset);
}
void movz2(Register src, Register dst) {
code.append(0x0f);
code.append(0xb7);
code.append(0xc0 | (dst << 3) | src);
}
void movz2(Register src, int32_t srcOffset, Register dst) {
code.append(0x0f);
2007-09-30 15:52:21 +00:00
offsetInstruction(0xb7, 0, 0x40, 0x80, dst, src, srcOffset);
}
void movs2(Register src, Register dst) {
code.append(0x0f);
code.append(0xbf);
code.append(0xc0 | (dst << 3) | src);
}
void movs2(Register src, int32_t srcOffset, Register dst) {
code.append(0x0f);
2007-09-30 15:52:21 +00:00
offsetInstruction(0xbf, 0, 0x40, 0x80, dst, src, srcOffset);
}
void mov4(Register src, int32_t srcOffset, Register dst) {
offsetInstruction(0x8b, 0, 0x40, 0x80, dst, src, srcOffset);
}
void mov1(Register src, Register dst, int32_t dstOffset) {
offsetInstruction(0x88, 0, 0x40, 0x80, src, dst, dstOffset);
}
void mov2(Register src, Register dst, int32_t dstOffset) {
code.append(0x66);
offsetInstruction(0x89, 0, 0x40, 0x80, src, dst, dstOffset);
}
void mov4(Register src, Register dst, int32_t dstOffset) {
offsetInstruction(0x89, 0, 0x40, 0x80, src, dst, dstOffset);
}
void mov(Register src, int32_t srcOffset, SSERegister dst) {
code.append(0xf3);
code.append(0x0f);
offsetInstruction(0x7e, 0, 0x40, 0x80, dst, src, srcOffset);
}
void mov(Register src, int32_t srcOffset, Register dst) {
rex();
mov4(src, srcOffset, dst);
2007-09-25 23:53:11 +00:00
}
void mov(Register src, Register dst, int32_t dstOffset) {
rex();
mov4(src, dst, dstOffset);
2007-09-25 23:53:11 +00:00
}
void mov(uintptr_t v, Register dst) {
rex();
code.append(0xb8 | dst);
code.appendAddress(v);
}
void alignedMov(uintptr_t v, Register dst) {
while ((code.length() + (BytesPerWord == 8 ? 2 : 1)) % BytesPerWord) {
nop();
}
rex();
code.append(0xb8 | dst);
code.appendAddress(v);
}
2007-10-04 00:41:54 +00:00
void lea(Register src, int32_t srcOffset, Register dst) {
rex();
offsetInstruction(0x8d, 0, 0x40, 0x80, dst, src, srcOffset);
}
void nop() {
code.append(0x90);
2007-09-25 23:53:11 +00:00
}
void push(Register reg) {
code.append(0x50 | reg);
2007-09-25 23:53:11 +00:00
}
void push(Register reg, int32_t offset) {
offsetInstruction(0xff, 0x30, 0x70, 0xb0, rax, reg, offset);
2007-09-25 23:53:11 +00:00
}
void push(int32_t v) {
if (isByte(v)) {
code.append(0x6a);
code.append(v);
} else {
code.append(0x68);
code.append4(v);
}
2007-09-25 23:53:11 +00:00
}
2007-10-03 00:22:48 +00:00
void push4(Register reg, int32_t offset) {
if (BytesPerWord == 8) {
2007-10-03 00:22:48 +00:00
mov4(reg, offset, rsi);
push(rsi);
} else {
2007-10-03 00:22:48 +00:00
push(reg, offset);
}
}
2007-10-03 00:22:48 +00:00
void pushAddress(uintptr_t v) {
2007-10-09 17:15:40 +00:00
if (BytesPerWord == 8 and not isInt32(v)) {
2007-10-03 00:22:48 +00:00
mov(v, rsi);
push(rsi);
} else {
2007-10-03 00:22:48 +00:00
push(v);
}
}
2007-09-25 23:53:11 +00:00
void pop(Register dst) {
code.append(0x58 | dst);
2007-09-25 23:53:11 +00:00
}
void pop(Register dst, int32_t offset) {
offsetInstruction(0x8f, 0, 0x40, 0x80, rax, dst, offset);
}
void pop4(Register reg, int32_t offset) {
if (BytesPerWord == 8) {
pop(rsi);
mov4(rsi, reg, offset);
} else {
pop(reg, offset);
}
2007-09-25 23:53:11 +00:00
}
void add(Register src, Register dst) {
rex();
code.append(0x01);
code.append(0xc0 | (src << 3) | dst);
2007-09-25 23:53:11 +00:00
}
void add(int32_t v, Register dst) {
assert(code.s, isByte(v)); // todo
rex();
code.append(0x83);
code.append(0xc0 | dst);
code.append(v);
2007-09-25 23:53:11 +00:00
}
2007-09-30 02:48:27 +00:00
void add(int32_t v, Register dst, unsigned offset) {
rex();
unsigned i = (isByte(v) ? 0x83 : 0x81);
offsetInstruction(i, 0, 0x40, 0x80, rax, dst, offset);
if (isByte(v)) {
code.append(v);
} else {
code.append4(v);
}
}
2007-10-09 17:15:40 +00:00
void add(Register src, Register dst, unsigned dstOffset) {
rex();
offsetInstruction(0x01, 0, 0x40, 0x80, src, dst, dstOffset);
}
void adc(int32_t v, Register dst) {
assert(code.s, isByte(v)); // todo
rex();
code.append(0x83);
code.append(0xd0 | dst);
code.append(v);
}
void adc(Register src, Register dst, unsigned dstOffset) {
rex();
offsetInstruction(0x11, 0, 0x40, 0x80, src, dst, dstOffset);
}
void sub(Register src, Register dst, unsigned dstOffset) {
rex();
offsetInstruction(0x29, 0, 0x40, 0x80, src, dst, dstOffset);
}
2007-09-25 23:53:11 +00:00
void sub(Register src, Register dst) {
rex();
code.append(0x29);
code.append(0xc0 | (src << 3) | dst);
2007-09-25 23:53:11 +00:00
}
void sub(int32_t v, Register dst) {
assert(code.s, isByte(v)); // todo
rex();
code.append(0x83);
code.append(0xe8 | dst);
code.append(v);
2007-09-25 23:53:11 +00:00
}
void sbb(Register src, Register dst, unsigned dstOffset) {
rex();
offsetInstruction(0x19, 0, 0x40, 0x80, src, dst, dstOffset);
}
2007-09-25 23:53:11 +00:00
void or_(Register src, Register dst) {
rex();
code.append(0x09);
code.append(0xc0 | (src << 3) | dst);
2007-09-25 23:53:11 +00:00
}
void or_(int32_t v, Register dst) {
assert(code.s, isByte(v)); // todo
rex();
code.append(0x83);
code.append(0xc8 | dst);
code.append(v);
2007-09-25 23:53:11 +00:00
}
void and_(Register src, Register dst) {
rex();
code.append(0x21);
code.append(0xc0 | (src << 3) | dst);
2007-09-25 23:53:11 +00:00
}
void and_(int32_t v, Register dst) {
assert(code.s, isByte(v)); // todo
rex();
code.append(0x83);
code.append(0xe0 | dst);
code.append(v);
2007-09-25 23:53:11 +00:00
}
2007-09-30 04:07:22 +00:00
void shl(int8_t v, Register dst) {
rex();
if (v == 1) {
code.append(0xd1);
code.append(0xe0 | dst);
} else {
code.append(0xc1);
code.append(0xe0 | dst);
code.append(v);
}
}
2007-09-25 23:53:11 +00:00
void ret() {
code.append(0xc3);
2007-09-25 23:53:11 +00:00
}
void jmp(Label& label) {
code.append(0xE9);
label.reference();
}
void jmp(unsigned javaIP) {
code.append(0xE9);
jumps.append4(javaIP);
jumps.append4(code.length());
code.append4(0);
2007-09-25 23:53:11 +00:00
}
void jmp(Register reg) {
code.append(0xff);
code.append(0xe0 | reg);
2007-09-25 23:53:11 +00:00
}
2007-09-30 02:48:27 +00:00
void conditional(Label& label, unsigned condition) {
code.append(0x0f);
2007-09-30 02:48:27 +00:00
code.append(condition);
label.reference();
}
void conditional(unsigned javaIP, unsigned condition) {
code.append(0x0f);
code.append(condition);
jumps.append4(javaIP);
jumps.append4(code.length());
code.append4(0);
2007-09-25 23:53:11 +00:00
}
2007-09-30 02:48:27 +00:00
void je(Label& label) {
conditional(label, 0x84);
}
2007-09-29 21:08:29 +00:00
void je(unsigned javaIP) {
conditional(javaIP, 0x84);
}
2007-09-29 21:08:29 +00:00
void jne(Label& label) {
2007-09-30 02:48:27 +00:00
conditional(label, 0x85);
2007-09-25 23:53:11 +00:00
}
2007-09-29 21:08:29 +00:00
void jne(unsigned javaIP) {
conditional(javaIP, 0x85);
}
2007-09-30 02:48:27 +00:00
void jg(Label& label) {
conditional(label, 0x8f);
}
void jg(unsigned javaIP) {
conditional(javaIP, 0x8f);
}
2007-09-30 02:48:27 +00:00
void jge(Label& label) {
conditional(label, 0x8d);
}
void jge(unsigned javaIP) {
conditional(javaIP, 0x8d);
}
2007-09-30 02:48:27 +00:00
void jl(Label& label) {
conditional(label, 0x8c);
}
void jl(unsigned javaIP) {
conditional(javaIP, 0x8c);
}
2007-09-30 02:48:27 +00:00
void jle(Label& label) {
conditional(label, 0x8e);
}
void jle(unsigned javaIP) {
conditional(javaIP, 0x8e);
2007-09-25 23:53:11 +00:00
}
void jb(Label& label) {
conditional(label, 0x82);
}
void ja(Label& label) {
conditional(label, 0x87);
}
2007-09-25 23:53:11 +00:00
void cmp(int v, Register reg) {
2007-09-30 15:52:21 +00:00
assert(code.s, isByte(v)); // todo
2007-10-09 19:30:01 +00:00
rex();
code.append(0x83);
code.append(0xf8 | reg);
code.append(v);
2007-09-25 23:53:11 +00:00
}
2007-09-30 15:52:21 +00:00
void cmp(Register a, Register b) {
2007-10-09 17:15:40 +00:00
rex();
2007-09-30 15:52:21 +00:00
code.append(0x39);
code.append(0xc0 | (a << 3) | b);
}
2007-09-25 23:53:11 +00:00
void call(Register reg) {
code.append(0xff);
code.append(0xd0 | reg);
2007-09-25 23:53:11 +00:00
}
void cdq() {
code.append(0x99);
}
2007-10-08 23:13:55 +00:00
void cqo() {
rex();
cdq();
}
void imul4(Register src, unsigned srcOffset, Register dst) {
code.append(0x0f);
offsetInstruction(0xaf, 0, 0x40, 0x80, dst, src, srcOffset);
}
void imul(Register src, unsigned srcOffset, Register dst) {
rex();
imul4(src, srcOffset, dst);
}
void imul(Register src) {
rex();
code.append(0xf7);
code.append(0xe8 | src);
}
void idiv(Register src) {
rex();
code.append(0xf7);
code.append(0xf8 | src);
}
void mul(Register src, unsigned offset) {
rex();
offsetInstruction(0xf7, 0x20, 0x60, 0xa0, rax, src, offset);
}
void neg(Register reg, unsigned offset) {
rex();
offsetInstruction(0xf7, 0x10, 0x50, 0x90, rax, reg, offset);
}
void neg(Register reg) {
rex();
code.append(0xf7);
code.append(0xd8 | reg);
}
2007-10-08 23:13:55 +00:00
void int3() {
code.append(0xcc);
}
Buffer code;
Buffer jumps;
};
2007-09-25 23:53:11 +00:00
int
localOffset(MyThread* t, int v, object method)
2007-09-25 23:53:11 +00:00
{
int parameterFootprint
= methodParameterFootprint(t, method) * BytesPerWord;
v *= BytesPerWord;
2007-09-25 23:53:11 +00:00
if (v < parameterFootprint) {
2007-09-30 02:48:27 +00:00
return (parameterFootprint - v - BytesPerWord) + (BytesPerWord * 2)
+ FrameFootprint;
2007-09-25 23:53:11 +00:00
} else {
return -(v + BytesPerWord - parameterFootprint);
2007-09-25 23:53:11 +00:00
}
}
Register
gpRegister(Thread* t, unsigned index)
{
switch (index) {
case 0:
return rdi;
case 1:
return rsi;
case 2:
return rdx;
case 3:
return rcx;
case 4:
return r8;
case 5:
return r9;
default:
abort(t);
}
}
SSERegister
2007-09-30 16:32:17 +00:00
sseRegister(Thread* t UNUSED, unsigned index)
{
assert(t, index < 8);
2007-09-30 16:32:17 +00:00
return static_cast<SSERegister>(index);
}
unsigned
2007-09-30 02:48:27 +00:00
parameterOffset(unsigned index)
{
2007-09-30 02:48:27 +00:00
return FrameFootprint + ((index + 2) * BytesPerWord);
}
2007-10-04 03:19:39 +00:00
Compiled*
caller(MyThread* t);
2007-10-10 22:39:40 +00:00
class Compiler: public Assembler {
public:
2007-10-10 22:39:40 +00:00
Compiler(MyThread* t):
Assembler(t->m->system),
t(t)
{ }
2007-10-10 21:34:04 +00:00
2007-10-10 22:39:40 +00:00
unsigned threadFrameOffset() {
return reinterpret_cast<uintptr_t>(&(t->frame))
- reinterpret_cast<uintptr_t>(t);
}
2007-10-10 21:34:04 +00:00
2007-10-10 22:39:40 +00:00
Compiled* compileStub() {
push(rbp);
mov(rsp, rbp);
2007-10-10 21:34:04 +00:00
2007-10-10 22:39:40 +00:00
if (BytesPerWord == 4) {
push(rbp, FrameMethod);
push(rbp, FrameThread);
} else {
mov(rbp, FrameMethod, rsi);
mov(rbp, FrameThread, rdi);
2007-10-10 21:34:04 +00:00
}
2007-10-10 22:39:40 +00:00
mov(reinterpret_cast<uintptr_t>(compileMethod), rbx);
callAddress(compiledCode(caller(t)));
2007-10-10 21:34:04 +00:00
2007-10-10 22:39:40 +00:00
if (BytesPerWord == 4) {
add(BytesPerWord * 2, rsp);
}
2007-10-10 21:34:04 +00:00
2007-10-10 22:39:40 +00:00
mov(rbp, FrameMethod, rax);
mov(rax, MethodCompiled, rax); // load compiled code
2007-10-10 22:39:40 +00:00
mov(rbp, rsp);
pop(rbp);
add(CompiledBody, rax);
jmp(rax); // call compiled code
2007-10-10 22:39:40 +00:00
return finish();
}
2007-10-10 22:39:40 +00:00
Compiled* compileNativeInvoker() {
push(rbp);
mov(rsp, rbp);
2007-10-10 22:39:40 +00:00
if (BytesPerWord == 4) {
push(rbp, FrameMethod);
push(rbp, FrameThread);
} else {
mov(rbp, FrameMethod, rsi);
mov(rbp, FrameThread, rdi);
}
2007-10-10 22:39:40 +00:00
mov(reinterpret_cast<uintptr_t>(invokeNative), rbx);
callAddress(compiledCode(caller(t)));
2007-10-10 22:39:40 +00:00
if (BytesPerWord == 4) {
add(BytesPerWord * 2, rsp);
}
2007-10-10 22:39:40 +00:00
mov(rbp, rsp);
pop(rbp);
ret();
2007-10-10 22:39:40 +00:00
return finish();
2007-10-10 21:34:04 +00:00
}
2007-10-10 22:39:40 +00:00
Compiled* compileCaller() {
mov(rbp, FrameThread, rdi);
lea(rsp, FrameFootprint + BytesPerWord, rcx);
mov(rcx, rdi, threadFrameOffset()); // set thread frame to current
jmp(rbx);
return finish();
}
2007-10-10 22:39:40 +00:00
Compiled* finish() {
return makeCompiled(t, &code);
}
2007-10-10 21:34:04 +00:00
2007-10-10 22:39:40 +00:00
void callAddress(void* function) {
mov(reinterpret_cast<uintptr_t>(function), rax);
call(rax);
2007-10-10 21:34:04 +00:00
}
2007-10-10 22:39:40 +00:00
void callAlignedAddress(void* function) {
alignedMov(reinterpret_cast<uintptr_t>(function), rax);
call(rax);
2007-10-10 21:34:04 +00:00
}
2007-10-10 22:39:40 +00:00
MyThread* t;
};
2007-10-10 22:39:40 +00:00
class JavaCompiler: public Compiler {
public:
2007-10-10 22:39:40 +00:00
JavaCompiler(MyThread* t, object method):
Compiler(t),
method(method),
2007-10-10 21:34:04 +00:00
stackMapper(t, method),
2007-10-03 01:54:21 +00:00
poolRegisterClobbered(true),
2007-10-10 22:39:40 +00:00
machineIPs(static_cast<uint32_t*>
(t->m->system->allocate
2007-10-10 22:39:40 +00:00
(codeLength(t, methodCode(t, method)) * 4))),
lineNumbers(codeLineNumberTable(t, methodCode(t, method)) ?
static_cast<NativeLineNumber*>
(t->m->system->allocate
(lineNumberTableLength
(t, codeLineNumberTable(t, methodCode(t, method)))
* sizeof(NativeLineNumber))) : 0),
2007-10-10 22:39:40 +00:00
exceptionHandlers(codeExceptionHandlerTable(t, methodCode(t, method)) ?
static_cast<NativeExceptionHandler*>
(t->m->system->allocate
(exceptionHandlerTableLength
(t, codeExceptionHandlerTable
(t, methodCode(t, method)))
* sizeof(NativeExceptionHandler))) : 0),
2007-10-04 00:41:54 +00:00
pool(t->m->system, 256)
{ }
2007-10-10 22:39:40 +00:00
~JavaCompiler() {
2007-10-10 21:34:04 +00:00
if (machineIPs) {
t->m->system->free(machineIPs);
}
if (lineNumbers) {
t->m->system->free(lineNumbers);
}
if (exceptionHandlers) {
t->m->system->free(exceptionHandlers);
}
}
void pushInt() {
sub(BytesPerWord, rsp);
2007-10-10 21:34:04 +00:00
stackMapper.pushedInt();
}
void pushInt(int32_t v) {
push(v);
2007-10-10 21:34:04 +00:00
stackMapper.pushedInt();
}
void pushInt(Register r) {
push(r);
2007-10-10 21:34:04 +00:00
stackMapper.pushedInt();
}
void pushInt(Register r, int32_t offset) {
push4(r, offset);
2007-10-10 21:34:04 +00:00
stackMapper.pushedInt();
}
void pushObject(int32_t v) {
push(v);
2007-10-10 21:34:04 +00:00
stackMapper.pushedObject();
}
void pushObject(Register r) {
push(r);
2007-10-10 21:34:04 +00:00
stackMapper.pushedObject();
}
void pushObject(Register r, int32_t offset) {
push(r, offset);
2007-10-10 21:34:04 +00:00
stackMapper.pushedObject();
}
void pushLong(uint64_t v) {
if (BytesPerWord == 8) {
pushAddress(v);
sub(8, rsp);
} else {
push((v >> 32) & 0xFFFFFFFF);
push((v ) & 0xFFFFFFFF);
}
2007-10-10 21:34:04 +00:00
stackMapper.pushedLong();
}
2007-10-09 17:15:40 +00:00
void pushLong(Register r) {
assert(t, BytesPerWord == 8);
push(r);
sub(8, rsp);
2007-10-10 21:34:04 +00:00
stackMapper.pushedLong();
}
void pushLong(Register r, int32_t offset) {
assert(t, BytesPerWord == 8);
push(r, offset);
sub(8, rsp);
2007-10-10 21:34:04 +00:00
stackMapper.pushedLong();
2007-10-09 17:15:40 +00:00
}
void pushLong(Register low, Register high) {
assert(t, BytesPerWord == 4);
push(high);
push(low);
2007-10-10 21:34:04 +00:00
stackMapper.pushedLong();
}
void pushLong(Register low, int32_t lowOffset,
Register high, int32_t highOffset)
{
assert(t, BytesPerWord == 4);
push(high, highOffset);
push(low, lowOffset);
2007-10-10 21:34:04 +00:00
stackMapper.pushedLong();
}
void popInt() {
add(BytesPerWord, rsp);
2007-10-10 21:34:04 +00:00
stackMapper.poppedInt();
}
void popInt(Register r) {
pop(r);
2007-10-10 21:34:04 +00:00
stackMapper.poppedInt();
}
void popInt(Register r, int32_t offset) {
pop4(r, offset);
2007-10-10 21:34:04 +00:00
stackMapper.poppedInt();
}
void popObject(Register r) {
pop(r);
2007-10-10 21:34:04 +00:00
stackMapper.poppedObject();
}
void popObject(Register r, int32_t offset) {
pop(r, offset);
2007-10-10 21:34:04 +00:00
stackMapper.poppedObject();
}
void popLong() {
add(BytesPerWord * 2, rsp);
2007-10-10 21:34:04 +00:00
stackMapper.poppedLong();
}
void popLong(Register r) {
assert(t, BytesPerWord == 8);
add(BytesPerWord, rsp);
pop(r);
2007-10-10 21:34:04 +00:00
stackMapper.poppedLong();
}
void popLong(Register r, int32_t offset) {
assert(t, BytesPerWord == 8);
add(BytesPerWord, rsp);
pop(r, offset);
2007-10-10 21:34:04 +00:00
stackMapper.poppedLong();
}
void popLong(Register low, Register high) {
assert(t, BytesPerWord == 4);
pop(low);
pop(high);
2007-10-10 21:34:04 +00:00
stackMapper.poppedLong();
}
void popLong(Register low, int32_t lowOffset,
Register high, int32_t highOffset)
{
assert(t, BytesPerWord == 4);
pop(low, lowOffset);
pop(high, highOffset);
2007-10-10 21:34:04 +00:00
stackMapper.poppedLong();
}
2007-10-10 21:34:04 +00:00
void loadInt(unsigned index) {
pushInt(rbp, localOffset(t, index, method));
}
2007-10-10 21:34:04 +00:00
void loadObject(unsigned index) {
pushObject(rbp, localOffset(t, index, method));
}
2007-10-10 21:34:04 +00:00
void loadLong(unsigned index) {
if (BytesPerWord == 8) {
pushLong(rbp, localOffset(t, index, method));
} else {
pushLong(rbp, localOffset(t, index + 1, method),
rbp, localOffset(t, index, method));
}
}
2007-10-10 21:34:04 +00:00
void storeInt(unsigned index) {
popInt(rbp, localOffset(t, index, method));
}
2007-10-10 21:34:04 +00:00
void storeObject(unsigned index) {
popObject(rbp, localOffset(t, index, method));
2007-10-10 21:34:04 +00:00
stackMapper.storedObject(index);
}
2007-10-10 21:34:04 +00:00
void storeLong(unsigned index) {
if (BytesPerWord == 8) {
popLong(rbp, localOffset(t, index, method));
} else {
popLong(rbp, localOffset(t, index, method),
rbp, localOffset(t, index + 1, method));
}
}
2007-10-03 00:22:48 +00:00
void pushReturnValue(unsigned code) {
switch (code) {
case ByteField:
case BooleanField:
case CharField:
case ShortField:
case FloatField:
case IntField:
push(rax);
2007-10-10 21:34:04 +00:00
stackMapper.pushedInt();
break;
case ObjectField:
push(rax);
2007-10-10 21:34:04 +00:00
stackMapper.pushedObject();
break;
case LongField:
case DoubleField:
push(rax);
push(rdx);
2007-10-10 21:34:04 +00:00
stackMapper.pushedLong();
break;
case VoidField:
break;
default:
abort(t);
}
}
2007-10-03 00:22:48 +00:00
void compileDirectInvoke(object target) {
unsigned footprint = FrameFootprint
+ (methodParameterFootprint(t, target) * BytesPerWord);
2007-10-04 00:41:54 +00:00
Compiled* code = reinterpret_cast<Compiled*>(methodCompiled(t, target));
2007-10-04 03:19:39 +00:00
push(rsp);
2007-10-03 00:22:48 +00:00
push(poolRegister(), poolReference(target));
push(rbp, FrameThread);
2007-10-04 00:41:54 +00:00
callAlignedAddress(compiledCode(code));
2007-10-04 03:19:39 +00:00
add(footprint, rsp); // pop arguments
2007-10-12 00:30:46 +00:00
stackMapper.popped(methodParameterFootprint(t, target));
2007-10-03 00:22:48 +00:00
pushReturnValue(methodReturnCode(t, target));
}
2007-10-04 00:41:54 +00:00
void compileCall2(void* function, unsigned argCount) {
2007-10-04 03:19:39 +00:00
if (BytesPerWord == 4) {
push(rbp, FrameThread);
} else {
mov(rbp, FrameThread, rdi);
}
mov(reinterpret_cast<uintptr_t>(function), rbx);
2007-10-04 00:41:54 +00:00
2007-10-04 03:19:39 +00:00
callAddress(compiledCode(caller(t)));
2007-10-04 00:41:54 +00:00
if (BytesPerWord == 4) {
add(BytesPerWord * argCount, rsp);
}
}
void compileCall(void* function) {
compileCall2(function, 1);
}
2007-10-03 00:22:48 +00:00
void compileCall(void* function, object arg1) {
if (BytesPerWord == 4) {
2007-10-03 00:22:48 +00:00
push(poolRegister(), poolReference(arg1));
2007-09-30 02:48:27 +00:00
} else {
2007-10-03 00:22:48 +00:00
mov(poolRegister(), poolReference(arg1), rsi);
2007-09-30 02:48:27 +00:00
}
2007-10-04 00:41:54 +00:00
compileCall2(function, 2);
2007-09-30 02:48:27 +00:00
}
2007-10-03 00:22:48 +00:00
void compileCall(void* function, Register arg1) {
2007-09-30 02:48:27 +00:00
if (BytesPerWord == 4) {
push(arg1);
} else {
mov(arg1, rsi);
}
2007-10-04 00:41:54 +00:00
compileCall2(function, 2);
}
2007-10-03 00:22:48 +00:00
void compileCall(void* function, object arg1, Register arg2) {
2007-09-30 02:48:27 +00:00
if (BytesPerWord == 4) {
push(arg2);
2007-10-03 00:22:48 +00:00
push(poolRegister(), poolReference(arg1));
} else {
mov(arg2, rdx);
mov(poolRegister(), poolReference(arg1), rsi);
}
2007-10-04 00:41:54 +00:00
compileCall2(function, 3);
2007-10-03 00:22:48 +00:00
}
void compileCall(void* function, void* arg1, Register arg2) {
if (BytesPerWord == 4) {
push(arg2);
2007-10-04 00:41:54 +00:00
pushAddress(reinterpret_cast<uintptr_t>(arg1));
2007-09-30 02:48:27 +00:00
} else {
mov(arg2, rdx);
2007-10-04 00:41:54 +00:00
mov(reinterpret_cast<uintptr_t>(arg1), rsi);
2007-09-30 02:48:27 +00:00
}
2007-10-04 00:41:54 +00:00
compileCall2(function, 3);
2007-09-30 02:48:27 +00:00
}
2007-10-03 00:22:48 +00:00
void compileCall(void* function, Register arg1, Register arg2) {
2007-09-29 21:08:29 +00:00
if (BytesPerWord == 4) {
push(arg2);
push(arg1);
} else {
mov(arg2, rdx);
mov(arg1, rsi);
}
2007-10-04 00:41:54 +00:00
compileCall2(function, 3);
2007-09-29 21:08:29 +00:00
}
Compiled* compile() {
object code = methodCode(t, method);
PROTECT(t, code);
unsigned parameterFootprint
= methodParameterFootprint(t, method) * BytesPerWord;
unsigned localFootprint = codeMaxLocals(t, code) * BytesPerWord;
push(rbp);
mov(rsp, rbp);
if (localFootprint > parameterFootprint) {
// reserve space for local variables
sub(localFootprint - parameterFootprint, rsp);
}
2007-10-03 00:22:48 +00:00
int lineNumberIndex;
object lnt = codeLineNumberTable(t, code);
if (lnt and lineNumberTableLength(t, lnt)) {
lineNumberIndex = 0;
} else {
2007-10-04 00:41:54 +00:00
lineNumberIndex = -1;
2007-10-03 00:22:48 +00:00
}
for (unsigned ip = 0; ip < codeLength(t, code);) {
2007-10-10 21:34:04 +00:00
stackMapper.newIp(ip);
machineIPs[ip] = this->code.length();
2007-10-03 00:22:48 +00:00
if (lineNumberIndex >= 0) {
object lnt = codeLineNumberTable(t, code);
LineNumber* ln = lineNumberTableBody(t, lnt, lineNumberIndex);
2007-10-04 00:41:54 +00:00
if (lineNumberIp(ln) == ip) {
nativeLineNumberIp(lineNumbers + lineNumberIndex)
= this->code.length();
nativeLineNumberLine(lineNumbers + lineNumberIndex)
= lineNumberLine(ln);
2007-10-04 00:41:54 +00:00
if (static_cast<unsigned>(lineNumberIndex) + 1
< lineNumberTableLength(t, lnt))
{
2007-10-03 00:22:48 +00:00
++ lineNumberIndex;
2007-10-04 00:41:54 +00:00
} else {
lineNumberIndex = -1;
2007-10-03 00:22:48 +00:00
}
}
}
unsigned instruction = codeBody(t, code, ip++);
switch (instruction) {
2007-09-30 04:07:22 +00:00
case aaload:
case baload:
case caload:
case daload:
case faload:
case iaload:
case laload:
case saload: {
Label next(this);
Label outOfBounds(this);
popInt(rcx);
popObject(rax);
2007-09-30 04:07:22 +00:00
cmp(0, rcx);
jl(outOfBounds);
mov(rax, BytesPerWord, rdx);
cmp(rdx, rcx);
jge(outOfBounds);
2007-09-30 15:52:21 +00:00
add(BytesPerWord * 2, rax);
2007-09-30 04:07:22 +00:00
switch (instruction) {
case aaload:
case faload:
case iaload:
shl(log(BytesPerWord), rcx);
2007-09-30 15:52:21 +00:00
add(rcx, rax);
if (instruction == aaload) {
pushObject(rax, 0);
} else {
pushInt(rax, 0);
}
2007-09-30 04:07:22 +00:00
break;
case baload:
2007-09-30 15:52:21 +00:00
add(rcx, rax);
2007-09-30 04:07:22 +00:00
movs1(rax, 0, rax);
pushInt(rax);
2007-09-30 04:07:22 +00:00
break;
case caload:
shl(1, rcx);
2007-09-30 15:52:21 +00:00
add(rcx, rax);
2007-09-30 04:07:22 +00:00
movz2(rax, 0, rax);
pushInt(rax);
2007-09-30 04:07:22 +00:00
break;
case daload:
case laload:
shl(3, rcx);
2007-09-30 15:52:21 +00:00
add(rcx, rax);
pushLong(rax, 0);
2007-09-30 04:07:22 +00:00
break;
case saload:
shl(1, rcx);
2007-09-30 15:52:21 +00:00
add(rcx, rax);
2007-09-30 04:07:22 +00:00
movs2(rax, 0, rax);
pushInt(rax);
2007-09-30 04:07:22 +00:00
break;
}
jmp(next);
outOfBounds.mark();
int3();
2007-09-30 04:07:22 +00:00
compileCall
2007-10-04 00:41:54 +00:00
(reinterpret_cast<void*>(throwNew),
2007-10-03 00:22:48 +00:00
arrayBody
(t, t->m->types, Machine::ArrayIndexOutOfBoundsExceptionType));
2007-09-30 04:07:22 +00:00
next.mark();
} break;
2007-09-30 15:52:21 +00:00
case aastore:
case bastore:
case castore:
case dastore:
case fastore:
case iastore:
case lastore:
case sastore: {
Label next(this);
Label outOfBounds(this);
if (instruction == dastore or instruction == lastore) {
popLong(rdx, rbx);
} else if (instruction == aastore) {
popObject(rbx);
} else {
popInt(rbx);
2007-09-30 15:52:21 +00:00
}
popInt(rcx);
popObject(rax);
2007-09-30 15:52:21 +00:00
cmp(0, rcx);
jl(outOfBounds);
2007-10-03 00:22:48 +00:00
mov(rax, BytesPerWord, rsi);
cmp(rsi, rcx);
2007-09-30 15:52:21 +00:00
jge(outOfBounds);
add(BytesPerWord * 2, rax);
switch (instruction) {
case aastore:
case fastore:
case iastore:
shl(log(BytesPerWord), rcx);
add(rcx, rax);
mov(rbx, rax, 0);
break;
case bastore:
add(rcx, rax);
mov1(rbx, rax, 0);
break;
case castore:
case sastore:
shl(1, rcx);
add(rcx, rax);
mov2(rbx, rax, 0);
break;
case dastore:
case lastore:
shl(3, rcx);
add(rcx, rax);
mov4(rbx, rax, 0);
mov4(rdx, rax, 4);
break;
}
jmp(next);
outOfBounds.mark();
compileCall
2007-10-04 00:41:54 +00:00
(reinterpret_cast<void*>(throwNew),
2007-10-03 00:22:48 +00:00
arrayBody
(t, t->m->types, Machine::ArrayIndexOutOfBoundsExceptionType));
2007-09-30 15:52:21 +00:00
next.mark();
} break;
case aconst_null:
pushObject(0);
break;
case aload:
loadObject(codeBody(t, code, ip++));
break;
case aload_0:
loadObject(0);
break;
case aload_1:
loadObject(1);
break;
case aload_2:
loadObject(2);
break;
case aload_3:
loadObject(3);
break;
2007-09-30 02:48:27 +00:00
case anewarray: {
uint16_t index = codeReadInt16(t, code, ip);
object class_ = resolveClass(t, codePool(t, code), index - 1);
2007-10-04 00:41:54 +00:00
if (UNLIKELY(t->exception)) return 0;
2007-09-30 02:48:27 +00:00
Label nonnegative(this);
popInt(rax);
2007-09-30 02:48:27 +00:00
cmp(0, rax);
2007-10-09 19:30:01 +00:00
jge(nonnegative);
2007-09-30 02:48:27 +00:00
compileCall
2007-10-04 00:41:54 +00:00
(reinterpret_cast<void*>(throwNew),
2007-10-03 00:22:48 +00:00
arrayBody(t, t->m->types, Machine::NegativeArraySizeExceptionType));
2007-09-30 02:48:27 +00:00
nonnegative.mark();
2007-10-04 00:41:54 +00:00
compileCall(reinterpret_cast<void*>(makeBlankObjectArray),
class_, rax);
pushObject(rax);
2007-09-30 02:48:27 +00:00
} break;
case areturn:
popObject(rax);
mov(rbp, rsp);
pop(rbp);
ret();
2007-10-12 00:30:46 +00:00
stackMapper.exited();
break;
2007-09-30 15:52:21 +00:00
case arraylength:
popObject(rax);
2007-10-12 00:30:46 +00:00
pushInt(rax, BytesPerWord);
2007-09-30 15:52:21 +00:00
break;
case astore:
storeObject(codeBody(t, code, ip++));
break;
case astore_0:
storeObject(0);
break;
case astore_1:
storeObject(1);
break;
case astore_2:
storeObject(2);
break;
case astore_3:
storeObject(3);
break;
2007-09-30 02:48:27 +00:00
case athrow:
popObject(rax);
2007-10-12 00:30:46 +00:00
compileCall(reinterpret_cast<void*>(throw_), rax);
stackMapper.exited();
2007-09-30 02:48:27 +00:00
break;
case bipush: {
pushInt(static_cast<int8_t>(codeBody(t, code, ip++)));
} break;
2007-09-29 21:08:29 +00:00
case checkcast: {
uint16_t index = codeReadInt16(t, code, ip);
object class_ = resolveClass(t, codePool(t, code), index - 1);
2007-10-04 00:41:54 +00:00
if (UNLIKELY(t->exception)) return 0;
2007-09-29 21:08:29 +00:00
Label next(this);
2007-09-30 02:48:27 +00:00
mov(rsp, 0, rax);
2007-09-29 21:08:29 +00:00
cmp(0, rax);
je(next);
2007-10-03 00:22:48 +00:00
mov(poolRegister(), poolReference(class_), rcx);
2007-09-29 21:08:29 +00:00
mov(rax, 0, rax);
cmp(rcx, rax);
je(next);
2007-10-04 00:41:54 +00:00
compileCall(reinterpret_cast<void*>(isAssignableFrom), rcx, rax);
2007-09-29 21:08:29 +00:00
cmp(0, rax);
jne(next);
compileCall
2007-10-04 00:41:54 +00:00
(reinterpret_cast<void*>(throwNew),
2007-10-03 00:22:48 +00:00
arrayBody(t, t->m->types, Machine::ClassCastExceptionType));
2007-09-29 21:08:29 +00:00
next.mark();
} break;
case dup:
2007-09-30 02:48:27 +00:00
push(rsp, 0);
2007-10-10 21:34:04 +00:00
stackMapper.dupped();
break;
case getfield: {
uint16_t index = codeReadInt16(t, code, ip);
object field = resolveField(t, codePool(t, code), index - 1);
2007-10-04 00:41:54 +00:00
if (UNLIKELY(t->exception)) return 0;
popObject(rax);
switch (fieldCode(t, field)) {
case ByteField:
case BooleanField:
movs1(rax, fieldOffset(t, field), rax);
pushInt(rax);
break;
case CharField:
movz2(rax, fieldOffset(t, field), rax);
pushInt(rax);
break;
case ShortField:
movs2(rax, fieldOffset(t, field), rax);
pushInt(rax);
break;
case FloatField:
case IntField:
pushInt(rax, fieldOffset(t, field));
break;
case DoubleField:
case LongField:
pushLong(rax, fieldOffset(t, field));
break;
case ObjectField:
pushObject(rax, fieldOffset(t, field));
break;
default:
abort(t);
}
} break;
case getstatic: {
uint16_t index = codeReadInt16(t, code, ip);
object field = resolveField(t, codePool(t, code), index - 1);
2007-10-04 00:41:54 +00:00
if (UNLIKELY(t->exception)) return 0;
PROTECT(t, field);
initClass(t, fieldClass(t, field));
2007-10-04 00:41:54 +00:00
if (UNLIKELY(t->exception)) return 0;
object table = classStaticTable(t, fieldClass(t, field));
2007-10-03 00:22:48 +00:00
mov(poolRegister(), poolReference(table), rax);
2007-09-30 02:48:27 +00:00
add((fieldOffset(t, field) * BytesPerWord) + ArrayBody, rax);
switch (fieldCode(t, field)) {
case ByteField:
case BooleanField:
case CharField:
case ShortField:
case FloatField:
case IntField: {
Label zero(this);
Label next(this);
cmp(0, rax);
2007-09-29 21:08:29 +00:00
je(zero);
pushInt(rax, IntValue);
jmp(next);
zero.mark();
pushInt(0);
next.mark();
} break;
case DoubleField:
case LongField: {
Label zero(this);
Label next(this);
cmp(0, rax);
2007-09-29 21:08:29 +00:00
je(zero);
pushLong(rax, LongValue);
jmp(next);
zero.mark();
pushLong(0);
next.mark();
} break;
case ObjectField: {
pushObject(rax, 0);
} break;
default: abort(t);
}
} break;
2007-09-30 02:48:27 +00:00
case goto_: {
int16_t offset = codeReadInt16(t, code, ip);
jmp((ip - 3) + offset);
stackMapper.jumped((ip - 3) + offset);
2007-09-30 02:48:27 +00:00
} break;
case goto_w: {
int32_t offset = codeReadInt32(t, code, ip);
jmp((ip - 5) + offset);
stackMapper.jumped((ip - 5) + offset);
2007-09-30 02:48:27 +00:00
} break;
2007-09-30 15:52:21 +00:00
case i2b:
mov(rsp, 0, rax);
movs1(rax, rax);
mov(rax, rsp, 0);
break;
case i2c:
mov(rsp, 0, rax);
movz2(rax, rax);
mov(rax, rsp, 0);
break;
case i2s:
mov(rsp, 0, rax);
movs2(rax, rax);
mov(rax, rsp, 0);
break;
2007-10-04 22:41:19 +00:00
case i2l:
if (BytesPerWord == 8) {
pushInt();
} else {
popInt(rax);
cdq();
pushLong(rax, rdx);
}
2007-10-04 22:41:19 +00:00
break;
case iadd:
popInt(rax);
popInt(rcx);
add(rcx, rax);
pushInt(rax);
break;
case iconst_m1:
pushInt(-1);
break;
case iconst_0:
pushInt(0);
break;
case iconst_1:
pushInt(1);
break;
case iconst_2:
pushInt(2);
break;
case iconst_3:
pushInt(3);
break;
case iconst_4:
pushInt(4);
break;
case iconst_5:
pushInt(5);
break;
case if_acmpeq: {
int16_t offset = codeReadInt16(t, code, ip);
popObject(rax);
popObject(rcx);
cmp(rax, rcx);
je((ip - 3) + offset);
stackMapper.branched((ip - 3) + offset);
} break;
case if_acmpne: {
int16_t offset = codeReadInt16(t, code, ip);
popObject(rax);
popObject(rcx);
cmp(rax, rcx);
jne((ip - 3) + offset);
stackMapper.branched((ip - 3) + offset);
} break;
case if_icmpeq: {
int16_t offset = codeReadInt16(t, code, ip);
popInt(rax);
popInt(rcx);
cmp(rax, rcx);
2007-09-29 21:08:29 +00:00
je((ip - 3) + offset);
stackMapper.branched((ip - 3) + offset);
} break;
case if_icmpne: {
int16_t offset = codeReadInt16(t, code, ip);
popInt(rax);
popInt(rcx);
cmp(rax, rcx);
2007-09-29 21:08:29 +00:00
jne((ip - 3) + offset);
stackMapper.branched((ip - 3) + offset);
} break;
case if_icmpgt: {
int16_t offset = codeReadInt16(t, code, ip);
popInt(rax);
popInt(rcx);
cmp(rax, rcx);
jg((ip - 3) + offset);
stackMapper.branched((ip - 3) + offset);
} break;
case if_icmpge: {
int16_t offset = codeReadInt16(t, code, ip);
popInt(rax);
popInt(rcx);
cmp(rax, rcx);
jge((ip - 3) + offset);
stackMapper.branched((ip - 3) + offset);
} break;
case if_icmplt: {
int16_t offset = codeReadInt16(t, code, ip);
popInt(rax);
popInt(rcx);
cmp(rax, rcx);
jl((ip - 3) + offset);
stackMapper.branched((ip - 3) + offset);
} break;
case if_icmple: {
int16_t offset = codeReadInt16(t, code, ip);
popInt(rax);
popInt(rcx);
cmp(rax, rcx);
jle((ip - 3) + offset);
stackMapper.branched((ip - 3) + offset);
} break;
case ifeq: {
int16_t offset = codeReadInt16(t, code, ip);
popInt(rax);
cmp(0, rax);
je((ip - 3) + offset);
2007-10-12 00:30:46 +00:00
stackMapper.branched((ip - 3) + offset);
} break;
case ifnull: {
int16_t offset = codeReadInt16(t, code, ip);
popObject(rax);
cmp(0, rax);
2007-09-29 21:08:29 +00:00
je((ip - 3) + offset);
stackMapper.branched((ip - 3) + offset);
} break;
case ifne: {
int16_t offset = codeReadInt16(t, code, ip);
popInt(rax);
cmp(0, rax);
jne((ip - 3) + offset);
stackMapper.branched((ip - 3) + offset);
} break;
case ifnonnull: {
int16_t offset = codeReadInt16(t, code, ip);
popObject(rax);
cmp(0, rax);
2007-09-29 21:08:29 +00:00
jne((ip - 3) + offset);
stackMapper.branched((ip - 3) + offset);
} break;
case ifgt: {
int16_t offset = codeReadInt16(t, code, ip);
popInt(rax);
cmp(0, rax);
jg((ip - 3) + offset);
stackMapper.branched((ip - 3) + offset);
} break;
case ifge: {
int16_t offset = codeReadInt16(t, code, ip);
popInt(rax);
cmp(0, rax);
jge((ip - 3) + offset);
stackMapper.branched((ip - 3) + offset);
} break;
case iflt: {
int16_t offset = codeReadInt16(t, code, ip);
popInt(rax);
cmp(0, rax);
jl((ip - 3) + offset);
stackMapper.branched((ip - 3) + offset);
} break;
case ifle: {
int16_t offset = codeReadInt16(t, code, ip);
popInt(rax);
cmp(0, rax);
jle((ip - 3) + offset);
stackMapper.branched((ip - 3) + offset);
} break;
2007-09-30 02:48:27 +00:00
case iinc: {
uint8_t index = codeBody(t, code, ip++);
int8_t c = codeBody(t, code, ip++);
add(c, rbp, localOffset(t, index, method));
} break;
case iload:
case fload:
loadInt(codeBody(t, code, ip++));
break;
case iload_0:
case fload_0:
loadInt(0);
break;
case iload_1:
case fload_1:
loadInt(1);
break;
case iload_2:
case fload_2:
loadInt(2);
break;
case iload_3:
case fload_3:
loadInt(3);
break;
case vm::imul:
popInt(rax);
popInt(rcx);
Assembler::imul(rcx);
pushInt(rax);
break;
case ineg:
neg(rsp, 0);
break;
2007-09-29 21:08:29 +00:00
case instanceof: {
uint16_t index = codeReadInt16(t, code, ip);
object class_ = resolveClass(t, codePool(t, code), index - 1);
2007-10-04 00:41:54 +00:00
if (UNLIKELY(t->exception)) return 0;
2007-09-29 21:08:29 +00:00
Label call(this);
Label zero(this);
Label next(this);
popObject(rax);
2007-09-29 21:08:29 +00:00
cmp(0, rax);
je(zero);
2007-10-03 00:22:48 +00:00
mov(poolRegister(), poolReference(class_), rcx);
2007-09-29 21:08:29 +00:00
mov(rax, 0, rax);
cmp(rcx, rax);
jne(call);
2007-10-12 00:30:46 +00:00
push(1);
2007-09-29 21:08:29 +00:00
jmp(next);
call.mark();
2007-10-04 00:41:54 +00:00
compileCall(reinterpret_cast<void*>(isAssignableFrom), rcx, rax);
2007-10-12 00:30:46 +00:00
push(rax);
2007-09-29 21:08:29 +00:00
jmp(next);
zero.mark();
2007-10-12 00:30:46 +00:00
push(0);
2007-09-29 21:08:29 +00:00
next.mark();
2007-10-12 00:30:46 +00:00
stackMapper.pushedInt();
2007-09-29 21:08:29 +00:00
} break;
case invokespecial: {
uint16_t index = codeReadInt16(t, code, ip);
object target = resolveMethod(t, codePool(t, code), index - 1);
2007-10-04 00:41:54 +00:00
if (UNLIKELY(t->exception)) return 0;
object class_ = methodClass(t, target);
if (isSpecialMethod(t, target, class_)) {
target = findMethod(t, target, classSuper(t, class_));
}
2007-10-04 00:41:54 +00:00
compileDirectInvoke(target);
} break;
case invokestatic: {
uint16_t index = codeReadInt16(t, code, ip);
object target = resolveMethod(t, codePool(t, code), index - 1);
2007-10-04 00:41:54 +00:00
if (UNLIKELY(t->exception)) return 0;
PROTECT(t, target);
initClass(t, methodClass(t, target));
2007-10-04 00:41:54 +00:00
if (UNLIKELY(t->exception)) return 0;
2007-10-04 00:41:54 +00:00
compileDirectInvoke(target);
} break;
case invokevirtual: {
uint16_t index = codeReadInt16(t, code, ip);
object target = resolveMethod(t, codePool(t, code), index - 1);
2007-10-04 00:41:54 +00:00
if (UNLIKELY(t->exception)) return 0;
unsigned parameterFootprint
= methodParameterFootprint(t, target) * BytesPerWord;
unsigned instance = parameterFootprint - BytesPerWord;
unsigned footprint = FrameFootprint + parameterFootprint;
unsigned offset = ArrayBody + (methodOffset(t, target) * BytesPerWord);
mov(rsp, instance, rax); // load instance
mov(rax, 0, rax); // load class
mov(rax, ClassVirtualTable, rax); // load vtable
mov(rax, offset, rax); // load method
2007-10-02 00:08:17 +00:00
push(rsp);
push(rax);
push(rbp, FrameThread);
mov(rax, MethodCompiled, rax); // load compiled code
add(CompiledBody, rax);
call(rax); // call compiled code
2007-10-03 00:22:48 +00:00
poolRegisterClobbered = true;
add(footprint, rsp); // pop arguments
2007-10-12 00:30:46 +00:00
stackMapper.popped(methodParameterFootprint(t, target));
2007-10-04 00:41:54 +00:00
pushReturnValue(methodReturnCode(t, target));
} break;
case ireturn:
case freturn:
popInt(rax);
mov(rbp, rsp);
pop(rbp);
ret();
2007-10-12 00:30:46 +00:00
stackMapper.exited();
break;
case istore:
case fstore:
storeInt(codeBody(t, code, ip++));
break;
case istore_0:
case fstore_0:
storeInt(0);
break;
case istore_1:
case fstore_1:
storeInt(1);
break;
case istore_2:
case fstore_2:
storeInt(2);
break;
case istore_3:
case fstore_3:
storeInt(3);
break;
2007-09-30 02:48:27 +00:00
case isub:
popInt(rax);
sub(rax, rsp, 0);
break;
case l2i:
if (BytesPerWord == 8) {
popInt();
} else {
popInt(rax);
mov(rax, rsp, 0);
}
break;
case ladd:
if (BytesPerWord == 8) {
popLong(rax);
add(rax, rsp, BytesPerWord);
} else {
popLong(rax, rdx);
add(rax, rsp, 0);
adc(rdx, rsp, BytesPerWord);
}
2007-09-30 02:48:27 +00:00
break;
case ldc:
case ldc_w: {
uint16_t index;
if (instruction == ldc) {
index = codeBody(t, code, ip++);
} else {
2007-10-04 22:41:19 +00:00
index = codeReadInt16(t, code, ip);
}
object v = arrayBody(t, codePool(t, code), index - 1);
if (objectClass(t, v) == arrayBody(t, t->m->types, Machine::IntType)) {
pushInt(intValue(t, v));
} else if (objectClass(t, v)
== arrayBody(t, t->m->types, Machine::FloatType))
{
pushInt(floatValue(t, v));
} else if (objectClass(t, v)
== arrayBody(t, t->m->types, Machine::StringType))
{
pushObject(poolRegister(), poolReference(v));
} else {
object class_ = resolveClass(t, codePool(t, code), index - 1);
pushObject(poolRegister(), poolReference(class_));
}
} break;
2007-10-04 22:41:19 +00:00
case ldc2_w: {
uint16_t index = codeReadInt16(t, code, ip);
object v = arrayBody(t, codePool(t, code), index - 1);
if (objectClass(t, v) == arrayBody(t, t->m->types, Machine::LongType))
{
pushLong(longValue(t, v));
2007-10-04 22:41:19 +00:00
} else if (objectClass(t, v)
== arrayBody(t, t->m->types, Machine::DoubleType))
{
pushLong(doubleValue(t, v));
2007-10-04 22:41:19 +00:00
} else {
abort(t);
}
} break;
case lconst_0:
pushLong(0);
2007-10-04 22:41:19 +00:00
break;
case lconst_1:
pushLong(1);
2007-10-04 22:41:19 +00:00
break;
case lcmp: {
Label next(this);
Label less(this);
Label greater(this);
2007-10-04 22:41:19 +00:00
if (BytesPerWord == 8) {
popLong(rax);
2007-10-08 23:13:55 +00:00
popLong(rcx);
2007-10-08 23:13:55 +00:00
cmp(rax, rcx);
jl(less);
jg(greater);
2007-10-04 22:41:19 +00:00
2007-10-12 14:26:36 +00:00
push(0);
jmp(next);
less.mark();
2007-10-12 14:26:36 +00:00
push(-1);
jmp(next);
2007-10-04 22:41:19 +00:00
greater.mark();
2007-10-12 14:26:36 +00:00
push(1);
2007-10-04 22:41:19 +00:00
next.mark();
2007-10-12 14:26:36 +00:00
stackMapper.pushedInt();
} else {
popLong(rax, rdx);
2007-10-08 23:13:55 +00:00
popLong(rcx, rbx);
2007-10-04 22:41:19 +00:00
cmp(rdx, rbx);
jl(less);
jg(greater);
cmp(rax, rcx);
jb(less);
ja(greater);
2007-10-04 22:41:19 +00:00
2007-10-12 14:26:36 +00:00
push(0);
jmp(next);
2007-10-04 22:41:19 +00:00
less.mark();
2007-10-12 14:26:36 +00:00
push(-1);
jmp(next);
2007-10-04 22:41:19 +00:00
greater.mark();
2007-10-12 14:26:36 +00:00
push(1);
2007-10-04 22:41:19 +00:00
next.mark();
2007-10-12 14:26:36 +00:00
stackMapper.pushedInt();
}
2007-10-04 22:41:19 +00:00
} break;
case ldiv_:
if (BytesPerWord == 8) {
popLong(rcx);
2007-10-08 23:13:55 +00:00
popLong(rax);
cqo();
Assembler::idiv(rcx);
pushLong(rax);
} else {
compileCall(reinterpret_cast<void*>(divideLong));
popLong();
mov(rax, rsp, 0);
mov(rdx, rsp, 4);
}
break;
2007-10-04 22:41:19 +00:00
case lload:
loadLong(codeBody(t, code, ip++));
break;
case lload_0:
loadLong(0);
break;
case lload_1:
loadLong(1);
break;
case lload_2:
loadLong(2);
break;
case lload_3:
loadLong(3);
break;
case lmul:
if (BytesPerWord == 8) {
popLong(rax);
popLong(rcx);
Assembler::imul(rcx);
pushLong(rax);
} else {
mov(rsp, 4, rcx);
Assembler::imul(rsp, 8, rcx);
mov(rsp, 12, rax);
Assembler::imul(rsp, 0, rax);
add(rax, rcx);
mov(rsp, 8, rax);
mul(rsp, 0);
add(rcx, rdx);
popLong();
mov(rax, rsp, 0);
mov(rdx, rsp, 4);
}
break;
case lneg:
if (BytesPerWord == 8) {
neg(rsp, 8);
} else {
mov(rsp, 0, rax);
mov(rsp, 4, rdx);
neg(rax);
adc(0, rdx);
neg(rdx);
mov(rax, rsp, 0);
mov(rdx, rsp, 4);
}
break;
case lrem:
if (BytesPerWord == 8) {
popLong(rcx);
2007-10-09 17:15:40 +00:00
popLong(rax);
2007-10-08 23:13:55 +00:00
cqo();
Assembler::idiv(rcx);
pushLong(rdx);
} else {
compileCall(reinterpret_cast<void*>(moduloLong));
popLong();
mov(rax, rsp, 0);
mov(rdx, rsp, 4);
}
break;
case lstore:
storeLong(codeBody(t, code, ip++));
break;
case lstore_0:
storeLong(0);
break;
case lstore_1:
storeLong(1);
break;
case lstore_2:
storeLong(2);
break;
case lstore_3:
storeLong(3);
break;
case lsub:
if (BytesPerWord == 8) {
popLong(rax);
sub(rax, rsp, BytesPerWord);
} else {
popLong(rax, rdx);
sub(rax, rsp, 0);
sbb(rdx, rsp, BytesPerWord);
}
break;
2007-10-04 22:41:19 +00:00
case new_: {
uint16_t index = codeReadInt16(t, code, ip);
object class_ = resolveClass(t, codePool(t, code), index - 1);
2007-10-04 00:41:54 +00:00
if (UNLIKELY(t->exception)) return 0;
PROTECT(t, class_);
initClass(t, class_);
2007-10-04 00:41:54 +00:00
if (UNLIKELY(t->exception)) return 0;
if (classVmFlags(t, class_) & WeakReferenceFlag) {
2007-10-04 00:41:54 +00:00
compileCall(reinterpret_cast<void*>(makeNewWeakReference), class_);
} else {
2007-10-04 00:41:54 +00:00
compileCall(reinterpret_cast<void*>(makeNew), class_);
}
pushObject(rax);
} break;
2007-09-30 02:48:27 +00:00
case newarray: {
uint8_t type = codeBody(t, code, ip++);
Label nonnegative(this);
popInt(rax);
2007-09-30 02:48:27 +00:00
cmp(0, rax);
jge(nonnegative);
compileCall
2007-10-04 00:41:54 +00:00
(reinterpret_cast<void*>(throwNew),
2007-10-03 00:22:48 +00:00
arrayBody
(t, t->m->types, Machine::NegativeArraySizeExceptionType));
2007-09-30 02:48:27 +00:00
nonnegative.mark();
object (*constructor)(Thread*, uintptr_t, bool);
switch (type) {
case T_BOOLEAN:
constructor = makeBooleanArray;
break;
case T_CHAR:
constructor = makeCharArray;
break;
case T_FLOAT:
constructor = makeFloatArray;
break;
case T_DOUBLE:
constructor = makeDoubleArray;
break;
case T_BYTE:
constructor = makeByteArray;
break;
case T_SHORT:
constructor = makeShortArray;
break;
case T_INT:
constructor = makeIntArray;
break;
case T_LONG:
constructor = makeLongArray;
break;
default: abort(t);
}
2007-10-04 00:41:54 +00:00
compileCall(reinterpret_cast<void*>(makeBlankArray),
reinterpret_cast<void*>(constructor), rax);
pushObject(rax);
2007-09-30 02:48:27 +00:00
} break;
case pop_: {
add(BytesPerWord, rsp);
2007-10-10 21:34:04 +00:00
stackMapper.poppedIntOrObject();
} break;
case putfield: {
uint16_t index = codeReadInt16(t, code, ip);
object field = resolveField(t, codePool(t, code), index - 1);
2007-10-04 00:41:54 +00:00
if (UNLIKELY(t->exception)) return 0;
switch (fieldCode(t, field)) {
case ByteField:
case BooleanField:
case CharField:
case ShortField:
case FloatField:
case IntField: {
popInt(rcx);
popObject(rax);
switch (fieldCode(t, field)) {
case ByteField:
case BooleanField:
mov1(rcx, rax, fieldOffset(t, field));
break;
case CharField:
case ShortField:
mov2(rcx, rax, fieldOffset(t, field));
break;
case FloatField:
case IntField:
mov4(rcx, rax, fieldOffset(t, field));
break;
}
} break;
case DoubleField:
case LongField: {
if (BytesPerWord == 8) {
popLong(rcx);
popObject(rax);
mov(rcx, rax, fieldOffset(t, field));
} else {
popLong(rcx, rbx);
popObject(rax);
mov(rcx, rax, fieldOffset(t, field));
mov(rbx, rax, fieldOffset(t, field) + 4);
}
} break;
case ObjectField: {
popObject(rcx);
popObject(rax);
mov(rcx, rax, fieldOffset(t, field));
} break;
default: abort(t);
}
} break;
case putstatic: {
uint16_t index = codeReadInt16(t, code, ip);
object field = resolveField(t, codePool(t, code), index - 1);
2007-10-04 00:41:54 +00:00
if (UNLIKELY(t->exception)) return 0;
initClass(t, fieldClass(t, field));
2007-10-04 00:41:54 +00:00
if (UNLIKELY(t->exception)) return 0;
object table = classStaticTable(t, fieldClass(t, field));
unsigned offset = (fieldOffset(t, field) * BytesPerWord) + ArrayBody;
switch (fieldCode(t, field)) {
case ByteField:
case BooleanField:
case CharField:
case ShortField:
case FloatField:
case IntField: {
2007-10-04 00:41:54 +00:00
compileCall(reinterpret_cast<void*>(makeNew),
arrayBody(t, t->m->types, Machine::IntType));
popInt(rax, IntValue);
mov(poolRegister(), poolReference(table), rcx);
mov(rax, rcx, offset);
} break;
case DoubleField:
case LongField: {
2007-10-04 00:41:54 +00:00
compileCall(reinterpret_cast<void*>(makeNew),
arrayBody(t, t->m->types, Machine::LongType));
if (BytesPerWord == 8) {
popLong(rax, LongValue);
} else {
popLong(rax, LongValue,
rax, LongValue + 4);
}
mov(poolRegister(), poolReference(table), rcx);
mov(rax, rcx, offset);
} break;
case ObjectField:
mov(poolRegister(), poolReference(table), rax);
popObject(rax, offset);
break;
default: abort(t);
}
} break;
case return_:
mov(rbp, rsp);
pop(rbp);
ret();
2007-10-12 00:30:46 +00:00
stackMapper.exited();
break;
2007-09-30 02:48:27 +00:00
case sipush: {
pushInt(static_cast<int16_t>(codeReadInt16(t, code, ip)));
2007-09-30 02:48:27 +00:00
} break;
default:
abort(t);
}
}
resolveJumps();
2007-10-03 00:22:48 +00:00
buildExceptionHandlerTable(code);
return finish();
}
void resolveJumps() {
for (unsigned i = 0; i < jumps.length(); i += 8) {
uint32_t ip = jumps.get4(i);
uint32_t offset = jumps.get4(i + 4);
code.set4(offset, machineIPs[ip] - (offset + 4));
2007-10-03 00:22:48 +00:00
}
}
void buildExceptionHandlerTable(object code) {
PROTECT(t, code);
object eht = codeExceptionHandlerTable(t, code);
2007-10-04 00:41:54 +00:00
if (eht) {
PROTECT(t, eht);
2007-10-03 00:22:48 +00:00
2007-10-04 00:41:54 +00:00
for (unsigned i = 0; i < exceptionHandlerTableLength(t, eht); ++i) {
ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i);
2007-10-03 00:22:48 +00:00
nativeExceptionHandlerStart(exceptionHandlers + i)
= machineIPs[exceptionHandlerStart(eh)];
2007-10-03 00:22:48 +00:00
nativeExceptionHandlerEnd(exceptionHandlers + i)
= machineIPs[exceptionHandlerEnd(eh)];
2007-10-04 00:41:54 +00:00
nativeExceptionHandlerIp(exceptionHandlers + i)
= machineIPs[exceptionHandlerIp(eh)];
2007-10-04 00:41:54 +00:00
unsigned ct = exceptionHandlerCatchType(eh);
object catchType;
if (ct) {
catchType = resolveClass
(t, codePool(t, code), exceptionHandlerCatchType(eh) - 1);
} else {
catchType = 0;
}
2007-10-03 00:22:48 +00:00
nativeExceptionHandlerCatchType(exceptionHandlers + i)
= (catchType ? (poolReference(catchType) / BytesPerWord) - 1 : 0);
2007-10-04 00:41:54 +00:00
}
}
}
2007-09-25 23:53:11 +00:00
Compiled* finish() {
stackMapper.finish();
2007-10-10 22:39:40 +00:00
return makeCompiled(t, method, &code, lineNumbers, exceptionHandlers,
&stackMapper);
2007-10-03 00:22:48 +00:00
}
object makePool() {
if (pool.length()) {
object array = makeArray(t, pool.length() / BytesPerWord, false);
2007-10-04 00:41:54 +00:00
pool.copyTo(&arrayBody(t, array, 0));
2007-10-03 00:22:48 +00:00
return array;
} else {
return 0;
}
}
Register poolRegister() {
return rdi;
}
uint32_t poolReference(object o) {
if (poolRegisterClobbered) {
mov(rbp, FrameMethod, rdi);
mov(rdi, MethodCode, rdi);
2007-10-09 19:30:01 +00:00
//poolRegisterClobbered = false;
2007-10-03 00:22:48 +00:00
}
2007-10-04 00:41:54 +00:00
pool.appendAddress(reinterpret_cast<uintptr_t>(o));
2007-10-03 00:22:48 +00:00
return pool.length() + BytesPerWord;
}
void callAddress(void* function) {
2007-10-10 22:39:40 +00:00
Compiler::callAddress(function);
stackMapper.called(code.length());
2007-10-03 00:22:48 +00:00
poolRegisterClobbered = true;
}
void callAlignedAddress(void* function) {
2007-10-10 22:39:40 +00:00
Compiler::callAlignedAddress(function);
stackMapper.called(code.length());
2007-10-03 00:22:48 +00:00
poolRegisterClobbered = true;
}
object method;
2007-10-10 21:34:04 +00:00
StackMapper stackMapper;
2007-10-03 00:22:48 +00:00
bool poolRegisterClobbered;
uint32_t* machineIPs;
NativeLineNumber* lineNumbers;
NativeExceptionHandler* exceptionHandlers;
2007-10-03 00:22:48 +00:00
Buffer pool;
};
2007-09-25 23:53:11 +00:00
void
compileMethod2(MyThread* t, object method)
2007-09-25 23:53:11 +00:00
{
2007-10-04 00:41:54 +00:00
if (reinterpret_cast<Compiled*>(methodCompiled(t, method))
== t->m->processor->methodStub(t))
{
2007-09-25 23:53:11 +00:00
PROTECT(t, method);
ACQUIRE(t, t->m->classLock);
2007-10-04 00:41:54 +00:00
if (reinterpret_cast<Compiled*>(methodCompiled(t, method))
== t->m->processor->methodStub(t))
{
2007-09-30 15:52:21 +00:00
if (Verbose) {
fprintf(stderr, "compiling %s.%s\n",
&byteArrayBody(t, className(t, methodClass(t, method)), 0),
&byteArrayBody(t, methodName(t, method), 0));
}
2007-10-12 00:30:46 +00:00
if (strcmp(reinterpret_cast<const char*>
(&byteArrayBody(t, methodName(t, method), 0)),
"charAt") == 0)
{
noop();
}
2007-10-10 22:39:40 +00:00
JavaCompiler c(t, method);
Compiled* code = c.compile();
2007-09-25 23:53:11 +00:00
2007-09-30 15:52:21 +00:00
if (Verbose) {
fprintf(stderr, "compiled %s.%s from %p to %p\n",
&byteArrayBody(t, className(t, methodClass(t, method)), 0),
&byteArrayBody(t, methodName(t, method), 0),
2007-10-04 00:41:54 +00:00
compiledCode(code),
compiledCode(code) + compiledCodeLength(code));
2007-09-30 15:52:21 +00:00
}
2007-10-04 00:41:54 +00:00
methodCompiled(t, method) = reinterpret_cast<uint64_t>(code);
2007-10-03 00:22:48 +00:00
object pool = c.makePool();
set(t, methodCode(t, method), pool);
2007-09-25 23:53:11 +00:00
}
}
}
void
updateCaller(MyThread* t, object method)
{
uintptr_t stub = reinterpret_cast<uintptr_t>
2007-10-04 00:41:54 +00:00
(compiledCode(static_cast<Compiled*>(t->m->processor->methodStub(t))));
Assembler a(t->m->system);
a.mov(stub, rax);
unsigned offset = a.code.length() - BytesPerWord;
a.call(rax);
2007-10-04 22:41:19 +00:00
uint8_t* caller = static_cast<uint8_t*>(frameAddress(t->frame))
- a.code.length();
if (memcmp(a.code.data, caller, a.code.length()) == 0) {
// it's a direct call - update caller to point to new code
// address must be aligned on a word boundary for this write to
// be atomic
assert(t, reinterpret_cast<uintptr_t>(caller + offset)
% BytesPerWord == 0);
*reinterpret_cast<void**>(caller + offset)
2007-10-04 00:41:54 +00:00
= compiledCode(reinterpret_cast<Compiled*>(methodCompiled(t, method)));
}
}
void
compileMethod(MyThread* t, object method)
{
compileMethod2(t, method);
if (UNLIKELY(t->exception)) {
unwind(t);
} else if (not methodVirtual(t, method)) {
updateCaller(t, method);
}
}
2007-09-25 23:53:11 +00:00
class ArgumentList {
public:
ArgumentList(Thread* t, uintptr_t* array, bool* objectMask, object this_,
const char* spec, bool indirectObjects, va_list arguments):
t(static_cast<MyThread*>(t)),
next(this->t->argumentList),
array(array),
objectMask(objectMask),
position(0)
{
this->t->argumentList = this;
addInt(reinterpret_cast<uintptr_t>(t));
addObject(0); // reserve space for method
addInt(reinterpret_cast<uintptr_t>(this->t->frame));
if (this_) {
addObject(this_);
}
const char* s = spec;
++ s; // skip '('
while (*s and *s != ')') {
switch (*s) {
case 'L':
while (*s and *s != ';') ++ s;
++ s;
if (indirectObjects) {
object* v = va_arg(arguments, object*);
addObject(v ? *v : 0);
} else {
addObject(va_arg(arguments, object));
}
break;
case '[':
while (*s == '[') ++ s;
switch (*s) {
case 'L':
while (*s and *s != ';') ++ s;
++ s;
break;
default:
++ s;
break;
}
if (indirectObjects) {
object* v = va_arg(arguments, object*);
addObject(v ? *v : 0);
} else {
addObject(va_arg(arguments, object));
}
break;
case 'J':
case 'D':
++ s;
addLong(va_arg(arguments, uint64_t));
break;
default:
++ s;
addInt(va_arg(arguments, uint32_t));
break;
}
}
}
ArgumentList(Thread* t, uintptr_t* array, bool* objectMask, object this_,
const char* spec, object arguments):
t(static_cast<MyThread*>(t)),
next(this->t->argumentList),
array(array),
objectMask(objectMask),
position(0)
{
this->t->argumentList = this;
addInt(0); // reserve space for trace pointer
addObject(0); // reserve space for method pointer
if (this_) {
addObject(this_);
}
unsigned index = 0;
const char* s = spec;
++ s; // skip '('
while (*s and *s != ')') {
switch (*s) {
case 'L':
while (*s and *s != ';') ++ s;
++ s;
addObject(objectArrayBody(t, arguments, index++));
break;
case '[':
while (*s == '[') ++ s;
switch (*s) {
case 'L':
while (*s and *s != ';') ++ s;
++ s;
break;
default:
++ s;
break;
}
addObject(objectArrayBody(t, arguments, index++));
break;
case 'J':
case 'D':
++ s;
addLong(cast<int64_t>(objectArrayBody(t, arguments, index++),
BytesPerWord));
break;
default:
++ s;
addInt(cast<int32_t>(objectArrayBody(t, arguments, index++),
BytesPerWord));
break;
}
}
}
~ArgumentList() {
t->argumentList = next;
}
void addObject(object v) {
array[position] = reinterpret_cast<uintptr_t>(v);
objectMask[position] = true;
++ position;
}
void addInt(uint32_t v) {
array[position] = v;
objectMask[position] = false;
++ position;
}
void addLong(uint64_t v) {
memcpy(array + position, &v, 8);
objectMask[position] = false;
objectMask[position] = false;
position += 2;
}
MyThread* t;
ArgumentList* next;
uintptr_t* array;
bool* objectMask;
unsigned position;
};
object
invoke(Thread* thread, object method, ArgumentList* arguments)
{
MyThread* t = static_cast<MyThread*>(thread);
arguments->array[1] = reinterpret_cast<uintptr_t>(method);
unsigned returnCode = methodReturnCode(t, method);
2007-09-25 23:53:11 +00:00
unsigned returnType = fieldType(t, returnCode);
2007-09-30 02:48:27 +00:00
void* frame = t->frame;
Reference* reference = t->reference;
2007-09-30 02:48:27 +00:00
2007-10-04 00:41:54 +00:00
Compiled* code = reinterpret_cast<Compiled*>(methodCompiled(t, method));
uint64_t result = vmInvoke
2007-10-04 00:41:54 +00:00
(compiledCode(code), arguments->array, arguments->position * BytesPerWord,
returnType);
2007-09-25 23:53:11 +00:00
while (t->reference != reference) {
dispose(t, t->reference);
}
2007-09-30 02:48:27 +00:00
t->frame = frame;
2007-09-25 23:53:11 +00:00
object r;
switch (returnCode) {
case ByteField:
case BooleanField:
case CharField:
case ShortField:
case FloatField:
case IntField:
r = makeInt(t, result);
break;
case LongField:
case DoubleField:
r = makeLong(t, result);
break;
case ObjectField:
r = (result == 0 ? 0 :
*reinterpret_cast<object*>(static_cast<uintptr_t>(result)));
break;
case VoidField:
r = 0;
break;
default:
abort(t);
};
return r;
}
2007-09-25 23:53:11 +00:00
class MyProcessor: public Processor {
public:
2007-09-25 23:53:11 +00:00
MyProcessor(System* s):
s(s),
methodStub_(0),
nativeInvoker_(0)
{ }
2007-09-25 23:53:11 +00:00
virtual Thread*
makeThread(Machine* m, object javaThread, Thread* parent)
{
return new (s->allocate(sizeof(MyThread))) MyThread(m, javaThread, parent);
}
2007-10-03 00:22:48 +00:00
virtual void*
2007-09-25 23:53:11 +00:00
methodStub(Thread* t)
{
if (methodStub_ == 0) {
2007-10-10 22:39:40 +00:00
Compiler c(static_cast<MyThread*>(t));
2007-10-03 00:22:48 +00:00
methodStub_ = c.compileStub();
}
return methodStub_;
}
2007-10-03 00:22:48 +00:00
virtual void*
nativeInvoker(Thread* t)
{
if (nativeInvoker_ == 0) {
2007-10-10 22:39:40 +00:00
Compiler c(static_cast<MyThread*>(t));
2007-10-03 00:22:48 +00:00
nativeInvoker_ = c.compileNativeInvoker();
2007-09-25 23:53:11 +00:00
}
return nativeInvoker_;
2007-09-25 23:53:11 +00:00
}
2007-10-04 03:19:39 +00:00
Compiled*
caller(Thread* t)
{
if (caller_ == 0) {
2007-10-10 22:39:40 +00:00
Compiler c(static_cast<MyThread*>(t));
2007-10-04 03:19:39 +00:00
caller_ = c.compileCaller();
}
return caller_;
}
virtual unsigned
parameterFootprint(vm::Thread*, const char* s, bool static_)
{
unsigned footprint = 0;
++ s; // skip '('
while (*s and *s != ')') {
switch (*s) {
case 'L':
while (*s and *s != ';') ++ s;
++ s;
break;
case '[':
while (*s == '[') ++ s;
switch (*s) {
case 'L':
while (*s and *s != ';') ++ s;
++ s;
break;
default:
++ s;
break;
}
break;
case 'J':
case 'D':
++ s;
2007-10-04 22:41:19 +00:00
++ footprint;
break;
default:
++ s;
break;
}
++ footprint;
}
if (not static_) {
++ footprint;
}
return footprint;
}
virtual void
initClass(Thread* t, object c)
{
PROTECT(t, c);
ACQUIRE(t, t->m->classLock);
if (classVmFlags(t, c) & NeedInitFlag
and (classVmFlags(t, c) & InitFlag) == 0)
{
classVmFlags(t, c) |= InitFlag;
invoke(t, classInitializer(t, c), 0);
if (t->exception) {
t->exception = makeExceptionInInitializerError(t, t->exception);
}
classVmFlags(t, c) &= ~(NeedInitFlag | InitFlag);
}
}
2007-09-25 23:53:11 +00:00
virtual void
visitObjects(Thread* t, Heap::Visitor*)
{
abort(t);
}
virtual uintptr_t
2007-10-02 00:08:17 +00:00
frameStart(Thread* vmt)
2007-09-25 23:53:11 +00:00
{
2007-10-04 00:41:54 +00:00
return reinterpret_cast<uintptr_t>(static_cast<MyThread*>(vmt)->frame);
2007-09-25 23:53:11 +00:00
}
virtual uintptr_t
2007-10-02 00:08:17 +00:00
frameNext(Thread*, uintptr_t frame)
2007-09-25 23:53:11 +00:00
{
2007-10-04 00:41:54 +00:00
return reinterpret_cast<uintptr_t>
(::frameNext(reinterpret_cast<void*>(frame)));
2007-09-25 23:53:11 +00:00
}
virtual bool
2007-10-02 00:08:17 +00:00
frameValid(Thread*, uintptr_t frame)
2007-09-25 23:53:11 +00:00
{
2007-10-04 00:41:54 +00:00
return ::frameValid(reinterpret_cast<void*>(frame));
2007-09-25 23:53:11 +00:00
}
virtual object
2007-10-02 00:08:17 +00:00
frameMethod(Thread*, uintptr_t frame)
2007-09-25 23:53:11 +00:00
{
2007-10-04 00:41:54 +00:00
return ::frameMethod(reinterpret_cast<void*>(frame));
2007-09-25 23:53:11 +00:00
}
virtual unsigned
2007-10-03 00:22:48 +00:00
frameIp(Thread* t, uintptr_t frame)
2007-09-25 23:53:11 +00:00
{
2007-10-04 00:41:54 +00:00
void* f = reinterpret_cast<void*>(frame);
return addressOffset(t, ::frameMethod(f), ::frameAddress(f));
2007-09-25 23:53:11 +00:00
}
2007-10-04 22:41:19 +00:00
virtual int
lineNumber(Thread* t, object method, unsigned ip)
{
if (methodFlags(t, method) & ACC_NATIVE) {
return NativeLine;
}
Compiled* code = reinterpret_cast<Compiled*>(methodCompiled(t, method));
if (compiledLineNumberCount(t, code)) {
unsigned bottom = 0;
unsigned top = compiledLineNumberCount(t, code);
for (unsigned span = top - bottom; span; span = top - bottom) {
unsigned middle = bottom + (span / 2);
NativeLineNumber* ln = compiledLineNumber(t, code, middle);
if (ip >= nativeLineNumberIp(ln)
and (middle + 1 == compiledLineNumberCount(t, code)
or ip < nativeLineNumberIp
(compiledLineNumber(t, code, middle + 1))))
{
return nativeLineNumberLine(ln);
} else if (ip < nativeLineNumberIp(ln)) {
top = middle;
} else if (ip > nativeLineNumberIp(ln)) {
bottom = middle + 1;
}
}
abort(t);
} else {
return UnknownLine;
}
}
2007-09-25 23:53:11 +00:00
virtual object*
makeLocalReference(Thread* vmt, object o)
2007-09-25 23:53:11 +00:00
{
if (o) {
MyThread* t = static_cast<MyThread*>(vmt);
Reference* r = new (t->m->system->allocate(sizeof(Reference)))
Reference(o, &(t->reference));
return &(r->target);
} else {
return 0;
}
2007-09-25 23:53:11 +00:00
}
virtual void
disposeLocalReference(Thread* t, object* r)
2007-09-25 23:53:11 +00:00
{
if (r) {
vm::dispose(t, reinterpret_cast<Reference*>(r));
}
2007-09-25 23:53:11 +00:00
}
virtual object
invokeArray(Thread* t, object method, object this_, object arguments)
{
assert(t, t->state == Thread::ActiveState
or t->state == Thread::ExclusiveState);
assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0));
2007-09-25 23:53:11 +00:00
const char* spec = reinterpret_cast<char*>
(&byteArrayBody(t, methodSpec(t, method), 0));
unsigned size = methodParameterFootprint(t, method) + FrameFootprint;
2007-09-25 23:53:11 +00:00
uintptr_t array[size];
bool objectMask[size];
ArgumentList list(t, array, objectMask, this_, spec, arguments);
2007-09-25 23:53:11 +00:00
return ::invoke(t, method, &list);
}
virtual object
invokeList(Thread* t, object method, object this_, bool indirectObjects,
va_list arguments)
{
assert(t, t->state == Thread::ActiveState
or t->state == Thread::ExclusiveState);
assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0));
2007-09-25 23:53:11 +00:00
const char* spec = reinterpret_cast<char*>
(&byteArrayBody(t, methodSpec(t, method), 0));
unsigned size = methodParameterFootprint(t, method) + FrameFootprint;
2007-09-25 23:53:11 +00:00
uintptr_t array[size];
bool objectMask[size];
ArgumentList list
(t, array, objectMask, this_, spec, indirectObjects, arguments);
2007-09-25 23:53:11 +00:00
return ::invoke(t, method, &list);
}
virtual object
invokeList(Thread* t, const char* className, const char* methodName,
const char* methodSpec, object this_, va_list arguments)
{
assert(t, t->state == Thread::ActiveState
or t->state == Thread::ExclusiveState);
unsigned size = parameterFootprint(t, methodSpec, false) + FrameFootprint;
2007-09-25 23:53:11 +00:00
uintptr_t array[size];
bool objectMask[size];
ArgumentList list
(t, array, objectMask, this_, methodSpec, false, arguments);
object method = resolveMethod(t, className, methodName, methodSpec);
if (LIKELY(t->exception == 0)) {
assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0));
2007-09-25 23:53:11 +00:00
return ::invoke(t, method, &list);
} else {
return 0;
}
}
virtual void dispose() {
2007-10-03 00:22:48 +00:00
if (methodStub_) {
s->free(methodStub_);
}
if (nativeInvoker_) {
s->free(nativeInvoker_);
}
2007-10-04 03:19:39 +00:00
if (caller_) {
s->free(caller_);
}
s->free(this);
}
System* s;
2007-10-04 00:41:54 +00:00
Compiled* methodStub_;
Compiled* nativeInvoker_;
2007-10-04 03:19:39 +00:00
Compiled* caller_;
};
2007-10-04 03:19:39 +00:00
Compiled*
caller(MyThread* t)
{
return static_cast<MyProcessor*>(t->m->processor)->caller(t);
}
} // namespace
namespace vm {
2007-09-25 23:53:11 +00:00
Processor*
makeProcessor(System* system)
{
2007-09-25 23:53:11 +00:00
return new (system->allocate(sizeof(MyProcessor))) MyProcessor(system);
}
} // namespace vm
2007-09-25 23:53:11 +00:00