2010-12-06 03:21:09 +00:00
|
|
|
/* Copyright (c) 2008-2010, Avian Contributors
|
2008-02-19 18:06:52 +00:00
|
|
|
|
|
|
|
Permission to use, copy, modify, and/or distribute this software
|
|
|
|
for any purpose with or without fee is hereby granted, provided
|
|
|
|
that the above copyright notice and this permission notice appear
|
|
|
|
in all copies.
|
|
|
|
|
|
|
|
There is NO WARRANTY for this software. See license.txt for
|
|
|
|
details. */
|
|
|
|
|
2008-01-28 17:27:02 +00:00
|
|
|
#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)
|
|
|
|
{
|
2009-05-03 20:57:11 +00:00
|
|
|
unsigned size = 0;
|
2008-01-28 17:27:02 +00:00
|
|
|
|
|
|
|
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
|
2009-05-03 20:57:11 +00:00
|
|
|
makeJNIName(Thread* t, const char* prefix, unsigned prefixLength, char* name,
|
|
|
|
object method, bool decorate)
|
2008-01-28 17:27:02 +00:00
|
|
|
{
|
2009-05-03 20:57:11 +00:00
|
|
|
memcpy(name, prefix, prefixLength);
|
|
|
|
name += prefixLength;
|
2008-01-28 17:27:02 +00:00
|
|
|
|
|
|
|
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*
|
2008-01-28 18:21:09 +00:00
|
|
|
resolveNativeMethod(Thread* t, const char* undecorated, const char* decorated)
|
2008-01-28 17:27:02 +00:00
|
|
|
{
|
2008-01-29 15:19:15 +00:00
|
|
|
for (System::Library* lib = t->m->libraries; lib; lib = lib->next()) {
|
2008-01-28 18:21:09 +00:00
|
|
|
void* p = lib->resolve(undecorated);
|
2008-01-28 17:27:02 +00:00
|
|
|
if (p) {
|
|
|
|
return p;
|
2008-01-28 18:21:09 +00:00
|
|
|
} else {
|
|
|
|
p = lib->resolve(decorated);
|
|
|
|
if (p) {
|
|
|
|
return p;
|
|
|
|
}
|
2008-01-28 17:27:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void*
|
2009-05-03 20:57:11 +00:00
|
|
|
resolveNativeMethod(Thread* t, object method, const char* prefix,
|
2009-05-31 20:41:07 +00:00
|
|
|
unsigned prefixLength, int footprint UNUSED)
|
2008-01-28 17:27:02 +00:00
|
|
|
{
|
2009-05-03 20:57:11 +00:00
|
|
|
unsigned undecoratedSize = prefixLength + jniNameLength(t, method, false);
|
2009-08-27 00:26:44 +00:00
|
|
|
// extra 6 is for code below:
|
|
|
|
RUNTIME_ARRAY(char, undecorated, undecoratedSize + 1 + 6);
|
|
|
|
makeJNIName(t, prefix, prefixLength, RUNTIME_ARRAY_BODY(undecorated) + 1,
|
|
|
|
method, false);
|
2008-01-28 18:21:09 +00:00
|
|
|
|
2009-05-03 20:57:11 +00:00
|
|
|
unsigned decoratedSize = prefixLength + jniNameLength(t, method, true);
|
2009-08-27 00:26:44 +00:00
|
|
|
// extra 6 is for code below:
|
|
|
|
RUNTIME_ARRAY(char, decorated, decoratedSize + 1 + 6);
|
|
|
|
makeJNIName(t, prefix, prefixLength, RUNTIME_ARRAY_BODY(decorated) + 1,
|
|
|
|
method, true);
|
2008-01-28 18:21:09 +00:00
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
void* p = resolveNativeMethod(t, RUNTIME_ARRAY_BODY(undecorated) + 1,
|
|
|
|
RUNTIME_ARRAY_BODY(decorated) + 1);
|
2008-01-28 17:27:02 +00:00
|
|
|
if (p) {
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
#ifdef PLATFORM_WINDOWS
|
2008-11-11 15:20:49 +00:00
|
|
|
// on windows, we also try the _%s@%d and %s@%d variants
|
2009-05-31 20:41:07 +00:00
|
|
|
if (footprint == -1) {
|
|
|
|
footprint = methodParameterFootprint(t, method) + 1;
|
|
|
|
if (methodFlags(t, method) & ACC_STATIC) {
|
|
|
|
++ footprint;
|
|
|
|
}
|
2008-01-28 17:27:02 +00:00
|
|
|
}
|
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
*RUNTIME_ARRAY_BODY(undecorated) = '_';
|
|
|
|
vm::snprintf(RUNTIME_ARRAY_BODY(undecorated) + undecoratedSize + 1, 5, "@%d",
|
|
|
|
footprint * BytesPerWord);
|
2008-01-28 18:21:09 +00:00
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
*RUNTIME_ARRAY_BODY(decorated) = '_';
|
|
|
|
vm::snprintf(RUNTIME_ARRAY_BODY(decorated) + decoratedSize + 1, 5, "@%d",
|
|
|
|
footprint * BytesPerWord);
|
2008-01-28 17:27:02 +00:00
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
p = resolveNativeMethod(t, RUNTIME_ARRAY_BODY(undecorated),
|
|
|
|
RUNTIME_ARRAY_BODY(decorated));
|
2008-01-28 17:27:02 +00:00
|
|
|
if (p) {
|
|
|
|
return p;
|
|
|
|
}
|
2008-11-11 15:20:49 +00:00
|
|
|
|
|
|
|
// one more try without the leading underscore
|
2009-08-27 00:26:44 +00:00
|
|
|
p = resolveNativeMethod(t, RUNTIME_ARRAY_BODY(undecorated) + 1,
|
|
|
|
RUNTIME_ARRAY_BODY(decorated) + 1);
|
2008-11-11 15:20:49 +00:00
|
|
|
if (p) {
|
|
|
|
return p;
|
|
|
|
}
|
2008-01-28 17:27:02 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-09-10 21:05:29 +00:00
|
|
|
object
|
2009-05-05 01:04:17 +00:00
|
|
|
resolveNativeMethod(Thread* t, object method)
|
2009-05-03 20:57:11 +00:00
|
|
|
{
|
2009-08-12 00:49:58 +00:00
|
|
|
void* p = ::resolveNativeMethod(t, method, "Avian_", 6, 3);
|
2009-05-03 20:57:11 +00:00
|
|
|
if (p) {
|
2010-09-10 21:05:29 +00:00
|
|
|
return makeNative(t, p, true);
|
2009-05-03 20:57:11 +00:00
|
|
|
}
|
|
|
|
|
2009-08-12 00:49:58 +00:00
|
|
|
p = ::resolveNativeMethod(t, method, "Java_", 5, -1);
|
2009-05-03 20:57:11 +00:00
|
|
|
if (p) {
|
2010-09-10 21:05:29 +00:00
|
|
|
return makeNative(t, p, false);
|
2009-05-03 20:57:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-09-27 23:12:08 +00:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace vm {
|
|
|
|
|
|
|
|
void
|
|
|
|
resolveNative(Thread* t, object method)
|
|
|
|
{
|
|
|
|
PROTECT(t, method);
|
|
|
|
|
|
|
|
assert(t, methodFlags(t, method) & ACC_NATIVE);
|
|
|
|
|
|
|
|
initClass(t, methodClass(t, method));
|
|
|
|
|
2010-11-26 19:41:31 +00:00
|
|
|
if (LIKELY(t->exception == 0)
|
|
|
|
and methodRuntimeDataNative(t, getMethodRuntimeData(t, method)) == 0)
|
|
|
|
{
|
2010-09-27 23:12:08 +00:00
|
|
|
object native = resolveNativeMethod(t, method);
|
|
|
|
if (UNLIKELY(native == 0)) {
|
|
|
|
object message = makeString
|
|
|
|
(t, "%s.%s%s",
|
|
|
|
&byteArrayBody(t, className(t, methodClass(t, method)), 0),
|
|
|
|
&byteArrayBody(t, methodName(t, method), 0),
|
|
|
|
&byteArrayBody(t, methodSpec(t, method), 0));
|
|
|
|
|
avoid inifinite recursion if java.lang.Object is missing; refactoring
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
2010-12-10 02:38:12 +00:00
|
|
|
t->exception = makeThrowable
|
2010-09-27 23:12:08 +00:00
|
|
|
(t, Machine::UnsatisfiedLinkErrorType, message);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-11-26 19:41:31 +00:00
|
|
|
PROTECT(t, native);
|
|
|
|
|
|
|
|
object runtimeData = getMethodRuntimeData(t, method);
|
|
|
|
|
|
|
|
// ensure other threads only see the methodRuntimeDataNative field
|
|
|
|
// populated once the object it points to has been populated:
|
2010-09-27 23:12:08 +00:00
|
|
|
storeStoreMemoryBarrier();
|
|
|
|
|
2010-11-26 19:41:31 +00:00
|
|
|
set(t, runtimeData, MethodRuntimeDataNative, native);
|
2010-09-27 23:12:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-28 17:27:02 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-21 22:36:13 +00:00
|
|
|
if (top < lineNumberTableLength(t, lnt)) {
|
|
|
|
return lineNumberLine(lineNumberTableBody(t, lnt, top));
|
|
|
|
} else {
|
|
|
|
return UnknownLine;
|
|
|
|
}
|
2008-01-28 17:27:02 +00:00
|
|
|
} else {
|
|
|
|
return UnknownLine;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace vm
|