refactor native method resolution to be simpler and more robust

This commit is contained in:
Joel Dice 2008-01-28 10:27:02 -07:00
parent de6a1ded92
commit 008ac07079
5 changed files with 266 additions and 253 deletions

View File

@ -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

View File

@ -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

View File

@ -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
View 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

View File

@ -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