2007-09-24 01:39:03 +00:00
|
|
|
#include "common.h"
|
|
|
|
#include "system.h"
|
|
|
|
#include "constants.h"
|
|
|
|
#include "machine.h"
|
2007-09-26 23:23:03 +00:00
|
|
|
#include "processor.h"
|
|
|
|
#include "process.h"
|
2007-09-24 01:39:03 +00:00
|
|
|
|
|
|
|
using namespace vm;
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
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
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
namespace {
|
|
|
|
|
2007-10-04 00:41:54 +00:00
|
|
|
const bool Verbose = true;
|
2007-09-30 15:52:21 +00:00
|
|
|
|
2007-09-26 23:23:03 +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;
|
2007-09-26 23:23:03 +00:00
|
|
|
const unsigned FrameFootprint = BytesPerWord * 3;
|
2007-09-25 23:53:11 +00:00
|
|
|
|
2007-10-01 15:19:15 +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 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-01 15:19:15 +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*>
|
|
|
|
(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
|
|
|
}
|
|
|
|
|
|
|
|
inline Compiled*
|
2007-10-04 22:41:19 +00:00
|
|
|
makeCompiled(Thread* t, object method, Buffer* code, Buffer* lineNumbers,
|
2007-10-04 00:41:54 +00:00
|
|
|
Buffer* exceptionHandlers)
|
|
|
|
{
|
|
|
|
Compiled* c = static_cast<Compiled*>
|
|
|
|
(t->m->system->allocate(sizeof(Compiled)
|
|
|
|
+ pad(code->length())
|
|
|
|
+ pad(lineNumbers->length())
|
|
|
|
+ pad(exceptionHandlers->length())));
|
|
|
|
|
2007-10-04 22:41:19 +00:00
|
|
|
if (method) {
|
|
|
|
compiledMaxLocals(c) = codeMaxLocals(t, methodCode(t, method));
|
|
|
|
compiledMaxStack(c) = codeMaxStack(t, methodCode(t, method));
|
|
|
|
} else {
|
|
|
|
compiledMaxLocals(c) = 0;
|
|
|
|
compiledMaxStack(c) = 0;
|
|
|
|
}
|
2007-10-04 00:41:54 +00:00
|
|
|
compiledCodeLength(c) = code->length();
|
|
|
|
compiledLineNumberTableLength(c) = lineNumbers->length();
|
|
|
|
compiledExceptionHandlerTableLength(c) = exceptionHandlers->length();
|
|
|
|
|
|
|
|
if (code->length()) {
|
|
|
|
code->copyTo(compiledCode(c));
|
|
|
|
}
|
|
|
|
if (lineNumbers->length()) {
|
|
|
|
lineNumbers->copyTo(compiledLineNumber(t, c, 0));
|
|
|
|
}
|
|
|
|
if (exceptionHandlers->length()) {
|
|
|
|
exceptionHandlers->copyTo(compiledExceptionHandler(t, c, 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2007-10-01 15:19:15 +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);
|
|
|
|
}
|
|
|
|
|
2007-10-01 15:19:15 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2007-10-01 15:19:15 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2007-10-08 21:41:41 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2007-10-01 15:19:15 +00:00
|
|
|
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))
|
2007-10-01 15:19:15 +00:00
|
|
|
+ (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,
|
2007-10-01 15:19:15 +00:00
|
|
|
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;
|
2007-10-01 15:19:15 +00:00
|
|
|
} 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);
|
|
|
|
|
2007-09-27 00:01:38 +00:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2007-09-28 23:41:03 +00:00
|
|
|
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
|
|
|
|
};
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
class Assembler {
|
|
|
|
public:
|
2007-09-25 23:53:11 +00:00
|
|
|
class Label {
|
|
|
|
public:
|
|
|
|
static const unsigned Capacity = 8;
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
Label(Assembler* a):
|
|
|
|
code(&(a->code)),
|
2007-09-25 23:53:11 +00:00
|
|
|
unresolvedCount(0),
|
|
|
|
mark_(-1)
|
|
|
|
{ }
|
|
|
|
|
2007-09-28 23:41:03 +00:00
|
|
|
void reference() {
|
2007-09-25 23:53:11 +00:00
|
|
|
if (mark_ == -1) {
|
2007-09-26 23:23:03 +00:00
|
|
|
expect(code->s, unresolvedCount < Capacity);
|
2007-09-28 23:41:03 +00:00
|
|
|
unresolved[unresolvedCount] = code->length();
|
2007-09-25 23:53:11 +00:00
|
|
|
++ unresolvedCount;
|
|
|
|
|
2007-09-28 23:41:03 +00:00
|
|
|
code->append4(0);
|
2007-09-25 23:53:11 +00:00
|
|
|
} else {
|
2007-09-28 23:41:03 +00:00
|
|
|
code->append4(mark_ - (code->length() + 4));
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
void mark() {
|
|
|
|
mark_ = code->length();
|
2007-09-25 23:53:11 +00:00
|
|
|
for (unsigned i = 0; i < unresolvedCount; ++i) {
|
2007-09-28 23:41:03 +00:00
|
|
|
code->set4(unresolved[i], mark_ - (unresolved[i] + 4));
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-28 23:41:03 +00:00
|
|
|
Buffer* code;
|
|
|
|
unsigned unresolved[Capacity];
|
2007-09-25 23:53:11 +00:00
|
|
|
unsigned unresolvedCount;
|
|
|
|
int mark_;
|
|
|
|
};
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
Assembler(System* s):
|
2007-09-28 23:41:03 +00:00
|
|
|
code(s, 1024),
|
|
|
|
jumps(s, 32)
|
2007-09-24 01:39:03 +00:00
|
|
|
{ }
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
void rex() {
|
|
|
|
if (BytesPerWord == 8) {
|
|
|
|
code.append(0x48);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-25 23:53:11 +00:00
|
|
|
void mov(Register src, Register dst) {
|
2007-09-26 23:23:03 +00:00
|
|
|
rex();
|
|
|
|
code.append(0x89);
|
|
|
|
code.append(0xc0 | (src << 3) | dst);
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
|
|
|
|
2007-09-28 14:45:26 +00:00
|
|
|
void offsetInstruction(uint8_t instruction, uint8_t zeroPrefix,
|
|
|
|
uint8_t bytePrefix, uint8_t wordPrefix,
|
2007-09-28 23:41:03 +00:00
|
|
|
unsigned a, unsigned b, int32_t offset)
|
2007-09-28 14:45:26 +00:00
|
|
|
{
|
|
|
|
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 {
|
2007-09-28 14:45:26 +00:00
|
|
|
prefix = wordPrefix;
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
2007-09-28 14:45:26 +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);
|
|
|
|
}
|
|
|
|
|
2007-09-29 20:24:14 +00:00
|
|
|
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);
|
2007-09-29 20:24:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2007-09-29 20:24:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2007-09-29 20:24:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2007-09-29 20:24:14 +00:00
|
|
|
}
|
|
|
|
|
2007-09-28 14:45:26 +00:00
|
|
|
void mov4(Register src, int32_t srcOffset, Register dst) {
|
|
|
|
offsetInstruction(0x8b, 0, 0x40, 0x80, dst, src, srcOffset);
|
|
|
|
}
|
|
|
|
|
2007-09-29 20:24:14 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2007-09-28 14:45:26 +00:00
|
|
|
void mov4(Register src, Register dst, int32_t dstOffset) {
|
|
|
|
offsetInstruction(0x89, 0, 0x40, 0x80, src, dst, dstOffset);
|
|
|
|
}
|
|
|
|
|
2007-09-28 23:41:03 +00:00
|
|
|
void mov(Register src, int32_t srcOffset, SSERegister dst) {
|
|
|
|
code.append(0xf3);
|
|
|
|
code.append(0x0f);
|
|
|
|
offsetInstruction(0x7e, 0, 0x40, 0x80, dst, src, srcOffset);
|
|
|
|
}
|
|
|
|
|
2007-09-28 14:45:26 +00:00
|
|
|
void mov(Register src, int32_t srcOffset, Register dst) {
|
|
|
|
rex();
|
|
|
|
mov4(src, srcOffset, dst);
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
|
|
|
|
2007-09-27 00:01:38 +00:00
|
|
|
void mov(Register src, Register dst, int32_t dstOffset) {
|
2007-09-26 23:23:03 +00:00
|
|
|
rex();
|
2007-09-28 14:45:26 +00:00
|
|
|
mov4(src, dst, dstOffset);
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
|
|
|
|
2007-09-26 23:23:03 +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);
|
|
|
|
}
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
void nop() {
|
|
|
|
code.append(0x90);
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void push(Register reg) {
|
2007-09-26 23:23:03 +00:00
|
|
|
code.append(0x50 | reg);
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
|
|
|
|
2007-09-27 00:01:38 +00:00
|
|
|
void push(Register reg, int32_t offset) {
|
2007-09-28 14:45:26 +00:00
|
|
|
offsetInstruction(0xff, 0x30, 0x70, 0xb0, rax, reg, offset);
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
|
|
|
|
2007-09-27 00:01:38 +00:00
|
|
|
void push(int32_t v) {
|
2007-09-29 18:34:56 +00:00
|
|
|
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) {
|
2007-09-27 22:20:54 +00:00
|
|
|
if (BytesPerWord == 8) {
|
2007-10-03 00:22:48 +00:00
|
|
|
mov4(reg, offset, rsi);
|
2007-09-27 22:20:54 +00:00
|
|
|
push(rsi);
|
|
|
|
} else {
|
2007-10-03 00:22:48 +00:00
|
|
|
push(reg, offset);
|
2007-09-27 22:20:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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);
|
2007-09-28 14:45:26 +00:00
|
|
|
push(rsi);
|
|
|
|
} else {
|
2007-10-03 00:22:48 +00:00
|
|
|
push(v);
|
2007-09-28 14:45:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-25 23:53:11 +00:00
|
|
|
void pop(Register dst) {
|
2007-09-26 23:23:03 +00:00
|
|
|
code.append(0x58 | dst);
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
|
|
|
|
2007-09-27 00:01:38 +00:00
|
|
|
void pop(Register dst, int32_t offset) {
|
2007-09-28 14:45:26 +00:00
|
|
|
offsetInstruction(0x8f, 0, 0x40, 0x80, rax, dst, offset);
|
|
|
|
}
|
2007-09-26 23:23:03 +00:00
|
|
|
|
2007-09-28 14:45:26 +00:00
|
|
|
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) {
|
2007-09-26 23:23:03 +00:00
|
|
|
rex();
|
|
|
|
code.append(0x01);
|
|
|
|
code.append(0xc0 | (src << 3) | dst);
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
|
|
|
|
2007-09-27 00:01:38 +00:00
|
|
|
void add(int32_t v, Register dst) {
|
|
|
|
assert(code.s, isByte(v)); // todo
|
2007-09-26 23:23:03 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2007-10-08 21:41:41 +00:00
|
|
|
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) {
|
2007-09-26 23:23:03 +00:00
|
|
|
rex();
|
|
|
|
code.append(0x29);
|
|
|
|
code.append(0xc0 | (src << 3) | dst);
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
|
|
|
|
2007-09-27 00:01:38 +00:00
|
|
|
void sub(int32_t v, Register dst) {
|
|
|
|
assert(code.s, isByte(v)); // todo
|
2007-09-26 23:23:03 +00:00
|
|
|
|
|
|
|
rex();
|
|
|
|
code.append(0x83);
|
|
|
|
code.append(0xe8 | dst);
|
|
|
|
code.append(v);
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
|
|
|
|
2007-10-08 21:41:41 +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) {
|
2007-09-26 23:23:03 +00:00
|
|
|
rex();
|
|
|
|
code.append(0x09);
|
|
|
|
code.append(0xc0 | (src << 3) | dst);
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
|
|
|
|
2007-09-27 00:01:38 +00:00
|
|
|
void or_(int32_t v, Register dst) {
|
|
|
|
assert(code.s, isByte(v)); // todo
|
2007-09-26 23:23:03 +00:00
|
|
|
|
|
|
|
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) {
|
2007-09-26 23:23:03 +00:00
|
|
|
rex();
|
|
|
|
code.append(0x21);
|
|
|
|
code.append(0xc0 | (src << 3) | dst);
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
|
|
|
|
2007-09-27 00:01:38 +00:00
|
|
|
void and_(int32_t v, Register dst) {
|
|
|
|
assert(code.s, isByte(v)); // todo
|
2007-09-26 23:23:03 +00:00
|
|
|
|
|
|
|
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() {
|
2007-09-26 23:23:03 +00:00
|
|
|
code.append(0xc3);
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void jmp(Label& label) {
|
2007-09-26 23:23:03 +00:00
|
|
|
code.append(0xE9);
|
2007-09-28 23:41:03 +00:00
|
|
|
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) {
|
2007-09-26 23:23:03 +00:00
|
|
|
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) {
|
2007-09-29 20:24:14 +00:00
|
|
|
code.append(0x0f);
|
2007-09-30 02:48:27 +00:00
|
|
|
code.append(condition);
|
2007-09-28 23:41:03 +00:00
|
|
|
label.reference();
|
2007-09-26 23:23:03 +00:00
|
|
|
}
|
|
|
|
|
2007-09-29 20:24:14 +00:00
|
|
|
void conditional(unsigned javaIP, unsigned condition) {
|
|
|
|
code.append(0x0f);
|
|
|
|
code.append(condition);
|
2007-09-28 23:41:03 +00:00
|
|
|
|
|
|
|
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) {
|
2007-09-29 20:24:14 +00:00
|
|
|
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) {
|
2007-09-29 20:24:14 +00:00
|
|
|
conditional(javaIP, 0x85);
|
|
|
|
}
|
2007-09-28 23:41:03 +00:00
|
|
|
|
2007-09-30 02:48:27 +00:00
|
|
|
void jg(Label& label) {
|
|
|
|
conditional(label, 0x8f);
|
|
|
|
}
|
|
|
|
|
2007-09-29 20:24:14 +00:00
|
|
|
void jg(unsigned javaIP) {
|
|
|
|
conditional(javaIP, 0x8f);
|
|
|
|
}
|
2007-09-28 23:41:03 +00:00
|
|
|
|
2007-09-30 02:48:27 +00:00
|
|
|
void jge(Label& label) {
|
|
|
|
conditional(label, 0x8d);
|
|
|
|
}
|
|
|
|
|
2007-09-29 20:24:14 +00:00
|
|
|
void jge(unsigned javaIP) {
|
|
|
|
conditional(javaIP, 0x8d);
|
|
|
|
}
|
|
|
|
|
2007-09-30 02:48:27 +00:00
|
|
|
void jl(Label& label) {
|
|
|
|
conditional(label, 0x8c);
|
|
|
|
}
|
|
|
|
|
2007-09-29 20:24:14 +00:00
|
|
|
void jl(unsigned javaIP) {
|
|
|
|
conditional(javaIP, 0x8c);
|
|
|
|
}
|
|
|
|
|
2007-09-30 02:48:27 +00:00
|
|
|
void jle(Label& label) {
|
|
|
|
conditional(label, 0x8e);
|
|
|
|
}
|
|
|
|
|
2007-09-29 20:24:14 +00:00
|
|
|
void jle(unsigned javaIP) {
|
|
|
|
conditional(javaIP, 0x8e);
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
|
|
|
|
2007-10-08 21:41:41 +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();
|
2007-09-26 23:23:03 +00:00
|
|
|
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) {
|
2007-09-26 23:23:03 +00:00
|
|
|
code.append(0xff);
|
|
|
|
code.append(0xd0 | reg);
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
|
|
|
|
2007-10-08 21:41:41 +00:00
|
|
|
void cdq() {
|
|
|
|
code.append(0x99);
|
|
|
|
}
|
|
|
|
|
2007-10-08 23:13:55 +00:00
|
|
|
void cqo() {
|
|
|
|
rex();
|
|
|
|
cdq();
|
|
|
|
}
|
|
|
|
|
2007-10-08 21:41:41 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2007-09-28 23:41:03 +00:00
|
|
|
Buffer code;
|
|
|
|
Buffer jumps;
|
2007-09-24 01:39:03 +00:00
|
|
|
};
|
|
|
|
|
2007-09-25 23:53:11 +00:00
|
|
|
int
|
|
|
|
localOffset(int v, int parameterFootprint)
|
|
|
|
{
|
2007-09-26 23:23:03 +00:00
|
|
|
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 {
|
2007-09-26 23:23:03 +00:00
|
|
|
return -(v + BytesPerWord - parameterFootprint);
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-28 23:41:03 +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)
|
2007-09-28 23:41:03 +00:00
|
|
|
{
|
|
|
|
assert(t, index < 8);
|
2007-09-30 16:32:17 +00:00
|
|
|
return static_cast<SSERegister>(index);
|
2007-09-28 23:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
2007-09-30 02:48:27 +00:00
|
|
|
parameterOffset(unsigned index)
|
2007-09-28 23:41:03 +00:00
|
|
|
{
|
2007-09-30 02:48:27 +00:00
|
|
|
return FrameFootprint + ((index + 2) * BytesPerWord);
|
2007-09-28 23:41:03 +00:00
|
|
|
}
|
|
|
|
|
2007-10-04 03:19:39 +00:00
|
|
|
Compiled*
|
|
|
|
caller(MyThread* t);
|
|
|
|
|
2007-09-25 23:53:11 +00:00
|
|
|
class Compiler: public Assembler {
|
2007-09-24 01:39:03 +00:00
|
|
|
public:
|
2007-10-04 00:41:54 +00:00
|
|
|
Compiler(MyThread* t):
|
|
|
|
Assembler(t->m->system),
|
2007-10-03 01:54:21 +00:00
|
|
|
t(t),
|
|
|
|
poolRegisterClobbered(true),
|
2007-10-04 00:41:54 +00:00
|
|
|
javaIPs(t->m->system, 1024),
|
|
|
|
machineIPs(t->m->system, 1024),
|
|
|
|
lineNumbers(t->m->system, 256),
|
|
|
|
exceptionHandlers(t->m->system, 256),
|
|
|
|
pool(t->m->system, 256)
|
2007-09-24 01:39:03 +00:00
|
|
|
{ }
|
|
|
|
|
2007-10-08 21:41:41 +00:00
|
|
|
void pushLong(uint64_t v) {
|
|
|
|
if (BytesPerWord == 8) {
|
|
|
|
pushAddress(v);
|
|
|
|
sub(8, rsp);
|
|
|
|
} else {
|
|
|
|
push((v >> 32) & 0xFFFFFFFF);
|
|
|
|
push((v ) & 0xFFFFFFFF);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-09 17:15:40 +00:00
|
|
|
void pushLong(Register r) {
|
|
|
|
assert(t, BytesPerWord == 8);
|
|
|
|
push(r);
|
|
|
|
sub(8, rsp);
|
|
|
|
}
|
|
|
|
|
2007-10-08 21:41:41 +00:00
|
|
|
void pushLong(Register low, Register high) {
|
|
|
|
assert(t, BytesPerWord == 4);
|
|
|
|
push(high);
|
|
|
|
push(low);
|
|
|
|
}
|
|
|
|
|
|
|
|
void popLong(Register r) {
|
|
|
|
assert(t, BytesPerWord == 8);
|
|
|
|
add(8, rsp);
|
|
|
|
pop(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
void popLong(Register low, Register high) {
|
|
|
|
assert(t, BytesPerWord == 4);
|
|
|
|
pop(low);
|
|
|
|
pop(high);
|
|
|
|
}
|
|
|
|
|
|
|
|
void loadLong(uint64_t index, unsigned parameterFootprint) {
|
|
|
|
if (BytesPerWord == 8) {
|
|
|
|
push(rbp, localOffset(index, parameterFootprint));
|
|
|
|
sub(8, rsp);
|
|
|
|
} else {
|
|
|
|
push(rbp, localOffset(index + 1, parameterFootprint));
|
|
|
|
push(rbp, localOffset(index, parameterFootprint));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void storeLong(uint64_t index, unsigned parameterFootprint) {
|
|
|
|
if (BytesPerWord == 8) {
|
|
|
|
add(8, rsp);
|
|
|
|
pop(rbp, localOffset(index, parameterFootprint));
|
|
|
|
} else {
|
|
|
|
pop(rbp, localOffset(index, parameterFootprint));
|
|
|
|
pop(rbp, localOffset(index + 1, parameterFootprint));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-03 00:22:48 +00:00
|
|
|
void pushReturnValue(unsigned code) {
|
2007-09-26 23:23:03 +00:00
|
|
|
switch (code) {
|
|
|
|
case ByteField:
|
|
|
|
case BooleanField:
|
|
|
|
case CharField:
|
|
|
|
case ShortField:
|
|
|
|
case FloatField:
|
|
|
|
case IntField:
|
|
|
|
case ObjectField:
|
|
|
|
push(rax);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LongField:
|
|
|
|
case DoubleField:
|
|
|
|
push(rax);
|
|
|
|
push(rdx);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VoidField:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
abort(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-03 00:22:48 +00:00
|
|
|
void compileDirectInvoke(object target) {
|
2007-09-28 14:45:26 +00:00
|
|
|
unsigned footprint = FrameFootprint
|
|
|
|
+ (methodParameterFootprint(t, target) * BytesPerWord);
|
|
|
|
|
2007-10-04 00:41:54 +00:00
|
|
|
Compiled* code = reinterpret_cast<Compiled*>(methodCompiled(t, target));
|
2007-09-28 14:45:26 +00:00
|
|
|
|
2007-10-04 03:19:39 +00:00
|
|
|
push(rsp);
|
2007-10-03 00:22:48 +00:00
|
|
|
push(poolRegister(), poolReference(target));
|
2007-09-28 14:45:26 +00:00
|
|
|
push(rbp, FrameThread);
|
|
|
|
|
2007-10-04 00:41:54 +00:00
|
|
|
callAlignedAddress(compiledCode(code));
|
2007-09-28 14:45:26 +00:00
|
|
|
|
2007-10-04 03:19:39 +00:00
|
|
|
add(footprint, rsp); // pop arguments
|
2007-09-28 14:45:26 +00:00
|
|
|
|
2007-10-03 00:22:48 +00:00
|
|
|
pushReturnValue(methodReturnCode(t, target));
|
2007-09-28 14:45:26 +00:00
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-08 21:41:41 +00:00
|
|
|
void compileCall(void* function) {
|
|
|
|
compileCall2(function, 1);
|
|
|
|
}
|
|
|
|
|
2007-10-03 00:22:48 +00:00
|
|
|
void compileCall(void* function, object arg1) {
|
2007-09-28 14:45:26 +00:00
|
|
|
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);
|
2007-09-28 14:45:26 +00:00
|
|
|
} else {
|
|
|
|
mov(arg1, rsi);
|
|
|
|
}
|
|
|
|
|
2007-10-04 00:41:54 +00:00
|
|
|
compileCall2(function, 2);
|
2007-09-28 14:45:26 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2007-10-04 00:41:54 +00:00
|
|
|
Compiled* compile(object method) {
|
2007-09-28 23:41:03 +00:00
|
|
|
PROTECT(t, method);
|
2007-09-24 01:39:03 +00:00
|
|
|
|
|
|
|
object code = methodCode(t, method);
|
2007-09-26 23:23:03 +00:00
|
|
|
PROTECT(t, code);
|
|
|
|
|
|
|
|
unsigned parameterFootprint
|
|
|
|
= methodParameterFootprint(t, method) * BytesPerWord;
|
|
|
|
|
|
|
|
unsigned localFootprint = codeMaxLocals(t, code) * BytesPerWord;
|
2007-09-24 01:39:03 +00:00
|
|
|
|
2007-09-28 23:41:03 +00:00
|
|
|
push(rbp);
|
|
|
|
mov(rsp, rbp);
|
|
|
|
|
2007-09-27 22:20:54 +00:00
|
|
|
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
|
|
|
}
|
2007-09-24 01:39:03 +00:00
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
for (unsigned ip = 0; ip < codeLength(t, code);) {
|
2007-09-28 23:41:03 +00:00
|
|
|
javaIPs.append2(ip);
|
|
|
|
machineIPs.append4(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) {
|
2007-10-03 00:22:48 +00:00
|
|
|
lineNumbers.append4(this->code.length());
|
2007-10-04 00:41:54 +00:00
|
|
|
lineNumbers.append4(lineNumberLine(ln));
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-26 23:23:03 +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);
|
|
|
|
|
|
|
|
pop(rcx);
|
|
|
|
pop(rax);
|
|
|
|
|
|
|
|
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);
|
2007-09-30 04:07:22 +00:00
|
|
|
push(rax, 0);
|
|
|
|
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);
|
|
|
|
push(rax);
|
|
|
|
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);
|
|
|
|
push(rax);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case daload:
|
|
|
|
case laload:
|
|
|
|
shl(3, rcx);
|
2007-09-30 15:52:21 +00:00
|
|
|
add(rcx, rax);
|
2007-09-30 04:07:22 +00:00
|
|
|
push4(rax, 0);
|
|
|
|
push4(rax, 4);
|
|
|
|
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);
|
|
|
|
push(rax);
|
|
|
|
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 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) {
|
|
|
|
pop(rdx);
|
|
|
|
}
|
|
|
|
pop(rbx);
|
|
|
|
pop(rcx);
|
|
|
|
pop(rax);
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2007-09-29 20:24:14 +00:00
|
|
|
case aconst_null:
|
|
|
|
push(0);
|
|
|
|
break;
|
|
|
|
|
2007-09-28 23:41:03 +00:00
|
|
|
case aload:
|
|
|
|
case iload:
|
|
|
|
case fload:
|
|
|
|
push(rbp, localOffset(codeBody(t, code, ip++), parameterFootprint));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case aload_0:
|
|
|
|
case iload_0:
|
|
|
|
case fload_0:
|
|
|
|
push(rbp, localOffset(0, parameterFootprint));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case aload_1:
|
|
|
|
case iload_1:
|
|
|
|
case fload_1:
|
|
|
|
push(rbp, localOffset(1, parameterFootprint));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case aload_2:
|
|
|
|
case iload_2:
|
|
|
|
case fload_2:
|
|
|
|
push(rbp, localOffset(2, parameterFootprint));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case aload_3:
|
|
|
|
case iload_3:
|
|
|
|
case fload_3:
|
|
|
|
push(rbp, localOffset(3, parameterFootprint));
|
|
|
|
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);
|
|
|
|
|
|
|
|
pop(rax);
|
|
|
|
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);
|
2007-09-30 02:48:27 +00:00
|
|
|
push(rax);
|
|
|
|
} break;
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
case areturn:
|
2007-09-29 21:08:29 +00:00
|
|
|
case ireturn:
|
|
|
|
case freturn:
|
2007-09-26 23:23:03 +00:00
|
|
|
pop(rax);
|
|
|
|
mov(rbp, rsp);
|
|
|
|
pop(rbp);
|
|
|
|
ret();
|
|
|
|
break;
|
|
|
|
|
2007-09-30 15:52:21 +00:00
|
|
|
case arraylength:
|
|
|
|
pop(rax);
|
|
|
|
push(rax, BytesPerWord);
|
|
|
|
break;
|
|
|
|
|
2007-09-28 23:41:03 +00:00
|
|
|
case astore:
|
|
|
|
case istore:
|
|
|
|
case fstore:
|
|
|
|
pop(rbp, localOffset(codeBody(t, code, ip++), parameterFootprint));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case astore_0:
|
|
|
|
case istore_0:
|
|
|
|
case fstore_0:
|
|
|
|
pop(rbp, localOffset(0, parameterFootprint));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case astore_1:
|
|
|
|
case istore_1:
|
|
|
|
case fstore_1:
|
|
|
|
pop(rbp, localOffset(1, parameterFootprint));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case astore_2:
|
|
|
|
case istore_2:
|
|
|
|
case fstore_2:
|
|
|
|
pop(rbp, localOffset(2, parameterFootprint));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case astore_3:
|
|
|
|
case istore_3:
|
|
|
|
case fstore_3:
|
|
|
|
pop(rbp, localOffset(3, parameterFootprint));
|
|
|
|
break;
|
|
|
|
|
2007-09-30 02:48:27 +00:00
|
|
|
case athrow:
|
|
|
|
pop(rax);
|
2007-10-04 00:41:54 +00:00
|
|
|
compileCall(reinterpret_cast<void*>(throw_), rax);
|
2007-09-30 02:48:27 +00:00
|
|
|
break;
|
|
|
|
|
2007-09-28 14:45:26 +00:00
|
|
|
case bipush: {
|
|
|
|
push(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;
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
case dup:
|
2007-09-30 02:48:27 +00:00
|
|
|
push(rsp, 0);
|
2007-09-26 23:23:03 +00:00
|
|
|
break;
|
|
|
|
|
2007-09-29 20:24:14 +00:00
|
|
|
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;
|
2007-09-29 20:24:14 +00:00
|
|
|
|
|
|
|
pop(rax);
|
|
|
|
|
|
|
|
switch (fieldCode(t, field)) {
|
|
|
|
case ByteField:
|
|
|
|
case BooleanField:
|
|
|
|
movs1(rax, fieldOffset(t, field), rax);
|
|
|
|
push(rax);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CharField:
|
|
|
|
movz2(rax, fieldOffset(t, field), rax);
|
|
|
|
push(rax);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ShortField:
|
|
|
|
movs2(rax, fieldOffset(t, field), rax);
|
|
|
|
push(rax);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FloatField:
|
|
|
|
case IntField:
|
|
|
|
push4(rax, fieldOffset(t, field));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DoubleField:
|
|
|
|
case LongField:
|
|
|
|
push4(rax, fieldOffset(t, field));
|
|
|
|
push4(rax, fieldOffset(t, field) + 4);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ObjectField:
|
|
|
|
push(rax, fieldOffset(t, field));
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
abort(t);
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
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;
|
2007-09-26 23:23:03 +00:00
|
|
|
PROTECT(t, field);
|
|
|
|
|
|
|
|
initClass(t, fieldClass(t, field));
|
2007-10-04 00:41:54 +00:00
|
|
|
if (UNLIKELY(t->exception)) return 0;
|
2007-09-26 23:23:03 +00:00
|
|
|
|
|
|
|
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);
|
2007-09-26 23:23:03 +00:00
|
|
|
|
|
|
|
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);
|
2007-09-26 23:23:03 +00:00
|
|
|
|
2007-09-28 14:45:26 +00:00
|
|
|
push4(rax, IntValue);
|
2007-09-26 23:23:03 +00:00
|
|
|
jmp(next);
|
|
|
|
|
|
|
|
zero.mark();
|
|
|
|
push(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);
|
2007-09-26 23:23:03 +00:00
|
|
|
|
2007-09-28 14:45:26 +00:00
|
|
|
push4(rax, LongValue);
|
|
|
|
push4(rax, LongValue + 4);
|
2007-09-26 23:23:03 +00:00
|
|
|
jmp(next);
|
|
|
|
|
|
|
|
zero.mark();
|
|
|
|
push(0);
|
|
|
|
push(0);
|
|
|
|
|
|
|
|
next.mark();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case ObjectField: {
|
2007-09-28 14:45:26 +00:00
|
|
|
push(rax, 0);
|
2007-09-26 23:23:03 +00:00
|
|
|
} 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);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case goto_w: {
|
|
|
|
int32_t offset = codeReadInt32(t, code, ip);
|
|
|
|
jmp((ip - 5) + offset);
|
|
|
|
} 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:
|
2007-10-08 21:41:41 +00:00
|
|
|
if (BytesPerWord == 8) {
|
|
|
|
sub(8, rsp);
|
|
|
|
} else {
|
|
|
|
pop(rax);
|
|
|
|
cdq();
|
|
|
|
pushLong(rax, rdx);
|
|
|
|
}
|
2007-10-04 22:41:19 +00:00
|
|
|
break;
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
case iadd:
|
2007-09-26 23:23:03 +00:00
|
|
|
pop(rax);
|
2007-09-27 22:20:54 +00:00
|
|
|
pop(rcx);
|
|
|
|
add(rax, rcx);
|
|
|
|
push(rcx);
|
2007-09-24 01:39:03 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case iconst_m1:
|
|
|
|
push(-1);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case iconst_0:
|
|
|
|
push(0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case iconst_1:
|
|
|
|
push(1);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case iconst_2:
|
|
|
|
push(2);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case iconst_3:
|
|
|
|
push(3);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case iconst_4:
|
|
|
|
push(4);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case iconst_5:
|
|
|
|
push(5);
|
|
|
|
break;
|
|
|
|
|
2007-09-29 20:24:14 +00:00
|
|
|
case if_acmpeq:
|
|
|
|
case if_icmpeq: {
|
|
|
|
int16_t offset = codeReadInt16(t, code, ip);
|
|
|
|
|
|
|
|
pop(rax);
|
|
|
|
pop(rcx);
|
|
|
|
cmp(rax, rcx);
|
2007-09-29 21:08:29 +00:00
|
|
|
je((ip - 3) + offset);
|
2007-09-29 20:24:14 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case if_acmpne:
|
|
|
|
case if_icmpne: {
|
|
|
|
int16_t offset = codeReadInt16(t, code, ip);
|
|
|
|
|
|
|
|
pop(rax);
|
|
|
|
pop(rcx);
|
|
|
|
cmp(rax, rcx);
|
2007-09-29 21:08:29 +00:00
|
|
|
jne((ip - 3) + offset);
|
2007-09-29 20:24:14 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case if_icmpgt: {
|
|
|
|
int16_t offset = codeReadInt16(t, code, ip);
|
|
|
|
|
|
|
|
pop(rax);
|
|
|
|
pop(rcx);
|
|
|
|
cmp(rax, rcx);
|
|
|
|
jg((ip - 3) + offset);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case if_icmpge: {
|
|
|
|
int16_t offset = codeReadInt16(t, code, ip);
|
|
|
|
|
|
|
|
pop(rax);
|
|
|
|
pop(rcx);
|
|
|
|
cmp(rax, rcx);
|
|
|
|
jge((ip - 3) + offset);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case if_icmplt: {
|
|
|
|
int16_t offset = codeReadInt16(t, code, ip);
|
|
|
|
|
|
|
|
pop(rax);
|
|
|
|
pop(rcx);
|
|
|
|
cmp(rax, rcx);
|
|
|
|
jl((ip - 3) + offset);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case if_icmple: {
|
|
|
|
int16_t offset = codeReadInt16(t, code, ip);
|
|
|
|
|
|
|
|
pop(rax);
|
|
|
|
pop(rcx);
|
|
|
|
cmp(rax, rcx);
|
|
|
|
jle((ip - 3) + offset);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case ifeq:
|
2007-09-28 23:41:03 +00:00
|
|
|
case ifnull: {
|
|
|
|
int16_t offset = codeReadInt16(t, code, ip);
|
|
|
|
|
|
|
|
pop(rax);
|
|
|
|
cmp(0, rax);
|
2007-09-29 21:08:29 +00:00
|
|
|
je((ip - 3) + offset);
|
2007-09-28 23:41:03 +00:00
|
|
|
} break;
|
2007-09-24 01:39:03 +00:00
|
|
|
|
2007-09-29 20:24:14 +00:00
|
|
|
case ifne:
|
|
|
|
case ifnonnull: {
|
|
|
|
int16_t offset = codeReadInt16(t, code, ip);
|
|
|
|
|
|
|
|
pop(rax);
|
|
|
|
cmp(0, rax);
|
2007-09-29 21:08:29 +00:00
|
|
|
jne((ip - 3) + offset);
|
2007-09-29 20:24:14 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case ifgt: {
|
|
|
|
int16_t offset = codeReadInt16(t, code, ip);
|
|
|
|
|
|
|
|
pop(rax);
|
|
|
|
cmp(0, rax);
|
|
|
|
jg((ip - 3) + offset);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case ifge: {
|
|
|
|
int16_t offset = codeReadInt16(t, code, ip);
|
|
|
|
|
|
|
|
pop(rax);
|
|
|
|
cmp(0, rax);
|
|
|
|
jge((ip - 3) + offset);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case iflt: {
|
|
|
|
int16_t offset = codeReadInt16(t, code, ip);
|
|
|
|
|
|
|
|
pop(rax);
|
|
|
|
cmp(0, rax);
|
|
|
|
jl((ip - 3) + offset);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case ifle: {
|
|
|
|
int16_t offset = codeReadInt16(t, code, ip);
|
|
|
|
|
|
|
|
pop(rax);
|
|
|
|
cmp(0, rax);
|
|
|
|
jle((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(index, parameterFootprint));
|
2007-09-29 20:24:14 +00:00
|
|
|
} break;
|
|
|
|
|
2007-10-08 21:41:41 +00:00
|
|
|
case vm::imul:
|
|
|
|
pop(rax);
|
|
|
|
pop(rcx);
|
|
|
|
Assembler::imul(rcx);
|
|
|
|
push(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);
|
|
|
|
|
|
|
|
pop(rax);
|
|
|
|
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);
|
|
|
|
|
|
|
|
push(1);
|
|
|
|
jmp(next);
|
|
|
|
|
|
|
|
call.mark();
|
2007-10-04 00:41:54 +00:00
|
|
|
compileCall(reinterpret_cast<void*>(isAssignableFrom), rcx, rax);
|
2007-09-29 21:08:29 +00:00
|
|
|
push(rax);
|
|
|
|
jmp(next);
|
|
|
|
|
|
|
|
zero.mark();
|
|
|
|
push(0);
|
|
|
|
|
|
|
|
next.mark();
|
|
|
|
} break;
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
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;
|
2007-09-26 23:23:03 +00:00
|
|
|
|
2007-09-29 20:24:14 +00:00
|
|
|
object class_ = methodClass(t, target);
|
2007-09-26 23:23:03 +00:00
|
|
|
if (isSpecialMethod(t, target, class_)) {
|
2007-09-28 14:45:26 +00:00
|
|
|
target = findMethod(t, target, classSuper(t, class_));
|
2007-09-26 23:23:03 +00:00
|
|
|
}
|
|
|
|
|
2007-10-04 00:41:54 +00:00
|
|
|
compileDirectInvoke(target);
|
2007-09-28 14:45:26 +00:00
|
|
|
} break;
|
2007-09-26 23:23:03 +00:00
|
|
|
|
2007-09-28 14:45:26 +00:00
|
|
|
case invokestatic: {
|
|
|
|
uint16_t index = codeReadInt16(t, code, ip);
|
2007-09-26 23:23:03 +00:00
|
|
|
|
2007-09-28 14:45:26 +00:00
|
|
|
object target = resolveMethod(t, codePool(t, code), index - 1);
|
2007-10-04 00:41:54 +00:00
|
|
|
if (UNLIKELY(t->exception)) return 0;
|
2007-09-28 14:45:26 +00:00
|
|
|
PROTECT(t, target);
|
2007-09-26 23:23:03 +00:00
|
|
|
|
2007-09-29 20:24:14 +00:00
|
|
|
initClass(t, methodClass(t, target));
|
2007-10-04 00:41:54 +00:00
|
|
|
if (UNLIKELY(t->exception)) return 0;
|
2007-09-26 23:23:03 +00:00
|
|
|
|
2007-10-04 00:41:54 +00:00
|
|
|
compileDirectInvoke(target);
|
2007-09-26 23:23:03 +00:00
|
|
|
} 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;
|
2007-09-26 23:23:03 +00:00
|
|
|
|
2007-09-27 22:20:54 +00:00
|
|
|
unsigned parameterFootprint
|
|
|
|
= methodParameterFootprint(t, target) * BytesPerWord;
|
|
|
|
|
|
|
|
unsigned instance = parameterFootprint - BytesPerWord;
|
|
|
|
|
|
|
|
unsigned footprint = FrameFootprint + parameterFootprint;
|
2007-09-26 23:23:03 +00:00
|
|
|
|
|
|
|
unsigned offset = ArrayBody + (methodOffset(t, target) * BytesPerWord);
|
2007-09-27 22:20:54 +00:00
|
|
|
|
|
|
|
mov(rsp, instance, rax); // load instance
|
|
|
|
mov(rax, 0, rax); // load class
|
2007-09-26 23:23:03 +00:00
|
|
|
mov(rax, ClassVirtualTable, rax); // load vtable
|
|
|
|
mov(rax, offset, rax); // load method
|
2007-09-27 22:20:54 +00:00
|
|
|
|
2007-10-02 00:08:17 +00:00
|
|
|
push(rsp);
|
2007-09-27 22:20:54 +00:00
|
|
|
push(rax);
|
|
|
|
push(rbp, FrameThread);
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
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;
|
2007-09-26 23:23:03 +00:00
|
|
|
|
|
|
|
add(footprint, rsp); // pop arguments
|
|
|
|
|
2007-10-04 00:41:54 +00:00
|
|
|
pushReturnValue(methodReturnCode(t, target));
|
2007-09-26 23:23:03 +00:00
|
|
|
} break;
|
|
|
|
|
2007-09-30 02:48:27 +00:00
|
|
|
case isub:
|
|
|
|
pop(rax);
|
2007-10-08 21:41:41 +00:00
|
|
|
sub(rax, rsp, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case l2i:
|
|
|
|
if (BytesPerWord == 8) {
|
|
|
|
add(BytesPerWord, rsp);
|
|
|
|
} else {
|
|
|
|
pop(rax);
|
|
|
|
mov(rax, rsp, 0);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ladd:
|
|
|
|
if (BytesPerWord == 8) {
|
|
|
|
add(8, rsp);
|
|
|
|
pop(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;
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
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);
|
2007-09-26 23:23:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
object v = arrayBody(t, codePool(t, code), index - 1);
|
|
|
|
|
|
|
|
if (objectClass(t, v) == arrayBody(t, t->m->types, Machine::IntType)) {
|
|
|
|
push(intValue(t, v));
|
|
|
|
} else if (objectClass(t, v)
|
|
|
|
== arrayBody(t, t->m->types, Machine::FloatType))
|
|
|
|
{
|
|
|
|
push(floatValue(t, v));
|
|
|
|
} else if (objectClass(t, v)
|
|
|
|
== arrayBody(t, t->m->types, Machine::StringType))
|
|
|
|
{
|
2007-10-03 00:22:48 +00:00
|
|
|
push(poolRegister(), poolReference(v));
|
2007-09-26 23:23:03 +00:00
|
|
|
} else {
|
|
|
|
object class_ = resolveClass(t, codePool(t, code), index - 1);
|
|
|
|
|
2007-10-03 00:22:48 +00:00
|
|
|
push(poolRegister(), poolReference(class_));
|
2007-09-26 23:23:03 +00:00
|
|
|
}
|
|
|
|
} 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))
|
|
|
|
{
|
2007-10-08 21:41:41 +00:00
|
|
|
pushLong(longValue(t, v));
|
2007-10-04 22:41:19 +00:00
|
|
|
} else if (objectClass(t, v)
|
|
|
|
== arrayBody(t, t->m->types, Machine::DoubleType))
|
|
|
|
{
|
2007-10-08 21:41:41 +00:00
|
|
|
pushLong(doubleValue(t, v));
|
2007-10-04 22:41:19 +00:00
|
|
|
} else {
|
|
|
|
abort(t);
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case lconst_0:
|
2007-10-08 21:41:41 +00:00
|
|
|
pushLong(0);
|
2007-10-04 22:41:19 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case lconst_1:
|
2007-10-08 21:41:41 +00:00
|
|
|
pushLong(1);
|
2007-10-04 22:41:19 +00:00
|
|
|
break;
|
|
|
|
|
2007-10-08 21:41:41 +00:00
|
|
|
case lcmp: {
|
|
|
|
Label next(this);
|
|
|
|
Label less(this);
|
|
|
|
Label greater(this);
|
2007-10-04 22:41:19 +00:00
|
|
|
|
2007-10-08 21:41:41 +00:00
|
|
|
if (BytesPerWord == 8) {
|
|
|
|
popLong(rax);
|
2007-10-08 23:13:55 +00:00
|
|
|
popLong(rcx);
|
2007-10-08 21:41:41 +00:00
|
|
|
|
2007-10-08 23:13:55 +00:00
|
|
|
cmp(rax, rcx);
|
2007-10-08 21:41:41 +00:00
|
|
|
jl(less);
|
|
|
|
jg(greater);
|
2007-10-04 22:41:19 +00:00
|
|
|
|
2007-10-08 21:41:41 +00:00
|
|
|
push(0);
|
|
|
|
jmp(next);
|
|
|
|
|
|
|
|
less.mark();
|
|
|
|
push(-1);
|
|
|
|
jmp(next);
|
2007-10-04 22:41:19 +00:00
|
|
|
|
2007-10-08 21:41:41 +00:00
|
|
|
greater.mark();
|
|
|
|
push(1);
|
2007-10-04 22:41:19 +00:00
|
|
|
|
2007-10-08 21:41:41 +00:00
|
|
|
next.mark();
|
|
|
|
} else {
|
|
|
|
popLong(rax, rdx);
|
2007-10-08 23:13:55 +00:00
|
|
|
popLong(rcx, rbx);
|
2007-10-04 22:41:19 +00:00
|
|
|
|
2007-10-08 21:41:41 +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-08 21:41:41 +00:00
|
|
|
push(0);
|
|
|
|
jmp(next);
|
2007-10-04 22:41:19 +00:00
|
|
|
|
2007-10-08 21:41:41 +00:00
|
|
|
less.mark();
|
|
|
|
push(-1);
|
|
|
|
jmp(next);
|
2007-10-04 22:41:19 +00:00
|
|
|
|
2007-10-08 21:41:41 +00:00
|
|
|
greater.mark();
|
|
|
|
push(1);
|
2007-10-04 22:41:19 +00:00
|
|
|
|
2007-10-08 21:41:41 +00:00
|
|
|
next.mark();
|
|
|
|
}
|
2007-10-04 22:41:19 +00:00
|
|
|
} break;
|
|
|
|
|
2007-10-08 21:41:41 +00:00
|
|
|
case ldiv_:
|
|
|
|
if (BytesPerWord == 8) {
|
|
|
|
popLong(rcx);
|
2007-10-08 23:13:55 +00:00
|
|
|
popLong(rax);
|
|
|
|
cqo();
|
2007-10-08 21:41:41 +00:00
|
|
|
Assembler::idiv(rcx);
|
|
|
|
pushLong(rax);
|
|
|
|
} else {
|
|
|
|
compileCall(reinterpret_cast<void*>(divideLong));
|
|
|
|
add(4, rsp);
|
|
|
|
mov(rax, rsp, 0);
|
|
|
|
mov(rdx, rsp, 4);
|
|
|
|
}
|
|
|
|
break;
|
2007-10-04 22:41:19 +00:00
|
|
|
|
2007-10-08 21:41:41 +00:00
|
|
|
case lload:
|
|
|
|
loadLong(codeBody(t, code, ip++), parameterFootprint);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case lload_0:
|
|
|
|
loadLong(0, parameterFootprint);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case lload_1:
|
|
|
|
loadLong(1, parameterFootprint);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case lload_2:
|
|
|
|
loadLong(2, parameterFootprint);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case lload_3:
|
|
|
|
loadLong(3, parameterFootprint);
|
|
|
|
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);
|
|
|
|
|
|
|
|
add(4, rsp);
|
|
|
|
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();
|
2007-10-08 21:41:41 +00:00
|
|
|
Assembler::idiv(rcx);
|
|
|
|
pushLong(rdx);
|
|
|
|
} else {
|
|
|
|
compileCall(reinterpret_cast<void*>(moduloLong));
|
|
|
|
add(4, rsp);
|
|
|
|
mov(rax, rsp, 0);
|
|
|
|
mov(rdx, rsp, 4);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case lstore:
|
|
|
|
storeLong(codeBody(t, code, ip++), parameterFootprint);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case lstore_0:
|
|
|
|
storeLong(0, parameterFootprint);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case lstore_1:
|
|
|
|
storeLong(1, parameterFootprint);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case lstore_2:
|
|
|
|
storeLong(2, parameterFootprint);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case lstore_3:
|
|
|
|
storeLong(3, parameterFootprint);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case lsub:
|
|
|
|
if (BytesPerWord == 8) {
|
|
|
|
add(8, rsp);
|
|
|
|
pop(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
|
|
|
|
2007-09-27 22:20:54 +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;
|
2007-09-27 22:20:54 +00:00
|
|
|
PROTECT(t, class_);
|
|
|
|
|
|
|
|
initClass(t, class_);
|
2007-10-04 00:41:54 +00:00
|
|
|
if (UNLIKELY(t->exception)) return 0;
|
2007-09-28 14:45:26 +00:00
|
|
|
|
2007-09-27 22:20:54 +00:00
|
|
|
if (classVmFlags(t, class_) & WeakReferenceFlag) {
|
2007-10-04 00:41:54 +00:00
|
|
|
compileCall(reinterpret_cast<void*>(makeNewWeakReference), class_);
|
2007-09-27 22:20:54 +00:00
|
|
|
} else {
|
2007-10-04 00:41:54 +00:00
|
|
|
compileCall(reinterpret_cast<void*>(makeNew), class_);
|
2007-09-27 22:20:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
push(rax);
|
|
|
|
} break;
|
|
|
|
|
2007-09-30 02:48:27 +00:00
|
|
|
case newarray: {
|
|
|
|
uint8_t type = codeBody(t, code, ip++);
|
|
|
|
|
|
|
|
Label nonnegative(this);
|
|
|
|
|
|
|
|
pop(rax);
|
|
|
|
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);
|
2007-09-30 02:48:27 +00:00
|
|
|
push(rax);
|
|
|
|
} break;
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
case pop_: {
|
|
|
|
add(BytesPerWord, rsp);
|
|
|
|
} break;
|
|
|
|
|
2007-09-29 20:24:14 +00:00
|
|
|
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;
|
2007-09-29 20:24:14 +00:00
|
|
|
|
|
|
|
switch (fieldCode(t, field)) {
|
|
|
|
case ByteField:
|
|
|
|
case BooleanField:
|
|
|
|
case CharField:
|
|
|
|
case ShortField:
|
|
|
|
case FloatField:
|
|
|
|
case IntField: {
|
|
|
|
pop(rcx);
|
|
|
|
pop(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: {
|
|
|
|
pop(rcx);
|
|
|
|
pop(rdx);
|
|
|
|
pop(rax);
|
|
|
|
mov4(rcx, rax, fieldOffset(t, field));
|
|
|
|
mov4(rdx, rax, fieldOffset(t, field) + 4);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case ObjectField: {
|
|
|
|
pop(rcx);
|
|
|
|
pop(rax);
|
|
|
|
mov(rcx, rax, fieldOffset(t, field));
|
|
|
|
} break;
|
|
|
|
|
|
|
|
default: abort(t);
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
2007-09-28 14:45:26 +00:00
|
|
|
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;
|
2007-09-28 14:45:26 +00:00
|
|
|
|
|
|
|
initClass(t, fieldClass(t, field));
|
2007-10-04 00:41:54 +00:00
|
|
|
if (UNLIKELY(t->exception)) return 0;
|
2007-09-28 14:45:26 +00:00
|
|
|
|
|
|
|
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);
|
2007-09-28 14:45:26 +00:00
|
|
|
|
|
|
|
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));
|
2007-09-28 14:45:26 +00:00
|
|
|
|
|
|
|
pop4(rax, IntValue);
|
|
|
|
} 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));
|
2007-09-28 14:45:26 +00:00
|
|
|
|
|
|
|
pop4(rax, LongValue);
|
|
|
|
pop4(rax, LongValue + 4);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case ObjectField:
|
|
|
|
pop(rax, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: abort(t);
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
case return_:
|
2007-09-26 23:23:03 +00:00
|
|
|
mov(rbp, rsp);
|
|
|
|
pop(rbp);
|
2007-09-24 01:39:03 +00:00
|
|
|
ret();
|
|
|
|
break;
|
|
|
|
|
2007-09-30 02:48:27 +00:00
|
|
|
case sipush: {
|
|
|
|
push(static_cast<int16_t>(codeReadInt16(t, code, ip)));
|
|
|
|
} break;
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
default:
|
|
|
|
abort(t);
|
|
|
|
}
|
|
|
|
}
|
2007-09-28 23:41:03 +00:00
|
|
|
|
|
|
|
resolveJumps();
|
2007-10-03 00:22:48 +00:00
|
|
|
buildExceptionHandlerTable(code);
|
|
|
|
|
2007-10-04 22:41:19 +00:00
|
|
|
return finish(method);
|
2007-10-03 00:22:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t machineIpForJavaIp(uint16_t javaIP) {
|
|
|
|
unsigned bottom = 0;
|
|
|
|
unsigned top = javaIPs.length() / 2;
|
|
|
|
for (unsigned span = top - bottom; span; span = top - bottom) {
|
|
|
|
unsigned middle = bottom + (span / 2);
|
|
|
|
uint32_t k = javaIPs.get2(middle * 2);
|
|
|
|
|
|
|
|
if (javaIP < k) {
|
|
|
|
top = middle;
|
|
|
|
} else if (javaIP > k) {
|
|
|
|
bottom = middle + 1;
|
|
|
|
} else {
|
|
|
|
return machineIPs.get4(middle * 4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
abort(code.s);
|
2007-09-28 23:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void resolveJumps() {
|
|
|
|
for (unsigned i = 0; i < jumps.length(); i += 8) {
|
|
|
|
uint32_t ip = jumps.get4(i);
|
|
|
|
uint32_t offset = jumps.get4(i + 4);
|
|
|
|
|
2007-10-03 00:22:48 +00:00
|
|
|
code.set4(offset, machineIpForJavaIp(ip) - (offset + 4));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
2007-10-04 00:41:54 +00:00
|
|
|
exceptionHandlers.append4
|
|
|
|
(machineIpForJavaIp(exceptionHandlerStart(eh)));
|
2007-10-03 00:22:48 +00:00
|
|
|
|
2007-10-04 00:41:54 +00:00
|
|
|
exceptionHandlers.append4
|
|
|
|
(machineIpForJavaIp(exceptionHandlerEnd(eh)));
|
|
|
|
|
|
|
|
exceptionHandlers.append4
|
|
|
|
(machineIpForJavaIp(exceptionHandlerIp(eh)));
|
|
|
|
|
|
|
|
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
|
|
|
|
2007-10-04 00:41:54 +00:00
|
|
|
exceptionHandlers.append4
|
|
|
|
(catchType ? (poolReference(catchType) / BytesPerWord) - 1 : 0);
|
|
|
|
}
|
2007-09-28 23:41:03 +00:00
|
|
|
}
|
2007-09-24 01:39:03 +00:00
|
|
|
}
|
2007-09-25 23:53:11 +00:00
|
|
|
|
2007-10-04 00:41:54 +00:00
|
|
|
unsigned threadFrameOffset() {
|
|
|
|
return reinterpret_cast<uintptr_t>(&(t->frame))
|
|
|
|
- reinterpret_cast<uintptr_t>(t);
|
|
|
|
}
|
|
|
|
|
2007-10-04 03:19:39 +00:00
|
|
|
Compiled* compileStub() {
|
2007-10-01 15:19:15 +00:00
|
|
|
push(rbp);
|
|
|
|
mov(rsp, rbp);
|
|
|
|
|
|
|
|
if (BytesPerWord == 4) {
|
|
|
|
push(rbp, FrameMethod);
|
|
|
|
push(rbp, FrameThread);
|
|
|
|
} else {
|
|
|
|
mov(rbp, FrameMethod, rsi);
|
|
|
|
mov(rbp, FrameThread, rdi);
|
|
|
|
}
|
|
|
|
|
2007-10-04 03:19:39 +00:00
|
|
|
mov(reinterpret_cast<uintptr_t>(compileMethod), rbx);
|
|
|
|
callAddress(compiledCode(caller(t)));
|
2007-10-01 15:19:15 +00:00
|
|
|
|
|
|
|
if (BytesPerWord == 4) {
|
|
|
|
add(BytesPerWord * 2, rsp);
|
|
|
|
}
|
|
|
|
|
2007-10-04 03:19:39 +00:00
|
|
|
mov(rbp, FrameMethod, rax);
|
|
|
|
mov(rax, MethodCompiled, rax); // load compiled code
|
|
|
|
|
2007-10-01 15:19:15 +00:00
|
|
|
mov(rbp, rsp);
|
|
|
|
pop(rbp);
|
2007-10-04 03:19:39 +00:00
|
|
|
|
|
|
|
add(CompiledBody, rax);
|
|
|
|
jmp(rax); // call compiled code
|
2007-10-03 00:22:48 +00:00
|
|
|
|
2007-10-04 22:41:19 +00:00
|
|
|
return finish(0);
|
2007-10-01 15:19:15 +00:00
|
|
|
}
|
|
|
|
|
2007-10-04 03:19:39 +00:00
|
|
|
Compiled* compileNativeInvoker() {
|
2007-09-26 23:23:03 +00:00
|
|
|
push(rbp);
|
|
|
|
mov(rsp, rbp);
|
|
|
|
|
|
|
|
if (BytesPerWord == 4) {
|
|
|
|
push(rbp, FrameMethod);
|
|
|
|
push(rbp, FrameThread);
|
|
|
|
} else {
|
|
|
|
mov(rbp, FrameMethod, rsi);
|
|
|
|
mov(rbp, FrameThread, rdi);
|
|
|
|
}
|
2007-09-25 23:53:11 +00:00
|
|
|
|
2007-10-04 03:19:39 +00:00
|
|
|
mov(reinterpret_cast<uintptr_t>(invokeNative), rbx);
|
|
|
|
callAddress(compiledCode(caller(t)));
|
2007-09-26 23:23:03 +00:00
|
|
|
|
|
|
|
if (BytesPerWord == 4) {
|
|
|
|
add(BytesPerWord * 2, rsp);
|
|
|
|
}
|
2007-09-25 23:53:11 +00:00
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
mov(rbp, rsp);
|
|
|
|
pop(rbp);
|
2007-10-04 03:19:39 +00:00
|
|
|
ret();
|
|
|
|
|
2007-10-04 22:41:19 +00:00
|
|
|
return finish(0);
|
2007-10-04 03:19:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Compiled* compileCaller() {
|
|
|
|
mov(rbp, FrameThread, rdi);
|
|
|
|
lea(rsp, FrameFootprint + BytesPerWord, rcx);
|
|
|
|
mov(rcx, rdi, threadFrameOffset()); // set thread frame to current
|
|
|
|
|
|
|
|
jmp(rbx);
|
2007-10-03 00:22:48 +00:00
|
|
|
|
2007-10-04 22:41:19 +00:00
|
|
|
return finish(0);
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
2007-09-28 23:41:03 +00:00
|
|
|
|
2007-10-04 22:41:19 +00:00
|
|
|
Compiled* finish(object method) {
|
|
|
|
return makeCompiled(t, method, &code, &lineNumbers, &exceptionHandlers);
|
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) {
|
|
|
|
mov(reinterpret_cast<uintptr_t>(function), rax);
|
|
|
|
call(rax);
|
|
|
|
poolRegisterClobbered = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void callAlignedAddress(void* function) {
|
|
|
|
alignedMov(reinterpret_cast<uintptr_t>(function), rax);
|
|
|
|
call(rax);
|
|
|
|
poolRegisterClobbered = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
MyThread* t;
|
|
|
|
bool poolRegisterClobbered;
|
2007-09-28 23:41:03 +00:00
|
|
|
Buffer javaIPs;
|
|
|
|
Buffer machineIPs;
|
2007-10-03 00:22:48 +00:00
|
|
|
Buffer lineNumbers;
|
|
|
|
Buffer exceptionHandlers;
|
|
|
|
Buffer pool;
|
2007-09-24 01:39:03 +00:00
|
|
|
};
|
|
|
|
|
2007-09-25 23:53:11 +00:00
|
|
|
void
|
2007-09-26 23:23:03 +00:00
|
|
|
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-09-29 20:24:14 +00:00
|
|
|
|
2007-10-03 00:22:48 +00:00
|
|
|
Compiler c(t);
|
2007-10-04 00:41:54 +00:00
|
|
|
Compiled* code = c.compile(method);
|
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-09-29 20:24:14 +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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-26 23:23:03 +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))));
|
2007-09-26 23:23:03 +00:00
|
|
|
|
|
|
|
Assembler a(t->m->system);
|
2007-09-28 23:41:03 +00:00
|
|
|
a.mov(stub, rax);
|
2007-09-26 23:23:03 +00:00
|
|
|
unsigned offset = a.code.length() - BytesPerWord;
|
|
|
|
|
2007-09-28 23:41:03 +00:00
|
|
|
a.call(rax);
|
2007-09-26 23:23:03 +00:00
|
|
|
|
2007-10-04 22:41:19 +00:00
|
|
|
uint8_t* caller = static_cast<uint8_t*>(frameAddress(t->frame))
|
|
|
|
- a.code.length();
|
2007-09-28 23:41:03 +00:00
|
|
|
if (memcmp(a.code.data, caller, a.code.length()) == 0) {
|
2007-09-26 23:23:03 +00:00
|
|
|
// 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)));
|
2007-09-26 23:23:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
compileMethod(MyThread* t, object method)
|
|
|
|
{
|
|
|
|
compileMethod2(t, method);
|
2007-09-27 22:20:54 +00:00
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
if (UNLIKELY(t->exception)) {
|
|
|
|
unwind(t);
|
2007-09-27 22:20:54 +00:00
|
|
|
} else if (not methodVirtual(t, method)) {
|
2007-09-26 23:23:03 +00:00
|
|
|
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);
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
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;
|
2007-09-30 03:33:38 +00:00
|
|
|
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));
|
2007-09-26 23:23:03 +00:00
|
|
|
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
|
|
|
|
2007-09-30 03:33:38 +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);
|
|
|
|
};
|
2007-09-24 01:39:03 +00:00
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2007-09-25 23:53:11 +00:00
|
|
|
class MyProcessor: public Processor {
|
2007-09-24 01:39:03 +00:00
|
|
|
public:
|
2007-09-25 23:53:11 +00:00
|
|
|
MyProcessor(System* s):
|
|
|
|
s(s),
|
2007-10-01 15:19:15 +00:00
|
|
|
methodStub_(0),
|
|
|
|
nativeInvoker_(0)
|
2007-09-24 01:39:03 +00:00
|
|
|
{ }
|
|
|
|
|
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)
|
|
|
|
{
|
2007-10-01 15:19:15 +00:00
|
|
|
if (methodStub_ == 0) {
|
2007-10-03 00:22:48 +00:00
|
|
|
Compiler c(static_cast<MyThread*>(t));
|
|
|
|
methodStub_ = c.compileStub();
|
2007-10-01 15:19:15 +00:00
|
|
|
}
|
|
|
|
return methodStub_;
|
|
|
|
}
|
|
|
|
|
2007-10-03 00:22:48 +00:00
|
|
|
virtual void*
|
2007-10-01 15:19:15 +00:00
|
|
|
nativeInvoker(Thread* t)
|
|
|
|
{
|
|
|
|
if (nativeInvoker_ == 0) {
|
2007-10-03 00:22:48 +00:00
|
|
|
Compiler c(static_cast<MyThread*>(t));
|
|
|
|
nativeInvoker_ = c.compileNativeInvoker();
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
2007-10-01 15:19:15 +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) {
|
|
|
|
Compiler c(static_cast<MyThread*>(t));
|
|
|
|
caller_ = c.compileCaller();
|
|
|
|
}
|
|
|
|
return caller_;
|
|
|
|
}
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
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;
|
2007-09-26 23:23:03 +00:00
|
|
|
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)
|
|
|
|
{
|
2007-09-28 23:41:03 +00:00
|
|
|
classVmFlags(t, c) |= InitFlag;
|
2007-09-26 23:23:03 +00:00
|
|
|
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*
|
2007-09-30 03:33:38 +00:00
|
|
|
makeLocalReference(Thread* vmt, object o)
|
2007-09-25 23:53:11 +00:00
|
|
|
{
|
2007-09-30 03:33:38 +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
|
2007-09-30 03:33:38 +00:00
|
|
|
disposeLocalReference(Thread* t, object* r)
|
2007-09-25 23:53:11 +00:00
|
|
|
{
|
2007-09-30 03:33:38 +00:00
|
|
|
if (r) {
|
|
|
|
vm::dispose(t, reinterpret_cast<Reference*>(r));
|
|
|
|
}
|
2007-09-25 23:53:11 +00:00
|
|
|
}
|
|
|
|
|
2007-09-24 01:39:03 +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));
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
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-24 01:39:03 +00:00
|
|
|
|
2007-09-25 23:53:11 +00:00
|
|
|
return ::invoke(t, method, &list);
|
2007-09-24 01:39:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
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-24 01:39:03 +00:00
|
|
|
|
2007-09-25 23:53:11 +00:00
|
|
|
return ::invoke(t, method, &list);
|
2007-09-24 01:39:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
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);
|
2007-09-24 01:39:03 +00:00
|
|
|
|
|
|
|
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);
|
2007-09-24 01:39:03 +00:00
|
|
|
} 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_);
|
|
|
|
}
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
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-09-24 01:39:03 +00:00
|
|
|
};
|
|
|
|
|
2007-10-04 03:19:39 +00:00
|
|
|
Compiled*
|
|
|
|
caller(MyThread* t)
|
|
|
|
{
|
|
|
|
return static_cast<MyProcessor*>(t->m->processor)->caller(t);
|
|
|
|
}
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace vm {
|
|
|
|
|
2007-09-25 23:53:11 +00:00
|
|
|
Processor*
|
|
|
|
makeProcessor(System* system)
|
2007-09-24 01:39:03 +00:00
|
|
|
{
|
2007-09-25 23:53:11 +00:00
|
|
|
return new (system->allocate(sizeof(MyProcessor))) MyProcessor(system);
|
2007-09-24 01:39:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace vm
|
2007-09-25 23:53:11 +00:00
|
|
|
|