mirror of
https://github.com/corda/corda.git
synced 2025-01-09 06:23:04 +00:00
3787 lines
101 KiB
C++
3787 lines
101 KiB
C++
/* Copyright (c) 2008-2014, Avian Contributors
|
|
|
|
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. */
|
|
|
|
#include "avian/jnienv.h"
|
|
#include "avian/machine.h"
|
|
#include "avian/util.h"
|
|
#include "avian/processor.h"
|
|
#include "avian/constants.h"
|
|
|
|
#include <avian/util/runtime-array.h>
|
|
|
|
using namespace vm;
|
|
|
|
namespace {
|
|
|
|
namespace local {
|
|
|
|
jint JNICALL AttachCurrentThread(Machine* m, Thread** t, void*)
|
|
{
|
|
*t = static_cast<Thread*>(m->localThread->get());
|
|
if (*t == 0) {
|
|
*t = attachThread(m, false);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
jint JNICALL AttachCurrentThreadAsDaemon(Machine* m, Thread** t, void*)
|
|
{
|
|
*t = static_cast<Thread*>(m->localThread->get());
|
|
if (*t == 0) {
|
|
*t = attachThread(m, true);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
jint JNICALL DetachCurrentThread(Machine* m)
|
|
{
|
|
Thread* t = static_cast<Thread*>(m->localThread->get());
|
|
if (t) {
|
|
// todo: detaching the root thread seems to cause stability
|
|
// problems which I haven't yet had a chance to investigate
|
|
// thoroughly. Meanwhile, we just ignore requests to detach it,
|
|
// which leaks a bit of memory but should be harmless otherwise.
|
|
if (m->rootThread != t) {
|
|
m->localThread->set(0);
|
|
|
|
ACQUIRE_RAW(t, t->m->stateLock);
|
|
|
|
enter(t, Thread::ActiveState);
|
|
|
|
t->javaThread->peer() = 0;
|
|
|
|
enter(t, Thread::ZombieState);
|
|
|
|
t->state = Thread::JoinedState;
|
|
}
|
|
|
|
return 0;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
uint64_t destroyJavaVM(Thread* t, uintptr_t*)
|
|
{
|
|
// wait for other non-daemon threads to exit
|
|
{
|
|
ACQUIRE(t, t->m->stateLock);
|
|
while (t->m->liveCount - t->m->daemonCount > 1) {
|
|
t->m->stateLock->wait(t->systemThread, 0);
|
|
}
|
|
}
|
|
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
t->m->classpath->shutDown(t);
|
|
}
|
|
|
|
// wait again in case the Classpath::shutDown process started new
|
|
// threads:
|
|
{
|
|
ACQUIRE(t, t->m->stateLock);
|
|
while (t->m->liveCount - t->m->daemonCount > 1) {
|
|
t->m->stateLock->wait(t->systemThread, 0);
|
|
}
|
|
|
|
enter(t, Thread::ExclusiveState);
|
|
}
|
|
|
|
shutDown(t);
|
|
|
|
return 1;
|
|
}
|
|
|
|
jint JNICALL DestroyJavaVM(Machine* m)
|
|
{
|
|
Thread* t;
|
|
AttachCurrentThread(m, &t, 0);
|
|
|
|
if (runRaw(t, destroyJavaVM, 0)) {
|
|
t->exit();
|
|
return 0;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
jint JNICALL GetEnv(Machine* m, Thread** t, jint version)
|
|
{
|
|
*t = static_cast<Thread*>(m->localThread->get());
|
|
if (*t) {
|
|
if (version <= JNI_VERSION_1_6) {
|
|
return AVIAN_JNI_OK;
|
|
} else {
|
|
return AVIAN_JNI_EVERSION;
|
|
}
|
|
} else {
|
|
return AVIAN_JNI_EDETACHED;
|
|
}
|
|
}
|
|
|
|
jint JNICALL GetVersion(Thread* t)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
return JNI_VERSION_1_6;
|
|
}
|
|
|
|
jsize JNICALL GetStringLength(Thread* t, jstring s)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
return (*s)->length(t);
|
|
}
|
|
|
|
const jchar* JNICALL GetStringChars(Thread* t, jstring s, jboolean* isCopy)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
jchar* chars = static_cast<jchar*>(
|
|
t->m->heap->allocate(((*s)->length(t) + 1) * sizeof(jchar)));
|
|
stringChars(t, *s, chars);
|
|
|
|
if (isCopy)
|
|
*isCopy = true;
|
|
return chars;
|
|
}
|
|
|
|
void JNICALL ReleaseStringChars(Thread* t, jstring s, const jchar* chars)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
t->m->heap->free(chars, ((*s)->length(t) + 1) * sizeof(jchar));
|
|
}
|
|
|
|
void JNICALL
|
|
GetStringRegion(Thread* t, jstring s, jsize start, jsize length, jchar* dst)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
stringChars(t, *s, start, length, dst);
|
|
}
|
|
|
|
const jchar* JNICALL GetStringCritical(Thread* t, jstring s, jboolean* isCopy)
|
|
{
|
|
if (t->criticalLevel == 0) {
|
|
enter(t, Thread::ActiveState);
|
|
}
|
|
|
|
++t->criticalLevel;
|
|
|
|
if (isCopy) {
|
|
*isCopy = true;
|
|
}
|
|
|
|
object data = (*s)->data();
|
|
if (objectClass(t, data) == type(t, GcByteArray::Type)) {
|
|
return GetStringChars(t, s, isCopy);
|
|
} else {
|
|
return &cast<GcCharArray>(t, data)->body()[(*s)->offset(t)];
|
|
}
|
|
}
|
|
|
|
void JNICALL ReleaseStringCritical(Thread* t, jstring s, const jchar* chars)
|
|
{
|
|
if (objectClass(t, (*s)->data()) == type(t, GcByteArray::Type)) {
|
|
ReleaseStringChars(t, s, chars);
|
|
}
|
|
|
|
if ((--t->criticalLevel) == 0) {
|
|
enter(t, Thread::IdleState);
|
|
}
|
|
}
|
|
|
|
jsize JNICALL GetStringUTFLength(Thread* t, jstring s)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
return stringUTFLength(t, *s);
|
|
}
|
|
|
|
const char* JNICALL GetStringUTFChars(Thread* t, jstring s, jboolean* isCopy)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
int length = stringUTFLength(t, *s);
|
|
char* chars = static_cast<char*>(t->m->heap->allocate(length + 1));
|
|
stringUTFChars(t, *s, chars, length);
|
|
|
|
if (isCopy)
|
|
*isCopy = true;
|
|
return chars;
|
|
}
|
|
|
|
void JNICALL ReleaseStringUTFChars(Thread* t, jstring s, const char* chars)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
t->m->heap->free(chars, stringUTFLength(t, *s) + 1);
|
|
}
|
|
|
|
void JNICALL GetStringUTFRegion(Thread* t,
|
|
jstring s,
|
|
jsize start,
|
|
jsize length,
|
|
char* dst)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
stringUTFChars(
|
|
t, *s, start, length, dst, stringUTFLength(t, *s, start, length));
|
|
}
|
|
|
|
jsize JNICALL GetArrayLength(Thread* t, jarray array)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
return fieldAtOffset<uintptr_t>(*array, BytesPerWord);
|
|
}
|
|
|
|
uint64_t newString(Thread* t, uintptr_t* arguments)
|
|
{
|
|
const jchar* chars = reinterpret_cast<const jchar*>(arguments[0]);
|
|
jsize size = arguments[1];
|
|
|
|
GcCharArray* a = makeCharArray(t, size);
|
|
if (size) {
|
|
memcpy(a->body().begin(), chars, size * sizeof(jchar));
|
|
}
|
|
|
|
return reinterpret_cast<uint64_t>(
|
|
makeLocalReference(t, t->m->classpath->makeString(t, a, 0, size)));
|
|
}
|
|
|
|
jstring JNICALL NewString(Thread* t, const jchar* chars, jsize size)
|
|
{
|
|
if (chars == 0)
|
|
return 0;
|
|
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(chars), static_cast<uintptr_t>(size)};
|
|
|
|
return reinterpret_cast<jstring>(run(t, newString, arguments));
|
|
}
|
|
|
|
uint64_t newStringUTF(Thread* t, uintptr_t* arguments)
|
|
{
|
|
const char* chars = reinterpret_cast<const char*>(arguments[0]);
|
|
|
|
object array = parseUtf8(t, chars, strlen(chars));
|
|
|
|
return reinterpret_cast<uint64_t>(makeLocalReference(
|
|
t,
|
|
t->m->classpath->makeString(
|
|
t, array, 0, fieldAtOffset<uintptr_t>(array, BytesPerWord) - 1)));
|
|
}
|
|
|
|
jstring JNICALL NewStringUTF(Thread* t, const char* chars)
|
|
{
|
|
if (chars == 0)
|
|
return 0;
|
|
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(chars)};
|
|
|
|
return reinterpret_cast<jstring>(run(t, newStringUTF, arguments));
|
|
}
|
|
|
|
void replace(int a, int b, const char* in, int8_t* out)
|
|
{
|
|
while (*in) {
|
|
*out = (*in == a ? b : *in);
|
|
++in;
|
|
++out;
|
|
}
|
|
*out = 0;
|
|
}
|
|
|
|
uint64_t defineClass(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject loader = reinterpret_cast<jobject>(arguments[0]);
|
|
const uint8_t* buffer = reinterpret_cast<const uint8_t*>(arguments[1]);
|
|
jsize length = arguments[2];
|
|
|
|
return reinterpret_cast<uint64_t>(makeLocalReference(
|
|
t,
|
|
getJClass(
|
|
t,
|
|
cast<GcClass>(t,
|
|
defineClass(t,
|
|
loader ? cast<GcClassLoader>(t, *loader)
|
|
: roots(t)->bootLoader(),
|
|
buffer,
|
|
length)))));
|
|
}
|
|
|
|
jclass JNICALL DefineClass(Thread* t,
|
|
const char*,
|
|
jobject loader,
|
|
const jbyte* buffer,
|
|
jsize length)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(loader),
|
|
reinterpret_cast<uintptr_t>(buffer),
|
|
static_cast<uintptr_t>(length)};
|
|
|
|
return reinterpret_cast<jclass>(run(t, defineClass, arguments));
|
|
}
|
|
|
|
uint64_t findClass(Thread* t, uintptr_t* arguments)
|
|
{
|
|
const char* name = reinterpret_cast<const char*>(arguments[0]);
|
|
|
|
GcByteArray* n = makeByteArray(t, strlen(name) + 1);
|
|
replace('.', '/', name, n->body().begin());
|
|
|
|
GcMethod* caller = getCaller(t, 0);
|
|
|
|
GcClass* c
|
|
= resolveClass(t,
|
|
caller ? t->m->classpath->libraryClassLoader(t, caller)
|
|
: roots(t)->appLoader(),
|
|
n);
|
|
|
|
if (t->m->classpath->mayInitClasses()) {
|
|
PROTECT(t, c);
|
|
|
|
initClass(t, c);
|
|
}
|
|
|
|
return reinterpret_cast<uint64_t>(makeLocalReference(t, getJClass(t, c)));
|
|
}
|
|
|
|
jclass JNICALL FindClass(Thread* t, const char* name)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(name)};
|
|
|
|
return reinterpret_cast<jclass>(run(t, findClass, arguments));
|
|
}
|
|
|
|
uint64_t throwNew(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jclass c = reinterpret_cast<jclass>(arguments[0]);
|
|
const char* message = reinterpret_cast<const char*>(arguments[1]);
|
|
|
|
GcString* m = 0;
|
|
PROTECT(t, m);
|
|
|
|
if (message) {
|
|
m = makeString(t, "%s", message);
|
|
}
|
|
|
|
object trace = makeTrace(t);
|
|
PROTECT(t, trace);
|
|
|
|
t->exception = cast<GcThrowable>(t, make(t, (*c)->vmClass()));
|
|
t->exception->setMessage(t, m);
|
|
t->exception->setTrace(t, trace);
|
|
|
|
return 1;
|
|
}
|
|
|
|
jint JNICALL ThrowNew(Thread* t, jclass c, const char* message)
|
|
{
|
|
if (t->exception) {
|
|
return -1;
|
|
}
|
|
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(c), reinterpret_cast<uintptr_t>(message)};
|
|
|
|
return run(t, throwNew, arguments) ? 0 : -1;
|
|
}
|
|
|
|
jint JNICALL Throw(Thread* t, jthrowable throwable)
|
|
{
|
|
if (t->exception) {
|
|
return -1;
|
|
}
|
|
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
t->exception = *throwable;
|
|
|
|
return 0;
|
|
}
|
|
|
|
jobject JNICALL NewLocalRef(Thread* t, jobject o)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
return makeLocalReference(t, *o);
|
|
}
|
|
|
|
void JNICALL DeleteLocalRef(Thread* t, jobject r)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
disposeLocalReference(t, r);
|
|
}
|
|
|
|
jboolean JNICALL ExceptionCheck(Thread* t)
|
|
{
|
|
return t->exception != 0;
|
|
}
|
|
|
|
uint64_t getObjectClass(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
|
|
return reinterpret_cast<uint64_t>(
|
|
makeLocalReference(t, getJClass(t, objectClass(t, *o))));
|
|
}
|
|
|
|
jclass JNICALL GetObjectClass(Thread* t, jobject o)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o)};
|
|
|
|
return reinterpret_cast<jclass>(run(t, getObjectClass, arguments));
|
|
}
|
|
|
|
uint64_t getSuperclass(Thread* t, uintptr_t* arguments)
|
|
{
|
|
GcClass* class_ = (*reinterpret_cast<jclass>(arguments[0]))->vmClass();
|
|
if (class_->flags() & ACC_INTERFACE) {
|
|
return 0;
|
|
} else {
|
|
GcClass* super = class_->super();
|
|
return super ? reinterpret_cast<uint64_t>(
|
|
makeLocalReference(t, getJClass(t, super)))
|
|
: 0;
|
|
}
|
|
}
|
|
|
|
jclass JNICALL GetSuperclass(Thread* t, jclass c)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(c)};
|
|
|
|
return reinterpret_cast<jclass>(run(t, getSuperclass, arguments));
|
|
}
|
|
|
|
uint64_t isInstanceOf(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
jclass c = reinterpret_cast<jclass>(arguments[1]);
|
|
|
|
return instanceOf(t, (*c)->vmClass(), *o);
|
|
}
|
|
|
|
jboolean JNICALL IsInstanceOf(Thread* t, jobject o, jclass c)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(o), reinterpret_cast<uintptr_t>(c)};
|
|
|
|
return run(t, isInstanceOf, arguments);
|
|
}
|
|
|
|
uint64_t isAssignableFrom(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jclass b = reinterpret_cast<jclass>(arguments[0]);
|
|
jclass a = reinterpret_cast<jclass>(arguments[1]);
|
|
|
|
return isAssignableFrom(t, (*a)->vmClass(), (*b)->vmClass());
|
|
}
|
|
|
|
jboolean JNICALL IsAssignableFrom(Thread* t, jclass b, jclass a)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(b), reinterpret_cast<uintptr_t>(a)};
|
|
|
|
return run(t, isAssignableFrom, arguments);
|
|
}
|
|
|
|
GcMethod* findMethod(Thread* t, jclass c, const char* name, const char* spec)
|
|
{
|
|
GcByteArray* n = makeByteArray(t, "%s", name);
|
|
PROTECT(t, n);
|
|
|
|
GcByteArray* s = makeByteArray(t, "%s", spec);
|
|
return vm::findMethod(t, (*c)->vmClass(), n, s);
|
|
}
|
|
|
|
jint methodID(Thread* t, GcMethod* method)
|
|
{
|
|
int id = method->nativeID();
|
|
|
|
loadMemoryBarrier();
|
|
|
|
if (id == 0) {
|
|
PROTECT(t, method);
|
|
|
|
ACQUIRE(t, t->m->referenceLock);
|
|
|
|
if (method->nativeID() == 0) {
|
|
GcVector* v = vectorAppend(t, roots(t)->jNIMethodTable(), method);
|
|
// sequence point, for gc (don't recombine statements)
|
|
roots(t)->setJNIMethodTable(t, v);
|
|
|
|
storeStoreMemoryBarrier();
|
|
|
|
method->nativeID() = roots(t)->jNIMethodTable()->size();
|
|
}
|
|
}
|
|
|
|
return method->nativeID();
|
|
}
|
|
|
|
uint64_t getMethodID(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jclass c = reinterpret_cast<jclass>(arguments[0]);
|
|
const char* name = reinterpret_cast<const char*>(arguments[1]);
|
|
const char* spec = reinterpret_cast<const char*>(arguments[2]);
|
|
|
|
GcMethod* method = findMethod(t, c, name, spec);
|
|
|
|
assertT(t, (method->flags() & ACC_STATIC) == 0);
|
|
|
|
return methodID(t, method);
|
|
}
|
|
|
|
jmethodID JNICALL
|
|
GetMethodID(Thread* t, jclass c, const char* name, const char* spec)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(c),
|
|
reinterpret_cast<uintptr_t>(name),
|
|
reinterpret_cast<uintptr_t>(spec)};
|
|
|
|
return run(t, getMethodID, arguments);
|
|
}
|
|
|
|
uint64_t getStaticMethodID(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jclass c = reinterpret_cast<jclass>(arguments[0]);
|
|
const char* name = reinterpret_cast<const char*>(arguments[1]);
|
|
const char* spec = reinterpret_cast<const char*>(arguments[2]);
|
|
|
|
GcMethod* method = findMethod(t, c, name, spec);
|
|
|
|
assertT(t, method->flags() & ACC_STATIC);
|
|
|
|
return methodID(t, method);
|
|
}
|
|
|
|
jmethodID JNICALL
|
|
GetStaticMethodID(Thread* t, jclass c, const char* name, const char* spec)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(c),
|
|
reinterpret_cast<uintptr_t>(name),
|
|
reinterpret_cast<uintptr_t>(spec)};
|
|
|
|
return run(t, getStaticMethodID, arguments);
|
|
}
|
|
|
|
GcMethod* getMethod(Thread* t, jmethodID m)
|
|
{
|
|
assertT(t, m);
|
|
|
|
GcMethod* method
|
|
= cast<GcMethod>(t, roots(t)->jNIMethodTable()->body()[m - 1]);
|
|
|
|
assertT(t, (method->flags() & ACC_STATIC) == 0);
|
|
|
|
return method;
|
|
}
|
|
|
|
uint64_t newObjectV(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jclass c = reinterpret_cast<jclass>(arguments[0]);
|
|
jmethodID m = arguments[1];
|
|
va_list* a = reinterpret_cast<va_list*>(arguments[2]);
|
|
|
|
object o = make(t, (*c)->vmClass());
|
|
PROTECT(t, o);
|
|
|
|
t->m->processor->invokeList(t, getMethod(t, m), o, true, *a);
|
|
|
|
return reinterpret_cast<uint64_t>(makeLocalReference(t, o));
|
|
}
|
|
|
|
jobject JNICALL NewObjectV(Thread* t, jclass c, jmethodID m, va_list a)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(c),
|
|
m,
|
|
reinterpret_cast<uintptr_t>(VA_LIST(a))};
|
|
|
|
return reinterpret_cast<jobject>(run(t, newObjectV, arguments));
|
|
}
|
|
|
|
jobject JNICALL NewObject(Thread* t, jclass c, jmethodID m, ...)
|
|
{
|
|
va_list a;
|
|
va_start(a, m);
|
|
|
|
jobject r = NewObjectV(t, c, m, a);
|
|
|
|
va_end(a);
|
|
|
|
return r;
|
|
}
|
|
|
|
uint64_t newObjectA(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jclass c = reinterpret_cast<jclass>(arguments[0]);
|
|
jmethodID m = arguments[1];
|
|
const jvalue* a = reinterpret_cast<const jvalue*>(arguments[2]);
|
|
|
|
object o = make(t, (*c)->vmClass());
|
|
PROTECT(t, o);
|
|
|
|
t->m->processor->invokeArray(t, getMethod(t, m), o, a);
|
|
|
|
return reinterpret_cast<uint64_t>(makeLocalReference(t, o));
|
|
}
|
|
|
|
jobject JNICALL NewObjectA(Thread* t, jclass c, jmethodID m, const jvalue* a)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(c), m, reinterpret_cast<uintptr_t>(a)};
|
|
|
|
return reinterpret_cast<jobject>(run(t, newObjectA, arguments));
|
|
}
|
|
|
|
uint64_t callObjectMethodV(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
jmethodID m = arguments[1];
|
|
va_list* a = reinterpret_cast<va_list*>(arguments[2]);
|
|
|
|
return reinterpret_cast<uint64_t>(makeLocalReference(
|
|
t, t->m->processor->invokeList(t, getMethod(t, m), *o, true, *a)));
|
|
}
|
|
|
|
jobject JNICALL CallObjectMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o),
|
|
m,
|
|
reinterpret_cast<uintptr_t>(VA_LIST(a))};
|
|
|
|
return reinterpret_cast<jobject>(run(t, callObjectMethodV, arguments));
|
|
}
|
|
|
|
jobject JNICALL CallObjectMethod(Thread* t, jobject o, jmethodID m, ...)
|
|
{
|
|
va_list a;
|
|
va_start(a, m);
|
|
|
|
jobject r = CallObjectMethodV(t, o, m, a);
|
|
|
|
va_end(a);
|
|
|
|
return r;
|
|
}
|
|
|
|
uint64_t callObjectMethodA(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
jmethodID m = arguments[1];
|
|
const jvalue* a = reinterpret_cast<const jvalue*>(arguments[2]);
|
|
|
|
return reinterpret_cast<uint64_t>(makeLocalReference(
|
|
t, t->m->processor->invokeArray(t, getMethod(t, m), *o, a)));
|
|
}
|
|
|
|
jobject JNICALL
|
|
CallObjectMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(o), m, reinterpret_cast<uintptr_t>(a)};
|
|
|
|
return reinterpret_cast<jobject>(run(t, callObjectMethodA, arguments));
|
|
}
|
|
|
|
uint64_t callIntMethodV(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
jmethodID m = arguments[1];
|
|
va_list* a = reinterpret_cast<va_list*>(arguments[2]);
|
|
|
|
return cast<GcInt>(
|
|
t, t->m->processor->invokeList(t, getMethod(t, m), *o, true, *a))
|
|
->value();
|
|
}
|
|
|
|
jboolean JNICALL
|
|
CallBooleanMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o),
|
|
m,
|
|
reinterpret_cast<uintptr_t>(VA_LIST(a))};
|
|
|
|
return run(t, callIntMethodV, arguments) != 0;
|
|
}
|
|
|
|
jboolean JNICALL CallBooleanMethod(Thread* t, jobject o, jmethodID m, ...)
|
|
{
|
|
va_list a;
|
|
va_start(a, m);
|
|
|
|
jboolean r = CallBooleanMethodV(t, o, m, a);
|
|
|
|
va_end(a);
|
|
|
|
return r;
|
|
}
|
|
|
|
uint64_t callIntMethodA(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
jmethodID m = arguments[1];
|
|
const jvalue* a = reinterpret_cast<const jvalue*>(arguments[2]);
|
|
|
|
return cast<GcInt>(t, t->m->processor->invokeArray(t, getMethod(t, m), *o, a))
|
|
->value();
|
|
}
|
|
|
|
jboolean JNICALL
|
|
CallBooleanMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(o), m, reinterpret_cast<uintptr_t>(a)};
|
|
|
|
return run(t, callIntMethodA, arguments) != 0;
|
|
}
|
|
|
|
jbyte JNICALL CallByteMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o),
|
|
m,
|
|
reinterpret_cast<uintptr_t>(VA_LIST(a))};
|
|
|
|
return run(t, callIntMethodV, arguments);
|
|
}
|
|
|
|
jbyte JNICALL CallByteMethod(Thread* t, jobject o, jmethodID m, ...)
|
|
{
|
|
va_list a;
|
|
va_start(a, m);
|
|
|
|
jbyte r = CallByteMethodV(t, o, m, a);
|
|
|
|
va_end(a);
|
|
|
|
return r;
|
|
}
|
|
|
|
jbyte JNICALL
|
|
CallByteMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(o), m, reinterpret_cast<uintptr_t>(a)};
|
|
|
|
return run(t, callIntMethodA, arguments);
|
|
}
|
|
|
|
jchar JNICALL CallCharMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o),
|
|
m,
|
|
reinterpret_cast<uintptr_t>(VA_LIST(a))};
|
|
|
|
return run(t, callIntMethodV, arguments);
|
|
}
|
|
|
|
jchar JNICALL CallCharMethod(Thread* t, jobject o, jmethodID m, ...)
|
|
{
|
|
va_list a;
|
|
va_start(a, m);
|
|
|
|
jchar r = CallCharMethodV(t, o, m, a);
|
|
|
|
va_end(a);
|
|
|
|
return r;
|
|
}
|
|
|
|
jchar JNICALL
|
|
CallCharMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(o), m, reinterpret_cast<uintptr_t>(a)};
|
|
|
|
return run(t, callIntMethodA, arguments);
|
|
}
|
|
|
|
jshort JNICALL CallShortMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o),
|
|
m,
|
|
reinterpret_cast<uintptr_t>(VA_LIST(a))};
|
|
|
|
return run(t, callIntMethodV, arguments);
|
|
}
|
|
|
|
jshort JNICALL CallShortMethod(Thread* t, jobject o, jmethodID m, ...)
|
|
{
|
|
va_list a;
|
|
va_start(a, m);
|
|
|
|
jshort r = CallShortMethodV(t, o, m, a);
|
|
|
|
va_end(a);
|
|
|
|
return r;
|
|
}
|
|
|
|
jshort JNICALL
|
|
CallShortMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(o), m, reinterpret_cast<uintptr_t>(a)};
|
|
|
|
return run(t, callIntMethodA, arguments);
|
|
}
|
|
|
|
jint JNICALL CallIntMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o),
|
|
m,
|
|
reinterpret_cast<uintptr_t>(VA_LIST(a))};
|
|
|
|
return run(t, callIntMethodV, arguments);
|
|
}
|
|
|
|
jint JNICALL CallIntMethod(Thread* t, jobject o, jmethodID m, ...)
|
|
{
|
|
va_list a;
|
|
va_start(a, m);
|
|
|
|
jint r = CallIntMethodV(t, o, m, a);
|
|
|
|
va_end(a);
|
|
|
|
return r;
|
|
}
|
|
|
|
jint JNICALL CallIntMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(o), m, reinterpret_cast<uintptr_t>(a)};
|
|
|
|
return run(t, callIntMethodA, arguments);
|
|
}
|
|
|
|
uint64_t callLongMethodV(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
jmethodID m = arguments[1];
|
|
va_list* a = reinterpret_cast<va_list*>(arguments[2]);
|
|
|
|
return cast<GcLong>(
|
|
t, t->m->processor->invokeList(t, getMethod(t, m), *o, true, *a))
|
|
->value();
|
|
}
|
|
|
|
jlong JNICALL CallLongMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o),
|
|
m,
|
|
reinterpret_cast<uintptr_t>(VA_LIST(a))};
|
|
|
|
return run(t, callLongMethodV, arguments);
|
|
}
|
|
|
|
jlong JNICALL CallLongMethod(Thread* t, jobject o, jmethodID m, ...)
|
|
{
|
|
va_list a;
|
|
va_start(a, m);
|
|
|
|
jlong r = CallLongMethodV(t, o, m, a);
|
|
|
|
va_end(a);
|
|
|
|
return r;
|
|
}
|
|
|
|
uint64_t callLongMethodA(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
jmethodID m = arguments[1];
|
|
const jvalue* a = reinterpret_cast<const jvalue*>(arguments[2]);
|
|
|
|
return cast<GcLong>(t,
|
|
t->m->processor->invokeArray(t, getMethod(t, m), *o, a))
|
|
->value();
|
|
}
|
|
|
|
jlong JNICALL
|
|
CallLongMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(o), m, reinterpret_cast<uintptr_t>(a)};
|
|
|
|
return run(t, callLongMethodA, arguments);
|
|
}
|
|
|
|
jfloat JNICALL CallFloatMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o),
|
|
m,
|
|
reinterpret_cast<uintptr_t>(VA_LIST(a))};
|
|
|
|
return bitsToFloat(run(t, callIntMethodV, arguments));
|
|
}
|
|
|
|
jfloat JNICALL CallFloatMethod(Thread* t, jobject o, jmethodID m, ...)
|
|
{
|
|
va_list a;
|
|
va_start(a, m);
|
|
|
|
jfloat r = CallFloatMethodV(t, o, m, a);
|
|
|
|
va_end(a);
|
|
|
|
return r;
|
|
}
|
|
|
|
jfloat JNICALL
|
|
CallFloatMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(o), m, reinterpret_cast<uintptr_t>(a)};
|
|
|
|
return bitsToFloat(run(t, callIntMethodA, arguments));
|
|
}
|
|
|
|
jdouble JNICALL CallDoubleMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o),
|
|
m,
|
|
reinterpret_cast<uintptr_t>(VA_LIST(a))};
|
|
|
|
return bitsToDouble(run(t, callLongMethodV, arguments));
|
|
}
|
|
|
|
jdouble JNICALL CallDoubleMethod(Thread* t, jobject o, jmethodID m, ...)
|
|
{
|
|
va_list a;
|
|
va_start(a, m);
|
|
|
|
jdouble r = CallDoubleMethodV(t, o, m, a);
|
|
|
|
va_end(a);
|
|
|
|
return r;
|
|
}
|
|
|
|
jdouble JNICALL
|
|
CallDoubleMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(o), m, reinterpret_cast<uintptr_t>(a)};
|
|
|
|
return bitsToDouble(run(t, callLongMethodA, arguments));
|
|
}
|
|
|
|
uint64_t callVoidMethodV(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
jmethodID m = arguments[1];
|
|
va_list* a = reinterpret_cast<va_list*>(arguments[2]);
|
|
|
|
t->m->processor->invokeList(t, getMethod(t, m), *o, true, *a);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void JNICALL CallVoidMethodV(Thread* t, jobject o, jmethodID m, va_list a)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o),
|
|
m,
|
|
reinterpret_cast<uintptr_t>(VA_LIST(a))};
|
|
|
|
run(t, callVoidMethodV, arguments);
|
|
}
|
|
|
|
void JNICALL CallVoidMethod(Thread* t, jobject o, jmethodID m, ...)
|
|
{
|
|
va_list a;
|
|
va_start(a, m);
|
|
|
|
CallVoidMethodV(t, o, m, a);
|
|
|
|
va_end(a);
|
|
}
|
|
|
|
uint64_t callVoidMethodA(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
jmethodID m = arguments[1];
|
|
const jvalue* a = reinterpret_cast<const jvalue*>(arguments[2]);
|
|
|
|
t->m->processor->invokeArray(t, getMethod(t, m), *o, a);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void JNICALL CallVoidMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(o), m, reinterpret_cast<uintptr_t>(a)};
|
|
|
|
run(t, callVoidMethodA, arguments);
|
|
}
|
|
|
|
GcMethod* getStaticMethod(Thread* t, jmethodID m)
|
|
{
|
|
assertT(t, m);
|
|
|
|
GcMethod* method
|
|
= cast<GcMethod>(t, roots(t)->jNIMethodTable()->body()[m - 1]);
|
|
|
|
assertT(t, method->flags() & ACC_STATIC);
|
|
|
|
return method;
|
|
}
|
|
|
|
uint64_t callStaticObjectMethodV(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jmethodID m = arguments[0];
|
|
va_list* a = reinterpret_cast<va_list*>(arguments[1]);
|
|
|
|
return reinterpret_cast<uint64_t>(makeLocalReference(
|
|
t, t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, *a)));
|
|
}
|
|
|
|
jobject JNICALL
|
|
CallStaticObjectMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
|
{
|
|
uintptr_t arguments[] = {m, reinterpret_cast<uintptr_t>(VA_LIST(a))};
|
|
|
|
return reinterpret_cast<jobject>(run(t, callStaticObjectMethodV, arguments));
|
|
}
|
|
|
|
jobject JNICALL CallStaticObjectMethod(Thread* t, jclass c, jmethodID m, ...)
|
|
{
|
|
va_list a;
|
|
va_start(a, m);
|
|
|
|
jobject r = CallStaticObjectMethodV(t, c, m, a);
|
|
|
|
va_end(a);
|
|
|
|
return r;
|
|
}
|
|
|
|
uint64_t callStaticObjectMethodA(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jmethodID m = arguments[0];
|
|
const jvalue* a = reinterpret_cast<const jvalue*>(arguments[1]);
|
|
|
|
return reinterpret_cast<uint64_t>(makeLocalReference(
|
|
t, t->m->processor->invokeArray(t, getStaticMethod(t, m), 0, a)));
|
|
}
|
|
|
|
jobject JNICALL
|
|
CallStaticObjectMethodA(Thread* t, jclass, jmethodID m, const jvalue* a)
|
|
{
|
|
uintptr_t arguments[] = {m, reinterpret_cast<uintptr_t>(a)};
|
|
|
|
return reinterpret_cast<jobject>(run(t, callStaticObjectMethodA, arguments));
|
|
}
|
|
|
|
uint64_t callStaticIntMethodV(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jmethodID m = arguments[0];
|
|
va_list* a = reinterpret_cast<va_list*>(arguments[1]);
|
|
|
|
return cast<GcInt>(t,
|
|
t->m->processor->invokeList(
|
|
t, getStaticMethod(t, m), 0, true, *a))->value();
|
|
}
|
|
|
|
jboolean JNICALL
|
|
CallStaticBooleanMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
|
{
|
|
uintptr_t arguments[] = {m, reinterpret_cast<uintptr_t>(VA_LIST(a))};
|
|
|
|
return run(t, callStaticIntMethodV, arguments) != 0;
|
|
}
|
|
|
|
jboolean JNICALL CallStaticBooleanMethod(Thread* t, jclass c, jmethodID m, ...)
|
|
{
|
|
va_list a;
|
|
va_start(a, m);
|
|
|
|
jboolean r = CallStaticBooleanMethodV(t, c, m, a);
|
|
|
|
va_end(a);
|
|
|
|
return r;
|
|
}
|
|
|
|
uint64_t callStaticIntMethodA(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jmethodID m = arguments[0];
|
|
const jvalue* a = reinterpret_cast<const jvalue*>(arguments[1]);
|
|
|
|
return cast<GcInt>(
|
|
t, t->m->processor->invokeArray(t, getStaticMethod(t, m), 0, a))
|
|
->value();
|
|
}
|
|
|
|
jboolean JNICALL
|
|
CallStaticBooleanMethodA(Thread* t, jclass, jmethodID m, const jvalue* a)
|
|
{
|
|
uintptr_t arguments[] = {m, reinterpret_cast<uintptr_t>(a)};
|
|
|
|
return run(t, callStaticIntMethodA, arguments) != 0;
|
|
}
|
|
|
|
jbyte JNICALL CallStaticByteMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
|
{
|
|
uintptr_t arguments[] = {m, reinterpret_cast<uintptr_t>(VA_LIST(a))};
|
|
|
|
return run(t, callStaticIntMethodV, arguments);
|
|
}
|
|
|
|
jbyte JNICALL CallStaticByteMethod(Thread* t, jclass c, jmethodID m, ...)
|
|
{
|
|
va_list a;
|
|
va_start(a, m);
|
|
|
|
jbyte r = CallStaticByteMethodV(t, c, m, a);
|
|
|
|
va_end(a);
|
|
|
|
return r;
|
|
}
|
|
|
|
jbyte JNICALL
|
|
CallStaticByteMethodA(Thread* t, jclass, jmethodID m, const jvalue* a)
|
|
{
|
|
uintptr_t arguments[] = {m, reinterpret_cast<uintptr_t>(a)};
|
|
|
|
return run(t, callStaticIntMethodA, arguments);
|
|
}
|
|
|
|
jchar JNICALL CallStaticCharMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
|
{
|
|
uintptr_t arguments[] = {m, reinterpret_cast<uintptr_t>(VA_LIST(a))};
|
|
|
|
return run(t, callStaticIntMethodV, arguments);
|
|
}
|
|
|
|
jchar JNICALL CallStaticCharMethod(Thread* t, jclass c, jmethodID m, ...)
|
|
{
|
|
va_list a;
|
|
va_start(a, m);
|
|
|
|
jchar r = CallStaticCharMethodV(t, c, m, a);
|
|
|
|
va_end(a);
|
|
|
|
return r;
|
|
}
|
|
|
|
jchar JNICALL
|
|
CallStaticCharMethodA(Thread* t, jclass, jmethodID m, const jvalue* a)
|
|
{
|
|
uintptr_t arguments[] = {m, reinterpret_cast<uintptr_t>(a)};
|
|
|
|
return run(t, callStaticIntMethodA, arguments);
|
|
}
|
|
|
|
jshort JNICALL CallStaticShortMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
|
{
|
|
uintptr_t arguments[] = {m, reinterpret_cast<uintptr_t>(VA_LIST(a))};
|
|
|
|
return run(t, callStaticIntMethodV, arguments);
|
|
}
|
|
|
|
jshort JNICALL CallStaticShortMethod(Thread* t, jclass c, jmethodID m, ...)
|
|
{
|
|
va_list a;
|
|
va_start(a, m);
|
|
|
|
jshort r = CallStaticShortMethodV(t, c, m, a);
|
|
|
|
va_end(a);
|
|
|
|
return r;
|
|
}
|
|
|
|
jshort JNICALL
|
|
CallStaticShortMethodA(Thread* t, jclass, jmethodID m, const jvalue* a)
|
|
{
|
|
uintptr_t arguments[] = {m, reinterpret_cast<uintptr_t>(a)};
|
|
|
|
return run(t, callStaticIntMethodA, arguments);
|
|
}
|
|
|
|
jint JNICALL CallStaticIntMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
|
{
|
|
uintptr_t arguments[] = {m, reinterpret_cast<uintptr_t>(VA_LIST(a))};
|
|
|
|
return run(t, callStaticIntMethodV, arguments);
|
|
}
|
|
|
|
jint JNICALL CallStaticIntMethod(Thread* t, jclass c, jmethodID m, ...)
|
|
{
|
|
va_list a;
|
|
va_start(a, m);
|
|
|
|
jint r = CallStaticIntMethodV(t, c, m, a);
|
|
|
|
va_end(a);
|
|
|
|
return r;
|
|
}
|
|
|
|
jint JNICALL
|
|
CallStaticIntMethodA(Thread* t, jclass, jmethodID m, const jvalue* a)
|
|
{
|
|
uintptr_t arguments[] = {m, reinterpret_cast<uintptr_t>(a)};
|
|
|
|
return run(t, callStaticIntMethodA, arguments);
|
|
}
|
|
|
|
uint64_t callStaticLongMethodV(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jmethodID m = arguments[0];
|
|
va_list* a = reinterpret_cast<va_list*>(arguments[1]);
|
|
|
|
return cast<GcLong>(t,
|
|
t->m->processor->invokeList(
|
|
t, getStaticMethod(t, m), 0, true, *a))->value();
|
|
}
|
|
|
|
jlong JNICALL CallStaticLongMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
|
{
|
|
uintptr_t arguments[] = {m, reinterpret_cast<uintptr_t>(VA_LIST(a))};
|
|
|
|
return run(t, callStaticLongMethodV, arguments);
|
|
}
|
|
|
|
jlong JNICALL CallStaticLongMethod(Thread* t, jclass c, jmethodID m, ...)
|
|
{
|
|
va_list a;
|
|
va_start(a, m);
|
|
|
|
jlong r = CallStaticLongMethodV(t, c, m, a);
|
|
|
|
va_end(a);
|
|
|
|
return r;
|
|
}
|
|
|
|
uint64_t callStaticLongMethodA(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jmethodID m = arguments[0];
|
|
const jvalue* a = reinterpret_cast<const jvalue*>(arguments[1]);
|
|
|
|
return cast<GcLong>(
|
|
t, t->m->processor->invokeArray(t, getStaticMethod(t, m), 0, a))
|
|
->value();
|
|
}
|
|
|
|
jlong JNICALL
|
|
CallStaticLongMethodA(Thread* t, jclass, jmethodID m, const jvalue* a)
|
|
{
|
|
uintptr_t arguments[] = {m, reinterpret_cast<uintptr_t>(a)};
|
|
|
|
return run(t, callStaticLongMethodA, arguments);
|
|
}
|
|
|
|
jfloat JNICALL CallStaticFloatMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
|
{
|
|
uintptr_t arguments[] = {m, reinterpret_cast<uintptr_t>(VA_LIST(a))};
|
|
|
|
return bitsToFloat(run(t, callStaticIntMethodV, arguments));
|
|
}
|
|
|
|
jfloat JNICALL CallStaticFloatMethod(Thread* t, jclass c, jmethodID m, ...)
|
|
{
|
|
va_list a;
|
|
va_start(a, m);
|
|
|
|
jfloat r = CallStaticFloatMethodV(t, c, m, a);
|
|
|
|
va_end(a);
|
|
|
|
return r;
|
|
}
|
|
|
|
jfloat JNICALL
|
|
CallStaticFloatMethodA(Thread* t, jclass, jmethodID m, const jvalue* a)
|
|
{
|
|
uintptr_t arguments[] = {m, reinterpret_cast<uintptr_t>(a)};
|
|
|
|
return bitsToFloat(run(t, callStaticIntMethodA, arguments));
|
|
}
|
|
|
|
jdouble JNICALL
|
|
CallStaticDoubleMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
|
{
|
|
uintptr_t arguments[] = {m, reinterpret_cast<uintptr_t>(VA_LIST(a))};
|
|
|
|
return bitsToDouble(run(t, callStaticLongMethodV, arguments));
|
|
}
|
|
|
|
jdouble JNICALL CallStaticDoubleMethod(Thread* t, jclass c, jmethodID m, ...)
|
|
{
|
|
va_list a;
|
|
va_start(a, m);
|
|
|
|
jdouble r = CallStaticDoubleMethodV(t, c, m, a);
|
|
|
|
va_end(a);
|
|
|
|
return r;
|
|
}
|
|
|
|
jdouble JNICALL
|
|
CallStaticDoubleMethodA(Thread* t, jclass, jmethodID m, const jvalue* a)
|
|
{
|
|
uintptr_t arguments[] = {m, reinterpret_cast<uintptr_t>(a)};
|
|
|
|
return bitsToDouble(run(t, callStaticLongMethodA, arguments));
|
|
}
|
|
|
|
uint64_t callStaticVoidMethodV(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jmethodID m = arguments[0];
|
|
va_list* a = reinterpret_cast<va_list*>(arguments[1]);
|
|
|
|
t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, *a);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void JNICALL CallStaticVoidMethodV(Thread* t, jclass, jmethodID m, va_list a)
|
|
{
|
|
uintptr_t arguments[] = {m, reinterpret_cast<uintptr_t>(VA_LIST(a))};
|
|
|
|
run(t, callStaticVoidMethodV, arguments);
|
|
}
|
|
|
|
void JNICALL CallStaticVoidMethod(Thread* t, jclass c, jmethodID m, ...)
|
|
{
|
|
va_list a;
|
|
va_start(a, m);
|
|
|
|
CallStaticVoidMethodV(t, c, m, a);
|
|
|
|
va_end(a);
|
|
}
|
|
|
|
uint64_t callStaticVoidMethodA(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jmethodID m = arguments[0];
|
|
const jvalue* a = reinterpret_cast<const jvalue*>(arguments[1]);
|
|
|
|
t->m->processor->invokeArray(t, getStaticMethod(t, m), 0, a);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void JNICALL
|
|
CallStaticVoidMethodA(Thread* t, jclass, jmethodID m, const jvalue* a)
|
|
{
|
|
uintptr_t arguments[] = {m, reinterpret_cast<uintptr_t>(a)};
|
|
|
|
run(t, callStaticVoidMethodA, arguments);
|
|
}
|
|
|
|
jint fieldID(Thread* t, GcField* field)
|
|
{
|
|
int id = field->nativeID();
|
|
|
|
loadMemoryBarrier();
|
|
|
|
if (id == 0) {
|
|
PROTECT(t, field);
|
|
|
|
ACQUIRE(t, t->m->referenceLock);
|
|
|
|
if (field->nativeID() == 0) {
|
|
GcVector* v = vectorAppend(t, roots(t)->jNIFieldTable(), field);
|
|
// sequence point, for gc (don't recombine statements)
|
|
roots(t)->setJNIFieldTable(t, v);
|
|
|
|
storeStoreMemoryBarrier();
|
|
|
|
field->nativeID() = roots(t)->jNIFieldTable()->size();
|
|
}
|
|
}
|
|
|
|
return field->nativeID();
|
|
}
|
|
|
|
uint64_t getFieldID(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jclass c = reinterpret_cast<jclass>(arguments[0]);
|
|
const char* name = reinterpret_cast<const char*>(arguments[1]);
|
|
const char* spec = reinterpret_cast<const char*>(arguments[2]);
|
|
|
|
return fieldID(t, resolveField(t, (*c)->vmClass(), name, spec));
|
|
}
|
|
|
|
jfieldID JNICALL
|
|
GetFieldID(Thread* t, jclass c, const char* name, const char* spec)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(c),
|
|
reinterpret_cast<uintptr_t>(name),
|
|
reinterpret_cast<uintptr_t>(spec)};
|
|
|
|
return run(t, getFieldID, arguments);
|
|
}
|
|
|
|
jfieldID JNICALL
|
|
GetStaticFieldID(Thread* t, jclass c, const char* name, const char* spec)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(c),
|
|
reinterpret_cast<uintptr_t>(name),
|
|
reinterpret_cast<uintptr_t>(spec)};
|
|
|
|
return run(t, getFieldID, arguments);
|
|
}
|
|
|
|
GcField* getField(Thread* t, jfieldID f)
|
|
{
|
|
assertT(t, f);
|
|
|
|
GcField* field = cast<GcField>(t, roots(t)->jNIFieldTable()->body()[f - 1]);
|
|
|
|
assertT(t, (field->flags() & ACC_STATIC) == 0);
|
|
|
|
return field;
|
|
}
|
|
|
|
uint64_t getObjectField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
GcField* field = getField(t, arguments[1]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_READ(t, field);
|
|
|
|
return reinterpret_cast<uintptr_t>(
|
|
makeLocalReference(t, fieldAtOffset<object>(*o, field->offset())));
|
|
}
|
|
|
|
jobject JNICALL GetObjectField(Thread* t, jobject o, jfieldID field)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o), field};
|
|
|
|
return reinterpret_cast<jobject>(run(t, getObjectField, arguments));
|
|
}
|
|
|
|
uint64_t getBooleanField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
GcField* field = getField(t, arguments[1]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_READ(t, field);
|
|
|
|
return fieldAtOffset<jboolean>(*o, field->offset());
|
|
}
|
|
|
|
jboolean JNICALL GetBooleanField(Thread* t, jobject o, jfieldID field)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o), field};
|
|
|
|
return run(t, getBooleanField, arguments);
|
|
}
|
|
|
|
uint64_t getByteField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
GcField* field = getField(t, arguments[1]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_READ(t, field);
|
|
|
|
return fieldAtOffset<jbyte>(*o, field->offset());
|
|
}
|
|
|
|
jbyte JNICALL GetByteField(Thread* t, jobject o, jfieldID field)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o), field};
|
|
|
|
return run(t, getByteField, arguments);
|
|
}
|
|
|
|
uint64_t getCharField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
GcField* field = getField(t, arguments[1]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_READ(t, field);
|
|
|
|
return fieldAtOffset<jchar>(*o, field->offset());
|
|
}
|
|
|
|
jchar JNICALL GetCharField(Thread* t, jobject o, jfieldID field)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o), field};
|
|
|
|
return run(t, getCharField, arguments);
|
|
}
|
|
|
|
uint64_t getShortField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
GcField* field = getField(t, arguments[1]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_READ(t, field);
|
|
|
|
return fieldAtOffset<jshort>(*o, field->offset());
|
|
}
|
|
|
|
jshort JNICALL GetShortField(Thread* t, jobject o, jfieldID field)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o), field};
|
|
|
|
return run(t, getShortField, arguments);
|
|
}
|
|
|
|
uint64_t getIntField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
GcField* field = getField(t, arguments[1]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_READ(t, field);
|
|
|
|
return fieldAtOffset<jint>(*o, field->offset());
|
|
}
|
|
|
|
jint JNICALL GetIntField(Thread* t, jobject o, jfieldID field)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o), field};
|
|
|
|
return run(t, getIntField, arguments);
|
|
}
|
|
|
|
uint64_t getLongField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
GcField* field = getField(t, arguments[1]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_READ(t, field);
|
|
|
|
return fieldAtOffset<jlong>(*o, field->offset());
|
|
}
|
|
|
|
jlong JNICALL GetLongField(Thread* t, jobject o, jfieldID field)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o), field};
|
|
|
|
return run(t, getLongField, arguments);
|
|
}
|
|
|
|
uint64_t getFloatField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
GcField* field = getField(t, arguments[1]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_READ(t, field);
|
|
|
|
return floatToBits(fieldAtOffset<jfloat>(*o, field->offset()));
|
|
}
|
|
|
|
jfloat JNICALL GetFloatField(Thread* t, jobject o, jfieldID field)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o), field};
|
|
|
|
return bitsToFloat(run(t, getFloatField, arguments));
|
|
}
|
|
|
|
uint64_t getDoubleField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
GcField* field = getField(t, arguments[1]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_READ(t, field);
|
|
|
|
return doubleToBits(fieldAtOffset<jdouble>(*o, field->offset()));
|
|
}
|
|
|
|
jdouble JNICALL GetDoubleField(Thread* t, jobject o, jfieldID field)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o), field};
|
|
|
|
return bitsToDouble(run(t, getDoubleField, arguments));
|
|
}
|
|
|
|
uint64_t setObjectField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
GcField* field = getField(t, arguments[1]);
|
|
jobject v = reinterpret_cast<jobject>(arguments[2]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_WRITE(t, field);
|
|
|
|
setField(t, *o, field->offset(), (v ? *v : 0));
|
|
|
|
return 1;
|
|
}
|
|
|
|
void JNICALL SetObjectField(Thread* t, jobject o, jfieldID field, jobject v)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(o), field, reinterpret_cast<uintptr_t>(v)};
|
|
|
|
run(t, setObjectField, arguments);
|
|
}
|
|
|
|
uint64_t setBooleanField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
GcField* field = getField(t, arguments[1]);
|
|
jboolean v = arguments[2];
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_WRITE(t, field);
|
|
|
|
fieldAtOffset<jboolean>(*o, field->offset()) = v;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void JNICALL SetBooleanField(Thread* t, jobject o, jfieldID field, jboolean v)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o), field, v};
|
|
|
|
run(t, setBooleanField, arguments);
|
|
}
|
|
|
|
uint64_t setByteField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
GcField* field = getField(t, arguments[1]);
|
|
jbyte v = arguments[2];
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_WRITE(t, field);
|
|
|
|
fieldAtOffset<jbyte>(*o, field->offset()) = v;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void JNICALL SetByteField(Thread* t, jobject o, jfieldID field, jbyte v)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(o), field, static_cast<uintptr_t>(v)};
|
|
|
|
run(t, setByteField, arguments);
|
|
}
|
|
|
|
uint64_t setCharField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
GcField* field = getField(t, arguments[1]);
|
|
jchar v = arguments[2];
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_WRITE(t, field);
|
|
|
|
fieldAtOffset<jchar>(*o, field->offset()) = v;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void JNICALL SetCharField(Thread* t, jobject o, jfieldID field, jchar v)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(o), field, v};
|
|
|
|
run(t, setCharField, arguments);
|
|
}
|
|
|
|
uint64_t setShortField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
GcField* field = getField(t, arguments[1]);
|
|
jshort v = arguments[2];
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_WRITE(t, field);
|
|
|
|
fieldAtOffset<jshort>(*o, field->offset()) = v;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void JNICALL SetShortField(Thread* t, jobject o, jfieldID field, jshort v)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(o), field, static_cast<uintptr_t>(v)};
|
|
|
|
run(t, setShortField, arguments);
|
|
}
|
|
|
|
uint64_t setIntField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
GcField* field = getField(t, arguments[1]);
|
|
jint v = arguments[2];
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_WRITE(t, field);
|
|
|
|
fieldAtOffset<jint>(*o, field->offset()) = v;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void JNICALL SetIntField(Thread* t, jobject o, jfieldID field, jint v)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(o), field, static_cast<uintptr_t>(v)};
|
|
|
|
run(t, setIntField, arguments);
|
|
}
|
|
|
|
uint64_t setLongField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
GcField* field = getField(t, arguments[1]);
|
|
jlong v;
|
|
memcpy(&v, arguments + 2, sizeof(jlong));
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_WRITE(t, field);
|
|
|
|
fieldAtOffset<jlong>(*o, field->offset()) = v;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void JNICALL SetLongField(Thread* t, jobject o, jfieldID field, jlong v)
|
|
{
|
|
uintptr_t arguments[2 + (sizeof(jlong) / BytesPerWord)];
|
|
arguments[0] = reinterpret_cast<uintptr_t>(o);
|
|
arguments[1] = field;
|
|
memcpy(arguments + 2, &v, sizeof(jlong));
|
|
|
|
run(t, setLongField, arguments);
|
|
}
|
|
|
|
uint64_t setFloatField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
GcField* field = getField(t, arguments[1]);
|
|
jfloat v = bitsToFloat(arguments[2]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_WRITE(t, field);
|
|
|
|
fieldAtOffset<jfloat>(*o, field->offset()) = v;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void JNICALL SetFloatField(Thread* t, jobject o, jfieldID field, jfloat v)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(o), field, floatToBits(v)};
|
|
|
|
run(t, setFloatField, arguments);
|
|
}
|
|
|
|
uint64_t setDoubleField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject o = reinterpret_cast<jobject>(arguments[0]);
|
|
GcField* field = getField(t, arguments[1]);
|
|
jdouble v;
|
|
memcpy(&v, arguments + 2, sizeof(jdouble));
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_WRITE(t, field);
|
|
|
|
fieldAtOffset<jdouble>(*o, field->offset()) = v;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void JNICALL SetDoubleField(Thread* t, jobject o, jfieldID field, jdouble v)
|
|
{
|
|
uintptr_t arguments[2 + (sizeof(jdouble) / BytesPerWord)];
|
|
arguments[0] = reinterpret_cast<uintptr_t>(o);
|
|
arguments[1] = field;
|
|
memcpy(arguments + 2, &v, sizeof(jdouble));
|
|
|
|
run(t, setDoubleField, arguments);
|
|
}
|
|
|
|
GcField* getStaticField(Thread* t, jfieldID f)
|
|
{
|
|
assertT(t, f);
|
|
|
|
GcField* field = cast<GcField>(t, roots(t)->jNIFieldTable()->body()[f - 1]);
|
|
|
|
assertT(t, field->flags() & ACC_STATIC);
|
|
|
|
return field;
|
|
}
|
|
|
|
uint64_t getStaticObjectField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
GcJclass* c = cast<GcJclass>(t, *reinterpret_cast<jobject>(arguments[0]));
|
|
|
|
initClass(t, c->vmClass());
|
|
|
|
GcField* field = getStaticField(t, arguments[1]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_READ(t, field);
|
|
|
|
return reinterpret_cast<uintptr_t>(makeLocalReference(
|
|
t, fieldAtOffset<object>(c->vmClass()->staticTable(), field->offset())));
|
|
}
|
|
|
|
jobject JNICALL GetStaticObjectField(Thread* t, jclass c, jfieldID field)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(c), field};
|
|
|
|
return reinterpret_cast<jobject>(run(t, getStaticObjectField, arguments));
|
|
}
|
|
|
|
uint64_t getStaticBooleanField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
GcJclass* c = cast<GcJclass>(t, *reinterpret_cast<jobject>(arguments[0]));
|
|
|
|
initClass(t, c->vmClass());
|
|
|
|
GcField* field = getStaticField(t, arguments[1]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_READ(t, field);
|
|
|
|
return fieldAtOffset<jboolean>(c->vmClass()->staticTable(), field->offset());
|
|
}
|
|
|
|
jboolean JNICALL GetStaticBooleanField(Thread* t, jclass c, jfieldID field)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(c), field};
|
|
|
|
return run(t, getStaticBooleanField, arguments);
|
|
}
|
|
|
|
uint64_t getStaticByteField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
GcJclass* c = cast<GcJclass>(t, *reinterpret_cast<jobject>(arguments[0]));
|
|
|
|
initClass(t, c->vmClass());
|
|
|
|
GcField* field = getStaticField(t, arguments[1]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_READ(t, field);
|
|
|
|
return fieldAtOffset<jbyte>(c->vmClass()->staticTable(), field->offset());
|
|
}
|
|
|
|
jbyte JNICALL GetStaticByteField(Thread* t, jclass c, jfieldID field)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(c), field};
|
|
|
|
return run(t, getStaticByteField, arguments);
|
|
}
|
|
|
|
uint64_t getStaticCharField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
GcJclass* c = cast<GcJclass>(t, *reinterpret_cast<jobject>(arguments[0]));
|
|
|
|
initClass(t, c->vmClass());
|
|
|
|
GcField* field = getStaticField(t, arguments[1]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_READ(t, field);
|
|
|
|
return fieldAtOffset<jchar>(c->vmClass()->staticTable(), field->offset());
|
|
}
|
|
|
|
jchar JNICALL GetStaticCharField(Thread* t, jclass c, jfieldID field)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(c), field};
|
|
|
|
return run(t, getStaticCharField, arguments);
|
|
}
|
|
|
|
uint64_t getStaticShortField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
GcJclass* c = cast<GcJclass>(t, *reinterpret_cast<jobject>(arguments[0]));
|
|
|
|
initClass(t, c->vmClass());
|
|
|
|
GcField* field = getStaticField(t, arguments[1]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_READ(t, field);
|
|
|
|
return fieldAtOffset<jshort>(c->vmClass()->staticTable(), field->offset());
|
|
}
|
|
|
|
jshort JNICALL GetStaticShortField(Thread* t, jclass c, jfieldID field)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(c), field};
|
|
|
|
return run(t, getStaticShortField, arguments);
|
|
}
|
|
|
|
uint64_t getStaticIntField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
GcJclass* c = cast<GcJclass>(t, *reinterpret_cast<jobject>(arguments[0]));
|
|
|
|
initClass(t, c->vmClass());
|
|
|
|
GcField* field = getStaticField(t, arguments[1]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_READ(t, field);
|
|
|
|
return fieldAtOffset<jint>(c->vmClass()->staticTable(), field->offset());
|
|
}
|
|
|
|
jint JNICALL GetStaticIntField(Thread* t, jclass c, jfieldID field)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(c), field};
|
|
|
|
return run(t, getStaticIntField, arguments);
|
|
}
|
|
|
|
uint64_t getStaticLongField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
GcJclass* c = cast<GcJclass>(t, *reinterpret_cast<jobject>(arguments[0]));
|
|
|
|
initClass(t, c->vmClass());
|
|
|
|
GcField* field = getStaticField(t, arguments[1]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_READ(t, field);
|
|
|
|
return fieldAtOffset<jlong>(c->vmClass()->staticTable(), field->offset());
|
|
}
|
|
|
|
jlong JNICALL GetStaticLongField(Thread* t, jclass c, jfieldID field)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(c), field};
|
|
|
|
return run(t, getStaticLongField, arguments);
|
|
}
|
|
|
|
uint64_t getStaticFloatField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
GcJclass* c = cast<GcJclass>(t, *reinterpret_cast<jobject>(arguments[0]));
|
|
|
|
initClass(t, c->vmClass());
|
|
|
|
GcField* field = getStaticField(t, arguments[1]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_READ(t, field);
|
|
|
|
return floatToBits(
|
|
fieldAtOffset<jfloat>(c->vmClass()->staticTable(), field->offset()));
|
|
}
|
|
|
|
jfloat JNICALL GetStaticFloatField(Thread* t, jclass c, jfieldID field)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(c), field};
|
|
|
|
return bitsToFloat(run(t, getStaticFloatField, arguments));
|
|
}
|
|
|
|
uint64_t getStaticDoubleField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
GcJclass* c = cast<GcJclass>(t, *reinterpret_cast<jobject>(arguments[0]));
|
|
|
|
initClass(t, c->vmClass());
|
|
|
|
GcField* field = getStaticField(t, arguments[1]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_READ(t, field);
|
|
|
|
return doubleToBits(
|
|
fieldAtOffset<jdouble>(c->vmClass()->staticTable(), field->offset()));
|
|
}
|
|
|
|
jdouble JNICALL GetStaticDoubleField(Thread* t, jclass c, jfieldID field)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(c), field};
|
|
|
|
return bitsToDouble(run(t, getStaticDoubleField, arguments));
|
|
}
|
|
|
|
uint64_t setStaticObjectField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
GcJclass* c = cast<GcJclass>(t, *reinterpret_cast<jobject>(arguments[0]));
|
|
|
|
initClass(t, c->vmClass());
|
|
|
|
GcField* field = getStaticField(t, arguments[1]);
|
|
jobject v = reinterpret_cast<jobject>(arguments[2]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_WRITE(t, field);
|
|
|
|
setField(t, c->vmClass()->staticTable(), field->offset(), (v ? *v : 0));
|
|
|
|
return 1;
|
|
}
|
|
|
|
void JNICALL
|
|
SetStaticObjectField(Thread* t, jclass c, jfieldID field, jobject v)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(c), field, reinterpret_cast<uintptr_t>(v)};
|
|
|
|
run(t, setStaticObjectField, arguments);
|
|
}
|
|
|
|
uint64_t setStaticBooleanField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
GcJclass* c = cast<GcJclass>(t, *reinterpret_cast<jobject>(arguments[0]));
|
|
|
|
initClass(t, c->vmClass());
|
|
|
|
GcField* field = getStaticField(t, arguments[1]);
|
|
jboolean v = arguments[2];
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_WRITE(t, field);
|
|
|
|
fieldAtOffset<jboolean>(c->vmClass()->staticTable(), field->offset()) = v;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void JNICALL
|
|
SetStaticBooleanField(Thread* t, jclass c, jfieldID field, jboolean v)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(c), field, v};
|
|
|
|
run(t, setStaticBooleanField, arguments);
|
|
}
|
|
|
|
uint64_t setStaticByteField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
GcJclass* c = cast<GcJclass>(t, *reinterpret_cast<jobject>(arguments[0]));
|
|
|
|
initClass(t, c->vmClass());
|
|
|
|
GcField* field = getStaticField(t, arguments[1]);
|
|
jbyte v = arguments[2];
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_WRITE(t, field);
|
|
|
|
fieldAtOffset<jbyte>(c->vmClass()->staticTable(), field->offset()) = v;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void JNICALL SetStaticByteField(Thread* t, jclass c, jfieldID field, jbyte v)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(c), field, static_cast<uintptr_t>(v)};
|
|
|
|
run(t, setStaticByteField, arguments);
|
|
}
|
|
|
|
uint64_t setStaticCharField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
GcJclass* c = cast<GcJclass>(t, *reinterpret_cast<jobject>(arguments[0]));
|
|
|
|
initClass(t, c->vmClass());
|
|
|
|
GcField* field = getStaticField(t, arguments[1]);
|
|
jchar v = arguments[2];
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_WRITE(t, field);
|
|
|
|
fieldAtOffset<jchar>(c->vmClass()->staticTable(), field->offset()) = v;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void JNICALL SetStaticCharField(Thread* t, jclass c, jfieldID field, jchar v)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(c), field, v};
|
|
|
|
run(t, setStaticCharField, arguments);
|
|
}
|
|
|
|
uint64_t setStaticShortField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
GcJclass* c = cast<GcJclass>(t, *reinterpret_cast<jobject>(arguments[0]));
|
|
|
|
initClass(t, c->vmClass());
|
|
|
|
GcField* field = getStaticField(t, arguments[1]);
|
|
jshort v = arguments[2];
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_WRITE(t, field);
|
|
|
|
fieldAtOffset<jshort>(c->vmClass()->staticTable(), field->offset()) = v;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void JNICALL SetStaticShortField(Thread* t, jclass c, jfieldID field, jshort v)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(c), field, static_cast<uintptr_t>(v)};
|
|
|
|
run(t, setStaticShortField, arguments);
|
|
}
|
|
|
|
uint64_t setStaticIntField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
GcJclass* c = cast<GcJclass>(t, *reinterpret_cast<jobject>(arguments[0]));
|
|
|
|
initClass(t, c->vmClass());
|
|
|
|
GcField* field = getStaticField(t, arguments[1]);
|
|
jint v = arguments[2];
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_WRITE(t, field);
|
|
|
|
fieldAtOffset<jint>(c->vmClass()->staticTable(), field->offset()) = v;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void JNICALL SetStaticIntField(Thread* t, jclass c, jfieldID field, jint v)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(c), field, static_cast<uintptr_t>(v)};
|
|
|
|
run(t, setStaticIntField, arguments);
|
|
}
|
|
|
|
uint64_t setStaticLongField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
GcJclass* c = cast<GcJclass>(t, *reinterpret_cast<jobject>(arguments[0]));
|
|
|
|
initClass(t, c->vmClass());
|
|
|
|
GcField* field = getStaticField(t, arguments[1]);
|
|
jlong v;
|
|
memcpy(&v, arguments + 2, sizeof(jlong));
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_WRITE(t, field);
|
|
|
|
fieldAtOffset<jlong>(c->vmClass()->staticTable(), field->offset()) = v;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void JNICALL SetStaticLongField(Thread* t, jclass c, jfieldID field, jlong v)
|
|
{
|
|
uintptr_t arguments[2 + (sizeof(jlong) / BytesPerWord)];
|
|
arguments[0] = reinterpret_cast<uintptr_t>(c);
|
|
arguments[1] = field;
|
|
memcpy(arguments + 2, &v, sizeof(jlong));
|
|
|
|
run(t, setStaticLongField, arguments);
|
|
}
|
|
|
|
uint64_t setStaticFloatField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
GcJclass* c = cast<GcJclass>(t, *reinterpret_cast<jobject>(arguments[0]));
|
|
|
|
initClass(t, c->vmClass());
|
|
|
|
GcField* field = getStaticField(t, arguments[1]);
|
|
jfloat v = bitsToFloat(arguments[2]);
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_WRITE(t, field);
|
|
|
|
fieldAtOffset<jfloat>(c->vmClass()->staticTable(), field->offset()) = v;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void JNICALL SetStaticFloatField(Thread* t, jclass c, jfieldID field, jfloat v)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(c), field, floatToBits(v)};
|
|
|
|
run(t, setStaticFloatField, arguments);
|
|
}
|
|
|
|
uint64_t setStaticDoubleField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
GcJclass* c = cast<GcJclass>(t, *reinterpret_cast<jobject>(arguments[0]));
|
|
|
|
initClass(t, c->vmClass());
|
|
|
|
GcField* field = getStaticField(t, arguments[1]);
|
|
jdouble v;
|
|
memcpy(&v, arguments + 2, sizeof(jdouble));
|
|
|
|
PROTECT(t, field);
|
|
ACQUIRE_FIELD_FOR_WRITE(t, field);
|
|
|
|
fieldAtOffset<jdouble>(c->vmClass()->staticTable(), field->offset()) = v;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void JNICALL
|
|
SetStaticDoubleField(Thread* t, jclass c, jfieldID field, jdouble v)
|
|
{
|
|
uintptr_t arguments[2 + (sizeof(jdouble) / BytesPerWord)];
|
|
arguments[0] = reinterpret_cast<uintptr_t>(c);
|
|
arguments[1] = field;
|
|
memcpy(arguments + 2, &v, sizeof(jdouble));
|
|
|
|
run(t, setStaticDoubleField, arguments);
|
|
}
|
|
|
|
jobject JNICALL newGlobalRef(Thread* t, jobject o, bool weak)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
ACQUIRE(t, t->m->referenceLock);
|
|
|
|
if (o) {
|
|
for (Reference* r = t->m->jniReferences; r; r = r->next) {
|
|
if (r->target == *o and r->weak == weak) {
|
|
acquire(t, r);
|
|
|
|
return &(r->target);
|
|
}
|
|
}
|
|
|
|
Reference* r = new (t->m->heap->allocate(sizeof(Reference)))
|
|
Reference(*o, &(t->m->jniReferences), weak);
|
|
|
|
acquire(t, r);
|
|
|
|
return &(r->target);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
jobject JNICALL NewGlobalRef(Thread* t, jobject o)
|
|
{
|
|
return newGlobalRef(t, o, false);
|
|
}
|
|
|
|
void JNICALL DeleteGlobalRef(Thread* t, jobject r)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
ACQUIRE(t, t->m->referenceLock);
|
|
|
|
if (r) {
|
|
release(t, reinterpret_cast<Reference*>(r));
|
|
}
|
|
}
|
|
|
|
jobject JNICALL NewWeakGlobalRef(Thread* t, jobject o)
|
|
{
|
|
return newGlobalRef(t, o, true);
|
|
}
|
|
|
|
void JNICALL DeleteWeakGlobalRef(Thread* t, jobject r)
|
|
{
|
|
DeleteGlobalRef(t, r);
|
|
}
|
|
|
|
jint JNICALL EnsureLocalCapacity(Thread*, jint)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
jthrowable JNICALL ExceptionOccurred(Thread* t)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
return reinterpret_cast<jthrowable>(makeLocalReference(t, t->exception));
|
|
}
|
|
|
|
void JNICALL ExceptionDescribe(Thread* t)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
return printTrace(t, t->exception);
|
|
}
|
|
|
|
void JNICALL ExceptionClear(Thread* t)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
t->exception = 0;
|
|
}
|
|
|
|
uint64_t newObjectArray(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jsize length = arguments[0];
|
|
jclass class_ = reinterpret_cast<jclass>(arguments[1]);
|
|
jobject init = reinterpret_cast<jobject>(arguments[2]);
|
|
|
|
object a = makeObjectArray(t, (*class_)->vmClass(), length);
|
|
object value = (init ? *init : 0);
|
|
for (jsize i = 0; i < length; ++i) {
|
|
reinterpret_cast<GcArray*>(a)->setBodyElement(t, i, value);
|
|
}
|
|
return reinterpret_cast<uint64_t>(makeLocalReference(t, a));
|
|
}
|
|
|
|
jobjectArray JNICALL
|
|
NewObjectArray(Thread* t, jsize length, jclass class_, jobject init)
|
|
{
|
|
uintptr_t arguments[] = {static_cast<uintptr_t>(length),
|
|
reinterpret_cast<uintptr_t>(class_),
|
|
reinterpret_cast<uintptr_t>(init)};
|
|
|
|
return reinterpret_cast<jobjectArray>(run(t, newObjectArray, arguments));
|
|
}
|
|
|
|
jobject JNICALL
|
|
GetObjectArrayElement(Thread* t, jobjectArray array, jsize index)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
return makeLocalReference(
|
|
t, objectArrayBody(t, reinterpret_cast<object>(*array), index));
|
|
}
|
|
|
|
void JNICALL SetObjectArrayElement(Thread* t,
|
|
jobjectArray array,
|
|
jsize index,
|
|
jobject value)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
setField(t,
|
|
reinterpret_cast<object>(*array),
|
|
ArrayBody + (index * BytesPerWord),
|
|
(value ? *value : 0));
|
|
}
|
|
|
|
uint64_t newArray(Thread* t, uintptr_t* arguments)
|
|
{
|
|
object (*constructor)(Thread*, unsigned)
|
|
= reinterpret_cast<object (*)(Thread*, unsigned)>(arguments[0]);
|
|
|
|
jsize length = arguments[1];
|
|
|
|
return reinterpret_cast<uint64_t>(
|
|
makeLocalReference(t, constructor(t, length)));
|
|
}
|
|
|
|
jbooleanArray JNICALL NewBooleanArray(Thread* t, jsize length)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(voidPointer(makeBooleanArray)),
|
|
static_cast<uintptr_t>(length)};
|
|
|
|
return reinterpret_cast<jbooleanArray>(run(t, newArray, arguments));
|
|
}
|
|
|
|
object makeByteArray0(Thread* t, unsigned length)
|
|
{
|
|
return makeByteArray(t, length);
|
|
}
|
|
|
|
jbyteArray JNICALL NewByteArray(Thread* t, jsize length)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(voidPointer(makeByteArray0)),
|
|
static_cast<uintptr_t>(length)};
|
|
|
|
return reinterpret_cast<jbyteArray>(run(t, newArray, arguments));
|
|
}
|
|
|
|
jcharArray JNICALL NewCharArray(Thread* t, jsize length)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(voidPointer(makeCharArray)),
|
|
static_cast<uintptr_t>(length)};
|
|
|
|
return reinterpret_cast<jcharArray>(run(t, newArray, arguments));
|
|
}
|
|
|
|
jshortArray JNICALL NewShortArray(Thread* t, jsize length)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(voidPointer(makeShortArray)),
|
|
static_cast<uintptr_t>(length)};
|
|
|
|
return reinterpret_cast<jshortArray>(run(t, newArray, arguments));
|
|
}
|
|
|
|
jintArray JNICALL NewIntArray(Thread* t, jsize length)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(voidPointer(makeIntArray)),
|
|
static_cast<uintptr_t>(length)};
|
|
|
|
return reinterpret_cast<jintArray>(run(t, newArray, arguments));
|
|
}
|
|
|
|
jlongArray JNICALL NewLongArray(Thread* t, jsize length)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(voidPointer(makeLongArray)),
|
|
static_cast<uintptr_t>(length)};
|
|
|
|
return reinterpret_cast<jlongArray>(run(t, newArray, arguments));
|
|
}
|
|
|
|
jfloatArray JNICALL NewFloatArray(Thread* t, jsize length)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(voidPointer(makeFloatArray)),
|
|
static_cast<uintptr_t>(length)};
|
|
|
|
return reinterpret_cast<jfloatArray>(run(t, newArray, arguments));
|
|
}
|
|
|
|
jdoubleArray JNICALL NewDoubleArray(Thread* t, jsize length)
|
|
{
|
|
uintptr_t arguments[]
|
|
= {reinterpret_cast<uintptr_t>(voidPointer(makeDoubleArray)),
|
|
static_cast<uintptr_t>(length)};
|
|
|
|
return reinterpret_cast<jdoubleArray>(run(t, newArray, arguments));
|
|
}
|
|
|
|
jboolean* JNICALL
|
|
GetBooleanArrayElements(Thread* t, jbooleanArray array, jboolean* isCopy)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
unsigned size = (*array)->length() * sizeof(jboolean);
|
|
jboolean* p = static_cast<jboolean*>(t->m->heap->allocate(size));
|
|
if (size) {
|
|
memcpy(p, (*array)->body().begin(), size);
|
|
}
|
|
|
|
if (isCopy) {
|
|
*isCopy = true;
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
jbyte* JNICALL
|
|
GetByteArrayElements(Thread* t, jbyteArray array, jboolean* isCopy)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
unsigned size = (*array)->length() * sizeof(jbyte);
|
|
jbyte* p = static_cast<jbyte*>(t->m->heap->allocate(size));
|
|
if (size) {
|
|
memcpy(p, (*array)->body().begin(), size);
|
|
}
|
|
|
|
if (isCopy) {
|
|
*isCopy = true;
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
jchar* JNICALL
|
|
GetCharArrayElements(Thread* t, jcharArray array, jboolean* isCopy)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
unsigned size = (*array)->length() * sizeof(jchar);
|
|
jchar* p = static_cast<jchar*>(t->m->heap->allocate(size));
|
|
if (size) {
|
|
memcpy(p, (*array)->body().begin(), size);
|
|
}
|
|
|
|
if (isCopy) {
|
|
*isCopy = true;
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
jshort* JNICALL
|
|
GetShortArrayElements(Thread* t, jshortArray array, jboolean* isCopy)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
unsigned size = (*array)->length() * sizeof(jshort);
|
|
jshort* p = static_cast<jshort*>(t->m->heap->allocate(size));
|
|
if (size) {
|
|
memcpy(p, (*array)->body().begin(), size);
|
|
}
|
|
|
|
if (isCopy) {
|
|
*isCopy = true;
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
jint* JNICALL GetIntArrayElements(Thread* t, jintArray array, jboolean* isCopy)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
unsigned size = (*array)->length() * sizeof(jint);
|
|
jint* p = static_cast<jint*>(t->m->heap->allocate(size));
|
|
if (size) {
|
|
memcpy(p, (*array)->body().begin(), size);
|
|
}
|
|
|
|
if (isCopy) {
|
|
*isCopy = true;
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
jlong* JNICALL
|
|
GetLongArrayElements(Thread* t, jlongArray array, jboolean* isCopy)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
unsigned size = (*array)->length() * sizeof(jlong);
|
|
jlong* p = static_cast<jlong*>(t->m->heap->allocate(size));
|
|
if (size) {
|
|
memcpy(p, (*array)->body().begin(), size);
|
|
}
|
|
|
|
if (isCopy) {
|
|
*isCopy = true;
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
jfloat* JNICALL
|
|
GetFloatArrayElements(Thread* t, jfloatArray array, jboolean* isCopy)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
unsigned size = (*array)->length() * sizeof(jfloat);
|
|
jfloat* p = static_cast<jfloat*>(t->m->heap->allocate(size));
|
|
if (size) {
|
|
memcpy(p, (*array)->body().begin(), size);
|
|
}
|
|
|
|
if (isCopy) {
|
|
*isCopy = true;
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
jdouble* JNICALL
|
|
GetDoubleArrayElements(Thread* t, jdoubleArray array, jboolean* isCopy)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
unsigned size = (*array)->length() * sizeof(jdouble);
|
|
jdouble* p = static_cast<jdouble*>(t->m->heap->allocate(size));
|
|
if (size) {
|
|
memcpy(p, (*array)->body().begin(), size);
|
|
}
|
|
|
|
if (isCopy) {
|
|
*isCopy = true;
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
void JNICALL ReleaseBooleanArrayElements(Thread* t,
|
|
jbooleanArray array,
|
|
jboolean* p,
|
|
jint mode)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
unsigned size = (*array)->length() * sizeof(jboolean);
|
|
|
|
if (mode == 0 or mode == AVIAN_JNI_COMMIT) {
|
|
if (size) {
|
|
memcpy((*array)->body().begin(), p, size);
|
|
}
|
|
}
|
|
|
|
if (mode == 0 or mode == AVIAN_JNI_ABORT) {
|
|
t->m->heap->free(p, size);
|
|
}
|
|
}
|
|
|
|
void JNICALL
|
|
ReleaseByteArrayElements(Thread* t, jbyteArray array, jbyte* p, jint mode)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
unsigned size = (*array)->length() * sizeof(jbyte);
|
|
|
|
if (mode == 0 or mode == AVIAN_JNI_COMMIT) {
|
|
if (size) {
|
|
memcpy((*array)->body().begin(), p, size);
|
|
}
|
|
}
|
|
|
|
if (mode == 0 or mode == AVIAN_JNI_ABORT) {
|
|
t->m->heap->free(p, size);
|
|
}
|
|
}
|
|
|
|
void JNICALL
|
|
ReleaseCharArrayElements(Thread* t, jcharArray array, jchar* p, jint mode)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
unsigned size = (*array)->length() * sizeof(jchar);
|
|
|
|
if (mode == 0 or mode == AVIAN_JNI_COMMIT) {
|
|
if (size) {
|
|
memcpy((*array)->body().begin(), p, size);
|
|
}
|
|
}
|
|
|
|
if (mode == 0 or mode == AVIAN_JNI_ABORT) {
|
|
t->m->heap->free(p, size);
|
|
}
|
|
}
|
|
|
|
void JNICALL ReleaseShortArrayElements(Thread* t,
|
|
jshortArray array,
|
|
jshort* p,
|
|
jint mode)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
unsigned size = (*array)->length() * sizeof(jshort);
|
|
|
|
if (mode == 0 or mode == AVIAN_JNI_COMMIT) {
|
|
if (size) {
|
|
memcpy((*array)->body().begin(), p, size);
|
|
}
|
|
}
|
|
|
|
if (mode == 0 or mode == AVIAN_JNI_ABORT) {
|
|
t->m->heap->free(p, size);
|
|
}
|
|
}
|
|
|
|
void JNICALL
|
|
ReleaseIntArrayElements(Thread* t, jintArray array, jint* p, jint mode)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
unsigned size = (*array)->length() * sizeof(jint);
|
|
|
|
if (mode == 0 or mode == AVIAN_JNI_COMMIT) {
|
|
if (size) {
|
|
memcpy((*array)->body().begin(), p, size);
|
|
}
|
|
}
|
|
|
|
if (mode == 0 or mode == AVIAN_JNI_ABORT) {
|
|
t->m->heap->free(p, size);
|
|
}
|
|
}
|
|
|
|
void JNICALL
|
|
ReleaseLongArrayElements(Thread* t, jlongArray array, jlong* p, jint mode)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
unsigned size = (*array)->length() * sizeof(jlong);
|
|
|
|
if (mode == 0 or mode == AVIAN_JNI_COMMIT) {
|
|
if (size) {
|
|
memcpy((*array)->body().begin(), p, size);
|
|
}
|
|
}
|
|
|
|
if (mode == 0 or mode == AVIAN_JNI_ABORT) {
|
|
t->m->heap->free(p, size);
|
|
}
|
|
}
|
|
|
|
void JNICALL ReleaseFloatArrayElements(Thread* t,
|
|
jfloatArray array,
|
|
jfloat* p,
|
|
jint mode)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
unsigned size = (*array)->length() * sizeof(jfloat);
|
|
|
|
if (mode == 0 or mode == AVIAN_JNI_COMMIT) {
|
|
if (size) {
|
|
memcpy((*array)->body().begin(), p, size);
|
|
}
|
|
}
|
|
|
|
if (mode == 0 or mode == AVIAN_JNI_ABORT) {
|
|
t->m->heap->free(p, size);
|
|
}
|
|
}
|
|
|
|
void JNICALL ReleaseDoubleArrayElements(Thread* t,
|
|
jdoubleArray array,
|
|
jdouble* p,
|
|
jint mode)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
unsigned size = (*array)->length() * sizeof(jdouble);
|
|
|
|
if (mode == 0 or mode == AVIAN_JNI_COMMIT) {
|
|
if (size) {
|
|
memcpy((*array)->body().begin(), p, size);
|
|
}
|
|
}
|
|
|
|
if (mode == 0 or mode == AVIAN_JNI_ABORT) {
|
|
t->m->heap->free(p, size);
|
|
}
|
|
}
|
|
|
|
void JNICALL GetBooleanArrayRegion(Thread* t,
|
|
jbooleanArray array,
|
|
jint offset,
|
|
jint length,
|
|
jboolean* dst)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
if (length) {
|
|
memcpy(dst, &(*array)->body()[offset], length * sizeof(jboolean));
|
|
}
|
|
}
|
|
|
|
void JNICALL GetByteArrayRegion(Thread* t,
|
|
jbyteArray array,
|
|
jint offset,
|
|
jint length,
|
|
jbyte* dst)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
if (length) {
|
|
memcpy(dst, &(*array)->body()[offset], length * sizeof(jbyte));
|
|
}
|
|
}
|
|
|
|
void JNICALL GetCharArrayRegion(Thread* t,
|
|
jcharArray array,
|
|
jint offset,
|
|
jint length,
|
|
jchar* dst)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
if (length) {
|
|
memcpy(dst, &(*array)->body()[offset], length * sizeof(jchar));
|
|
}
|
|
}
|
|
|
|
void JNICALL GetShortArrayRegion(Thread* t,
|
|
jshortArray array,
|
|
jint offset,
|
|
jint length,
|
|
jshort* dst)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
if (length) {
|
|
memcpy(dst, &(*array)->body()[offset], length * sizeof(jshort));
|
|
}
|
|
}
|
|
|
|
void JNICALL GetIntArrayRegion(Thread* t,
|
|
jintArray array,
|
|
jint offset,
|
|
jint length,
|
|
jint* dst)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
if (length) {
|
|
memcpy(dst, &(*array)->body()[offset], length * sizeof(jint));
|
|
}
|
|
}
|
|
|
|
void JNICALL GetLongArrayRegion(Thread* t,
|
|
jlongArray array,
|
|
jint offset,
|
|
jint length,
|
|
jlong* dst)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
if (length) {
|
|
memcpy(dst, &(*array)->body()[offset], length * sizeof(jlong));
|
|
}
|
|
}
|
|
|
|
void JNICALL GetFloatArrayRegion(Thread* t,
|
|
jfloatArray array,
|
|
jint offset,
|
|
jint length,
|
|
jfloat* dst)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
if (length) {
|
|
memcpy(dst, &(*array)->body()[offset], length * sizeof(jfloat));
|
|
}
|
|
}
|
|
|
|
void JNICALL GetDoubleArrayRegion(Thread* t,
|
|
jdoubleArray array,
|
|
jint offset,
|
|
jint length,
|
|
jdouble* dst)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
if (length) {
|
|
memcpy(dst, &(*array)->body()[offset], length * sizeof(jdouble));
|
|
}
|
|
}
|
|
|
|
void JNICALL SetBooleanArrayRegion(Thread* t,
|
|
jbooleanArray array,
|
|
jint offset,
|
|
jint length,
|
|
const jboolean* src)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
if (length) {
|
|
memcpy(&(*array)->body()[offset], src, length * sizeof(jboolean));
|
|
}
|
|
}
|
|
|
|
void JNICALL SetByteArrayRegion(Thread* t,
|
|
jbyteArray array,
|
|
jint offset,
|
|
jint length,
|
|
const jbyte* src)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
if (length) {
|
|
memcpy(&(*array)->body()[offset], src, length * sizeof(jbyte));
|
|
}
|
|
}
|
|
|
|
void JNICALL SetCharArrayRegion(Thread* t,
|
|
jcharArray array,
|
|
jint offset,
|
|
jint length,
|
|
const jchar* src)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
if (length) {
|
|
memcpy(&(*array)->body()[offset], src, length * sizeof(jchar));
|
|
}
|
|
}
|
|
|
|
void JNICALL SetShortArrayRegion(Thread* t,
|
|
jshortArray array,
|
|
jint offset,
|
|
jint length,
|
|
const jshort* src)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
if (length) {
|
|
memcpy(&(*array)->body()[offset], src, length * sizeof(jshort));
|
|
}
|
|
}
|
|
|
|
void JNICALL SetIntArrayRegion(Thread* t,
|
|
jintArray array,
|
|
jint offset,
|
|
jint length,
|
|
const jint* src)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
if (length) {
|
|
memcpy(&(*array)->body()[offset], src, length * sizeof(jint));
|
|
}
|
|
}
|
|
|
|
void JNICALL SetLongArrayRegion(Thread* t,
|
|
jlongArray array,
|
|
jint offset,
|
|
jint length,
|
|
const jlong* src)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
if (length) {
|
|
memcpy(&(*array)->body()[offset], src, length * sizeof(jlong));
|
|
}
|
|
}
|
|
|
|
void JNICALL SetFloatArrayRegion(Thread* t,
|
|
jfloatArray array,
|
|
jint offset,
|
|
jint length,
|
|
const jfloat* src)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
if (length) {
|
|
memcpy(&(*array)->body()[offset], src, length * sizeof(jfloat));
|
|
}
|
|
}
|
|
|
|
void JNICALL SetDoubleArrayRegion(Thread* t,
|
|
jdoubleArray array,
|
|
jint offset,
|
|
jint length,
|
|
const jdouble* src)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
if (length) {
|
|
memcpy(&(*array)->body()[offset], src, length * sizeof(jdouble));
|
|
}
|
|
}
|
|
|
|
void* JNICALL
|
|
GetPrimitiveArrayCritical(Thread* t, jarray array, jboolean* isCopy)
|
|
{
|
|
if (t->criticalLevel == 0) {
|
|
enter(t, Thread::ActiveState);
|
|
}
|
|
|
|
++t->criticalLevel;
|
|
|
|
if (isCopy) {
|
|
*isCopy = true;
|
|
}
|
|
|
|
expect(t, *array);
|
|
|
|
return reinterpret_cast<uintptr_t*>(*array) + 2;
|
|
}
|
|
|
|
void JNICALL ReleasePrimitiveArrayCritical(Thread* t, jarray, void*, jint)
|
|
{
|
|
if ((--t->criticalLevel) == 0) {
|
|
enter(t, Thread::IdleState);
|
|
}
|
|
}
|
|
|
|
uint64_t fromReflectedMethod(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject m = reinterpret_cast<jobject>(arguments[0]);
|
|
|
|
return methodID(t, t->m->classpath->getVMMethod(t, *m));
|
|
}
|
|
|
|
jmethodID JNICALL FromReflectedMethod(Thread* t, jobject method)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(method)};
|
|
|
|
return static_cast<jmethodID>(run(t, fromReflectedMethod, arguments));
|
|
}
|
|
|
|
uint64_t toReflectedMethod(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jmethodID m = arguments[1];
|
|
jboolean isStatic = arguments[2];
|
|
|
|
return reinterpret_cast<uintptr_t>(makeLocalReference(
|
|
t,
|
|
t->m->classpath->makeJMethod(
|
|
t, isStatic ? getStaticMethod(t, m) : getMethod(t, m))));
|
|
}
|
|
|
|
jobject JNICALL
|
|
ToReflectedMethod(Thread* t, jclass c, jmethodID method, jboolean isStatic)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(c),
|
|
static_cast<uintptr_t>(method),
|
|
static_cast<uintptr_t>(isStatic)};
|
|
|
|
return reinterpret_cast<jobject>(run(t, toReflectedMethod, arguments));
|
|
}
|
|
|
|
uint64_t fromReflectedField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jobject f = reinterpret_cast<jobject>(arguments[0]);
|
|
|
|
return fieldID(t, t->m->classpath->getVMField(t, cast<GcJfield>(t, *f)));
|
|
}
|
|
|
|
jfieldID JNICALL FromReflectedField(Thread* t, jobject field)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(field)};
|
|
|
|
return static_cast<jfieldID>(run(t, fromReflectedField, arguments));
|
|
}
|
|
|
|
uint64_t toReflectedField(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jfieldID f = arguments[1];
|
|
jboolean isStatic = arguments[2];
|
|
|
|
return reinterpret_cast<uintptr_t>(makeLocalReference(
|
|
t,
|
|
t->m->classpath->makeJField(
|
|
t, isStatic ? getStaticField(t, f) : getField(t, f))));
|
|
}
|
|
|
|
jobject JNICALL
|
|
ToReflectedField(Thread* t, jclass c, jfieldID field, jboolean isStatic)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(c),
|
|
static_cast<uintptr_t>(field),
|
|
static_cast<uintptr_t>(isStatic)};
|
|
|
|
return reinterpret_cast<jobject>(run(t, toReflectedField, arguments));
|
|
}
|
|
|
|
uint64_t registerNatives(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jclass c = reinterpret_cast<jclass>(arguments[0]);
|
|
const JNINativeMethod* methods
|
|
= reinterpret_cast<const JNINativeMethod*>(arguments[1]);
|
|
jint methodCount = arguments[2];
|
|
|
|
for (int i = 0; i < methodCount; ++i) {
|
|
if (methods[i].function) {
|
|
// Android's class library sometimes prepends a mysterious "!"
|
|
// to the method signature, which we happily ignore:
|
|
const char* sig = methods[i].signature;
|
|
if (*sig == '!')
|
|
++sig;
|
|
|
|
GcMethod* method
|
|
= findMethodOrNull(t, (*c)->vmClass(), methods[i].name, sig);
|
|
|
|
if (method == 0 or (method->flags() & ACC_NATIVE) == 0) {
|
|
// The JNI spec says we must throw a NoSuchMethodError in this
|
|
// case, but that would prevent using a code shrinker like
|
|
// ProGuard effectively. Instead, we just ignore it.
|
|
|
|
if (false) {
|
|
fprintf(stderr,
|
|
"not found: %s.%s%s\n",
|
|
(*c)->vmClass()->name()->body().begin(),
|
|
methods[i].name,
|
|
sig);
|
|
abort(t);
|
|
}
|
|
} else {
|
|
registerNative(t, method, methods[i].function);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
jint JNICALL RegisterNatives(Thread* t,
|
|
jclass c,
|
|
const JNINativeMethod* methods,
|
|
jint methodCount)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(c),
|
|
reinterpret_cast<uintptr_t>(methods),
|
|
static_cast<uintptr_t>(methodCount)};
|
|
|
|
return run(t, registerNatives, arguments) ? 0 : -1;
|
|
}
|
|
|
|
jint JNICALL UnregisterNatives(Thread* t, jclass c)
|
|
{
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
unregisterNatives(t, (*c)->vmClass());
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint64_t monitorOp(Thread* t, uintptr_t* arguments)
|
|
{
|
|
void (*op)(Thread*, object)
|
|
= reinterpret_cast<void (*)(Thread*, object)>(arguments[0]);
|
|
|
|
jobject o = reinterpret_cast<jobject>(arguments[1]);
|
|
|
|
op(t, *o);
|
|
|
|
return 1;
|
|
}
|
|
|
|
void acquire0(Thread* t, object o)
|
|
{
|
|
return acquire(t, o);
|
|
}
|
|
|
|
jint JNICALL MonitorEnter(Thread* t, jobject o)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(voidPointer(acquire0)),
|
|
reinterpret_cast<uintptr_t>(o)};
|
|
|
|
return run(t, monitorOp, arguments) ? 0 : -1;
|
|
}
|
|
|
|
void release0(Thread* t, object o)
|
|
{
|
|
return release(t, o);
|
|
}
|
|
|
|
jint JNICALL MonitorExit(Thread* t, jobject o)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(voidPointer(release0)),
|
|
reinterpret_cast<uintptr_t>(o)};
|
|
|
|
return run(t, monitorOp, arguments) ? 0 : -1;
|
|
}
|
|
|
|
jint JNICALL GetJavaVM(Thread* t, Machine** m)
|
|
{
|
|
*m = t->m;
|
|
return 0;
|
|
}
|
|
|
|
jboolean JNICALL IsSameObject(Thread* t, jobject a, jobject b)
|
|
{
|
|
if (a and b) {
|
|
ENTER(t, Thread::ActiveState);
|
|
|
|
return *a == *b;
|
|
} else {
|
|
return a == b;
|
|
}
|
|
}
|
|
|
|
uint64_t pushLocalFrame(Thread* t, uintptr_t* arguments)
|
|
{
|
|
if (t->m->processor->pushLocalFrame(t, arguments[0])) {
|
|
return 1;
|
|
} else {
|
|
throw_(t, roots(t)->outOfMemoryError());
|
|
}
|
|
}
|
|
|
|
jint JNICALL PushLocalFrame(Thread* t, jint capacity)
|
|
{
|
|
uintptr_t arguments[] = {static_cast<uintptr_t>(capacity)};
|
|
|
|
return run(t, pushLocalFrame, arguments) ? 0 : -1;
|
|
}
|
|
|
|
uint64_t popLocalFrame(Thread* t, uintptr_t* arguments)
|
|
{
|
|
uint64_t r;
|
|
jobject presult = reinterpret_cast<jobject>(arguments[0]);
|
|
if (presult != NULL) {
|
|
object result = *presult;
|
|
PROTECT(t, result);
|
|
|
|
t->m->processor->popLocalFrame(t);
|
|
|
|
r = reinterpret_cast<uint64_t>(makeLocalReference(t, result));
|
|
} else {
|
|
t->m->processor->popLocalFrame(t);
|
|
r = 0;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
jobject JNICALL PopLocalFrame(Thread* t, jobject result)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(result)};
|
|
|
|
return reinterpret_cast<jobject>(run(t, popLocalFrame, arguments));
|
|
}
|
|
|
|
uint64_t newDirectByteBuffer(Thread* t, uintptr_t* arguments)
|
|
{
|
|
jlong capacity;
|
|
memcpy(&capacity, arguments + 1, sizeof(jlong));
|
|
|
|
return reinterpret_cast<uintptr_t>(makeLocalReference(
|
|
t,
|
|
t->m->classpath->makeDirectByteBuffer(
|
|
t, reinterpret_cast<void*>(arguments[0]), capacity)));
|
|
}
|
|
|
|
jobject JNICALL NewDirectByteBuffer(Thread* t, void* p, jlong capacity)
|
|
{
|
|
uintptr_t arguments[1 + (sizeof(jlong) / BytesPerWord)];
|
|
arguments[0] = reinterpret_cast<uintptr_t>(p);
|
|
memcpy(arguments + 1, &capacity, sizeof(jlong));
|
|
|
|
return reinterpret_cast<jobject>(run(t, newDirectByteBuffer, arguments));
|
|
}
|
|
|
|
uint64_t getDirectBufferAddress(Thread* t, uintptr_t* arguments)
|
|
{
|
|
return reinterpret_cast<uintptr_t>(t->m->classpath->getDirectBufferAddress(
|
|
t, *reinterpret_cast<jobject>(arguments[0])));
|
|
}
|
|
|
|
void* JNICALL GetDirectBufferAddress(Thread* t, jobject b)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(b)};
|
|
|
|
return reinterpret_cast<void*>(run(t, getDirectBufferAddress, arguments));
|
|
}
|
|
|
|
uint64_t getDirectBufferCapacity(Thread* t, uintptr_t* arguments)
|
|
{
|
|
return t->m->classpath->getDirectBufferCapacity(
|
|
t, *reinterpret_cast<jobject>(arguments[0]));
|
|
}
|
|
|
|
jlong JNICALL GetDirectBufferCapacity(Thread* t, jobject b)
|
|
{
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(b)};
|
|
|
|
return run(t, getDirectBufferCapacity, arguments);
|
|
}
|
|
|
|
struct JavaVMOption {
|
|
char* optionString;
|
|
void* extraInfo;
|
|
};
|
|
|
|
struct JavaVMInitArgs {
|
|
jint version;
|
|
|
|
jint nOptions;
|
|
JavaVMOption* options;
|
|
jboolean ignoreUnrecognized;
|
|
};
|
|
|
|
int parseSize(const char* s)
|
|
{
|
|
unsigned length = strlen(s);
|
|
RUNTIME_ARRAY(char, buffer, length + 1);
|
|
|
|
if (length == 0)
|
|
return 0;
|
|
|
|
char suffix = s[length - 1];
|
|
if (suffix== 'k' or suffix == 'K') {
|
|
memcpy(RUNTIME_ARRAY_BODY(buffer), s, length - 1);
|
|
RUNTIME_ARRAY_BODY(buffer)[length - 1] = 0;
|
|
return atoi(RUNTIME_ARRAY_BODY(buffer)) * 1024;
|
|
}
|
|
|
|
if (suffix == 'm' or suffix == 'M') {
|
|
memcpy(RUNTIME_ARRAY_BODY(buffer), s, length - 1);
|
|
RUNTIME_ARRAY_BODY(buffer)[length - 1] = 0;
|
|
return atoi(RUNTIME_ARRAY_BODY(buffer)) * 1024 * 1024;
|
|
}
|
|
|
|
if (suffix == 'g' or suffix == 'G') {
|
|
memcpy(RUNTIME_ARRAY_BODY(buffer), s, length - 1);
|
|
RUNTIME_ARRAY_BODY(buffer)[length - 1] = 0;
|
|
return atoi(RUNTIME_ARRAY_BODY(buffer)) * 1024 * 1024 * 1024;
|
|
}
|
|
|
|
return atoi(s);
|
|
}
|
|
|
|
void append(char** p, const char* value, unsigned length, char tail)
|
|
{
|
|
if (length) {
|
|
memcpy(*p, value, length);
|
|
*p += length;
|
|
*((*p)++) = tail;
|
|
}
|
|
}
|
|
|
|
uint64_t boot(Thread* t, uintptr_t*)
|
|
{
|
|
GcThrowable* throwable = makeThrowable(t, GcNullPointerException::Type);
|
|
// sequence point, for gc (don't recombine statements)
|
|
roots(t)->setNullPointerException(t, throwable);
|
|
|
|
throwable = makeThrowable(t, GcArithmeticException::Type);
|
|
// sequence point, for gc (don't recombine statements)
|
|
roots(t)->setArithmeticException(t, throwable);
|
|
|
|
throwable = makeThrowable(t, GcArrayIndexOutOfBoundsException::Type);
|
|
// sequence point, for gc (don't recombine statements)
|
|
roots(t)->setArrayIndexOutOfBoundsException(t, throwable);
|
|
|
|
throwable = makeThrowable(t, GcOutOfMemoryError::Type);
|
|
// sequence point, for gc (don't recombine statements)
|
|
roots(t)->setOutOfMemoryError(t, throwable);
|
|
|
|
throwable = makeThrowable(t, GcThrowable::Type);
|
|
// sequence point, for gc (don't recombine statements)
|
|
roots(t)->setShutdownInProgress(t, throwable);
|
|
|
|
t->m->classpath->preBoot(t);
|
|
|
|
t->javaThread = t->m->classpath->makeThread(t, 0);
|
|
|
|
t->javaThread->peer() = reinterpret_cast<jlong>(t);
|
|
|
|
GcThread* jthread = t->m->classpath->makeThread(t, t);
|
|
// sequence point, for gc (don't recombine statements)
|
|
roots(t)->setFinalizerThread(t, jthread);
|
|
|
|
roots(t)->finalizerThread()->daemon() = true;
|
|
|
|
t->m->classpath->boot(t);
|
|
|
|
const char* port = findProperty(t, "avian.trace.port");
|
|
if (port) {
|
|
GcString* host = makeString(t, "0.0.0.0");
|
|
PROTECT(t, host);
|
|
|
|
GcMethod* method = resolveMethod(t,
|
|
roots(t)->bootLoader(),
|
|
"avian/Traces",
|
|
"startTraceListener",
|
|
"(Ljava/lang/String;I)V");
|
|
|
|
t->m->processor->invoke(t, method, 0, host, atoi(port));
|
|
}
|
|
|
|
enter(t, Thread::IdleState);
|
|
|
|
return 1;
|
|
}
|
|
|
|
} // namespace local
|
|
|
|
} // namespace
|
|
|
|
namespace vm {
|
|
|
|
void populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable)
|
|
{
|
|
memset(vmTable, 0, sizeof(JavaVMVTable));
|
|
|
|
vmTable->DestroyJavaVM = local::DestroyJavaVM;
|
|
vmTable->AttachCurrentThread = local::AttachCurrentThread;
|
|
vmTable->AttachCurrentThreadAsDaemon = local::AttachCurrentThreadAsDaemon;
|
|
vmTable->DetachCurrentThread = local::DetachCurrentThread;
|
|
vmTable->GetEnv = local::GetEnv;
|
|
|
|
memset(envTable, 0, sizeof(JNIEnvVTable));
|
|
|
|
envTable->GetVersion = local::GetVersion;
|
|
envTable->GetStringLength = local::GetStringLength;
|
|
envTable->GetStringChars = local::GetStringChars;
|
|
envTable->ReleaseStringChars = local::ReleaseStringChars;
|
|
envTable->GetStringRegion = local::GetStringRegion;
|
|
envTable->GetStringCritical = local::GetStringCritical;
|
|
envTable->ReleaseStringCritical = local::ReleaseStringCritical;
|
|
envTable->GetStringUTFLength = local::GetStringUTFLength;
|
|
envTable->GetStringUTFChars = local::GetStringUTFChars;
|
|
envTable->ReleaseStringUTFChars = local::ReleaseStringUTFChars;
|
|
envTable->GetStringUTFRegion = local::GetStringUTFRegion;
|
|
envTable->GetArrayLength = local::GetArrayLength;
|
|
envTable->NewString = local::NewString;
|
|
envTable->NewStringUTF = local::NewStringUTF;
|
|
envTable->DefineClass = local::DefineClass;
|
|
envTable->FindClass = local::FindClass;
|
|
envTable->ThrowNew = local::ThrowNew;
|
|
envTable->Throw = local::Throw;
|
|
envTable->ExceptionCheck = local::ExceptionCheck;
|
|
envTable->NewDirectByteBuffer = local::NewDirectByteBuffer;
|
|
envTable->GetDirectBufferAddress = local::GetDirectBufferAddress;
|
|
envTable->GetDirectBufferCapacity = local::GetDirectBufferCapacity;
|
|
envTable->NewLocalRef = local::NewLocalRef;
|
|
envTable->DeleteLocalRef = local::DeleteLocalRef;
|
|
envTable->GetObjectClass = local::GetObjectClass;
|
|
envTable->GetSuperclass = local::GetSuperclass;
|
|
envTable->IsInstanceOf = local::IsInstanceOf;
|
|
envTable->IsAssignableFrom = local::IsAssignableFrom;
|
|
envTable->GetFieldID = local::GetFieldID;
|
|
envTable->GetMethodID = local::GetMethodID;
|
|
envTable->GetStaticMethodID = local::GetStaticMethodID;
|
|
envTable->NewObjectV = local::NewObjectV;
|
|
envTable->NewObjectA = local::NewObjectA;
|
|
envTable->NewObject = local::NewObject;
|
|
envTable->CallObjectMethodV = local::CallObjectMethodV;
|
|
envTable->CallObjectMethodA = local::CallObjectMethodA;
|
|
envTable->CallObjectMethod = local::CallObjectMethod;
|
|
envTable->CallBooleanMethodV = local::CallBooleanMethodV;
|
|
envTable->CallBooleanMethodA = local::CallBooleanMethodA;
|
|
envTable->CallBooleanMethod = local::CallBooleanMethod;
|
|
envTable->CallByteMethodV = local::CallByteMethodV;
|
|
envTable->CallByteMethodA = local::CallByteMethodA;
|
|
envTable->CallByteMethod = local::CallByteMethod;
|
|
envTable->CallCharMethodV = local::CallCharMethodV;
|
|
envTable->CallCharMethodA = local::CallCharMethodA;
|
|
envTable->CallCharMethod = local::CallCharMethod;
|
|
envTable->CallShortMethodV = local::CallShortMethodV;
|
|
envTable->CallShortMethodA = local::CallShortMethodA;
|
|
envTable->CallShortMethod = local::CallShortMethod;
|
|
envTable->CallIntMethodV = local::CallIntMethodV;
|
|
envTable->CallIntMethodA = local::CallIntMethodA;
|
|
envTable->CallIntMethod = local::CallIntMethod;
|
|
envTable->CallLongMethodV = local::CallLongMethodV;
|
|
envTable->CallLongMethodA = local::CallLongMethodA;
|
|
envTable->CallLongMethod = local::CallLongMethod;
|
|
envTable->CallFloatMethodV = local::CallFloatMethodV;
|
|
envTable->CallFloatMethodA = local::CallFloatMethodA;
|
|
envTable->CallFloatMethod = local::CallFloatMethod;
|
|
envTable->CallDoubleMethodV = local::CallDoubleMethodV;
|
|
envTable->CallDoubleMethodA = local::CallDoubleMethodA;
|
|
envTable->CallDoubleMethod = local::CallDoubleMethod;
|
|
envTable->CallVoidMethodV = local::CallVoidMethodV;
|
|
envTable->CallVoidMethodA = local::CallVoidMethodA;
|
|
envTable->CallVoidMethod = local::CallVoidMethod;
|
|
envTable->CallStaticObjectMethodV = local::CallStaticObjectMethodV;
|
|
envTable->CallStaticObjectMethodA = local::CallStaticObjectMethodA;
|
|
envTable->CallStaticObjectMethod = local::CallStaticObjectMethod;
|
|
envTable->CallStaticBooleanMethodV = local::CallStaticBooleanMethodV;
|
|
envTable->CallStaticBooleanMethodA = local::CallStaticBooleanMethodA;
|
|
envTable->CallStaticBooleanMethod = local::CallStaticBooleanMethod;
|
|
envTable->CallStaticByteMethodV = local::CallStaticByteMethodV;
|
|
envTable->CallStaticByteMethodA = local::CallStaticByteMethodA;
|
|
envTable->CallStaticByteMethod = local::CallStaticByteMethod;
|
|
envTable->CallStaticCharMethodV = local::CallStaticCharMethodV;
|
|
envTable->CallStaticCharMethodA = local::CallStaticCharMethodA;
|
|
envTable->CallStaticCharMethod = local::CallStaticCharMethod;
|
|
envTable->CallStaticShortMethodV = local::CallStaticShortMethodV;
|
|
envTable->CallStaticShortMethodA = local::CallStaticShortMethodA;
|
|
envTable->CallStaticShortMethod = local::CallStaticShortMethod;
|
|
envTable->CallStaticIntMethodV = local::CallStaticIntMethodV;
|
|
envTable->CallStaticIntMethodA = local::CallStaticIntMethodA;
|
|
envTable->CallStaticIntMethod = local::CallStaticIntMethod;
|
|
envTable->CallStaticLongMethodV = local::CallStaticLongMethodV;
|
|
envTable->CallStaticLongMethodA = local::CallStaticLongMethodA;
|
|
envTable->CallStaticLongMethod = local::CallStaticLongMethod;
|
|
envTable->CallStaticFloatMethodV = local::CallStaticFloatMethodV;
|
|
envTable->CallStaticFloatMethodA = local::CallStaticFloatMethodA;
|
|
envTable->CallStaticFloatMethod = local::CallStaticFloatMethod;
|
|
envTable->CallStaticDoubleMethodV = local::CallStaticDoubleMethodV;
|
|
envTable->CallStaticDoubleMethodA = local::CallStaticDoubleMethodA;
|
|
envTable->CallStaticDoubleMethod = local::CallStaticDoubleMethod;
|
|
envTable->CallStaticVoidMethodV = local::CallStaticVoidMethodV;
|
|
envTable->CallStaticVoidMethodA = local::CallStaticVoidMethodA;
|
|
envTable->CallStaticVoidMethod = local::CallStaticVoidMethod;
|
|
envTable->GetStaticFieldID = local::GetStaticFieldID;
|
|
envTable->GetObjectField = local::GetObjectField;
|
|
envTable->GetBooleanField = local::GetBooleanField;
|
|
envTable->GetByteField = local::GetByteField;
|
|
envTable->GetCharField = local::GetCharField;
|
|
envTable->GetShortField = local::GetShortField;
|
|
envTable->GetIntField = local::GetIntField;
|
|
envTable->GetLongField = local::GetLongField;
|
|
envTable->GetFloatField = local::GetFloatField;
|
|
envTable->GetDoubleField = local::GetDoubleField;
|
|
envTable->SetObjectField = local::SetObjectField;
|
|
envTable->SetBooleanField = local::SetBooleanField;
|
|
envTable->SetByteField = local::SetByteField;
|
|
envTable->SetCharField = local::SetCharField;
|
|
envTable->SetShortField = local::SetShortField;
|
|
envTable->SetIntField = local::SetIntField;
|
|
envTable->SetLongField = local::SetLongField;
|
|
envTable->SetFloatField = local::SetFloatField;
|
|
envTable->SetDoubleField = local::SetDoubleField;
|
|
envTable->GetStaticObjectField = local::GetStaticObjectField;
|
|
envTable->GetStaticBooleanField = local::GetStaticBooleanField;
|
|
envTable->GetStaticByteField = local::GetStaticByteField;
|
|
envTable->GetStaticCharField = local::GetStaticCharField;
|
|
envTable->GetStaticShortField = local::GetStaticShortField;
|
|
envTable->GetStaticIntField = local::GetStaticIntField;
|
|
envTable->GetStaticLongField = local::GetStaticLongField;
|
|
envTable->GetStaticFloatField = local::GetStaticFloatField;
|
|
envTable->GetStaticDoubleField = local::GetStaticDoubleField;
|
|
envTable->SetStaticObjectField = local::SetStaticObjectField;
|
|
envTable->SetStaticBooleanField = local::SetStaticBooleanField;
|
|
envTable->SetStaticByteField = local::SetStaticByteField;
|
|
envTable->SetStaticCharField = local::SetStaticCharField;
|
|
envTable->SetStaticShortField = local::SetStaticShortField;
|
|
envTable->SetStaticIntField = local::SetStaticIntField;
|
|
envTable->SetStaticLongField = local::SetStaticLongField;
|
|
envTable->SetStaticFloatField = local::SetStaticFloatField;
|
|
envTable->SetStaticDoubleField = local::SetStaticDoubleField;
|
|
envTable->NewGlobalRef = local::NewGlobalRef;
|
|
envTable->NewWeakGlobalRef = local::NewWeakGlobalRef;
|
|
envTable->DeleteGlobalRef = local::DeleteGlobalRef;
|
|
envTable->DeleteWeakGlobalRef = local::DeleteWeakGlobalRef;
|
|
envTable->EnsureLocalCapacity = local::EnsureLocalCapacity;
|
|
envTable->ExceptionOccurred = local::ExceptionOccurred;
|
|
envTable->ExceptionDescribe = local::ExceptionDescribe;
|
|
envTable->ExceptionClear = local::ExceptionClear;
|
|
envTable->NewObjectArray = local::NewObjectArray;
|
|
envTable->GetObjectArrayElement = local::GetObjectArrayElement;
|
|
envTable->SetObjectArrayElement = local::SetObjectArrayElement;
|
|
envTable->NewBooleanArray = local::NewBooleanArray;
|
|
envTable->NewByteArray = local::NewByteArray;
|
|
envTable->NewCharArray = local::NewCharArray;
|
|
envTable->NewShortArray = local::NewShortArray;
|
|
envTable->NewIntArray = local::NewIntArray;
|
|
envTable->NewLongArray = local::NewLongArray;
|
|
envTable->NewFloatArray = local::NewFloatArray;
|
|
envTable->NewDoubleArray = local::NewDoubleArray;
|
|
envTable->GetBooleanArrayElements = local::GetBooleanArrayElements;
|
|
envTable->GetByteArrayElements = local::GetByteArrayElements;
|
|
envTable->GetCharArrayElements = local::GetCharArrayElements;
|
|
envTable->GetShortArrayElements = local::GetShortArrayElements;
|
|
envTable->GetIntArrayElements = local::GetIntArrayElements;
|
|
envTable->GetLongArrayElements = local::GetLongArrayElements;
|
|
envTable->GetFloatArrayElements = local::GetFloatArrayElements;
|
|
envTable->GetDoubleArrayElements = local::GetDoubleArrayElements;
|
|
envTable->ReleaseBooleanArrayElements = local::ReleaseBooleanArrayElements;
|
|
envTable->ReleaseByteArrayElements = local::ReleaseByteArrayElements;
|
|
envTable->ReleaseCharArrayElements = local::ReleaseCharArrayElements;
|
|
envTable->ReleaseShortArrayElements = local::ReleaseShortArrayElements;
|
|
envTable->ReleaseIntArrayElements = local::ReleaseIntArrayElements;
|
|
envTable->ReleaseLongArrayElements = local::ReleaseLongArrayElements;
|
|
envTable->ReleaseFloatArrayElements = local::ReleaseFloatArrayElements;
|
|
envTable->ReleaseDoubleArrayElements = local::ReleaseDoubleArrayElements;
|
|
envTable->GetBooleanArrayRegion = local::GetBooleanArrayRegion;
|
|
envTable->GetByteArrayRegion = local::GetByteArrayRegion;
|
|
envTable->GetCharArrayRegion = local::GetCharArrayRegion;
|
|
envTable->GetShortArrayRegion = local::GetShortArrayRegion;
|
|
envTable->GetIntArrayRegion = local::GetIntArrayRegion;
|
|
envTable->GetLongArrayRegion = local::GetLongArrayRegion;
|
|
envTable->GetFloatArrayRegion = local::GetFloatArrayRegion;
|
|
envTable->GetDoubleArrayRegion = local::GetDoubleArrayRegion;
|
|
envTable->SetBooleanArrayRegion = local::SetBooleanArrayRegion;
|
|
envTable->SetByteArrayRegion = local::SetByteArrayRegion;
|
|
envTable->SetCharArrayRegion = local::SetCharArrayRegion;
|
|
envTable->SetShortArrayRegion = local::SetShortArrayRegion;
|
|
envTable->SetIntArrayRegion = local::SetIntArrayRegion;
|
|
envTable->SetLongArrayRegion = local::SetLongArrayRegion;
|
|
envTable->SetFloatArrayRegion = local::SetFloatArrayRegion;
|
|
envTable->SetDoubleArrayRegion = local::SetDoubleArrayRegion;
|
|
envTable->GetPrimitiveArrayCritical = local::GetPrimitiveArrayCritical;
|
|
envTable->ReleasePrimitiveArrayCritical
|
|
= local::ReleasePrimitiveArrayCritical;
|
|
envTable->RegisterNatives = local::RegisterNatives;
|
|
envTable->UnregisterNatives = local::UnregisterNatives;
|
|
envTable->MonitorEnter = local::MonitorEnter;
|
|
envTable->MonitorExit = local::MonitorExit;
|
|
envTable->GetJavaVM = local::GetJavaVM;
|
|
envTable->IsSameObject = local::IsSameObject;
|
|
envTable->PushLocalFrame = local::PushLocalFrame;
|
|
envTable->PopLocalFrame = local::PopLocalFrame;
|
|
envTable->FromReflectedMethod = local::FromReflectedMethod;
|
|
envTable->ToReflectedMethod = local::ToReflectedMethod;
|
|
envTable->FromReflectedField = local::FromReflectedField;
|
|
envTable->ToReflectedField = local::ToReflectedField;
|
|
}
|
|
|
|
} // namespace vm
|
|
|
|
extern "C" AVIAN_EXPORT jint JNICALL JNI_GetDefaultJavaVMInitArgs(void*)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT jint JNICALL
|
|
JNI_GetCreatedJavaVMs(Machine**, jsize, jsize*)
|
|
{
|
|
// todo
|
|
return -1;
|
|
}
|
|
|
|
extern "C" AVIAN_EXPORT jint JNICALL
|
|
JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
|
|
{
|
|
local::JavaVMInitArgs* a = static_cast<local::JavaVMInitArgs*>(args);
|
|
|
|
unsigned heapLimit = 0;
|
|
unsigned stackLimit = 0;
|
|
const char* bootLibraries = 0;
|
|
const char* classpath = 0;
|
|
const char* javaHome = AVIAN_JAVA_HOME;
|
|
const char* embedPrefix = AVIAN_EMBED_PREFIX;
|
|
const char* bootClasspathPrepend = "";
|
|
const char* bootClasspath = 0;
|
|
const char* bootClasspathAppend = "";
|
|
const char* crashDumpDirectory = 0;
|
|
|
|
unsigned propertyCount = 0;
|
|
|
|
for (int i = 0; i < a->nOptions; ++i) {
|
|
if (strncmp(a->options[i].optionString, "-X", 2) == 0) {
|
|
const char* p = a->options[i].optionString + 2;
|
|
if (strncmp(p, "mx", 2) == 0) {
|
|
heapLimit = local::parseSize(p + 2);
|
|
} else if (strncmp(p, "ss", 2) == 0) {
|
|
stackLimit = local::parseSize(p + 2);
|
|
} else if (strncmp(p,
|
|
BOOTCLASSPATH_PREPEND_OPTION ":",
|
|
sizeof(BOOTCLASSPATH_PREPEND_OPTION)) == 0) {
|
|
bootClasspathPrepend = p + sizeof(BOOTCLASSPATH_PREPEND_OPTION);
|
|
} else if (strncmp(
|
|
p, BOOTCLASSPATH_OPTION ":", sizeof(BOOTCLASSPATH_OPTION))
|
|
== 0) {
|
|
bootClasspath = p + sizeof(BOOTCLASSPATH_OPTION);
|
|
} else if (strncmp(p,
|
|
BOOTCLASSPATH_APPEND_OPTION ":",
|
|
sizeof(BOOTCLASSPATH_APPEND_OPTION)) == 0) {
|
|
bootClasspathAppend = p + sizeof(BOOTCLASSPATH_APPEND_OPTION);
|
|
}
|
|
} else if (strncmp(a->options[i].optionString, "-D", 2) == 0) {
|
|
const char* p = a->options[i].optionString + 2;
|
|
if (strncmp(p, BOOTSTRAP_PROPERTY "=", sizeof(BOOTSTRAP_PROPERTY)) == 0) {
|
|
bootLibraries = p + sizeof(BOOTSTRAP_PROPERTY);
|
|
} else if (strncmp(p,
|
|
JAVA_COMMAND_PROPERTY "=",
|
|
sizeof(JAVA_COMMAND_PROPERTY)) == 0
|
|
or strncmp(p,
|
|
JAVA_LAUNCHER_PROPERTY "=",
|
|
sizeof(JAVA_LAUNCHER_PROPERTY)) == 0) {
|
|
// this means we're being invoked via the javac or java
|
|
// command, so the bootstrap library should be e.g. libjvm.so
|
|
bootLibraries = SO_PREFIX "jvm" SO_SUFFIX;
|
|
} else if (strncmp(p, CRASHDIR_PROPERTY "=", sizeof(CRASHDIR_PROPERTY))
|
|
== 0) {
|
|
crashDumpDirectory = p + sizeof(CRASHDIR_PROPERTY);
|
|
} else if (strncmp(p, CLASSPATH_PROPERTY "=", sizeof(CLASSPATH_PROPERTY))
|
|
== 0) {
|
|
classpath = p + sizeof(CLASSPATH_PROPERTY);
|
|
} else if (strncmp(p, JAVA_HOME_PROPERTY "=", sizeof(JAVA_HOME_PROPERTY))
|
|
== 0) {
|
|
javaHome = p + sizeof(JAVA_HOME_PROPERTY);
|
|
} else if (strncmp(p,
|
|
EMBED_PREFIX_PROPERTY "=",
|
|
sizeof(EMBED_PREFIX_PROPERTY)) == 0) {
|
|
embedPrefix = p + sizeof(EMBED_PREFIX_PROPERTY);
|
|
}
|
|
|
|
++propertyCount;
|
|
}
|
|
}
|
|
|
|
if (heapLimit == 0)
|
|
heapLimit = 128 * 1024 * 1024;
|
|
|
|
if (stackLimit == 0)
|
|
stackLimit = 128 * 1024;
|
|
|
|
bool addClasspathProperty = classpath == 0;
|
|
if (addClasspathProperty) {
|
|
classpath = ".";
|
|
++propertyCount;
|
|
}
|
|
|
|
System* s = makeSystem();
|
|
Heap* h = makeHeap(s, heapLimit);
|
|
Classpath* c = makeClasspath(s, h, javaHome, embedPrefix);
|
|
|
|
if (bootClasspath == 0) {
|
|
bootClasspath = c->bootClasspath();
|
|
}
|
|
|
|
unsigned bcppl = strlen(bootClasspathPrepend);
|
|
unsigned bcpl = strlen(bootClasspath);
|
|
unsigned bcpal = strlen(bootClasspathAppend);
|
|
|
|
unsigned bootClasspathBufferSize = bcppl + bcpl + bcpal + 3;
|
|
RUNTIME_ARRAY(char, bootClasspathBuffer, bootClasspathBufferSize);
|
|
char* bootClasspathPointer = RUNTIME_ARRAY_BODY(bootClasspathBuffer);
|
|
if (bootClasspathBufferSize > 3) {
|
|
local::append(&bootClasspathPointer,
|
|
bootClasspathPrepend,
|
|
bcppl,
|
|
bcpl + bcpal ? PATH_SEPARATOR : 0);
|
|
local::append(
|
|
&bootClasspathPointer, bootClasspath, bcpl, bcpal ? PATH_SEPARATOR : 0);
|
|
local::append(&bootClasspathPointer, bootClasspathAppend, bcpal, 0);
|
|
} else {
|
|
*RUNTIME_ARRAY_BODY(bootClasspathBuffer) = 0;
|
|
}
|
|
|
|
char* bootLibrary = bootLibraries ? strdup(bootLibraries) : 0;
|
|
char* bootLibraryEnd = bootLibrary ? strchr(bootLibrary, PATH_SEPARATOR) : 0;
|
|
if (bootLibraryEnd)
|
|
*bootLibraryEnd = 0;
|
|
|
|
Finder* bf
|
|
= makeFinder(s, h, RUNTIME_ARRAY_BODY(bootClasspathBuffer), bootLibrary);
|
|
Finder* af = makeFinder(s, h, classpath, bootLibrary);
|
|
if (bootLibrary)
|
|
free(bootLibrary);
|
|
Processor* p = makeProcessor(s, h, crashDumpDirectory, true);
|
|
|
|
// reserve space for avian.version and file.encoding:
|
|
propertyCount += 2;
|
|
|
|
const char** properties = static_cast<const char**>(
|
|
h->allocate(sizeof(const char*) * propertyCount));
|
|
|
|
const char** propertyPointer = properties;
|
|
|
|
const char** arguments = static_cast<const char**>(
|
|
h->allocate(sizeof(const char*) * a->nOptions));
|
|
|
|
const char** argumentPointer = arguments;
|
|
|
|
for (int i = 0; i < a->nOptions; ++i) {
|
|
if (strncmp(a->options[i].optionString, "-D", 2) == 0) {
|
|
*(propertyPointer++) = a->options[i].optionString + 2;
|
|
}
|
|
*(argumentPointer++) = a->options[i].optionString;
|
|
}
|
|
|
|
unsigned cpl = strlen(classpath);
|
|
RUNTIME_ARRAY(char, classpathProperty, cpl + strlen(CLASSPATH_PROPERTY) + 2);
|
|
if (addClasspathProperty) {
|
|
char* p = RUNTIME_ARRAY_BODY(classpathProperty);
|
|
local::append(&p, CLASSPATH_PROPERTY, strlen(CLASSPATH_PROPERTY), '=');
|
|
local::append(&p, classpath, cpl, 0);
|
|
*(propertyPointer++) = RUNTIME_ARRAY_BODY(classpathProperty);
|
|
}
|
|
|
|
*(propertyPointer++) = "avian.version=" AVIAN_VERSION;
|
|
|
|
// todo: should this be derived from the OS locale? Should it be
|
|
// overrideable via JavaVMInitArgs?
|
|
*(propertyPointer++) = "file.encoding=UTF-8";
|
|
|
|
*m = new (h->allocate(sizeof(Machine))) Machine(s,
|
|
h,
|
|
bf,
|
|
af,
|
|
p,
|
|
c,
|
|
properties,
|
|
propertyCount,
|
|
arguments,
|
|
a->nOptions,
|
|
stackLimit);
|
|
|
|
h->free(properties, sizeof(const char*) * propertyCount);
|
|
|
|
*t = p->makeThread(*m, 0, 0);
|
|
|
|
enter(*t, Thread::ActiveState);
|
|
enter(*t, Thread::IdleState);
|
|
|
|
return run(*t, local::boot, 0) ? 0 : -1;
|
|
}
|