mirror of
https://github.com/corda/corda.git
synced 2025-01-04 04:04:27 +00:00
invoke native methods using a common routine, instead of compiling code specific to each method
This commit is contained in:
parent
7ecb5b9c30
commit
45dc118ab9
425
src/compile.cpp
425
src/compile.cpp
@ -20,21 +20,37 @@ const unsigned FrameMethod = FrameThread + BytesPerWord;
|
|||||||
const unsigned FrameNext = FrameNext + BytesPerWord;
|
const unsigned FrameNext = FrameNext + BytesPerWord;
|
||||||
const unsigned FrameFootprint = BytesPerWord * 3;
|
const unsigned FrameFootprint = BytesPerWord * 3;
|
||||||
|
|
||||||
void
|
class ArgumentList;
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
void NO_RETURN
|
||||||
unwind(Thread* t)
|
unwind(Thread* t)
|
||||||
{
|
{
|
||||||
// todo
|
// todo
|
||||||
abort(t);
|
abort(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void NO_RETURN
|
||||||
throwNew(Thread* t, object class_)
|
throwNew(Thread* t, object class_)
|
||||||
{
|
{
|
||||||
t->exception = makeNew(t, class_);
|
t->exception = makeNew(t, class_);
|
||||||
unwind(t);
|
unwind(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void NO_RETURN
|
||||||
throw_(Thread* t, object o)
|
throw_(Thread* t, object o)
|
||||||
{
|
{
|
||||||
if (o) {
|
if (o) {
|
||||||
@ -58,6 +74,140 @@ makeBlankArray(Thread* t, object (*constructor)(Thread*, uintptr_t, bool),
|
|||||||
return constructor(t, length, true);
|
return constructor(t, length, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
invokeNative2(MyThread* t, object method)
|
||||||
|
{
|
||||||
|
PROTECT(t, method);
|
||||||
|
|
||||||
|
if (objectClass(t, methodCode(t, method))
|
||||||
|
== arrayBody(t, t->m->types, Machine::ByteArrayType))
|
||||||
|
{
|
||||||
|
void* function = resolveNativeMethod(t, method);
|
||||||
|
if (UNLIKELY(function == 0)) {
|
||||||
|
object message = makeString
|
||||||
|
(t, "%s", &byteArrayBody(t, methodCode(t, method), 0));
|
||||||
|
t->exception = makeUnsatisfiedLinkError(t, message);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
object p = makePointer(t, function);
|
||||||
|
set(t, methodCode(t, method), p);
|
||||||
|
}
|
||||||
|
|
||||||
|
object class_ = methodClass(t, method);
|
||||||
|
PROTECT(t, class_);
|
||||||
|
|
||||||
|
unsigned footprint = methodParameterFootprint(t, method) + 1;
|
||||||
|
unsigned count = methodParameterCount(t, method) + 1;
|
||||||
|
if (methodFlags(t, method) & ACC_STATIC) {
|
||||||
|
++ footprint;
|
||||||
|
++ count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t args[footprint];
|
||||||
|
unsigned argOffset = 0;
|
||||||
|
uint8_t types[count];
|
||||||
|
unsigned typeOffset = 0;
|
||||||
|
|
||||||
|
args[argOffset++] = reinterpret_cast<uintptr_t>(t);
|
||||||
|
types[typeOffset++] = POINTER_TYPE;
|
||||||
|
|
||||||
|
uintptr_t* sp = static_cast<uintptr_t*>(t->frame)
|
||||||
|
+ (methodParameterFootprint(t, method) + 1)
|
||||||
|
+ (FrameFootprint / BytesPerWord);
|
||||||
|
|
||||||
|
if (methodFlags(t, method) & ACC_STATIC) {
|
||||||
|
args[argOffset++] = reinterpret_cast<uintptr_t>(&class_);
|
||||||
|
} else {
|
||||||
|
args[argOffset++] = reinterpret_cast<uintptr_t>(sp--);
|
||||||
|
}
|
||||||
|
types[typeOffset++] = POINTER_TYPE;
|
||||||
|
|
||||||
|
MethodSpecIterator it
|
||||||
|
(t, reinterpret_cast<const char*>
|
||||||
|
(&byteArrayBody(t, methodSpec(t, method), 0)));
|
||||||
|
|
||||||
|
while (it.hasNext()) {
|
||||||
|
unsigned type = types[typeOffset++]
|
||||||
|
= fieldType(t, fieldCode(t, *it.next()));
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case INT8_TYPE:
|
||||||
|
case INT16_TYPE:
|
||||||
|
case INT32_TYPE:
|
||||||
|
case FLOAT_TYPE:
|
||||||
|
args[argOffset++] = *(sp--);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INT64_TYPE:
|
||||||
|
case DOUBLE_TYPE: {
|
||||||
|
if (BytesPerWord == 8) {
|
||||||
|
uint64_t a = *(sp--);
|
||||||
|
uint64_t b = *(sp--);
|
||||||
|
args[argOffset++] = (a << 32) | b;
|
||||||
|
} else {
|
||||||
|
memcpy(args + argOffset, sp, 8);
|
||||||
|
argOffset += 2;
|
||||||
|
sp -= 2;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case POINTER_TYPE: {
|
||||||
|
args[argOffset++] = reinterpret_cast<uintptr_t>(sp--);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: abort(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* function = pointerValue(t, methodCode(t, method));
|
||||||
|
unsigned returnType = fieldType(t, methodReturnCode(t, method));
|
||||||
|
uint64_t result;
|
||||||
|
|
||||||
|
if (Verbose) {
|
||||||
|
fprintf(stderr, "invoke native method %s.%s\n",
|
||||||
|
&byteArrayBody(t, className(t, methodClass(t, method)), 0),
|
||||||
|
&byteArrayBody(t, methodName(t, method), 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
{ ENTER(t, Thread::IdleState);
|
||||||
|
|
||||||
|
result = t->m->system->call
|
||||||
|
(function,
|
||||||
|
args,
|
||||||
|
types,
|
||||||
|
count + 1,
|
||||||
|
footprint,
|
||||||
|
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) {
|
||||||
|
return *reinterpret_cast<uintptr_t*>(result);
|
||||||
|
} 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);
|
||||||
|
|
||||||
class Buffer {
|
class Buffer {
|
||||||
public:
|
public:
|
||||||
Buffer(System* s, unsigned minimumCapacity):
|
Buffer(System* s, unsigned minimumCapacity):
|
||||||
@ -154,22 +304,6 @@ class Buffer {
|
|||||||
unsigned minimumCapacity;
|
unsigned minimumCapacity;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ArgumentList;
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
isByte(int32_t v)
|
isByte(int32_t v)
|
||||||
{
|
{
|
||||||
@ -631,9 +765,6 @@ class Assembler {
|
|||||||
Buffer jumps;
|
Buffer jumps;
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
|
||||||
compileMethod(MyThread* t, object method);
|
|
||||||
|
|
||||||
int
|
int
|
||||||
localOffset(int v, int parameterFootprint)
|
localOffset(int v, int parameterFootprint)
|
||||||
{
|
{
|
||||||
@ -805,193 +936,6 @@ class Compiler: public Assembler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void compile(MyThread* t, object method) {
|
void compile(MyThread* t, object method) {
|
||||||
if (methodFlags(t, method) & ACC_NATIVE) {
|
|
||||||
compileNative(t, method);
|
|
||||||
} else {
|
|
||||||
compileJava(t, method);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void compileNative(MyThread* t, object method) {
|
|
||||||
unsigned frameOffset = reinterpret_cast<uintptr_t>(&(t->frame))
|
|
||||||
- reinterpret_cast<uintptr_t>(t);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
push(rbp);
|
|
||||||
mov(rsp, rbp);
|
|
||||||
|
|
||||||
mov(rbp, FrameThread, rax);
|
|
||||||
mov(rbp, rax, frameOffset); // set thread frame to current
|
|
||||||
|
|
||||||
unsigned index;
|
|
||||||
if (methodFlags(t, method) & ACC_STATIC) {
|
|
||||||
pushAddress(reinterpret_cast<uintptr_t>(methodClass(t, method)));
|
|
||||||
index = 0;
|
|
||||||
} else {
|
|
||||||
index = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned parameterCodes[methodParameterCount(t, method)];
|
|
||||||
MethodSpecIterator it
|
|
||||||
(t, reinterpret_cast<const char*>
|
|
||||||
(&byteArrayBody(t, methodSpec(t, method), 0)));
|
|
||||||
|
|
||||||
for (unsigned i = 0; it.hasNext(); ++i) {
|
|
||||||
parameterCodes[i] = fieldCode(t, *it.next());
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned stackFootprint;
|
|
||||||
unsigned parameterCodeIndex = methodParameterCount(t, method);
|
|
||||||
|
|
||||||
if (BytesPerWord == 4) {
|
|
||||||
while (parameterCodeIndex) {
|
|
||||||
unsigned offset = parameterOffset(index);
|
|
||||||
|
|
||||||
switch (parameterCodes[--parameterCodeIndex]) {
|
|
||||||
case BooleanField:
|
|
||||||
case ByteField:
|
|
||||||
case ShortField:
|
|
||||||
case CharField:
|
|
||||||
case IntField:
|
|
||||||
case FloatField: {
|
|
||||||
push(rbp, offset);
|
|
||||||
++ index;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case LongField:
|
|
||||||
case DoubleField: {
|
|
||||||
push(rbp, offset);
|
|
||||||
push(rbp, offset - BytesPerWord);
|
|
||||||
index += 2;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case ObjectField: {
|
|
||||||
mov(rbp, rax);
|
|
||||||
add(offset, rax);
|
|
||||||
push(rax);
|
|
||||||
++ index;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
abort(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (methodFlags(t, method) & ACC_STATIC) {
|
|
||||||
mov(rbp, rax);
|
|
||||||
sub(BytesPerWord, rax);
|
|
||||||
push(rax); // push pointer to class pointer
|
|
||||||
} else {
|
|
||||||
unsigned offset = parameterOffset
|
|
||||||
(methodParameterFootprint(t, method) - 1);
|
|
||||||
mov(rbp, rax);
|
|
||||||
add(offset, rax);
|
|
||||||
push(rax); // push pointer to this pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
push(rbp, FrameThread); // push thread pointer
|
|
||||||
|
|
||||||
stackFootprint = FrameFootprint
|
|
||||||
+ (methodParameterFootprint(t, method) * BytesPerWord);
|
|
||||||
} else {
|
|
||||||
const unsigned GprCount = 6;
|
|
||||||
unsigned gprIndex = 0;
|
|
||||||
|
|
||||||
const unsigned SseCount = 8;
|
|
||||||
unsigned sseIndex = 0;
|
|
||||||
|
|
||||||
stackFootprint = 0;
|
|
||||||
|
|
||||||
while (parameterCodeIndex) {
|
|
||||||
unsigned offset = parameterOffset(index);
|
|
||||||
|
|
||||||
switch (parameterCodes[--parameterCodeIndex]) {
|
|
||||||
case BooleanField:
|
|
||||||
case ByteField:
|
|
||||||
case ShortField:
|
|
||||||
case CharField:
|
|
||||||
case IntField:
|
|
||||||
case LongField: {
|
|
||||||
if (gprIndex < GprCount - 2) {
|
|
||||||
Register reg = gpRegister(t, gprIndex + 2);
|
|
||||||
mov(rbp, offset, reg);
|
|
||||||
++ gprIndex;
|
|
||||||
} else {
|
|
||||||
push(rbp, offset);
|
|
||||||
stackFootprint += BytesPerWord;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case ObjectField: {
|
|
||||||
if (gprIndex < GprCount - 2) {
|
|
||||||
Register reg = gpRegister(t, gprIndex + 2);
|
|
||||||
mov(rbp, reg);
|
|
||||||
add(offset, reg);
|
|
||||||
++ gprIndex;
|
|
||||||
} else {
|
|
||||||
mov(rbp, rax);
|
|
||||||
add(offset, rax);
|
|
||||||
push(rax);
|
|
||||||
stackFootprint += BytesPerWord;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case FloatField:
|
|
||||||
case DoubleField: {
|
|
||||||
if (sseIndex < SseCount) {
|
|
||||||
SSERegister reg = sseRegister(t, sseIndex);
|
|
||||||
mov(rbp, offset, reg);
|
|
||||||
++ sseIndex;
|
|
||||||
} else {
|
|
||||||
push(rbp, offset);
|
|
||||||
stackFootprint += BytesPerWord;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
abort(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
++ index;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (methodFlags(t, method) & ACC_STATIC) {
|
|
||||||
mov(rbp, rsi);
|
|
||||||
sub(BytesPerWord, rsi); // push pointer to class pointer
|
|
||||||
} else {
|
|
||||||
unsigned offset = parameterOffset
|
|
||||||
(methodParameterFootprint(t, method) - 1);
|
|
||||||
mov(rbp, rsi);
|
|
||||||
add(offset, rsi); // push pointer to this pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
mov(rbp, FrameThread, rdi); // push thread pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
mov(reinterpret_cast<uintptr_t>(function), rax);
|
|
||||||
call(rax);
|
|
||||||
|
|
||||||
if (stackFootprint) {
|
|
||||||
add(stackFootprint, rsp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (methodReturnCode(t, method) == ObjectField) {
|
|
||||||
mov(rax, 0, rax);
|
|
||||||
}
|
|
||||||
|
|
||||||
mov(rbp, rsp);
|
|
||||||
pop(rbp);
|
|
||||||
ret();
|
|
||||||
}
|
|
||||||
|
|
||||||
void compileJava(MyThread* t, object method) {
|
|
||||||
PROTECT(t, method);
|
PROTECT(t, method);
|
||||||
|
|
||||||
object code = methodCode(t, method);
|
object code = methodCode(t, method);
|
||||||
@ -1947,6 +1891,36 @@ class Compiler: public Assembler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void compileNativeInvoker(MyThread* t) {
|
||||||
|
unsigned frameOffset = reinterpret_cast<uintptr_t>(&(t->frame))
|
||||||
|
- reinterpret_cast<uintptr_t>(t);
|
||||||
|
|
||||||
|
push(rbp);
|
||||||
|
mov(rsp, rbp);
|
||||||
|
|
||||||
|
mov(rbp, FrameThread, rax);
|
||||||
|
mov(rbp, rax, frameOffset); // set thread frame to current
|
||||||
|
|
||||||
|
if (BytesPerWord == 4) {
|
||||||
|
push(rbp, FrameMethod);
|
||||||
|
push(rbp, FrameThread);
|
||||||
|
} else {
|
||||||
|
mov(rbp, FrameMethod, rsi);
|
||||||
|
mov(rbp, FrameThread, rdi);
|
||||||
|
}
|
||||||
|
|
||||||
|
mov(reinterpret_cast<uintptr_t>(invokeNative), rax);
|
||||||
|
call(rax);
|
||||||
|
|
||||||
|
if (BytesPerWord == 4) {
|
||||||
|
add(BytesPerWord * 2, rsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
mov(rbp, rsp);
|
||||||
|
pop(rbp);
|
||||||
|
ret();
|
||||||
|
}
|
||||||
|
|
||||||
void compileStub(MyThread* t) {
|
void compileStub(MyThread* t) {
|
||||||
unsigned frameOffset = reinterpret_cast<uintptr_t>(&(t->frame))
|
unsigned frameOffset = reinterpret_cast<uintptr_t>(&(t->frame))
|
||||||
- reinterpret_cast<uintptr_t>(t);
|
- reinterpret_cast<uintptr_t>(t);
|
||||||
@ -2072,6 +2046,18 @@ compileStub(Thread* t)
|
|||||||
return stub;
|
return stub;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object
|
||||||
|
compileNativeInvoker(Thread* t)
|
||||||
|
{
|
||||||
|
Compiler c(t->m->system);
|
||||||
|
c.compileNativeInvoker(static_cast<MyThread*>(t));
|
||||||
|
|
||||||
|
object stub = makeCompiled(t, c.code.length(), false);
|
||||||
|
c.code.copyTo(&compiledBody(t, stub, 0));
|
||||||
|
|
||||||
|
return stub;
|
||||||
|
}
|
||||||
|
|
||||||
class ArgumentList {
|
class ArgumentList {
|
||||||
public:
|
public:
|
||||||
ArgumentList(Thread* t, uintptr_t* array, bool* objectMask, object this_,
|
ArgumentList(Thread* t, uintptr_t* array, bool* objectMask, object this_,
|
||||||
@ -2290,7 +2276,8 @@ class MyProcessor: public Processor {
|
|||||||
public:
|
public:
|
||||||
MyProcessor(System* s):
|
MyProcessor(System* s):
|
||||||
s(s),
|
s(s),
|
||||||
stub(0)
|
methodStub_(0),
|
||||||
|
nativeInvoker_(0)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual Thread*
|
virtual Thread*
|
||||||
@ -2302,10 +2289,19 @@ class MyProcessor: public Processor {
|
|||||||
virtual object
|
virtual object
|
||||||
methodStub(Thread* t)
|
methodStub(Thread* t)
|
||||||
{
|
{
|
||||||
if (stub == 0) {
|
if (methodStub_ == 0) {
|
||||||
stub = compileStub(t);
|
methodStub_ = compileStub(t);
|
||||||
}
|
}
|
||||||
return stub;
|
return methodStub_;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual object
|
||||||
|
nativeInvoker(Thread* t)
|
||||||
|
{
|
||||||
|
if (nativeInvoker_ == 0) {
|
||||||
|
nativeInvoker_ = compileNativeInvoker(t);
|
||||||
|
}
|
||||||
|
return nativeInvoker_;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual unsigned
|
virtual unsigned
|
||||||
@ -2501,7 +2497,8 @@ class MyProcessor: public Processor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
object stub;
|
object methodStub_;
|
||||||
|
object nativeInvoker_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -2847,6 +2847,12 @@ class MyProcessor: public Processor {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual object
|
||||||
|
nativeInvoker(vm::Thread*)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
virtual unsigned
|
virtual unsigned
|
||||||
parameterFootprint(vm::Thread*, const char* s, bool static_)
|
parameterFootprint(vm::Thread*, const char* s, bool static_)
|
||||||
{
|
{
|
||||||
|
@ -992,6 +992,13 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
unsigned parameterFootprint = t->m->processor->parameterFootprint
|
unsigned parameterFootprint = t->m->processor->parameterFootprint
|
||||||
(t, specString, flags & ACC_STATIC);
|
(t, specString, flags & ACC_STATIC);
|
||||||
|
|
||||||
|
object compiled;
|
||||||
|
if (flags & ACC_NATIVE) {
|
||||||
|
compiled = t->m->processor->nativeInvoker(t);
|
||||||
|
} else {
|
||||||
|
compiled = t->m->processor->methodStub(t);
|
||||||
|
}
|
||||||
|
|
||||||
object method = makeMethod(t,
|
object method = makeMethod(t,
|
||||||
0, // vm flags
|
0, // vm flags
|
||||||
returnCode,
|
returnCode,
|
||||||
@ -1003,7 +1010,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
arrayBody(t, pool, spec - 1),
|
arrayBody(t, pool, spec - 1),
|
||||||
class_,
|
class_,
|
||||||
code,
|
code,
|
||||||
t->m->processor->methodStub(t));
|
compiled);
|
||||||
PROTECT(t, method);
|
PROTECT(t, method);
|
||||||
|
|
||||||
if (flags & ACC_STATIC) {
|
if (flags & ACC_STATIC) {
|
||||||
|
@ -17,6 +17,9 @@ class Processor {
|
|||||||
virtual object
|
virtual object
|
||||||
methodStub(Thread* t) = 0;
|
methodStub(Thread* t) = 0;
|
||||||
|
|
||||||
|
virtual object
|
||||||
|
nativeInvoker(Thread* t) = 0;
|
||||||
|
|
||||||
virtual unsigned
|
virtual unsigned
|
||||||
parameterFootprint(Thread* t, const char* spec, bool static_) = 0;
|
parameterFootprint(Thread* t, const char* spec, bool static_) = 0;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user