mirror of
https://github.com/corda/corda.git
synced 2025-01-01 02:36:44 +00:00
refactor native method resolution to be simpler and more robust
This commit is contained in:
parent
de6a1ded92
commit
008ac07079
3
makefile
3
makefile
@ -161,7 +161,8 @@ vm-sources = \
|
||||
$(src)/heap.cpp \
|
||||
$(src)/$(process).cpp \
|
||||
$(src)/builtin.cpp \
|
||||
$(src)/jnienv.cpp
|
||||
$(src)/jnienv.cpp \
|
||||
$(src)/process.cpp
|
||||
|
||||
vm-asm-sources = $(src)/$(asm).S
|
||||
|
||||
|
@ -3917,9 +3917,7 @@ invokeNative2(MyThread* t, object method)
|
||||
initClass(t, methodClass(t, method));
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
if (objectClass(t, methodCode(t, method))
|
||||
== arrayBody(t, t->m->types, Machine::ByteArrayType))
|
||||
{
|
||||
if (methodCode(t, method) == 0) {
|
||||
void* function = resolveNativeMethod(t, method);
|
||||
if (UNLIKELY(function == 0)) {
|
||||
object message = makeString
|
||||
|
143
src/machine.cpp
143
src/machine.cpp
@ -511,121 +511,6 @@ makeByteArray(Thread* t, const char* format, va_list a)
|
||||
return s;
|
||||
}
|
||||
|
||||
unsigned
|
||||
mangledSize(int8_t c)
|
||||
{
|
||||
switch (c) {
|
||||
case '_':
|
||||
case ';':
|
||||
case '[':
|
||||
return 2;
|
||||
|
||||
case '$':
|
||||
return 6;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
mangle(int8_t c, int8_t* dst)
|
||||
{
|
||||
switch (c) {
|
||||
case '/':
|
||||
dst[0] = '_';
|
||||
return 1;
|
||||
|
||||
case '_':
|
||||
dst[0] = '_';
|
||||
dst[1] = '1';
|
||||
return 2;
|
||||
|
||||
case ';':
|
||||
dst[0] = '_';
|
||||
dst[1] = '2';
|
||||
return 2;
|
||||
|
||||
case '[':
|
||||
dst[0] = '_';
|
||||
dst[1] = '3';
|
||||
return 2;
|
||||
|
||||
case '$':
|
||||
memcpy(dst, "_00024", 6);
|
||||
return 6;
|
||||
|
||||
default:
|
||||
dst[0] = c;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
makeJNIName(Thread* t, object method, bool decorate)
|
||||
{
|
||||
unsigned size = 5;
|
||||
object className = ::className(t, methodClass(t, method));
|
||||
PROTECT(t, className);
|
||||
for (unsigned i = 0; i < byteArrayLength(t, className) - 1; ++i) {
|
||||
size += mangledSize(byteArrayBody(t, className, i));
|
||||
}
|
||||
|
||||
++ size;
|
||||
|
||||
object methodName = ::methodName(t, method);
|
||||
PROTECT(t, methodName);
|
||||
for (unsigned i = 0; i < byteArrayLength(t, methodName) - 1; ++i) {
|
||||
size += mangledSize(byteArrayBody(t, methodName, i));
|
||||
}
|
||||
|
||||
object methodSpec = ::methodSpec(t, method);
|
||||
PROTECT(t, methodSpec);
|
||||
if (decorate) {
|
||||
size += 2;
|
||||
for (unsigned i = 1; i < byteArrayLength(t, methodSpec) - 1
|
||||
and byteArrayBody(t, methodSpec, i) != ')'; ++i)
|
||||
{
|
||||
size += mangledSize(byteArrayBody(t, methodSpec, i));
|
||||
}
|
||||
}
|
||||
|
||||
object name = makeByteArray(t, size + 1, false);
|
||||
unsigned index = 0;
|
||||
|
||||
memcpy(&byteArrayBody(t, name, index), "Java_", 5);
|
||||
index += 5;
|
||||
|
||||
for (unsigned i = 0; i < byteArrayLength(t, className) - 1; ++i) {
|
||||
index += mangle(byteArrayBody(t, className, i),
|
||||
&byteArrayBody(t, name, index));
|
||||
}
|
||||
|
||||
byteArrayBody(t, name, index++) = '_';
|
||||
|
||||
for (unsigned i = 0; i < byteArrayLength(t, methodName) - 1; ++i) {
|
||||
index += mangle(byteArrayBody(t, methodName, i),
|
||||
&byteArrayBody(t, name, index));
|
||||
}
|
||||
|
||||
if (decorate) {
|
||||
byteArrayBody(t, name, index++) = '_';
|
||||
byteArrayBody(t, name, index++) = '_';
|
||||
for (unsigned i = 1; i < byteArrayLength(t, methodSpec) - 1
|
||||
and byteArrayBody(t, methodSpec, i) != ')'; ++i)
|
||||
{
|
||||
index += mangle(byteArrayBody(t, methodSpec, i),
|
||||
&byteArrayBody(t, name, index));
|
||||
}
|
||||
}
|
||||
|
||||
byteArrayBody(t, name, index++) = 0;
|
||||
|
||||
assert(t, index == size + 1);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
object
|
||||
parseUtf8(Thread* t, Stream& s, unsigned length)
|
||||
{
|
||||
@ -1180,9 +1065,6 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
object virtualMap = makeHashMap(t, 0, 0);
|
||||
PROTECT(t, virtualMap);
|
||||
|
||||
object nativeMap = makeHashMap(t, 0, 0);
|
||||
PROTECT(t, nativeMap);
|
||||
|
||||
unsigned virtualCount = 0;
|
||||
unsigned declaredVirtualCount = 0;
|
||||
|
||||
@ -1313,34 +1195,9 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & ACC_NATIVE) {
|
||||
object p = hashMapFindNode
|
||||
(t, nativeMap, methodName(t, method), byteArrayHash, byteArrayEqual);
|
||||
|
||||
if (p) {
|
||||
set(t, p, TripleSecond, method);
|
||||
} else {
|
||||
hashMapInsert(t, nativeMap, methodName(t, method), 0, byteArrayHash);
|
||||
}
|
||||
}
|
||||
|
||||
set(t, methodTable, ArrayBody + (i * BytesPerWord), method);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
object method = arrayBody(t, methodTable, i);
|
||||
|
||||
if (methodFlags(t, method) & ACC_NATIVE) {
|
||||
PROTECT(t, method);
|
||||
|
||||
object overloaded = hashMapFind
|
||||
(t, nativeMap, methodName(t, method), byteArrayHash, byteArrayEqual);
|
||||
|
||||
object jniName = makeJNIName(t, method, overloaded);
|
||||
set(t, method, MethodCode, jniName);
|
||||
}
|
||||
}
|
||||
|
||||
set(t, class_, ClassMethodTable, methodTable);
|
||||
}
|
||||
|
||||
|
250
src/process.cpp
Normal file
250
src/process.cpp
Normal file
@ -0,0 +1,250 @@
|
||||
#include "process.h"
|
||||
|
||||
using namespace vm;
|
||||
|
||||
namespace {
|
||||
|
||||
unsigned
|
||||
mangledSize(int8_t c)
|
||||
{
|
||||
switch (c) {
|
||||
case '_':
|
||||
case ';':
|
||||
case '[':
|
||||
return 2;
|
||||
|
||||
case '$':
|
||||
return 6;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
mangle(int8_t c, char* dst)
|
||||
{
|
||||
switch (c) {
|
||||
case '/':
|
||||
dst[0] = '_';
|
||||
return 1;
|
||||
|
||||
case '_':
|
||||
dst[0] = '_';
|
||||
dst[1] = '1';
|
||||
return 2;
|
||||
|
||||
case ';':
|
||||
dst[0] = '_';
|
||||
dst[1] = '2';
|
||||
return 2;
|
||||
|
||||
case '[':
|
||||
dst[0] = '_';
|
||||
dst[1] = '3';
|
||||
return 2;
|
||||
|
||||
case '$':
|
||||
memcpy(dst, "_00024", 6);
|
||||
return 6;
|
||||
|
||||
default:
|
||||
dst[0] = c;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
jniNameLength(Thread* t, object method, bool decorate)
|
||||
{
|
||||
unsigned size = 5;
|
||||
|
||||
object className = ::className(t, methodClass(t, method));
|
||||
for (unsigned i = 0; i < byteArrayLength(t, className) - 1; ++i) {
|
||||
size += mangledSize(byteArrayBody(t, className, i));
|
||||
}
|
||||
|
||||
++ size;
|
||||
|
||||
object methodName = ::methodName(t, method);
|
||||
for (unsigned i = 0; i < byteArrayLength(t, methodName) - 1; ++i) {
|
||||
size += mangledSize(byteArrayBody(t, methodName, i));
|
||||
}
|
||||
|
||||
if (decorate) {
|
||||
size += 2;
|
||||
|
||||
object methodSpec = ::methodSpec(t, method);
|
||||
for (unsigned i = 1; i < byteArrayLength(t, methodSpec) - 1
|
||||
and byteArrayBody(t, methodSpec, i) != ')'; ++i)
|
||||
{
|
||||
size += mangledSize(byteArrayBody(t, methodSpec, i));
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void
|
||||
makeJNIName(Thread* t, char* name, object method, bool decorate)
|
||||
{
|
||||
memcpy(name, "Java_", 5);
|
||||
name += 5;
|
||||
|
||||
object className = ::className(t, methodClass(t, method));
|
||||
for (unsigned i = 0; i < byteArrayLength(t, className) - 1; ++i) {
|
||||
name += mangle(byteArrayBody(t, className, i), name);
|
||||
}
|
||||
|
||||
*(name++) = '_';
|
||||
|
||||
object methodName = ::methodName(t, method);
|
||||
for (unsigned i = 0; i < byteArrayLength(t, methodName) - 1; ++i) {
|
||||
name += mangle(byteArrayBody(t, methodName, i), name);
|
||||
}
|
||||
|
||||
if (decorate) {
|
||||
*(name++) = '_';
|
||||
*(name++) = '_';
|
||||
|
||||
object methodSpec = ::methodSpec(t, method);
|
||||
for (unsigned i = 1; i < byteArrayLength(t, methodSpec) - 1
|
||||
and byteArrayBody(t, methodSpec, i) != ')'; ++i)
|
||||
{
|
||||
name += mangle(byteArrayBody(t, methodSpec, i), name);
|
||||
}
|
||||
}
|
||||
|
||||
*(name++) = 0;
|
||||
}
|
||||
|
||||
void*
|
||||
resolveNativeMethod(Thread* t, const char* name)
|
||||
{
|
||||
for (System::Library* lib = t->m->firstLibrary; lib; lib = lib->next()) {
|
||||
void* p = lib->resolve(name);
|
||||
if (p) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace vm {
|
||||
|
||||
void*
|
||||
resolveNativeMethod(Thread* t, object method, bool decorate)
|
||||
{
|
||||
unsigned size = jniNameLength(t, method, decorate);
|
||||
char name[size + 5]; // extra 5 is for code below
|
||||
makeJNIName(t, name, method, decorate);
|
||||
void* p = ::resolveNativeMethod(t, name);
|
||||
if (p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
#ifdef __MINGW32__
|
||||
// on windows, we also try the _%s@%d variant, since the SWT
|
||||
// libraries use it.
|
||||
unsigned footprint = methodParameterFootprint(t, method) + 1;
|
||||
if (methodFlags(t, method) & ACC_STATIC) {
|
||||
++ footprint;
|
||||
}
|
||||
|
||||
snprintf(name + size - 1, 5, "@%d", footprint * BytesPerWord);
|
||||
|
||||
p = resolveNativeMethod(t, reinterpret_cast<const int8_t*>(name));
|
||||
if (p) {
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ExceptionHandler*
|
||||
findExceptionHandler(Thread* t, object method, unsigned ip)
|
||||
{
|
||||
PROTECT(t, method);
|
||||
|
||||
object eht = codeExceptionHandlerTable(t, methodCode(t, method));
|
||||
|
||||
if (eht) {
|
||||
for (unsigned i = 0; i < exceptionHandlerTableLength(t, eht); ++i) {
|
||||
ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i);
|
||||
|
||||
if (ip - 1 >= exceptionHandlerStart(eh)
|
||||
and ip - 1 < exceptionHandlerEnd(eh))
|
||||
{
|
||||
object catchType = 0;
|
||||
if (exceptionHandlerCatchType(eh)) {
|
||||
object e = t->exception;
|
||||
t->exception = 0;
|
||||
PROTECT(t, e);
|
||||
|
||||
PROTECT(t, eht);
|
||||
catchType = resolveClassInPool
|
||||
(t, codePool(t, methodCode(t, method)),
|
||||
exceptionHandlerCatchType(eh) - 1);
|
||||
|
||||
if (catchType) {
|
||||
eh = exceptionHandlerTableBody(t, eht, i);
|
||||
t->exception = e;
|
||||
} else {
|
||||
// can't find what we're supposed to catch - move on.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (catchType == 0 or instanceOf(t, catchType, t->exception)) {
|
||||
return eh;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
findLineNumber(Thread* t, object method, unsigned ip)
|
||||
{
|
||||
if (methodFlags(t, method) & ACC_NATIVE) {
|
||||
return NativeLine;
|
||||
}
|
||||
|
||||
// our parameter indicates the instruction following the one we care
|
||||
// about, so we back up first:
|
||||
-- ip;
|
||||
|
||||
object code = methodCode(t, method);
|
||||
object lnt = codeLineNumberTable(t, code);
|
||||
if (lnt) {
|
||||
unsigned bottom = 0;
|
||||
unsigned top = lineNumberTableLength(t, lnt);
|
||||
for (unsigned span = top - bottom; span; span = top - bottom) {
|
||||
unsigned middle = bottom + (span / 2);
|
||||
LineNumber* ln = lineNumberTableBody(t, lnt, middle);
|
||||
|
||||
if (ip >= lineNumberIp(ln)
|
||||
and (middle + 1 == lineNumberTableLength(t, lnt)
|
||||
or ip < lineNumberIp(lineNumberTableBody(t, lnt, middle + 1))))
|
||||
{
|
||||
return lineNumberLine(ln);
|
||||
} else if (ip < lineNumberIp(ln)) {
|
||||
top = middle;
|
||||
} else if (ip > lineNumberIp(ln)) {
|
||||
bottom = middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
abort(t);
|
||||
} else {
|
||||
return UnknownLine;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace vm
|
119
src/process.h
119
src/process.h
@ -124,39 +124,22 @@ findMethod(Thread* t, object method, object class_)
|
||||
methodOffset(t, method));
|
||||
}
|
||||
|
||||
void*
|
||||
resolveNativeMethod(Thread* t, object method, bool decorate);
|
||||
|
||||
inline void*
|
||||
resolveNativeMethod(Thread* t, object method)
|
||||
{
|
||||
for (System::Library* lib = t->m->firstLibrary; lib; lib = lib->next()) {
|
||||
void* p = lib->resolve(reinterpret_cast<const char*>
|
||||
(&byteArrayBody(t, methodCode(t, method), 0)));
|
||||
if (methodCode(t, method)) {
|
||||
return pointerValue(t, methodCode(t, method));
|
||||
} else {
|
||||
void* p = resolveNativeMethod(t, method, false);
|
||||
if (p) {
|
||||
return p;
|
||||
} else {
|
||||
return resolveNativeMethod(t, method, true);
|
||||
}
|
||||
#ifdef __MINGW32__
|
||||
else {
|
||||
// on windows, we also try the _%s@%d variant, since the SWT
|
||||
// libraries use it.
|
||||
|
||||
unsigned footprint = methodParameterFootprint(t, method) + 1;
|
||||
if (methodFlags(t, method) & ACC_STATIC) {
|
||||
++ footprint;
|
||||
}
|
||||
|
||||
unsigned size = byteArrayLength(t, methodCode(t, method)) + 5;
|
||||
char buffer[size];
|
||||
snprintf(buffer, size, "_%s@%d",
|
||||
&byteArrayBody(t, methodCode(t, method), 0),
|
||||
footprint * BytesPerWord);
|
||||
|
||||
p = lib->resolve(buffer);
|
||||
if (p) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline object
|
||||
@ -206,87 +189,11 @@ populateMultiArray(Thread* t, object array, int32_t* counts,
|
||||
}
|
||||
}
|
||||
|
||||
inline ExceptionHandler*
|
||||
findExceptionHandler(Thread* t, object method, unsigned ip)
|
||||
{
|
||||
PROTECT(t, method);
|
||||
ExceptionHandler*
|
||||
findExceptionHandler(Thread* t, object method, unsigned ip);
|
||||
|
||||
object eht = codeExceptionHandlerTable(t, methodCode(t, method));
|
||||
|
||||
if (eht) {
|
||||
for (unsigned i = 0; i < exceptionHandlerTableLength(t, eht); ++i) {
|
||||
ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i);
|
||||
|
||||
if (ip - 1 >= exceptionHandlerStart(eh)
|
||||
and ip - 1 < exceptionHandlerEnd(eh))
|
||||
{
|
||||
object catchType = 0;
|
||||
if (exceptionHandlerCatchType(eh)) {
|
||||
object e = t->exception;
|
||||
t->exception = 0;
|
||||
PROTECT(t, e);
|
||||
|
||||
PROTECT(t, eht);
|
||||
catchType = resolveClassInPool
|
||||
(t, codePool(t, methodCode(t, method)),
|
||||
exceptionHandlerCatchType(eh) - 1);
|
||||
|
||||
if (catchType) {
|
||||
eh = exceptionHandlerTableBody(t, eht, i);
|
||||
t->exception = e;
|
||||
} else {
|
||||
// can't find what we're supposed to catch - move on.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (catchType == 0 or instanceOf(t, catchType, t->exception)) {
|
||||
return eh;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int
|
||||
findLineNumber(Thread* t, object method, unsigned ip)
|
||||
{
|
||||
if (methodFlags(t, method) & ACC_NATIVE) {
|
||||
return NativeLine;
|
||||
}
|
||||
|
||||
// our parameter indicates the instruction following the one we care
|
||||
// about, so we back up first:
|
||||
-- ip;
|
||||
|
||||
object code = methodCode(t, method);
|
||||
object lnt = codeLineNumberTable(t, code);
|
||||
if (lnt) {
|
||||
unsigned bottom = 0;
|
||||
unsigned top = lineNumberTableLength(t, lnt);
|
||||
for (unsigned span = top - bottom; span; span = top - bottom) {
|
||||
unsigned middle = bottom + (span / 2);
|
||||
LineNumber* ln = lineNumberTableBody(t, lnt, middle);
|
||||
|
||||
if (ip >= lineNumberIp(ln)
|
||||
and (middle + 1 == lineNumberTableLength(t, lnt)
|
||||
or ip < lineNumberIp(lineNumberTableBody(t, lnt, middle + 1))))
|
||||
{
|
||||
return lineNumberLine(ln);
|
||||
} else if (ip < lineNumberIp(ln)) {
|
||||
top = middle;
|
||||
} else if (ip > lineNumberIp(ln)) {
|
||||
bottom = middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
abort(t);
|
||||
} else {
|
||||
return UnknownLine;
|
||||
}
|
||||
}
|
||||
int
|
||||
findLineNumber(Thread* t, object method, unsigned ip);
|
||||
|
||||
} // namespace vm
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user