mirror of
https://github.com/corda/corda.git
synced 2025-04-04 09:59:23 +00:00
clean up compile.cpp and support both x86_64 and i386; further refactoring to support JIT
This commit is contained in:
parent
749ae86d49
commit
2f3f97d550
@ -2,8 +2,9 @@ package java.lang.reflect;
|
||||
|
||||
public class Method<T> extends AccessibleObject implements Member {
|
||||
private byte vmFlags;
|
||||
private byte returnCode;
|
||||
private byte parameterCount;
|
||||
private short parameterFootprint;
|
||||
private byte parameterFootprint;
|
||||
private short flags;
|
||||
private short offset;
|
||||
private byte[] name;
|
||||
@ -45,9 +46,6 @@ public class Method<T> extends AccessibleObject implements Member {
|
||||
|
||||
public Class[] getParameterTypes() {
|
||||
int count = parameterCount;
|
||||
if ((flags & Modifier.STATIC) == 0) {
|
||||
-- count;
|
||||
}
|
||||
|
||||
Class[] types = new Class[count];
|
||||
int index = 0;
|
||||
@ -91,14 +89,8 @@ public class Method<T> extends AccessibleObject implements Member {
|
||||
public Object invoke(Object instance, Object ... arguments)
|
||||
throws InvocationTargetException, IllegalAccessException
|
||||
{
|
||||
if ((flags & Modifier.STATIC) != 0) {
|
||||
if ((flags & Modifier.STATIC) != 0 || class_.isInstance(instance)) {
|
||||
if (arguments.length == parameterCount) {
|
||||
return invoke(this, instance, arguments);
|
||||
} else {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
} else if (class_.isInstance(instance)) {
|
||||
if (arguments.length == parameterCount - 1) {
|
||||
return invoke(this, instance, arguments);
|
||||
} else {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
|
6
makefile
6
makefile
@ -111,11 +111,13 @@ interpreter-sources = \
|
||||
$(src)/jnienv.cpp \
|
||||
$(src)/main.cpp
|
||||
|
||||
interpreter-asm-sources = $(src)/vmInvoke.S
|
||||
|
||||
ifeq ($(arch),i386)
|
||||
interpreter-asm-sources = $(src)/cdecl.S
|
||||
interpreter-asm-sources += $(src)/cdecl.S
|
||||
endif
|
||||
ifeq ($(arch),x86_64)
|
||||
interpreter-asm-sources = $(src)/amd64.S
|
||||
interpreter-asm-sources += $(src)/amd64.S
|
||||
endif
|
||||
|
||||
interpreter-cpp-objects = \
|
||||
|
16
src/common.h
16
src/common.h
@ -45,22 +45,6 @@
|
||||
|
||||
inline void* operator new(size_t, void* p) throw() { return p; }
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
extern "C" uint64_t
|
||||
cdeclCall(void* function, void* stack, unsigned stackSize,
|
||||
unsigned returnType);
|
||||
|
||||
#elif defined __x86_64__
|
||||
|
||||
extern "C" uint64_t
|
||||
amd64Call(void* function, void* stack, unsigned stackSize,
|
||||
void* gprTable, void* sseTable, unsigned returnType);
|
||||
|
||||
#else
|
||||
# error unsupported platform
|
||||
#endif
|
||||
|
||||
namespace vm {
|
||||
|
||||
const unsigned BytesPerWord = sizeof(uintptr_t);
|
||||
|
674
src/compile.cpp
674
src/compile.cpp
@ -2,15 +2,21 @@
|
||||
#include "system.h"
|
||||
#include "constants.h"
|
||||
#include "machine.h"
|
||||
#include "processor.h"
|
||||
#include "process.h"
|
||||
|
||||
using namespace vm;
|
||||
|
||||
extern "C" uint64_t
|
||||
vmInvoke(void* function, void* stack, unsigned stackSize,
|
||||
unsigned returnType);
|
||||
|
||||
namespace {
|
||||
|
||||
const unsigned FrameThread = 8;
|
||||
const unsigned FrameMethod = 12;
|
||||
const unsigned FrameNext = 16;
|
||||
const unsigned FrameFootprint = 12;
|
||||
const unsigned FrameThread = BytesPerWord * 2;
|
||||
const unsigned FrameMethod = FrameThread + BytesPerWord;
|
||||
const unsigned FrameNext = FrameNext + BytesPerWord;
|
||||
const unsigned FrameFootprint = BytesPerWord * 3;
|
||||
|
||||
class Rope {
|
||||
public:
|
||||
@ -56,7 +62,7 @@ class Rope {
|
||||
rear->data[position++] = v;
|
||||
}
|
||||
|
||||
void append4(uint32_t v) {
|
||||
void appendAddress(uintptr_t v) {
|
||||
append((v >> 0) & 0xFF);
|
||||
append((v >> 8) & 0xFF);
|
||||
append((v >> 16) & 0xFF);
|
||||
@ -110,178 +116,241 @@ class Assembler {
|
||||
public:
|
||||
class Snapshot {
|
||||
public:
|
||||
Rope rope;
|
||||
Rope code;
|
||||
unsigned ip;
|
||||
};
|
||||
|
||||
static const unsigned Capacity = 8;
|
||||
|
||||
Label():
|
||||
Label(Assembler* a):
|
||||
code(&(a->code)),
|
||||
unresolvedCount(0),
|
||||
mark_(-1)
|
||||
{ }
|
||||
|
||||
void reference(Rope* r, unsigned ip) {
|
||||
void reference(unsigned ip) {
|
||||
if (mark_ == -1) {
|
||||
expect(r->s, unresolvedCount < Capacity);
|
||||
unresolved[unresolvedCount].rope = *r;
|
||||
expect(code->s, unresolvedCount < Capacity);
|
||||
unresolved[unresolvedCount].code = *code;
|
||||
unresolved[unresolvedCount].ip = ip;
|
||||
++ unresolvedCount;
|
||||
|
||||
r->append4(0);
|
||||
code->appendAddress(0);
|
||||
} else {
|
||||
r->append4(mark_ - ip);
|
||||
code->appendAddress(mark_ - ip);
|
||||
}
|
||||
}
|
||||
|
||||
void mark(Rope* r) {
|
||||
mark_ = r->length();
|
||||
void mark() {
|
||||
mark_ = code->length();
|
||||
for (unsigned i = 0; i < unresolvedCount; ++i) {
|
||||
unresolved[i].rope.append4(mark_ - unresolved[i].ip);
|
||||
unresolved[i].code.appendAddress(mark_ - unresolved[i].ip);
|
||||
}
|
||||
}
|
||||
|
||||
Rope* code;
|
||||
Snapshot unresolved[Capacity];
|
||||
unsigned unresolvedCount;
|
||||
int mark_;
|
||||
};
|
||||
|
||||
enum Register {
|
||||
eax = 0,
|
||||
ecx = 1,
|
||||
edx = 2,
|
||||
ebx = 3,
|
||||
esp = 4,
|
||||
ebp = 5
|
||||
rax = 0,
|
||||
rcx = 1,
|
||||
rdx = 2,
|
||||
rbx = 3,
|
||||
rsp = 4,
|
||||
rbp = 5,
|
||||
rsi = 6,
|
||||
rdi = 7
|
||||
};
|
||||
|
||||
Assembler(System* s):
|
||||
r(s)
|
||||
code(s)
|
||||
{ }
|
||||
|
||||
void rex() {
|
||||
if (BytesPerWord == 8) {
|
||||
code.append(0x48);
|
||||
}
|
||||
}
|
||||
|
||||
void mov(Register src, Register dst) {
|
||||
r.append(0x89);
|
||||
r.append(0xc0 | (src << 3) | dst);
|
||||
rex();
|
||||
code.append(0x89);
|
||||
code.append(0xc0 | (src << 3) | dst);
|
||||
}
|
||||
|
||||
void mov(Register src, int srcOffset, Register dst) {
|
||||
r.append(0x8b);
|
||||
rex();
|
||||
code.append(0x8b);
|
||||
if (srcOffset) {
|
||||
r.append(0x40 | (dst << 3) | src);
|
||||
r.append(srcOffset);
|
||||
assert(code.s, (srcOffset & 0xFFFFFF00) == 0); // todo
|
||||
|
||||
code.append(0x40 | (dst << 3) | src);
|
||||
code.append(srcOffset);
|
||||
} else {
|
||||
r.append((dst << 3) | src);
|
||||
code.append((dst << 3) | src);
|
||||
}
|
||||
}
|
||||
|
||||
void mov(Register src, Register dst, int dstOffset) {
|
||||
r.append(0x89);
|
||||
rex();
|
||||
code.append(0x89);
|
||||
if (dstOffset) {
|
||||
r.append(0x40 | (src << 3) | dst);
|
||||
r.append(dstOffset);
|
||||
assert(code.s, (dstOffset & 0xFFFFFF00) == 0); // todo
|
||||
|
||||
code.append(0x40 | (src << 3) | dst);
|
||||
code.append(dstOffset);
|
||||
} else {
|
||||
r.append((src << 3) | dst);
|
||||
code.append((src << 3) | dst);
|
||||
}
|
||||
}
|
||||
|
||||
void mov(uintptr_t src, Register dst) {
|
||||
r.append(0xb8 | dst);
|
||||
r.append4(src);
|
||||
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);
|
||||
}
|
||||
|
||||
void nop() {
|
||||
code.append(0x90);
|
||||
}
|
||||
|
||||
void push(Register reg) {
|
||||
r.append(0x50 | reg);
|
||||
code.append(0x50 | reg);
|
||||
}
|
||||
|
||||
void push(Register reg, int offset) {
|
||||
r.append(0xff);
|
||||
r.append(0x70 | reg);
|
||||
r.append(offset);
|
||||
assert(code.s, (offset & 0xFFFFFF00) == 0); // todo
|
||||
|
||||
code.append(0xff);
|
||||
code.append(0x70 | reg);
|
||||
code.append(offset);
|
||||
}
|
||||
|
||||
void push(int v) {
|
||||
r.append(0x6a);
|
||||
r.append(v);
|
||||
assert(code.s, (v & 0xFFFFFF00) == 0); // todo
|
||||
|
||||
code.append(0x6a);
|
||||
code.append(v);
|
||||
}
|
||||
|
||||
void pop(Register dst) {
|
||||
r.append(0x58 | dst);
|
||||
code.append(0x58 | dst);
|
||||
}
|
||||
|
||||
void pop(Register dst, int offset) {
|
||||
r.append(0x8f);
|
||||
r.append(0x40 | dst);
|
||||
r.append(offset);
|
||||
assert(code.s, (offset & 0xFFFFFF00) == 0); // todo
|
||||
|
||||
code.append(0x8f);
|
||||
code.append(0x40 | dst);
|
||||
code.append(offset);
|
||||
}
|
||||
|
||||
void add(Register src, Register dst) {
|
||||
r.append(0x01);
|
||||
r.append(0xc0 | (src << 3) | dst);
|
||||
rex();
|
||||
code.append(0x01);
|
||||
code.append(0xc0 | (src << 3) | dst);
|
||||
}
|
||||
|
||||
void add(int src, Register dst) {
|
||||
r.append(0x83);
|
||||
r.append(0xc0 | dst);
|
||||
r.append(src);
|
||||
void add(int v, Register dst) {
|
||||
assert(code.s, (v & 0xFFFFFF00) == 0); // todo
|
||||
|
||||
rex();
|
||||
code.append(0x83);
|
||||
code.append(0xc0 | dst);
|
||||
code.append(v);
|
||||
}
|
||||
|
||||
void sub(Register src, Register dst) {
|
||||
r.append(0x29);
|
||||
r.append(0xc0 | (src << 3) | dst);
|
||||
rex();
|
||||
code.append(0x29);
|
||||
code.append(0xc0 | (src << 3) | dst);
|
||||
}
|
||||
|
||||
void sub(int src, Register dst) {
|
||||
r.append(0x83);
|
||||
r.append(0xe8 | dst);
|
||||
r.append(src);
|
||||
void sub(int v, Register dst) {
|
||||
assert(code.s, (v & 0xFFFFFF00) == 0); // todo
|
||||
|
||||
rex();
|
||||
code.append(0x83);
|
||||
code.append(0xe8 | dst);
|
||||
code.append(v);
|
||||
}
|
||||
|
||||
void or_(Register src, Register dst) {
|
||||
r.append(0x09);
|
||||
r.append(0xc0 | (src << 3) | dst);
|
||||
rex();
|
||||
code.append(0x09);
|
||||
code.append(0xc0 | (src << 3) | dst);
|
||||
}
|
||||
|
||||
void or_(int src, Register dst) {
|
||||
r.append(0x83);
|
||||
r.append(0xc8 | dst);
|
||||
r.append(src);
|
||||
void or_(int v, Register dst) {
|
||||
assert(code.s, (v & 0xFFFFFF00) == 0); // todo
|
||||
|
||||
rex();
|
||||
code.append(0x83);
|
||||
code.append(0xc8 | dst);
|
||||
code.append(v);
|
||||
}
|
||||
|
||||
void and_(Register src, Register dst) {
|
||||
r.append(0x21);
|
||||
r.append(0xc0 | (src << 3) | dst);
|
||||
rex();
|
||||
code.append(0x21);
|
||||
code.append(0xc0 | (src << 3) | dst);
|
||||
}
|
||||
|
||||
void and_(int src, Register dst) {
|
||||
r.append(0x83);
|
||||
r.append(0xe0 | dst);
|
||||
r.append(src);
|
||||
void and_(int v, Register dst) {
|
||||
assert(code.s, (v & 0xFFFFFF00) == 0); // todo
|
||||
|
||||
rex();
|
||||
code.append(0x83);
|
||||
code.append(0xe0 | dst);
|
||||
code.append(v);
|
||||
}
|
||||
|
||||
void ret() {
|
||||
r.append(0xc3);
|
||||
code.append(0xc3);
|
||||
}
|
||||
|
||||
void jmp(Label& label) {
|
||||
r.append(0xE9);
|
||||
label.reference(&r, r.length() + 4);
|
||||
code.append(0xE9);
|
||||
label.reference(code.length() + BytesPerWord);
|
||||
}
|
||||
|
||||
void jmp(Register reg) {
|
||||
r.append(0xff);
|
||||
r.append(0xe0 | reg);
|
||||
code.append(0xff);
|
||||
code.append(0xe0 | reg);
|
||||
}
|
||||
|
||||
void jmp(Register reg, int offset) {
|
||||
r.append(0xff);
|
||||
r.append(0x60 | reg);
|
||||
r.append(offset);
|
||||
// void jmp(Register reg, int offset) {
|
||||
// code.append(0xff);
|
||||
// code.append(0x60 | reg);
|
||||
// code.append(offset);
|
||||
// }
|
||||
|
||||
void jz(Label& label) {
|
||||
code.append(0x0F);
|
||||
code.append(0x84);
|
||||
label.reference(code.length() + BytesPerWord);
|
||||
}
|
||||
|
||||
void je(Label& label) {
|
||||
jz(label);
|
||||
}
|
||||
|
||||
void jnz(Label& label) {
|
||||
r.append(0x0F);
|
||||
r.append(0x85);
|
||||
label.reference(&r, r.length() + 4);
|
||||
code.append(0x0F);
|
||||
code.append(0x85);
|
||||
label.reference(code.length() + BytesPerWord);
|
||||
}
|
||||
|
||||
void jne(Label& label) {
|
||||
@ -289,30 +358,30 @@ class Assembler {
|
||||
}
|
||||
|
||||
void cmp(int v, Register reg) {
|
||||
r.append(0x83);
|
||||
r.append(0xf8 | reg);
|
||||
r.append(v);
|
||||
code.append(0x83);
|
||||
code.append(0xf8 | reg);
|
||||
code.append(v);
|
||||
}
|
||||
|
||||
void call(Register reg) {
|
||||
r.append(0xff);
|
||||
r.append(0xd0 | reg);
|
||||
code.append(0xff);
|
||||
code.append(0xd0 | reg);
|
||||
}
|
||||
|
||||
Rope r;
|
||||
Rope code;
|
||||
};
|
||||
|
||||
void
|
||||
compileMethod(Thread* t, object method);
|
||||
compileMethod(MyThread* t, object method);
|
||||
|
||||
int
|
||||
localOffset(int v, int parameterFootprint)
|
||||
{
|
||||
v *= 4;
|
||||
v *= BytesPerWord;
|
||||
if (v < parameterFootprint) {
|
||||
return v + 8 + FrameFootprint;
|
||||
return v + (BytesPerWord * 2) + FrameFootprint;
|
||||
} else {
|
||||
return -(v + 4 - parameterFootprint);
|
||||
return -(v + BytesPerWord - parameterFootprint);
|
||||
}
|
||||
}
|
||||
|
||||
@ -322,23 +391,133 @@ class Compiler: public Assembler {
|
||||
Assembler(s)
|
||||
{ }
|
||||
|
||||
void pushReturnValue(Thread* t, unsigned code) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void compile(Thread* t, object method) {
|
||||
push(ebp);
|
||||
mov(esp, ebp);
|
||||
PROTECT(t, method);
|
||||
|
||||
push(rbp);
|
||||
mov(rsp, rbp);
|
||||
|
||||
object code = methodCode(t, method);
|
||||
unsigned parameterFootprint = methodParameterFootprint(t, method) * 4;
|
||||
PROTECT(t, code);
|
||||
|
||||
unsigned parameterFootprint
|
||||
= methodParameterFootprint(t, method) * BytesPerWord;
|
||||
|
||||
unsigned localFootprint = codeMaxLocals(t, code) * BytesPerWord;
|
||||
|
||||
// reserve space for local variables
|
||||
sub((codeMaxLocals(t, code) * 4) - parameterFootprint, esp);
|
||||
sub(localFootprint - parameterFootprint, rsp);
|
||||
|
||||
for (unsigned i = 0; i < codeLength(t, code);) {
|
||||
switch (codeBody(t, code, i++)) {
|
||||
for (unsigned ip = 0; ip < codeLength(t, code);) {
|
||||
unsigned instruction = codeBody(t, code, ip++);
|
||||
|
||||
switch (instruction) {
|
||||
case areturn:
|
||||
pop(rax);
|
||||
mov(rbp, rsp);
|
||||
pop(rbp);
|
||||
ret();
|
||||
break;
|
||||
|
||||
case dup:
|
||||
push(rsp, 4);
|
||||
break;
|
||||
|
||||
case getstatic: {
|
||||
uint16_t index = codeReadInt16(t, code, ip);
|
||||
|
||||
object field = resolveField(t, codePool(t, code), index - 1);
|
||||
if (UNLIKELY(t->exception)) return;
|
||||
PROTECT(t, field);
|
||||
|
||||
initClass(t, fieldClass(t, field));
|
||||
if (UNLIKELY(t->exception)) return;
|
||||
|
||||
object table = classStaticTable(t, fieldClass(t, field));
|
||||
|
||||
mov(reinterpret_cast<uintptr_t>(table), rax);
|
||||
add(fieldOffset(t, field), rax);
|
||||
|
||||
switch (fieldCode(t, field)) {
|
||||
case ByteField:
|
||||
case BooleanField:
|
||||
case CharField:
|
||||
case ShortField:
|
||||
case FloatField:
|
||||
case IntField: {
|
||||
Label zero(this);
|
||||
Label next(this);
|
||||
|
||||
cmp(0, rax);
|
||||
je(zero);
|
||||
|
||||
push(rax, IntValue);
|
||||
jmp(next);
|
||||
|
||||
zero.mark();
|
||||
push(0);
|
||||
|
||||
next.mark();
|
||||
} break;
|
||||
|
||||
case DoubleField:
|
||||
case LongField: {
|
||||
Label zero(this);
|
||||
Label next(this);
|
||||
|
||||
cmp(0, rax);
|
||||
je(zero);
|
||||
|
||||
push(rax, LongValue);
|
||||
push(rax, LongValue + 4);
|
||||
jmp(next);
|
||||
|
||||
zero.mark();
|
||||
push(0);
|
||||
push(0);
|
||||
|
||||
next.mark();
|
||||
} break;
|
||||
|
||||
case ObjectField: {
|
||||
push(rax);
|
||||
} break;
|
||||
|
||||
default: abort(t);
|
||||
}
|
||||
} break;
|
||||
|
||||
case iadd:
|
||||
pop(eax);
|
||||
pop(edx);
|
||||
add(eax, edx);
|
||||
push(edx);
|
||||
pop(rax);
|
||||
pop(rdx);
|
||||
add(rax, rdx);
|
||||
push(rdx);
|
||||
break;
|
||||
|
||||
case iconst_m1:
|
||||
@ -371,47 +550,139 @@ class Compiler: public Assembler {
|
||||
|
||||
case iload_0:
|
||||
case fload_0:
|
||||
push(ebp, localOffset(0, parameterFootprint));
|
||||
push(rbp, localOffset(0, parameterFootprint));
|
||||
break;
|
||||
|
||||
case iload_1:
|
||||
case fload_1:
|
||||
push(ebp, localOffset(1, parameterFootprint));
|
||||
push(rbp, localOffset(1, parameterFootprint));
|
||||
break;
|
||||
|
||||
case iload_2:
|
||||
case fload_2:
|
||||
push(ebp, localOffset(2, parameterFootprint));
|
||||
push(rbp, localOffset(2, parameterFootprint));
|
||||
break;
|
||||
|
||||
case iload_3:
|
||||
case fload_3:
|
||||
push(ebp, localOffset(3, parameterFootprint));
|
||||
push(rbp, localOffset(3, parameterFootprint));
|
||||
break;
|
||||
|
||||
case invokespecial: {
|
||||
uint16_t index = codeReadInt16(t, code, ip);
|
||||
|
||||
object target = resolveMethod(t, codePool(t, code), index - 1);
|
||||
if (UNLIKELY(t->exception)) return;
|
||||
|
||||
object class_ = methodClass(t, method);
|
||||
if (isSpecialMethod(t, target, class_)) {
|
||||
class_ = classSuper(t, class_);
|
||||
target = findMethod(t, target, class_);
|
||||
}
|
||||
|
||||
unsigned footprint = FrameFootprint
|
||||
+ methodParameterFootprint(t, target) * BytesPerWord;
|
||||
|
||||
uint8_t* code = &compiledBody(t, methodCompiled(t, target), 0);
|
||||
|
||||
push(rbp, 0);
|
||||
push(reinterpret_cast<uintptr_t>(target));
|
||||
push(rbp, FrameThread);
|
||||
|
||||
alignedMov(reinterpret_cast<uintptr_t>(code), rax);
|
||||
call(rax);
|
||||
|
||||
add(footprint, rsp); // pop arguments
|
||||
|
||||
pushReturnValue(t, methodReturnCode(t, method));
|
||||
} break;
|
||||
|
||||
case invokevirtual: {
|
||||
uint16_t index = codeReadInt16(t, code, ip);
|
||||
|
||||
object target = resolveMethod(t, codePool(t, code), index - 1);
|
||||
if (UNLIKELY(t->exception)) return;
|
||||
|
||||
unsigned footprint = FrameFootprint
|
||||
+ methodParameterFootprint(t, target) * BytesPerWord;
|
||||
|
||||
unsigned offset = ArrayBody + (methodOffset(t, target) * BytesPerWord);
|
||||
|
||||
push(rbp, 0);
|
||||
push(reinterpret_cast<uintptr_t>(target));
|
||||
push(rbp, FrameThread);
|
||||
|
||||
mov(rsp, BytesPerWord * 3, rax); // load target object
|
||||
mov(rax, 0, rax); // load target class
|
||||
mov(rax, ClassVirtualTable, rax); // load vtable
|
||||
mov(rax, offset, rax); // load method
|
||||
mov(rax, MethodCompiled, rax); // load compiled code
|
||||
add(CompiledBody, rax);
|
||||
call(rax); // call compiled code
|
||||
|
||||
add(footprint, rsp); // pop arguments
|
||||
|
||||
pushReturnValue(t, methodReturnCode(t, method));
|
||||
} break;
|
||||
|
||||
case istore_0:
|
||||
case fstore_0:
|
||||
pop(ebp, localOffset(0, parameterFootprint));
|
||||
pop(rbp, localOffset(0, parameterFootprint));
|
||||
break;
|
||||
|
||||
case istore_1:
|
||||
case fstore_1:
|
||||
pop(ebp, localOffset(1, parameterFootprint));
|
||||
pop(rbp, localOffset(1, parameterFootprint));
|
||||
break;
|
||||
|
||||
case istore_2:
|
||||
case fstore_2:
|
||||
pop(ebp, localOffset(2, parameterFootprint));
|
||||
pop(rbp, localOffset(2, parameterFootprint));
|
||||
break;
|
||||
|
||||
case istore_3:
|
||||
case fstore_3:
|
||||
pop(ebp, localOffset(3, parameterFootprint));
|
||||
pop(rbp, localOffset(3, parameterFootprint));
|
||||
break;
|
||||
|
||||
case ldc:
|
||||
case ldc_w: {
|
||||
uint16_t index;
|
||||
|
||||
if (instruction == ldc) {
|
||||
index = codeBody(t, code, ip++);
|
||||
} else {
|
||||
uint8_t index1 = codeBody(t, code, ip++);
|
||||
uint8_t index2 = codeBody(t, code, ip++);
|
||||
index = (index1 << 8) | index2;
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
push(reinterpret_cast<uintptr_t>(v));
|
||||
} else {
|
||||
object class_ = resolveClass(t, codePool(t, code), index - 1);
|
||||
|
||||
push(reinterpret_cast<uintptr_t>(class_));
|
||||
}
|
||||
} break;
|
||||
|
||||
case pop_: {
|
||||
add(BytesPerWord, rsp);
|
||||
} break;
|
||||
|
||||
case return_:
|
||||
mov(ebp, esp);
|
||||
pop(ebp);
|
||||
mov(rbp, rsp);
|
||||
pop(rbp);
|
||||
ret();
|
||||
break;
|
||||
|
||||
@ -425,31 +696,40 @@ class Compiler: public Assembler {
|
||||
unsigned frameOffset = reinterpret_cast<uintptr_t>(&(t->frame))
|
||||
- reinterpret_cast<uintptr_t>(t);
|
||||
|
||||
push(ebp);
|
||||
mov(esp, ebp);
|
||||
push(rbp);
|
||||
mov(rsp, rbp);
|
||||
|
||||
mov(ebp, FrameThread, eax);
|
||||
mov(ebp, eax, frameOffset); // set thread frame to current
|
||||
mov(rbp, FrameThread, rax);
|
||||
mov(rbp, rax, frameOffset); // set thread frame to current
|
||||
|
||||
push(ebp, FrameMethod);
|
||||
push(ebp, FrameThread);
|
||||
mov(reinterpret_cast<uintptr_t>(compileMethod), eax);
|
||||
call(eax);
|
||||
add(8, esp);
|
||||
if (BytesPerWord == 4) {
|
||||
push(rbp, FrameMethod);
|
||||
push(rbp, FrameThread);
|
||||
} else {
|
||||
mov(rbp, FrameMethod, rsi);
|
||||
mov(rbp, FrameThread, rdi);
|
||||
}
|
||||
|
||||
mov(ebp, FrameMethod, eax);
|
||||
mov(eax, MethodCompiled, eax); // load compiled code
|
||||
mov(reinterpret_cast<uintptr_t>(compileMethod), rax);
|
||||
call(rax);
|
||||
|
||||
mov(ebp, esp);
|
||||
pop(ebp);
|
||||
if (BytesPerWord == 4) {
|
||||
add(BytesPerWord * 2, rsp);
|
||||
}
|
||||
|
||||
mov(rbp, FrameMethod, rax);
|
||||
mov(rax, MethodCompiled, rax); // load compiled code
|
||||
|
||||
mov(rbp, rsp);
|
||||
pop(rbp);
|
||||
|
||||
add(CompiledBody, eax);
|
||||
jmp(eax); // call compiled code
|
||||
add(CompiledBody, rax);
|
||||
jmp(rax); // call compiled code
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
compileMethod(Thread* t, object method)
|
||||
compileMethod2(MyThread* t, object method)
|
||||
{
|
||||
if (methodCompiled(t, method) == t->m->processor->methodStub(t)) {
|
||||
PROTECT(t, method);
|
||||
@ -460,22 +740,74 @@ compileMethod(Thread* t, object method)
|
||||
Compiler c(t->m->system);
|
||||
c.compile(t, method);
|
||||
|
||||
object compiled = makeCompiled(t, 0, c.r.length(), false);
|
||||
c.r.copyTo(&compiledBody(t, compiled, 0));
|
||||
object compiled = makeCompiled(t, 0, c.code.length(), false);
|
||||
if (UNLIKELY(t->exception)) return;
|
||||
|
||||
c.code.copyTo(&compiledBody(t, compiled, 0));
|
||||
|
||||
set(t, methodCompiled(t, method), compiled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
updateCaller(MyThread* t, object method)
|
||||
{
|
||||
uintptr_t stub = reinterpret_cast<uintptr_t>
|
||||
(&compiledBody(t, t->m->processor->methodStub(t), 0));
|
||||
|
||||
Assembler a(t->m->system);
|
||||
a.mov(stub, Assembler::rax);
|
||||
unsigned offset = a.code.length() - BytesPerWord;
|
||||
|
||||
a.call(Assembler::rax);
|
||||
|
||||
uint8_t* caller = static_cast<uint8_t**>(t->frame)[1] - a.code.length();
|
||||
if (memcmp(a.code.front->data, caller, a.code.length()) == 0) {
|
||||
// it's a direct call - update caller to point to new code
|
||||
|
||||
// address must be aligned on a word boundary for this write to
|
||||
// be atomic
|
||||
assert(t, reinterpret_cast<uintptr_t>(caller + offset)
|
||||
% BytesPerWord == 0);
|
||||
|
||||
*reinterpret_cast<void**>(caller + offset)
|
||||
= &compiledBody(t, methodCompiled(t, method), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
unwind(Thread* t)
|
||||
{
|
||||
// todo
|
||||
abort(t);
|
||||
}
|
||||
|
||||
void
|
||||
compileMethod(MyThread* t, object method)
|
||||
{
|
||||
if (methodVirtual(t, method)) {
|
||||
object this_ = static_cast<object*>
|
||||
(t->frame)[2 + (FrameFootprint / BytesPerWord)];
|
||||
method = findMethod(t, method, objectClass(t, this_));
|
||||
}
|
||||
|
||||
compileMethod2(t, method);
|
||||
if (UNLIKELY(t->exception)) {
|
||||
unwind(t);
|
||||
} else {
|
||||
updateCaller(t, method);
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
compileStub(Thread* t)
|
||||
{
|
||||
Compiler c(t->m->system);
|
||||
c.compileStub(static_cast<MyThread*>(t));
|
||||
|
||||
object stub = makeCompiled(t, 0, c.r.length(), false);
|
||||
c.r.copyTo(&compiledBody(t, stub, 0));
|
||||
object stub = makeCompiled(t, 0, c.code.length(), false);
|
||||
c.code.copyTo(&compiledBody(t, stub, 0));
|
||||
|
||||
return stub;
|
||||
}
|
||||
@ -647,15 +979,12 @@ invoke(Thread* thread, object method, ArgumentList* arguments)
|
||||
|
||||
arguments->array[1] = reinterpret_cast<uintptr_t>(method);
|
||||
|
||||
const char* s = reinterpret_cast<const char*>
|
||||
(&byteArrayBody(t, methodSpec(t, method), 0));
|
||||
while (*s and *s != ')') ++s;
|
||||
unsigned returnCode = fieldCode(t, s[1]);
|
||||
unsigned returnCode = methodReturnCode(t, method);
|
||||
unsigned returnType = fieldType(t, returnCode);
|
||||
|
||||
uint64_t result = cdeclCall
|
||||
uint64_t result = vmInvoke
|
||||
(&compiledBody(t, methodCompiled(t, method), 0), arguments->array,
|
||||
arguments->position * 4, returnType);
|
||||
arguments->position * BytesPerWord, returnType);
|
||||
|
||||
object r;
|
||||
switch (returnCode) {
|
||||
@ -711,6 +1040,71 @@ class MyProcessor: public Processor {
|
||||
return stub;
|
||||
}
|
||||
|
||||
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;
|
||||
if (BytesPerWord == 4) {
|
||||
++ footprint;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
break;
|
||||
}
|
||||
|
||||
++ footprint;
|
||||
}
|
||||
|
||||
if (not static_) {
|
||||
++ footprint;
|
||||
}
|
||||
return footprint;
|
||||
}
|
||||
|
||||
virtual void
|
||||
initClass(Thread* t, object c)
|
||||
{
|
||||
PROTECT(t, c);
|
||||
|
||||
ACQUIRE(t, t->m->classLock);
|
||||
if (classVmFlags(t, c) & NeedInitFlag
|
||||
and (classVmFlags(t, c) & InitFlag) == 0)
|
||||
{
|
||||
invoke(t, classInitializer(t, c), 0);
|
||||
if (t->exception) {
|
||||
t->exception = makeExceptionInInitializerError(t, t->exception);
|
||||
}
|
||||
classVmFlags(t, c) &= ~(NeedInitFlag | InitFlag);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void
|
||||
visitObjects(Thread* t, Heap::Visitor*)
|
||||
{
|
||||
@ -770,7 +1164,7 @@ class MyProcessor: public Processor {
|
||||
const char* spec = reinterpret_cast<char*>
|
||||
(&byteArrayBody(t, methodSpec(t, method), 0));
|
||||
|
||||
unsigned size = methodParameterCount(t, method) * 2;
|
||||
unsigned size = methodParameterFootprint(t, method) + FrameFootprint;
|
||||
uintptr_t array[size];
|
||||
bool objectMask[size];
|
||||
ArgumentList list(t, array, objectMask, this_, spec, arguments);
|
||||
@ -790,7 +1184,7 @@ class MyProcessor: public Processor {
|
||||
const char* spec = reinterpret_cast<char*>
|
||||
(&byteArrayBody(t, methodSpec(t, method), 0));
|
||||
|
||||
unsigned size = methodParameterCount(t, method) * 2;
|
||||
unsigned size = methodParameterFootprint(t, method) + FrameFootprint;
|
||||
uintptr_t array[size];
|
||||
bool objectMask[size];
|
||||
ArgumentList list
|
||||
@ -806,7 +1200,7 @@ class MyProcessor: public Processor {
|
||||
assert(t, t->state == Thread::ActiveState
|
||||
or t->state == Thread::ExclusiveState);
|
||||
|
||||
unsigned size = parameterCount(methodSpec) * 2;
|
||||
unsigned size = parameterFootprint(t, methodSpec, false) + FrameFootprint;
|
||||
uintptr_t array[size];
|
||||
bool objectMask[size];
|
||||
ArgumentList list
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "constants.h"
|
||||
#include "machine.h"
|
||||
#include "processor.h"
|
||||
#include "process.h"
|
||||
|
||||
using namespace vm;
|
||||
|
||||
@ -375,119 +376,16 @@ findInterfaceMethod(Thread* t, object method, object class_)
|
||||
abort(t);
|
||||
}
|
||||
|
||||
inline object
|
||||
findMethod(Thread* t, object method, object class_)
|
||||
{
|
||||
return arrayBody(t, classVirtualTable(t, class_),
|
||||
methodOffset(t, method));
|
||||
}
|
||||
|
||||
bool
|
||||
isSuperclass(Thread* t, object class_, object base)
|
||||
{
|
||||
for (object oc = classSuper(t, base); oc; oc = classSuper(t, oc)) {
|
||||
if (oc == class_) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool
|
||||
isSpecialMethod(Thread* t, object method, object class_)
|
||||
{
|
||||
return (classFlags(t, class_) & ACC_SUPER)
|
||||
and strcmp(reinterpret_cast<const int8_t*>("<init>"),
|
||||
&byteArrayBody(t, methodName(t, method), 0)) != 0
|
||||
and isSuperclass(t, methodClass(t, method), class_);
|
||||
}
|
||||
|
||||
inline object
|
||||
resolveClass(Thread* t, object pool, unsigned index)
|
||||
{
|
||||
object o = arrayBody(t, pool, index);
|
||||
if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ByteArrayType))
|
||||
{
|
||||
PROTECT(t, pool);
|
||||
|
||||
o = resolveClass(t, o);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
set(t, arrayBody(t, pool, index), o);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
inline object
|
||||
resolveClass(Thread* t, object container,
|
||||
object& (*class_)(vm::Thread*, object))
|
||||
{
|
||||
object o = class_(t, container);
|
||||
if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ByteArrayType))
|
||||
{
|
||||
PROTECT(t, container);
|
||||
|
||||
o = resolveClass(t, o);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
set(t, class_(t, container), o);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
inline object
|
||||
resolve(Thread* t, object pool, unsigned index,
|
||||
object (*find)(vm::Thread*, object, object, object),
|
||||
object (*makeError)(vm::Thread*, object))
|
||||
{
|
||||
object o = arrayBody(t, pool, index);
|
||||
if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ReferenceType))
|
||||
{
|
||||
PROTECT(t, pool);
|
||||
|
||||
object reference = o;
|
||||
PROTECT(t, reference);
|
||||
|
||||
object class_ = resolveClass(t, o, referenceClass);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
o = findInHierarchy
|
||||
(t, class_, referenceName(t, reference), referenceSpec(t, reference),
|
||||
find, makeError);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
set(t, arrayBody(t, pool, index), o);
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
inline object
|
||||
resolveField(Thread* t, object pool, unsigned index)
|
||||
{
|
||||
return resolve(t, pool, index, findFieldInClass, makeNoSuchFieldError);
|
||||
}
|
||||
|
||||
inline object
|
||||
resolveMethod(Thread* t, object pool, unsigned index)
|
||||
{
|
||||
return resolve(t, pool, index, findMethodInClass, makeNoSuchMethodError);
|
||||
}
|
||||
|
||||
object
|
||||
makeNativeMethodData(Thread* t, object method, void* function)
|
||||
{
|
||||
PROTECT(t, method);
|
||||
|
||||
unsigned count = methodParameterCount(t, method) + 1;
|
||||
if (methodFlags(t, method) & ACC_STATIC) {
|
||||
++ count;
|
||||
}
|
||||
unsigned count = methodParameterCount(t, method) + 2;
|
||||
|
||||
object data = makeNativeMethodData(t,
|
||||
function,
|
||||
0, // argument table size
|
||||
0, // return code,
|
||||
count,
|
||||
false);
|
||||
|
||||
@ -534,7 +432,6 @@ makeNativeMethodData(Thread* t, object method, void* function)
|
||||
}
|
||||
|
||||
nativeMethodDataArgumentTableSize(t, data) = argumentTableSize;
|
||||
nativeMethodDataReturnCode(t, data) = fieldCode(t, s[1]);
|
||||
|
||||
return data;
|
||||
}
|
||||
@ -598,10 +495,7 @@ invokeNative(Thread* t, object method)
|
||||
|
||||
pushFrame(t, method);
|
||||
|
||||
unsigned count = methodParameterCount(t, method);
|
||||
if (methodFlags(t, method) & ACC_STATIC) {
|
||||
++ count;
|
||||
}
|
||||
unsigned count = nativeMethodDataLength(t, data) - 1;
|
||||
|
||||
unsigned size = nativeMethodDataArgumentTableSize(t, data);
|
||||
uintptr_t args[size / BytesPerWord];
|
||||
@ -648,7 +542,7 @@ invokeNative(Thread* t, object method)
|
||||
}
|
||||
}
|
||||
|
||||
unsigned returnCode = nativeMethodDataReturnCode(t, data);
|
||||
unsigned returnCode = methodReturnCode(t, method);
|
||||
unsigned returnType = fieldType(t, returnCode);
|
||||
void* function = nativeMethodDataFunction(t, data);
|
||||
|
||||
@ -721,7 +615,7 @@ invokeNative(Thread* t, object method)
|
||||
|
||||
default:
|
||||
abort(t);
|
||||
};
|
||||
}
|
||||
|
||||
return returnCode;
|
||||
}
|
||||
@ -754,24 +648,6 @@ classInit(Thread* t, object class_, unsigned ipOffset)
|
||||
}
|
||||
}
|
||||
|
||||
inline int16_t
|
||||
codeReadInt16(Thread* t, unsigned& i)
|
||||
{
|
||||
uint8_t v1 = codeBody(t, t->code, i++);
|
||||
uint8_t v2 = codeBody(t, t->code, i++);
|
||||
return ((v1 << 8) | v2);
|
||||
}
|
||||
|
||||
inline int32_t
|
||||
codeReadInt32(Thread* t, unsigned& i)
|
||||
{
|
||||
uint8_t v1 = codeBody(t, t->code, i++);
|
||||
uint8_t v2 = codeBody(t, t->code, i++);
|
||||
uint8_t v3 = codeBody(t, t->code, i++);
|
||||
uint8_t v4 = codeBody(t, t->code, i++);
|
||||
return ((v1 << 24) | (v2 << 16) | (v3 << 8) | v4);
|
||||
}
|
||||
|
||||
inline void
|
||||
store(Thread* t, unsigned index)
|
||||
{
|
||||
@ -929,7 +805,7 @@ interpret(Thread* t)
|
||||
int32_t count = popInt(t);
|
||||
|
||||
if (LIKELY(count >= 0)) {
|
||||
uint16_t index = codeReadInt16(t, ip);
|
||||
uint16_t index = codeReadInt16(t, code, ip);
|
||||
|
||||
object class_ = resolveClass(t, codePool(t, code), index - 1);
|
||||
if (UNLIKELY(exception)) goto throw_;
|
||||
@ -1114,7 +990,7 @@ interpret(Thread* t)
|
||||
} goto loop;
|
||||
|
||||
case checkcast: {
|
||||
uint16_t index = codeReadInt16(t, ip);
|
||||
uint16_t index = codeReadInt16(t, code, ip);
|
||||
|
||||
if (peekObject(t, sp - 1)) {
|
||||
object class_ = resolveClass(t, codePool(t, code), index - 1);
|
||||
@ -1443,7 +1319,7 @@ interpret(Thread* t)
|
||||
|
||||
case getfield: {
|
||||
if (LIKELY(peekObject(t, sp - 1))) {
|
||||
uint16_t index = codeReadInt16(t, ip);
|
||||
uint16_t index = codeReadInt16(t, code, ip);
|
||||
|
||||
object field = resolveField(t, codePool(t, code), index - 1);
|
||||
if (UNLIKELY(exception)) goto throw_;
|
||||
@ -1485,7 +1361,7 @@ interpret(Thread* t)
|
||||
} goto loop;
|
||||
|
||||
case getstatic: {
|
||||
uint16_t index = codeReadInt16(t, ip);
|
||||
uint16_t index = codeReadInt16(t, code, ip);
|
||||
|
||||
object field = resolveField(t, codePool(t, code), index - 1);
|
||||
if (UNLIKELY(exception)) goto throw_;
|
||||
@ -1520,12 +1396,12 @@ interpret(Thread* t)
|
||||
} goto loop;
|
||||
|
||||
case goto_: {
|
||||
int16_t offset = codeReadInt16(t, ip);
|
||||
int16_t offset = codeReadInt16(t, code, ip);
|
||||
ip = (ip - 3) + offset;
|
||||
} goto loop;
|
||||
|
||||
case goto_w: {
|
||||
int32_t offset = codeReadInt32(t, ip);
|
||||
int32_t offset = codeReadInt32(t, code, ip);
|
||||
ip = (ip - 5) + offset;
|
||||
} goto loop;
|
||||
|
||||
@ -1882,7 +1758,7 @@ interpret(Thread* t)
|
||||
} goto loop;
|
||||
|
||||
case invokeinterface: {
|
||||
uint16_t index = codeReadInt16(t, ip);
|
||||
uint16_t index = codeReadInt16(t, code, ip);
|
||||
|
||||
ip += 2;
|
||||
|
||||
@ -1901,7 +1777,7 @@ interpret(Thread* t)
|
||||
} goto loop;
|
||||
|
||||
case invokespecial: {
|
||||
uint16_t index = codeReadInt16(t, ip);
|
||||
uint16_t index = codeReadInt16(t, code, ip);
|
||||
|
||||
object method = resolveMethod(t, codePool(t, code), index - 1);
|
||||
if (UNLIKELY(exception)) goto throw_;
|
||||
@ -1935,7 +1811,7 @@ interpret(Thread* t)
|
||||
} goto loop;
|
||||
|
||||
case invokestatic: {
|
||||
uint16_t index = codeReadInt16(t, ip);
|
||||
uint16_t index = codeReadInt16(t, code, ip);
|
||||
|
||||
object method = resolveMethod(t, codePool(t, code), index - 1);
|
||||
if (UNLIKELY(exception)) goto throw_;
|
||||
@ -1947,7 +1823,7 @@ interpret(Thread* t)
|
||||
} goto invoke;
|
||||
|
||||
case invokevirtual: {
|
||||
uint16_t index = codeReadInt16(t, ip);
|
||||
uint16_t index = codeReadInt16(t, code, ip);
|
||||
|
||||
object method = resolveMethod(t, codePool(t, code), index - 1);
|
||||
if (UNLIKELY(exception)) goto throw_;
|
||||
@ -2253,8 +2129,8 @@ interpret(Thread* t)
|
||||
ip += 3;
|
||||
ip -= (ip % 4);
|
||||
|
||||
int32_t default_ = codeReadInt32(t, ip);
|
||||
int32_t pairCount = codeReadInt32(t, ip);
|
||||
int32_t default_ = codeReadInt32(t, code, ip);
|
||||
int32_t pairCount = codeReadInt32(t, code, ip);
|
||||
|
||||
int32_t key = popInt(t);
|
||||
|
||||
@ -2264,14 +2140,14 @@ interpret(Thread* t)
|
||||
int32_t middle = bottom + (span / 2);
|
||||
unsigned index = ip + (middle * 8);
|
||||
|
||||
int32_t k = codeReadInt32(t, index);
|
||||
int32_t k = codeReadInt32(t, code, index);
|
||||
|
||||
if (key < k) {
|
||||
top = middle;
|
||||
} else if (key > k) {
|
||||
bottom = middle + 1;
|
||||
} else {
|
||||
ip = base + codeReadInt32(t, index);
|
||||
ip = base + codeReadInt32(t, code, index);
|
||||
goto loop;
|
||||
}
|
||||
}
|
||||
@ -2386,7 +2262,7 @@ interpret(Thread* t)
|
||||
} goto loop;
|
||||
|
||||
case multianewarray: {
|
||||
uint16_t index = codeReadInt16(t, ip);
|
||||
uint16_t index = codeReadInt16(t, code, ip);
|
||||
uint8_t dimensions = codeBody(t, code, ip++);
|
||||
|
||||
object class_ = resolveClass(t, codePool(t, code), index - 1);
|
||||
@ -2413,7 +2289,7 @@ interpret(Thread* t)
|
||||
} goto loop;
|
||||
|
||||
case new_: {
|
||||
uint16_t index = codeReadInt16(t, ip);
|
||||
uint16_t index = codeReadInt16(t, code, ip);
|
||||
|
||||
object class_ = resolveClass(t, codePool(t, code), index - 1);
|
||||
if (UNLIKELY(exception)) goto throw_;
|
||||
@ -2487,7 +2363,7 @@ interpret(Thread* t)
|
||||
} goto loop;
|
||||
|
||||
case putfield: {
|
||||
uint16_t index = codeReadInt16(t, ip);
|
||||
uint16_t index = codeReadInt16(t, code, ip);
|
||||
|
||||
object field = resolveField(t, codePool(t, code), index - 1);
|
||||
if (UNLIKELY(exception)) goto throw_;
|
||||
@ -2552,7 +2428,7 @@ interpret(Thread* t)
|
||||
} goto loop;
|
||||
|
||||
case putstatic: {
|
||||
uint16_t index = codeReadInt16(t, ip);
|
||||
uint16_t index = codeReadInt16(t, code, ip);
|
||||
|
||||
object field = resolveField(t, codePool(t, code), index - 1);
|
||||
if (UNLIKELY(exception)) goto throw_;
|
||||
@ -2664,15 +2540,15 @@ interpret(Thread* t)
|
||||
ip += 3;
|
||||
ip -= (ip % 4);
|
||||
|
||||
int32_t default_ = codeReadInt32(t, ip);
|
||||
int32_t bottom = codeReadInt32(t, ip);
|
||||
int32_t top = codeReadInt32(t, ip);
|
||||
int32_t default_ = codeReadInt32(t, code, ip);
|
||||
int32_t bottom = codeReadInt32(t, code, ip);
|
||||
int32_t top = codeReadInt32(t, code, ip);
|
||||
|
||||
int32_t key = popInt(t);
|
||||
|
||||
if (key >= bottom and key <= top) {
|
||||
unsigned index = ip + ((key - bottom) * 4);
|
||||
ip = base + codeReadInt32(t, index);
|
||||
ip = base + codeReadInt32(t, code, index);
|
||||
} else {
|
||||
ip = base + default_;
|
||||
}
|
||||
@ -2686,38 +2562,38 @@ interpret(Thread* t)
|
||||
wide:
|
||||
switch (codeBody(t, code, ip++)) {
|
||||
case aload: {
|
||||
pushObject(t, localObject(t, codeReadInt16(t, ip)));
|
||||
pushObject(t, localObject(t, codeReadInt16(t, code, ip)));
|
||||
} goto loop;
|
||||
|
||||
case astore: {
|
||||
setLocalObject(t, codeReadInt16(t, ip), popObject(t));
|
||||
setLocalObject(t, codeReadInt16(t, code, ip), popObject(t));
|
||||
} goto loop;
|
||||
|
||||
case iinc: {
|
||||
uint16_t index = codeReadInt16(t, ip);
|
||||
uint16_t count = codeReadInt16(t, ip);
|
||||
uint16_t index = codeReadInt16(t, code, ip);
|
||||
uint16_t count = codeReadInt16(t, code, ip);
|
||||
|
||||
setLocalInt(t, index, localInt(t, index) + count);
|
||||
} goto loop;
|
||||
|
||||
case iload: {
|
||||
pushInt(t, localInt(t, codeReadInt16(t, ip)));
|
||||
pushInt(t, localInt(t, codeReadInt16(t, code, ip)));
|
||||
} goto loop;
|
||||
|
||||
case istore: {
|
||||
setLocalInt(t, codeReadInt16(t, ip), popInt(t));
|
||||
setLocalInt(t, codeReadInt16(t, code, ip), popInt(t));
|
||||
} goto loop;
|
||||
|
||||
case lload: {
|
||||
pushLong(t, localLong(t, codeReadInt16(t, ip)));
|
||||
pushLong(t, localLong(t, codeReadInt16(t, code, ip)));
|
||||
} goto loop;
|
||||
|
||||
case lstore: {
|
||||
setLocalLong(t, codeReadInt16(t, ip), popLong(t));
|
||||
setLocalLong(t, codeReadInt16(t, code, ip), popLong(t));
|
||||
} goto loop;
|
||||
|
||||
case ret: {
|
||||
ip = localInt(t, codeReadInt16(t, ip));
|
||||
ip = localInt(t, codeReadInt16(t, code, ip));
|
||||
} goto loop;
|
||||
|
||||
default: abort(t);
|
||||
@ -3024,6 +2900,68 @@ class MyProcessor: public Processor {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
++ footprint;
|
||||
break;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
break;
|
||||
}
|
||||
|
||||
++ footprint;
|
||||
}
|
||||
|
||||
if (not static_) {
|
||||
++ footprint;
|
||||
}
|
||||
return footprint;
|
||||
}
|
||||
|
||||
virtual void
|
||||
initClass(vm::Thread* t, object c)
|
||||
{
|
||||
PROTECT(t, c);
|
||||
|
||||
acquire(t, t->m->classLock);
|
||||
if (classVmFlags(t, c) & NeedInitFlag
|
||||
and (classVmFlags(t, c) & InitFlag) == 0)
|
||||
{
|
||||
classVmFlags(t, c) |= InitFlag;
|
||||
t->m->processor->invoke(t, classInitializer(t, c), 0);
|
||||
} else {
|
||||
release(t, t->m->classLock);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void
|
||||
visitObjects(vm::Thread* vmt, Heap::Visitor* v)
|
||||
{
|
||||
@ -3156,7 +3094,7 @@ class MyProcessor: public Processor {
|
||||
assert(t, t->state == Thread::ActiveState
|
||||
or t->state == Thread::ExclusiveState);
|
||||
|
||||
if (UNLIKELY(t->sp + parameterFootprint(methodSpec) + 1
|
||||
if (UNLIKELY(t->sp + parameterFootprint(vmt, methodSpec, false)
|
||||
> Thread::StackSizeInWords / 2))
|
||||
{
|
||||
t->exception = makeStackOverflowError(t);
|
||||
|
136
src/machine.cpp
136
src/machine.cpp
@ -876,6 +876,45 @@ parseCode(Thread* t, Stream& s, object pool)
|
||||
return code;
|
||||
}
|
||||
|
||||
void
|
||||
scanMethodSpec(Thread* t, const char* s, unsigned* parameterCount,
|
||||
unsigned* returnCode)
|
||||
{
|
||||
unsigned count = 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;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
break;
|
||||
}
|
||||
|
||||
++ count;
|
||||
}
|
||||
|
||||
*parameterCount = count;
|
||||
*returnCode = fieldCode(t, s[1]);
|
||||
}
|
||||
|
||||
void
|
||||
parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
{
|
||||
@ -910,6 +949,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
method = makeMethod
|
||||
(t,
|
||||
methodVmFlags(t, method),
|
||||
methodReturnCode(t, method),
|
||||
methodParameterCount(t, method),
|
||||
methodParameterFootprint(t, method),
|
||||
methodFlags(t, method),
|
||||
@ -967,19 +1007,19 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
}
|
||||
}
|
||||
|
||||
unsigned parameterCount = ::parameterCount
|
||||
(t, arrayBody(t, pool, spec - 1));
|
||||
const char* specString = reinterpret_cast<const char*>
|
||||
(&byteArrayBody(t, arrayBody(t, pool, spec - 1), 0));
|
||||
|
||||
unsigned parameterFootprint = ::parameterFootprint
|
||||
(t, arrayBody(t, pool, spec - 1));
|
||||
unsigned parameterCount;
|
||||
unsigned returnCode;
|
||||
scanMethodSpec(t, specString, ¶meterCount, &returnCode);
|
||||
|
||||
if ((flags & ACC_STATIC) == 0) {
|
||||
++ parameterCount;
|
||||
++ parameterFootprint;
|
||||
}
|
||||
unsigned parameterFootprint = t->m->processor->parameterFootprint
|
||||
(t, specString, flags & ACC_STATIC);
|
||||
|
||||
object method = makeMethod(t,
|
||||
0, // vm flags
|
||||
returnCode,
|
||||
parameterCount,
|
||||
parameterFootprint,
|
||||
flags,
|
||||
@ -1793,86 +1833,6 @@ classInitializer(Thread* t, object class_)
|
||||
abort(t);
|
||||
}
|
||||
|
||||
unsigned
|
||||
parameterFootprint(const char* s)
|
||||
{
|
||||
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;
|
||||
++ footprint;
|
||||
break;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
break;
|
||||
}
|
||||
|
||||
++ footprint;
|
||||
}
|
||||
|
||||
return footprint;
|
||||
}
|
||||
|
||||
unsigned
|
||||
parameterCount(const char* s)
|
||||
{
|
||||
unsigned count = 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;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
break;
|
||||
}
|
||||
|
||||
++ count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
object
|
||||
hashMapFindNode(Thread* t, object map, object key,
|
||||
uint32_t (*hash)(Thread*, object),
|
||||
|
@ -1841,17 +1841,7 @@ resolveObjectArrayClass(Thread* t, object elementSpec);
|
||||
inline void
|
||||
initClass(Thread* t, object c)
|
||||
{
|
||||
PROTECT(t, c);
|
||||
|
||||
acquire(t, t->m->classLock);
|
||||
if (classVmFlags(t, c) & NeedInitFlag
|
||||
and (classVmFlags(t, c) & InitFlag) == 0)
|
||||
{
|
||||
classVmFlags(t, c) |= InitFlag;
|
||||
t->m->processor->invoke(t, classInitializer(t, c), 0);
|
||||
} else {
|
||||
release(t, t->m->classLock);
|
||||
}
|
||||
t->m->processor->initClass(t, c);
|
||||
}
|
||||
|
||||
object
|
||||
@ -1914,26 +1904,6 @@ objectArrayBody(Thread* t UNUSED, object array, unsigned index)
|
||||
return cast<object>(array, (2 + index) * BytesPerWord);
|
||||
}
|
||||
|
||||
unsigned
|
||||
parameterFootprint(const char* s);
|
||||
|
||||
inline unsigned
|
||||
parameterFootprint(Thread* t, object spec)
|
||||
{
|
||||
return parameterFootprint
|
||||
(reinterpret_cast<const char*>(&byteArrayBody(t, spec, 0)));
|
||||
}
|
||||
|
||||
unsigned
|
||||
parameterCount(const char* s);
|
||||
|
||||
inline unsigned
|
||||
parameterCount(Thread* t, object spec)
|
||||
{
|
||||
return parameterCount
|
||||
(reinterpret_cast<const char*>(&byteArrayBody(t, spec, 0)));
|
||||
}
|
||||
|
||||
int
|
||||
lineNumber(Thread* t, object method, unsigned ip);
|
||||
|
||||
|
137
src/process.h
Normal file
137
src/process.h
Normal file
@ -0,0 +1,137 @@
|
||||
#ifndef PROCESS_H
|
||||
#define PROCESS_H
|
||||
|
||||
#include "common.h"
|
||||
#include "system.h"
|
||||
#include "machine.h"
|
||||
#include "constants.h"
|
||||
|
||||
namespace vm {
|
||||
|
||||
inline int16_t
|
||||
codeReadInt16(Thread* t, object code, unsigned& ip)
|
||||
{
|
||||
uint8_t v1 = codeBody(t, code, ip++);
|
||||
uint8_t v2 = codeBody(t, code, ip++);
|
||||
return ((v1 << 8) | v2);
|
||||
}
|
||||
|
||||
inline int32_t
|
||||
codeReadInt32(Thread* t, object code, unsigned& ip)
|
||||
{
|
||||
uint8_t v1 = codeBody(t, code, ip++);
|
||||
uint8_t v2 = codeBody(t, code, ip++);
|
||||
uint8_t v3 = codeBody(t, code, ip++);
|
||||
uint8_t v4 = codeBody(t, code, ip++);
|
||||
return ((v1 << 24) | (v2 << 16) | (v3 << 8) | v4);
|
||||
}
|
||||
|
||||
inline object
|
||||
resolveClass(Thread* t, object container,
|
||||
object& (*class_)(vm::Thread*, object))
|
||||
{
|
||||
object o = class_(t, container);
|
||||
if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ByteArrayType))
|
||||
{
|
||||
PROTECT(t, container);
|
||||
|
||||
o = resolveClass(t, o);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
set(t, class_(t, container), o);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
inline object
|
||||
resolveClass(Thread* t, object pool, unsigned index)
|
||||
{
|
||||
object o = arrayBody(t, pool, index);
|
||||
if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ByteArrayType))
|
||||
{
|
||||
PROTECT(t, pool);
|
||||
|
||||
o = resolveClass(t, o);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
set(t, arrayBody(t, pool, index), o);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
inline object
|
||||
resolve(Thread* t, object pool, unsigned index,
|
||||
object (*find)(vm::Thread*, object, object, object),
|
||||
object (*makeError)(vm::Thread*, object))
|
||||
{
|
||||
object o = arrayBody(t, pool, index);
|
||||
if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ReferenceType))
|
||||
{
|
||||
PROTECT(t, pool);
|
||||
|
||||
object reference = o;
|
||||
PROTECT(t, reference);
|
||||
|
||||
object class_ = resolveClass(t, o, referenceClass);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
o = findInHierarchy
|
||||
(t, class_, referenceName(t, reference), referenceSpec(t, reference),
|
||||
find, makeError);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
set(t, arrayBody(t, pool, index), o);
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
inline object
|
||||
resolveField(Thread* t, object pool, unsigned index)
|
||||
{
|
||||
return resolve(t, pool, index, findFieldInClass, makeNoSuchFieldError);
|
||||
}
|
||||
|
||||
inline object
|
||||
resolveMethod(Thread* t, object pool, unsigned index)
|
||||
{
|
||||
return resolve(t, pool, index, findMethodInClass, makeNoSuchMethodError);
|
||||
}
|
||||
|
||||
inline bool
|
||||
isSuperclass(Thread* t, object class_, object base)
|
||||
{
|
||||
for (object oc = classSuper(t, base); oc; oc = classSuper(t, oc)) {
|
||||
if (oc == class_) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool
|
||||
isSpecialMethod(Thread* t, object method, object class_)
|
||||
{
|
||||
return (classFlags(t, class_) & ACC_SUPER)
|
||||
and strcmp(reinterpret_cast<const int8_t*>("<init>"),
|
||||
&byteArrayBody(t, methodName(t, method), 0)) != 0
|
||||
and isSuperclass(t, methodClass(t, method), class_);
|
||||
}
|
||||
|
||||
inline object
|
||||
findMethod(Thread* t, object method, object class_)
|
||||
{
|
||||
return arrayBody(t, classVirtualTable(t, class_),
|
||||
methodOffset(t, method));
|
||||
}
|
||||
|
||||
inline bool
|
||||
methodVirtual(Thread* t, object method)
|
||||
{
|
||||
return (methodFlags(t, method) & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE))
|
||||
!= 0;
|
||||
}
|
||||
|
||||
} // namespace vm
|
||||
|
||||
#endif//PROCESS_H
|
@ -17,6 +17,12 @@ class Processor {
|
||||
virtual object
|
||||
methodStub(Thread* t) = 0;
|
||||
|
||||
virtual unsigned
|
||||
parameterFootprint(Thread* t, const char* spec, bool static_) = 0;
|
||||
|
||||
virtual void
|
||||
initClass(Thread* t, object c) = 0;
|
||||
|
||||
virtual void
|
||||
visitObjects(Thread* t, Heap::Visitor* v) = 0;
|
||||
|
||||
|
@ -15,10 +15,14 @@
|
||||
|
||||
#define ACQUIRE(x) MutexResource MAKE_NAME(mutexResource_) (x)
|
||||
|
||||
namespace {
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
extern "C" uint64_t
|
||||
cdeclCall(void* function, void* stack, unsigned stackSize,
|
||||
unsigned returnType);
|
||||
|
||||
namespace {
|
||||
|
||||
inline uint64_t
|
||||
dynamicCall(void* function, uintptr_t* arguments, uint8_t*,
|
||||
unsigned, unsigned argumentsSize, unsigned returnType)
|
||||
@ -26,8 +30,16 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t*,
|
||||
return cdeclCall(function, arguments, argumentsSize, returnType);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#elif defined __x86_64__
|
||||
|
||||
extern "C" uint64_t
|
||||
amd64Call(void* function, void* stack, unsigned stackSize,
|
||||
void* gprTable, void* sseTable, unsigned returnType);
|
||||
|
||||
namespace {
|
||||
|
||||
uint64_t
|
||||
dynamicCall(void* function, uint64_t* arguments, uint8_t* argumentTypes,
|
||||
unsigned argumentCount, unsigned, unsigned returnType)
|
||||
@ -68,12 +80,12 @@ dynamicCall(void* function, uint64_t* arguments, uint8_t* argumentTypes,
|
||||
(sseIndex ? sseTable : 0), returnType);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#else
|
||||
# error unsupported platform
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
using namespace vm;
|
||||
|
||||
namespace {
|
||||
|
@ -41,8 +41,9 @@
|
||||
(type method java/lang/reflect/Method
|
||||
(extends accessibleObject)
|
||||
(uint8_t vmFlags)
|
||||
(uint8_t returnCode)
|
||||
(uint8_t parameterCount)
|
||||
(uint16_t parameterFootprint)
|
||||
(uint8_t parameterFootprint)
|
||||
(uint16_t flags)
|
||||
(uint16_t offset)
|
||||
(object name)
|
||||
@ -58,7 +59,6 @@
|
||||
(type nativeMethodData
|
||||
(void* function)
|
||||
(uint16_t argumentTableSize)
|
||||
(uint8_t returnCode)
|
||||
(array uint8_t parameterTypes))
|
||||
|
||||
(type pointer
|
||||
|
102
src/vmInvoke.S
Normal file
102
src/vmInvoke.S
Normal file
@ -0,0 +1,102 @@
|
||||
#include "types.h"
|
||||
|
||||
.text
|
||||
|
||||
.globl vmInvoke
|
||||
vmInvoke:
|
||||
#ifdef __x86_64__
|
||||
|
||||
pushq %rbp
|
||||
movq %rsp,%rbp
|
||||
|
||||
// %rdi: function
|
||||
// %rsi: stack
|
||||
// %rdx: stackSize
|
||||
// %rcx: returnType
|
||||
|
||||
// reserve space for arguments
|
||||
subq %rdx,%rsp
|
||||
|
||||
// copy memory arguments into place
|
||||
movq $0,%r8
|
||||
jmp test
|
||||
|
||||
loop:
|
||||
movq %r8,%rax
|
||||
movq %r8,%r9
|
||||
addq %rsp,%r9
|
||||
addq %rsi,%rax
|
||||
movq (%rax),%rax
|
||||
movq %rax,(%r9)
|
||||
addq $8,%r8
|
||||
|
||||
test:
|
||||
cmpq %rdx,%r8
|
||||
jb loop
|
||||
|
||||
// call function
|
||||
call *%rdi
|
||||
|
||||
movq %rbp,%rsp
|
||||
popq %rbp
|
||||
ret
|
||||
|
||||
#elif defined __i386__
|
||||
|
||||
pushl %ebp
|
||||
movl %esp,%ebp
|
||||
|
||||
// 8(%ebp): function
|
||||
// 12(%ebp): stack
|
||||
// 16(%ebp): stackSize
|
||||
// 20(%ebp): returnType
|
||||
|
||||
// reserve space for arguments
|
||||
movl 16(%ebp),%ecx
|
||||
|
||||
subl %ecx,%esp
|
||||
|
||||
// copy arguments into place
|
||||
movl $0,%ecx
|
||||
jmp test
|
||||
|
||||
loop:
|
||||
movl %ecx,%eax
|
||||
movl %ecx,%edx
|
||||
addl %esp,%edx
|
||||
addl 12(%ebp),%eax
|
||||
movl (%eax),%eax
|
||||
movl %eax,(%edx)
|
||||
addl $4,%ecx
|
||||
|
||||
test:
|
||||
cmpl 16(%ebp),%ecx
|
||||
jb loop
|
||||
|
||||
// call function
|
||||
call *8(%ebp)
|
||||
|
||||
// handle return value based on expected type
|
||||
movl 20(%ebp),%ecx
|
||||
|
||||
void:
|
||||
cmpl $VOID_TYPE,%ecx
|
||||
jne int64
|
||||
jmp exit
|
||||
|
||||
int64:
|
||||
cmpl $INT64_TYPE,%ecx
|
||||
jne int32
|
||||
jmp exit
|
||||
|
||||
int32:
|
||||
movl $0,%edx
|
||||
|
||||
exit:
|
||||
movl %ebp,%esp
|
||||
popl %ebp
|
||||
ret
|
||||
|
||||
#else
|
||||
# error unsupported platform
|
||||
#endif
|
@ -1,7 +1,19 @@
|
||||
public class Instructions {
|
||||
private String foo(String s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
public String bar(String s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
int a = 2;
|
||||
int b = 2;
|
||||
int c = a + b;
|
||||
|
||||
// Instructions i = new Instructions();
|
||||
// i.foo("hello");
|
||||
// i.bar("hello");
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user