2015-03-13 18:52:59 +00:00
|
|
|
/* Copyright (c) 2008-2015, 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. */
|
|
|
|
|
2013-02-27 20:25:50 +00:00
|
|
|
#include "avian/process.h"
|
2008-01-28 17:27:02 +00:00
|
|
|
|
2013-02-20 05:56:05 +00:00
|
|
|
#include <avian/util/runtime-array.h>
|
2013-02-11 00:51:59 +00:00
|
|
|
|
2008-01-28 17:27:02 +00:00
|
|
|
using namespace vm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
unsigned mangledSize(int8_t c)
|
2008-01-28 17:27:02 +00:00
|
|
|
{
|
|
|
|
switch (c) {
|
|
|
|
case '_':
|
|
|
|
case ';':
|
|
|
|
case '[':
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
case '$':
|
|
|
|
return 6;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
unsigned mangle(int8_t c, char* dst)
|
2008-01-28 17:27:02 +00:00
|
|
|
{
|
|
|
|
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:
|
2014-06-29 05:37:24 +00:00
|
|
|
dst[0] = c;
|
2008-01-28 17:27:02 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
unsigned jniNameLength(Thread* t UNUSED, GcMethod* method, bool decorate)
|
2008-01-28 17:27:02 +00:00
|
|
|
{
|
2009-05-03 20:57:11 +00:00
|
|
|
unsigned size = 0;
|
2008-01-28 17:27:02 +00:00
|
|
|
|
2014-06-29 05:37:24 +00:00
|
|
|
GcByteArray* className = method->class_()->name();
|
|
|
|
for (unsigned i = 0; i < className->length() - 1; ++i) {
|
|
|
|
size += mangledSize(className->body()[i]);
|
2008-01-28 17:27:02 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
++size;
|
2008-01-28 17:27:02 +00:00
|
|
|
|
2014-06-29 05:37:24 +00:00
|
|
|
GcByteArray* methodName = method->name();
|
|
|
|
for (unsigned i = 0; i < methodName->length() - 1; ++i) {
|
|
|
|
size += mangledSize(methodName->body()[i]);
|
2008-01-28 17:27:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (decorate) {
|
|
|
|
size += 2;
|
|
|
|
|
2014-06-29 05:37:24 +00:00
|
|
|
GcByteArray* methodSpec = method->spec();
|
2014-07-11 15:47:57 +00:00
|
|
|
for (unsigned i = 1;
|
|
|
|
i < methodSpec->length() - 1 and methodSpec->body()[i] != ')';
|
|
|
|
++i) {
|
2014-06-29 05:37:24 +00:00
|
|
|
size += mangledSize(methodSpec->body()[i]);
|
2008-01-28 17:27:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void makeJNIName(Thread* t UNUSED,
|
|
|
|
const char* prefix,
|
|
|
|
unsigned prefixLength,
|
|
|
|
char* name,
|
|
|
|
GcMethod* 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
|
|
|
|
2014-06-29 05:37:24 +00:00
|
|
|
GcByteArray* className = method->class_()->name();
|
|
|
|
for (unsigned i = 0; i < className->length() - 1; ++i) {
|
|
|
|
name += mangle(className->body()[i], name);
|
2008-01-28 17:27:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*(name++) = '_';
|
|
|
|
|
2014-06-29 05:37:24 +00:00
|
|
|
GcByteArray* methodName = method->name();
|
|
|
|
for (unsigned i = 0; i < methodName->length() - 1; ++i) {
|
|
|
|
name += mangle(methodName->body()[i], name);
|
2008-01-28 17:27:02 +00:00
|
|
|
}
|
2014-07-11 15:50:18 +00:00
|
|
|
|
2008-01-28 17:27:02 +00:00
|
|
|
if (decorate) {
|
|
|
|
*(name++) = '_';
|
|
|
|
*(name++) = '_';
|
|
|
|
|
2014-06-29 05:37:24 +00:00
|
|
|
GcByteArray* methodSpec = method->spec();
|
2014-07-11 15:47:57 +00:00
|
|
|
for (unsigned i = 1;
|
|
|
|
i < methodSpec->length() - 1 and methodSpec->body()[i] != ')';
|
|
|
|
++i) {
|
2014-06-29 05:37:24 +00:00
|
|
|
name += mangle(methodSpec->body()[i], name);
|
2008-01-28 17:27:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*(name++) = 0;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void* 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;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void* resolveNativeMethod(Thread* t,
|
|
|
|
GcMethod* method,
|
|
|
|
const char* prefix,
|
|
|
|
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:
|
2010-12-27 22:55:23 +00:00
|
|
|
THREAD_RUNTIME_ARRAY(t, char, undecorated, undecoratedSize + 1 + 6);
|
2014-07-11 15:50:18 +00:00
|
|
|
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:
|
2010-12-27 22:55:23 +00:00
|
|
|
THREAD_RUNTIME_ARRAY(t, char, decorated, decoratedSize + 1 + 6);
|
2014-07-11 15:50:18 +00:00
|
|
|
makeJNIName(
|
|
|
|
t, prefix, prefixLength, RUNTIME_ARRAY_BODY(decorated) + 1, method, true);
|
2008-01-28 18:21:09 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void* p = resolveNativeMethod(t,
|
|
|
|
RUNTIME_ARRAY_BODY(undecorated) + 1,
|
2009-08-27 00:26:44 +00:00
|
|
|
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) {
|
2014-07-14 14:57:03 +00:00
|
|
|
footprint = method->parameterFootprint() + 1;
|
2014-05-29 04:17:25 +00:00
|
|
|
if (method->flags() & ACC_STATIC) {
|
2014-07-11 15:50:18 +00:00
|
|
|
++footprint;
|
2009-05-31 20:41:07 +00:00
|
|
|
}
|
2008-01-28 17:27:02 +00:00
|
|
|
}
|
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
*RUNTIME_ARRAY_BODY(undecorated) = '_';
|
2014-07-11 15:50:18 +00:00
|
|
|
vm::snprintf(RUNTIME_ARRAY_BODY(undecorated) + undecoratedSize + 1,
|
|
|
|
5,
|
|
|
|
"@%d",
|
2009-08-27 00:26:44 +00:00
|
|
|
footprint * BytesPerWord);
|
2008-01-28 18:21:09 +00:00
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
*RUNTIME_ARRAY_BODY(decorated) = '_';
|
2014-07-11 15:50:18 +00:00
|
|
|
vm::snprintf(RUNTIME_ARRAY_BODY(decorated) + decoratedSize + 1,
|
|
|
|
5,
|
|
|
|
"@%d",
|
2009-08-27 00:26:44 +00:00
|
|
|
footprint * BytesPerWord);
|
2008-01-28 17:27:02 +00:00
|
|
|
|
2014-07-11 15:50:18 +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
|
2014-07-11 15:50:18 +00:00
|
|
|
p = resolveNativeMethod(t,
|
|
|
|
RUNTIME_ARRAY_BODY(undecorated) + 1,
|
2009-08-27 00:26:44 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcNative* resolveNativeMethod(Thread* t, GcMethod* method)
|
2009-05-03 20:57:11 +00:00
|
|
|
{
|
2011-01-21 23:14:21 +00:00
|
|
|
void* p = resolveNativeMethod(t, method, "Avian_", 6, 3);
|
2009-05-03 20:57:11 +00:00
|
|
|
if (p) {
|
2014-06-26 02:17:27 +00:00
|
|
|
return makeNative(t, p, true);
|
2009-05-03 20:57:11 +00:00
|
|
|
}
|
|
|
|
|
2011-01-21 23:14:21 +00:00
|
|
|
p = resolveNativeMethod(t, method, "Java_", 5, -1);
|
2009-05-03 20:57:11 +00:00
|
|
|
if (p) {
|
2014-06-26 02:17:27 +00:00
|
|
|
return makeNative(t, p, false);
|
2009-05-03 20:57:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
} // namespace
|
2010-09-27 23:12:08 +00:00
|
|
|
|
|
|
|
namespace vm {
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void resolveNative(Thread* t, GcMethod* method)
|
2010-09-27 23:12:08 +00:00
|
|
|
{
|
|
|
|
PROTECT(t, method);
|
|
|
|
|
2014-06-04 01:52:01 +00:00
|
|
|
assertT(t, method->flags() & ACC_NATIVE);
|
2010-09-27 23:12:08 +00:00
|
|
|
|
2014-06-21 04:16:33 +00:00
|
|
|
initClass(t, method->class_());
|
2010-09-27 23:12:08 +00:00
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
if (getMethodRuntimeData(t, method)->native() == 0) {
|
2014-06-26 02:17:27 +00:00
|
|
|
GcNative* native = resolveNativeMethod(t, method);
|
2010-09-27 23:12:08 +00:00
|
|
|
if (UNLIKELY(native == 0)) {
|
2014-07-11 15:47:57 +00:00
|
|
|
throwNew(t,
|
|
|
|
GcUnsatisfiedLinkError::Type,
|
|
|
|
"%s.%s%s",
|
2014-06-21 04:16:33 +00:00
|
|
|
method->class_()->name()->body().begin(),
|
|
|
|
method->name()->body().begin(),
|
|
|
|
method->spec()->body().begin());
|
2010-09-27 23:12:08 +00:00
|
|
|
}
|
|
|
|
|
2010-11-26 19:41:31 +00:00
|
|
|
PROTECT(t, native);
|
|
|
|
|
2014-06-29 05:37:24 +00:00
|
|
|
GcMethodRuntimeData* runtimeData = getMethodRuntimeData(t, method);
|
2010-11-26 19:41:31 +00:00
|
|
|
|
|
|
|
// 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();
|
|
|
|
|
2014-06-26 02:17:27 +00:00
|
|
|
runtimeData->setNative(t, native);
|
|
|
|
}
|
2010-09-27 23:12:08 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
int findLineNumber(Thread* t UNUSED, GcMethod* method, unsigned ip)
|
2008-01-28 17:27:02 +00:00
|
|
|
{
|
2014-05-29 04:17:25 +00:00
|
|
|
if (method->flags() & ACC_NATIVE) {
|
2008-01-28 17:27:02 +00:00
|
|
|
return NativeLine;
|
|
|
|
}
|
|
|
|
|
|
|
|
// our parameter indicates the instruction following the one we care
|
|
|
|
// about, so we back up first:
|
2014-07-11 15:50:18 +00:00
|
|
|
--ip;
|
2008-01-28 17:27:02 +00:00
|
|
|
|
2014-06-29 05:37:24 +00:00
|
|
|
GcLineNumberTable* lnt = method->code()->lineNumberTable();
|
2008-01-28 17:27:02 +00:00
|
|
|
if (lnt) {
|
|
|
|
unsigned bottom = 0;
|
2014-06-29 05:37:24 +00:00
|
|
|
unsigned top = lnt->length();
|
2008-01-28 17:27:02 +00:00
|
|
|
for (unsigned span = top - bottom; span; span = top - bottom) {
|
|
|
|
unsigned middle = bottom + (span / 2);
|
2014-06-29 05:37:24 +00:00
|
|
|
uint64_t ln = lnt->body()[middle];
|
2008-01-28 17:27:02 +00:00
|
|
|
|
|
|
|
if (ip >= lineNumberIp(ln)
|
2014-06-29 05:37:24 +00:00
|
|
|
and (middle + 1 == lnt->length()
|
2014-07-11 15:47:57 +00:00
|
|
|
or ip < lineNumberIp(lnt->body()[middle + 1]))) {
|
2008-01-28 17:27:02 +00:00
|
|
|
return lineNumberLine(ln);
|
|
|
|
} else if (ip < lineNumberIp(ln)) {
|
|
|
|
top = middle;
|
|
|
|
} else if (ip > lineNumberIp(ln)) {
|
|
|
|
bottom = middle + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-29 05:37:24 +00:00
|
|
|
if (top < lnt->length()) {
|
|
|
|
return lineNumberLine(lnt->body()[top]);
|
2008-04-21 22:36:13 +00:00
|
|
|
} else {
|
|
|
|
return UnknownLine;
|
|
|
|
}
|
2008-01-28 17:27:02 +00:00
|
|
|
} else {
|
|
|
|
return UnknownLine;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
} // namespace vm
|