/* Copyright (c) 2008-2011 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 "jnienv.h" #include "machine.h" #include "util.h" #include "processor.h" #include "constants.h" #include "util/runtime-array.h" using namespace vm; namespace { namespace local { jint JNICALL AttachCurrentThread(Machine* m, Thread** t, void*) { *t = static_cast(m->localThread->get()); if (*t == 0) { *t = attachThread(m, false); } return 0; } jint JNICALL AttachCurrentThreadAsDaemon(Machine* m, Thread** t, void*) { *t = static_cast(m->localThread->get()); if (*t == 0) { *t = attachThread(m, true); } return 0; } jint JNICALL DetachCurrentThread(Machine* m) { Thread* t = static_cast(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); threadPeer(t, t->javaThread) = 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); } } 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(m->localThread->get()); if (*t) { if (version <= JNI_VERSION_1_6) { return JNI_OK; } else { return JNI_EVERSION; } } else { return 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 stringLength(t, *s); } const jchar* JNICALL GetStringChars(Thread* t, jstring s, jboolean* isCopy) { ENTER(t, Thread::ActiveState); jchar* chars = static_cast (t->m->heap->allocate((stringLength(t, *s) + 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, (stringLength(t, *s) + 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 = stringData(t, *s); if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { return GetStringChars(t, s, isCopy); } else { return &charArrayBody(t, data, stringOffset(t, *s)); } } void JNICALL ReleaseStringCritical(Thread* t, jstring s, const jchar* chars) { if (objectClass(t, stringData(t, *s)) == type(t, Machine::ByteArrayType)) { 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 (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(*array, BytesPerWord); } uint64_t newString(Thread* t, uintptr_t* arguments) { const jchar* chars = reinterpret_cast(arguments[0]); jsize size = arguments[1]; object a = makeCharArray(t, size); if (size) { memcpy(&charArrayBody(t, a, 0), chars, size * sizeof(jchar)); } return reinterpret_cast (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(chars), static_cast(size) }; return reinterpret_cast(run(t, newString, arguments)); } uint64_t newStringUTF(Thread* t, uintptr_t* arguments) { const char* chars = reinterpret_cast(arguments[0]); object array = parseUtf8(t, chars, strlen(chars)); return reinterpret_cast (makeLocalReference (t, t->m->classpath->makeString (t, array, 0, fieldAtOffset(array, BytesPerWord) - 1))); } jstring JNICALL NewStringUTF(Thread* t, const char* chars) { if (chars == 0) return 0; uintptr_t arguments[] = { reinterpret_cast(chars) }; return reinterpret_cast(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(arguments[0]); const uint8_t* buffer = reinterpret_cast(arguments[1]); jsize length = arguments[2]; return reinterpret_cast (makeLocalReference (t, getJClass (t, defineClass (t, loader ? *loader : root(t, Machine::BootLoader), buffer, length)))); } jclass JNICALL DefineClass(Thread* t, const char*, jobject loader, const jbyte* buffer, jsize length) { uintptr_t arguments[] = { reinterpret_cast(loader), reinterpret_cast(buffer), static_cast(length) }; return reinterpret_cast(run(t, defineClass, arguments)); } uint64_t findClass(Thread* t, uintptr_t* arguments) { const char* name = reinterpret_cast(arguments[0]); object n = makeByteArray(t, strlen(name) + 1); replace('.', '/', name, &byteArrayBody(t, n, 0)); object caller = getCaller(t, 0); return reinterpret_cast (makeLocalReference (t, getJClass (t, resolveClass (t, caller ? classLoader(t, methodClass(t, caller)) : root(t, Machine::AppLoader), n)))); } jclass JNICALL FindClass(Thread* t, const char* name) { uintptr_t arguments[] = { reinterpret_cast(name) }; return reinterpret_cast(run(t, findClass, arguments)); } uint64_t throwNew(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); const char* message = reinterpret_cast(arguments[1]); object m = 0; PROTECT(t, m); if (message) { m = makeString(t, "%s", message); } object trace = makeTrace(t); PROTECT(t, trace); t->exception = make(t, jclassVmClass(t, *c)); set(t, t->exception, ThrowableMessage, m); set(t, t->exception, ThrowableTrace, trace); return 1; } jint JNICALL ThrowNew(Thread* t, jclass c, const char* message) { if (t->exception) { return -1; } uintptr_t arguments[] = { reinterpret_cast(c), reinterpret_cast(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(arguments[0]); return reinterpret_cast (makeLocalReference(t, getJClass(t, objectClass(t, *o)))); } jclass JNICALL GetObjectClass(Thread* t, jobject o) { uintptr_t arguments[] = { reinterpret_cast(o) }; return reinterpret_cast(run(t, getObjectClass, arguments)); } uint64_t getSuperclass(Thread* t, uintptr_t* arguments) { object class_ = jclassVmClass(t, *reinterpret_cast(arguments[0])); if (classFlags(t, class_) & ACC_INTERFACE) { return 0; } else { object super = classSuper(t, class_); return super ? reinterpret_cast (makeLocalReference(t, getJClass(t, super))) : 0; } } jclass JNICALL GetSuperclass(Thread* t, jclass c) { uintptr_t arguments[] = { reinterpret_cast(c) }; return reinterpret_cast(run(t, getSuperclass, arguments)); } uint64_t isInstanceOf(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); jclass c = reinterpret_cast(arguments[1]); return instanceOf(t, jclassVmClass(t, *c), *o); } jboolean JNICALL IsInstanceOf(Thread* t, jobject o, jclass c) { uintptr_t arguments[] = { reinterpret_cast(o), reinterpret_cast(c) }; return run(t, isInstanceOf, arguments); } uint64_t isAssignableFrom(Thread* t, uintptr_t* arguments) { jclass b = reinterpret_cast(arguments[0]); jclass a = reinterpret_cast(arguments[1]); return isAssignableFrom(t, jclassVmClass(t, *a), jclassVmClass(t, *b)); } jboolean JNICALL IsAssignableFrom(Thread* t, jclass b, jclass a) { uintptr_t arguments[] = { reinterpret_cast(b), reinterpret_cast(a) }; return run(t, isAssignableFrom, arguments); } object findMethod(Thread* t, jclass c, const char* name, const char* spec) { object n = makeByteArray(t, "%s", name); PROTECT(t, n); object s = makeByteArray(t, "%s", spec); return vm::findMethod(t, jclassVmClass(t, *c), n, s); } jint methodID(Thread* t, object method) { int id = methodNativeID(t, method); loadMemoryBarrier(); if (id == 0) { PROTECT(t, method); ACQUIRE(t, t->m->referenceLock); if (methodNativeID(t, method) == 0) { setRoot(t, Machine::JNIMethodTable, vectorAppend (t, root(t, Machine::JNIMethodTable), method)); storeStoreMemoryBarrier(); methodNativeID(t, method) = vectorSize (t, root(t, Machine::JNIMethodTable)); } } return methodNativeID(t, method); } uint64_t getMethodID(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); const char* name = reinterpret_cast(arguments[1]); const char* spec = reinterpret_cast(arguments[2]); object method = findMethod(t, c, name, spec); assert(t, (methodFlags(t, method) & 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(c), reinterpret_cast(name), reinterpret_cast(spec) }; return run(t, getMethodID, arguments); } uint64_t getStaticMethodID(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); const char* name = reinterpret_cast(arguments[1]); const char* spec = reinterpret_cast(arguments[2]); object method = findMethod(t, c, name, spec); assert(t, methodFlags(t, method) & ACC_STATIC); return methodID(t, method); } jmethodID JNICALL GetStaticMethodID(Thread* t, jclass c, const char* name, const char* spec) { uintptr_t arguments[] = { reinterpret_cast(c), reinterpret_cast(name), reinterpret_cast(spec) }; return run(t, getStaticMethodID, arguments); } object getMethod(Thread* t, jmethodID m) { assert(t, m); object method = vectorBody(t, root(t, Machine::JNIMethodTable), m - 1); assert(t, (methodFlags(t, method) & ACC_STATIC) == 0); return method; } uint64_t newObjectV(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); jmethodID m = arguments[1]; va_list* a = reinterpret_cast(arguments[2]); object o = make(t, jclassVmClass(t, *c)); PROTECT(t, o); t->m->processor->invokeList(t, getMethod(t, m), o, true, *a); return reinterpret_cast(makeLocalReference(t, o)); } jobject JNICALL NewObjectV(Thread* t, jclass c, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(c), m, reinterpret_cast(VA_LIST(a)) }; return reinterpret_cast(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(arguments[0]); jmethodID m = arguments[1]; const jvalue* a = reinterpret_cast(arguments[2]); object o = make(t, jclassVmClass(t, *c)); PROTECT(t, o); t->m->processor->invokeArray(t, getMethod(t, m), o, a); return reinterpret_cast(makeLocalReference(t, o)); } jobject JNICALL NewObjectA(Thread* t, jobject o, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(a) }; return reinterpret_cast(run(t, newObjectA, arguments)); } uint64_t callObjectMethodV(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); jmethodID m = arguments[1]; va_list* a = reinterpret_cast(arguments[2]); return reinterpret_cast (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(o), m, reinterpret_cast(VA_LIST(a)) }; return reinterpret_cast(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(arguments[0]); jmethodID m = arguments[1]; const jvalue* a = reinterpret_cast(arguments[2]); return reinterpret_cast (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(o), m, reinterpret_cast(a) }; return reinterpret_cast(run(t, callObjectMethodA, arguments)); } uint64_t callIntMethodV(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); jmethodID m = arguments[1]; va_list* a = reinterpret_cast(arguments[2]); return intValue (t, t->m->processor->invokeList(t, getMethod(t, m), *o, true, *a)); } jboolean JNICALL CallBooleanMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(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(arguments[0]); jmethodID m = arguments[1]; const jvalue* a = reinterpret_cast(arguments[2]); return intValue (t, t->m->processor->invokeArray(t, getMethod(t, m), *o, a)); } jboolean JNICALL CallBooleanMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(a) }; return run(t, callIntMethodA, arguments) != 0; } jbyte JNICALL CallByteMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(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(o), m, reinterpret_cast(a) }; return run(t, callIntMethodA, arguments); } jchar JNICALL CallCharMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(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(o), m, reinterpret_cast(a) }; return run(t, callIntMethodA, arguments); } jshort JNICALL CallShortMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(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(o), m, reinterpret_cast(a) }; return run(t, callIntMethodA, arguments); } jint JNICALL CallIntMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(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(o), m, reinterpret_cast(a) }; return run(t, callIntMethodA, arguments); } uint64_t callLongMethodV(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); jmethodID m = arguments[1]; va_list* a = reinterpret_cast(arguments[2]); return longValue (t, t->m->processor->invokeList(t, getMethod(t, m), *o, true, *a)); } jlong JNICALL CallLongMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(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(arguments[0]); jmethodID m = arguments[1]; const jvalue* a = reinterpret_cast(arguments[2]); return longValue (t, t->m->processor->invokeArray(t, getMethod(t, m), *o, a)); } jlong JNICALL CallLongMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(a) }; return run(t, callLongMethodA, arguments); } jfloat JNICALL CallFloatMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(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(o), m, reinterpret_cast(a) }; return bitsToFloat(run(t, callIntMethodA, arguments)); } jdouble JNICALL CallDoubleMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(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(o), m, reinterpret_cast(a) }; return bitsToDouble(run(t, callLongMethodA, arguments)); } uint64_t callVoidMethodV(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); jmethodID m = arguments[1]; va_list* a = reinterpret_cast(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(o), m, reinterpret_cast(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(arguments[0]); jmethodID m = arguments[1]; const jvalue* a = reinterpret_cast(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(o), m, reinterpret_cast(a) }; run(t, callVoidMethodA, arguments); } object getStaticMethod(Thread* t, jmethodID m) { assert(t, m); object method = vectorBody(t, root(t, Machine::JNIMethodTable), m - 1); assert(t, methodFlags(t, method) & ACC_STATIC); return method; } uint64_t callStaticObjectMethodV(Thread* t, uintptr_t* arguments) { jmethodID m = arguments[0]; va_list* a = reinterpret_cast(arguments[1]); return reinterpret_cast (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(VA_LIST(a)) }; return reinterpret_cast(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(arguments[1]); return reinterpret_cast (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(a) }; return reinterpret_cast(run(t, callStaticObjectMethodA, arguments)); } uint64_t callStaticIntMethodV(Thread* t, uintptr_t* arguments) { jmethodID m = arguments[0]; va_list* a = reinterpret_cast(arguments[1]); return intValue (t, t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, *a)); } jboolean JNICALL CallStaticBooleanMethodV(Thread* t, jclass, jmethodID m, va_list a) { uintptr_t arguments[] = { m, reinterpret_cast(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(arguments[1]); return intValue (t, t->m->processor->invokeArray(t, getStaticMethod(t, m), 0, a)); } jboolean JNICALL CallStaticBooleanMethodA(Thread* t, jclass, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { m, reinterpret_cast(a) }; return run(t, callStaticIntMethodA, arguments) != 0; } jbyte JNICALL CallStaticByteMethodV(Thread* t, jclass, jmethodID m, va_list a) { uintptr_t arguments[] = { m, reinterpret_cast(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(a) }; return run(t, callStaticIntMethodA, arguments); } jchar JNICALL CallStaticCharMethodV(Thread* t, jclass, jmethodID m, va_list a) { uintptr_t arguments[] = { m, reinterpret_cast(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(a) }; return run(t, callStaticIntMethodA, arguments); } jshort JNICALL CallStaticShortMethodV(Thread* t, jclass, jmethodID m, va_list a) { uintptr_t arguments[] = { m, reinterpret_cast(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(a) }; return run(t, callStaticIntMethodA, arguments); } jint JNICALL CallStaticIntMethodV(Thread* t, jclass, jmethodID m, va_list a) { uintptr_t arguments[] = { m, reinterpret_cast(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(a) }; return run(t, callStaticIntMethodA, arguments); } uint64_t callStaticLongMethodV(Thread* t, uintptr_t* arguments) { jmethodID m = arguments[0]; va_list* a = reinterpret_cast(arguments[1]); return longValue (t, t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, *a)); } jlong JNICALL CallStaticLongMethodV(Thread* t, jclass, jmethodID m, va_list a) { uintptr_t arguments[] = { m, reinterpret_cast(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(arguments[1]); return longValue (t, t->m->processor->invokeArray(t, getStaticMethod(t, m), 0, a)); } jlong JNICALL CallStaticLongMethodA(Thread* t, jclass, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { m, reinterpret_cast(a) }; return run(t, callStaticLongMethodA, arguments); } jfloat JNICALL CallStaticFloatMethodV(Thread* t, jclass, jmethodID m, va_list a) { uintptr_t arguments[] = { m, reinterpret_cast(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(a) }; return bitsToFloat(run(t, callStaticIntMethodA, arguments)); } jdouble JNICALL CallStaticDoubleMethodV(Thread* t, jclass, jmethodID m, va_list a) { uintptr_t arguments[] = { m, reinterpret_cast(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(a) }; return bitsToDouble(run(t, callStaticLongMethodA, arguments)); } uint64_t callStaticVoidMethodV(Thread* t, uintptr_t* arguments) { jmethodID m = arguments[0]; va_list* a = reinterpret_cast(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(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(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(a) }; run(t, callStaticVoidMethodA, arguments); } jint fieldID(Thread* t, object field) { int id = fieldNativeID(t, field); loadMemoryBarrier(); if (id == 0) { PROTECT(t, field); ACQUIRE(t, t->m->referenceLock); if (fieldNativeID(t, field) == 0) { setRoot(t, Machine::JNIFieldTable, vectorAppend (t, root(t, Machine::JNIFieldTable), field)); storeStoreMemoryBarrier(); fieldNativeID(t, field) = vectorSize(t, root(t, Machine::JNIFieldTable)); } } return fieldNativeID(t, field); } uint64_t getFieldID(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); const char* name = reinterpret_cast(arguments[1]); const char* spec = reinterpret_cast(arguments[2]); return fieldID(t, resolveField(t, jclassVmClass(t, *c), name, spec)); } jfieldID JNICALL GetFieldID(Thread* t, jclass c, const char* name, const char* spec) { uintptr_t arguments[] = { reinterpret_cast(c), reinterpret_cast(name), reinterpret_cast(spec) }; return run(t, getFieldID, arguments); } jfieldID JNICALL GetStaticFieldID(Thread* t, jclass c, const char* name, const char* spec) { uintptr_t arguments[] = { reinterpret_cast(c), reinterpret_cast(name), reinterpret_cast(spec) }; return run(t, getFieldID, arguments); } object getField(Thread* t, jfieldID f) { assert(t, f); object field = vectorBody(t, root(t, Machine::JNIFieldTable), f - 1); assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); return field; } uint64_t getObjectField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return reinterpret_cast (makeLocalReference(t, fieldAtOffset(*o, fieldOffset(t, field)))); } jobject JNICALL GetObjectField(Thread* t, jobject o, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(o), field }; return reinterpret_cast(run(t, getObjectField, arguments)); } uint64_t getBooleanField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset(*o, fieldOffset(t, field)); } jboolean JNICALL GetBooleanField(Thread* t, jobject o, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(o), field }; return run(t, getBooleanField, arguments); } uint64_t getByteField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset(*o, fieldOffset(t, field)); } jbyte JNICALL GetByteField(Thread* t, jobject o, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(o), field }; return run(t, getByteField, arguments); } uint64_t getCharField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset(*o, fieldOffset(t, field)); } jchar JNICALL GetCharField(Thread* t, jobject o, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(o), field }; return run(t, getCharField, arguments); } uint64_t getShortField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset(*o, fieldOffset(t, field)); } jshort JNICALL GetShortField(Thread* t, jobject o, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(o), field }; return run(t, getShortField, arguments); } uint64_t getIntField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset(*o, fieldOffset(t, field)); } jint JNICALL GetIntField(Thread* t, jobject o, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(o), field }; return run(t, getIntField, arguments); } uint64_t getLongField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset(*o, fieldOffset(t, field)); } jlong JNICALL GetLongField(Thread* t, jobject o, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(o), field }; return run(t, getLongField, arguments); } uint64_t getFloatField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return floatToBits(fieldAtOffset(*o, fieldOffset(t, field))); } jfloat JNICALL GetFloatField(Thread* t, jobject o, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(o), field }; return bitsToFloat(run(t, getFloatField, arguments)); } uint64_t getDoubleField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return doubleToBits(fieldAtOffset(*o, fieldOffset(t, field))); } jdouble JNICALL GetDoubleField(Thread* t, jobject o, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(o), field }; return bitsToDouble(run(t, getDoubleField, arguments)); } uint64_t setObjectField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); jobject v = reinterpret_cast(arguments[2]); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); set(t, *o, fieldOffset(t, field), (v ? *v : 0)); return 1; } void JNICALL SetObjectField(Thread* t, jobject o, jfieldID field, jobject v) { uintptr_t arguments[] = { reinterpret_cast(o), field, reinterpret_cast(v) }; run(t, setObjectField, arguments); } uint64_t setBooleanField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); jboolean v = arguments[2]; PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset(*o, fieldOffset(t, field)) = v; return 1; } void JNICALL SetBooleanField(Thread* t, jobject o, jfieldID field, jboolean v) { uintptr_t arguments[] = { reinterpret_cast(o), field, v }; run(t, setBooleanField, arguments); } uint64_t setByteField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); jbyte v = arguments[2]; PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset(*o, fieldOffset(t, field)) = v; return 1; } void JNICALL SetByteField(Thread* t, jobject o, jfieldID field, jbyte v) { uintptr_t arguments[] = { reinterpret_cast(o), field, static_cast(v) }; run(t, setByteField, arguments); } uint64_t setCharField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); jchar v = arguments[2]; PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset(*o, fieldOffset(t, field)) = v; return 1; } void JNICALL SetCharField(Thread* t, jobject o, jfieldID field, jchar v) { uintptr_t arguments[] = { reinterpret_cast(o), field, v }; run(t, setCharField, arguments); } uint64_t setShortField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); jshort v = arguments[2]; PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset(*o, fieldOffset(t, field)) = v; return 1; } void JNICALL SetShortField(Thread* t, jobject o, jfieldID field, jshort v) { uintptr_t arguments[] = { reinterpret_cast(o), field, static_cast(v) }; run(t, setShortField, arguments); } uint64_t setIntField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); jint v = arguments[2]; PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset(*o, fieldOffset(t, field)) = v; return 1; } void JNICALL SetIntField(Thread* t, jobject o, jfieldID field, jint v) { uintptr_t arguments[] = { reinterpret_cast(o), field, static_cast(v) }; run(t, setIntField, arguments); } uint64_t setLongField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); jlong v; memcpy(&v, arguments + 2, sizeof(jlong)); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset(*o, fieldOffset(t, field)) = 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(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(arguments[0]); object field = getField(t, arguments[1]); jfloat v = bitsToFloat(arguments[2]); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset(*o, fieldOffset(t, field)) = v; return 1; } void JNICALL SetFloatField(Thread* t, jobject o, jfieldID field, jfloat v) { uintptr_t arguments[] = { reinterpret_cast(o), field, floatToBits(v) }; run(t, setFloatField, arguments); } uint64_t setDoubleField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); jdouble v; memcpy(&v, arguments + 2, sizeof(jdouble)); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset(*o, fieldOffset(t, field)) = 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(o); arguments[1] = field; memcpy(arguments + 2, &v, sizeof(jdouble)); run(t, setDoubleField, arguments); } object getStaticField(Thread* t, jfieldID f) { assert(t, f); object field = vectorBody(t, root(t, Machine::JNIFieldTable), f - 1); assert(t, fieldFlags(t, field) & ACC_STATIC); return field; } uint64_t getStaticObjectField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return reinterpret_cast (makeLocalReference (t, fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)))); } jobject JNICALL GetStaticObjectField(Thread* t, jobject c, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(c), field }; return reinterpret_cast(run(t, getStaticObjectField, arguments)); } uint64_t getStaticBooleanField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)); } jboolean JNICALL GetStaticBooleanField(Thread* t, jobject c, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(c), field }; return run(t, getStaticBooleanField, arguments); } uint64_t getStaticByteField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)); } jbyte JNICALL GetStaticByteField(Thread* t, jobject c, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(c), field }; return run(t, getStaticByteField, arguments); } uint64_t getStaticCharField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)); } jchar JNICALL GetStaticCharField(Thread* t, jobject c, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(c), field }; return run(t, getStaticCharField, arguments); } uint64_t getStaticShortField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)); } jshort JNICALL GetStaticShortField(Thread* t, jobject c, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(c), field }; return run(t, getStaticShortField, arguments); } uint64_t getStaticIntField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)); } jint JNICALL GetStaticIntField(Thread* t, jobject c, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(c), field }; return run(t, getStaticIntField, arguments); } uint64_t getStaticLongField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)); } jlong JNICALL GetStaticLongField(Thread* t, jobject c, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(c), field }; return run(t, getStaticLongField, arguments); } uint64_t getStaticFloatField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return floatToBits (fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field))); } jfloat JNICALL GetStaticFloatField(Thread* t, jobject c, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(c), field }; return bitsToFloat(run(t, getStaticFloatField, arguments)); } uint64_t getStaticDoubleField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return doubleToBits (fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field))); } jdouble JNICALL GetStaticDoubleField(Thread* t, jobject c, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(c), field }; return bitsToDouble(run(t, getStaticDoubleField, arguments)); } uint64_t setStaticObjectField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); jobject v = reinterpret_cast(arguments[2]); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); set(t, classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field), (v ? *v : 0)); return 1; } void JNICALL SetStaticObjectField(Thread* t, jobject c, jfieldID field, jobject v) { uintptr_t arguments[] = { reinterpret_cast(c), field, reinterpret_cast(v) }; run(t, setStaticObjectField, arguments); } uint64_t setStaticBooleanField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); jboolean v = arguments[2]; PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; return 1; } void JNICALL SetStaticBooleanField(Thread* t, jobject c, jfieldID field, jboolean v) { uintptr_t arguments[] = { reinterpret_cast(c), field, v }; run(t, setStaticBooleanField, arguments); } uint64_t setStaticByteField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); jbyte v = arguments[2]; PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; return 1; } void JNICALL SetStaticByteField(Thread* t, jobject c, jfieldID field, jbyte v) { uintptr_t arguments[] = { reinterpret_cast(c), field, static_cast(v) }; run(t, setStaticByteField, arguments); } uint64_t setStaticCharField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); jchar v = arguments[2]; PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; return 1; } void JNICALL SetStaticCharField(Thread* t, jobject c, jfieldID field, jchar v) { uintptr_t arguments[] = { reinterpret_cast(c), field, v }; run(t, setStaticCharField, arguments); } uint64_t setStaticShortField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); jshort v = arguments[2]; PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; return 1; } void JNICALL SetStaticShortField(Thread* t, jobject c, jfieldID field, jshort v) { uintptr_t arguments[] = { reinterpret_cast(c), field, static_cast(v) }; run(t, setStaticShortField, arguments); } uint64_t setStaticIntField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); jint v = arguments[2]; PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; return 1; } void JNICALL SetStaticIntField(Thread* t, jobject c, jfieldID field, jint v) { uintptr_t arguments[] = { reinterpret_cast(c), field, static_cast(v) }; run(t, setStaticIntField, arguments); } uint64_t setStaticLongField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); jlong v; memcpy(&v, arguments + 2, sizeof(jlong)); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; return 1; } void JNICALL SetStaticLongField(Thread* t, jobject c, jfieldID field, jlong v) { uintptr_t arguments[2 + (sizeof(jlong) / BytesPerWord)]; arguments[0] = reinterpret_cast(c); arguments[1] = field; memcpy(arguments + 2, &v, sizeof(jlong)); run(t, setStaticLongField, arguments); } uint64_t setStaticFloatField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); jfloat v = bitsToFloat(arguments[2]); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; return 1; } void JNICALL SetStaticFloatField(Thread* t, jobject c, jfieldID field, jfloat v) { uintptr_t arguments[] = { reinterpret_cast(c), field, floatToBits(v) }; run(t, setStaticFloatField, arguments); } uint64_t setStaticDoubleField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); jdouble v; memcpy(&v, arguments + 2, sizeof(jdouble)); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; return 1; } void JNICALL SetStaticDoubleField(Thread* t, jobject c, jfieldID field, jdouble v) { uintptr_t arguments[2 + (sizeof(jdouble) / BytesPerWord)]; arguments[0] = reinterpret_cast(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(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 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(arguments[1]); jobject init = reinterpret_cast(arguments[2]); object a = makeObjectArray(t, jclassVmClass(t, *class_), length); object value = (init ? *init : 0); for (jsize i = 0; i < length; ++i) { set(t, a, ArrayBody + (i * BytesPerWord), value); } return reinterpret_cast(makeLocalReference(t, a)); } jobjectArray JNICALL NewObjectArray(Thread* t, jsize length, jclass class_, jobject init) { uintptr_t arguments[] = { static_cast(length), reinterpret_cast(class_), reinterpret_cast(init) }; return reinterpret_cast(run(t, newObjectArray, arguments)); } jobject JNICALL GetObjectArrayElement(Thread* t, jobjectArray array, jsize index) { ENTER(t, Thread::ActiveState); return makeLocalReference(t, objectArrayBody(t, *array, index)); } void JNICALL SetObjectArrayElement(Thread* t, jobjectArray array, jsize index, jobject value) { ENTER(t, Thread::ActiveState); set(t, *array, ArrayBody + (index * BytesPerWord), (value ? *value : 0)); } uint64_t newArray(Thread* t, uintptr_t* arguments) { object (*constructor)(Thread*, unsigned) = reinterpret_cast(arguments[0]); jsize length = arguments[1]; return reinterpret_cast (makeLocalReference(t, constructor(t, length))); } jbooleanArray JNICALL NewBooleanArray(Thread* t, jsize length) { uintptr_t arguments[] = { reinterpret_cast(voidPointer(makeBooleanArray)), static_cast(length) }; return reinterpret_cast(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(voidPointer(makeByteArray0)), static_cast(length) }; return reinterpret_cast(run(t, newArray, arguments)); } jcharArray JNICALL NewCharArray(Thread* t, jsize length) { uintptr_t arguments[] = { reinterpret_cast(voidPointer(makeCharArray)), static_cast(length) }; return reinterpret_cast(run(t, newArray, arguments)); } jshortArray JNICALL NewShortArray(Thread* t, jsize length) { uintptr_t arguments[] = { reinterpret_cast(voidPointer(makeShortArray)), static_cast(length) }; return reinterpret_cast(run(t, newArray, arguments)); } jintArray JNICALL NewIntArray(Thread* t, jsize length) { uintptr_t arguments[] = { reinterpret_cast(voidPointer(makeIntArray)), static_cast(length) }; return reinterpret_cast(run(t, newArray, arguments)); } jlongArray JNICALL NewLongArray(Thread* t, jsize length) { uintptr_t arguments[] = { reinterpret_cast(voidPointer(makeLongArray)), static_cast(length) }; return reinterpret_cast(run(t, newArray, arguments)); } jfloatArray JNICALL NewFloatArray(Thread* t, jsize length) { uintptr_t arguments[] = { reinterpret_cast(voidPointer(makeFloatArray)), static_cast(length) }; return reinterpret_cast(run(t, newArray, arguments)); } jdoubleArray JNICALL NewDoubleArray(Thread* t, jsize length) { uintptr_t arguments[] = { reinterpret_cast(voidPointer(makeDoubleArray)), static_cast(length) }; return reinterpret_cast(run(t, newArray, arguments)); } jboolean* JNICALL GetBooleanArrayElements(Thread* t, jbooleanArray array, jboolean* isCopy) { ENTER(t, Thread::ActiveState); unsigned size = booleanArrayLength(t, *array) * sizeof(jboolean); jboolean* p = static_cast(t->m->heap->allocate(size)); if (size) { memcpy(p, &booleanArrayBody(t, *array, 0), size); } if (isCopy) { *isCopy = true; } return p; } jbyte* JNICALL GetByteArrayElements(Thread* t, jbyteArray array, jboolean* isCopy) { ENTER(t, Thread::ActiveState); unsigned size = byteArrayLength(t, *array) * sizeof(jbyte); jbyte* p = static_cast(t->m->heap->allocate(size)); if (size) { memcpy(p, &byteArrayBody(t, *array, 0), size); } if (isCopy) { *isCopy = true; } return p; } jchar* JNICALL GetCharArrayElements(Thread* t, jcharArray array, jboolean* isCopy) { ENTER(t, Thread::ActiveState); unsigned size = charArrayLength(t, *array) * sizeof(jchar); jchar* p = static_cast(t->m->heap->allocate(size)); if (size) { memcpy(p, &charArrayBody(t, *array, 0), size); } if (isCopy) { *isCopy = true; } return p; } jshort* JNICALL GetShortArrayElements(Thread* t, jshortArray array, jboolean* isCopy) { ENTER(t, Thread::ActiveState); unsigned size = shortArrayLength(t, *array) * sizeof(jshort); jshort* p = static_cast(t->m->heap->allocate(size)); if (size) { memcpy(p, &shortArrayBody(t, *array, 0), size); } if (isCopy) { *isCopy = true; } return p; } jint* JNICALL GetIntArrayElements(Thread* t, jintArray array, jboolean* isCopy) { ENTER(t, Thread::ActiveState); unsigned size = intArrayLength(t, *array) * sizeof(jint); jint* p = static_cast(t->m->heap->allocate(size)); if (size) { memcpy(p, &intArrayBody(t, *array, 0), size); } if (isCopy) { *isCopy = true; } return p; } jlong* JNICALL GetLongArrayElements(Thread* t, jlongArray array, jboolean* isCopy) { ENTER(t, Thread::ActiveState); unsigned size = longArrayLength(t, *array) * sizeof(jlong); jlong* p = static_cast(t->m->heap->allocate(size)); if (size) { memcpy(p, &longArrayBody(t, *array, 0), size); } if (isCopy) { *isCopy = true; } return p; } jfloat* JNICALL GetFloatArrayElements(Thread* t, jfloatArray array, jboolean* isCopy) { ENTER(t, Thread::ActiveState); unsigned size = floatArrayLength(t, *array) * sizeof(jfloat); jfloat* p = static_cast(t->m->heap->allocate(size)); if (size) { memcpy(p, &floatArrayBody(t, *array, 0), size); } if (isCopy) { *isCopy = true; } return p; } jdouble* JNICALL GetDoubleArrayElements(Thread* t, jdoubleArray array, jboolean* isCopy) { ENTER(t, Thread::ActiveState); unsigned size = doubleArrayLength(t, *array) * sizeof(jdouble); jdouble* p = static_cast(t->m->heap->allocate(size)); if (size) { memcpy(p, &doubleArrayBody(t, *array, 0), size); } if (isCopy) { *isCopy = true; } return p; } void JNICALL ReleaseBooleanArrayElements(Thread* t, jbooleanArray array, jboolean* p, jint mode) { ENTER(t, Thread::ActiveState); unsigned size = booleanArrayLength(t, *array) * sizeof(jboolean); if (mode == 0 or mode == JNI_COMMIT) { if (size) { memcpy(&booleanArrayBody(t, *array, 0), p, size); } } if (mode == 0 or mode == 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 = byteArrayLength(t, *array) * sizeof(jbyte); if (mode == 0 or mode == JNI_COMMIT) { if (size) { memcpy(&byteArrayBody(t, *array, 0), p, size); } } if (mode == 0 or mode == 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 = charArrayLength(t, *array) * sizeof(jchar); if (mode == 0 or mode == JNI_COMMIT) { if (size) { memcpy(&charArrayBody(t, *array, 0), p, size); } } if (mode == 0 or mode == 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 = shortArrayLength(t, *array) * sizeof(jshort); if (mode == 0 or mode == JNI_COMMIT) { if (size) { memcpy(&shortArrayBody(t, *array, 0), p, size); } } if (mode == 0 or mode == 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 = intArrayLength(t, *array) * sizeof(jint); if (mode == 0 or mode == JNI_COMMIT) { if (size) { memcpy(&intArrayBody(t, *array, 0), p, size); } } if (mode == 0 or mode == 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 = longArrayLength(t, *array) * sizeof(jlong); if (mode == 0 or mode == JNI_COMMIT) { if (size) { memcpy(&longArrayBody(t, *array, 0), p, size); } } if (mode == 0 or mode == 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 = floatArrayLength(t, *array) * sizeof(jfloat); if (mode == 0 or mode == JNI_COMMIT) { if (size) { memcpy(&floatArrayBody(t, *array, 0), p, size); } } if (mode == 0 or mode == 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 = doubleArrayLength(t, *array) * sizeof(jdouble); if (mode == 0 or mode == JNI_COMMIT) { if (size) { memcpy(&doubleArrayBody(t, *array, 0), p, size); } } if (mode == 0 or mode == 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, &booleanArrayBody(t, *array, 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, &byteArrayBody(t, *array, 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, &charArrayBody(t, *array, 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, &shortArrayBody(t, *array, 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, &intArrayBody(t, *array, 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, &longArrayBody(t, *array, 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, &floatArrayBody(t, *array, 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, &doubleArrayBody(t, *array, 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(&booleanArrayBody(t, *array, 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(&byteArrayBody(t, *array, 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(&charArrayBody(t, *array, 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(&shortArrayBody(t, *array, 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(&intArrayBody(t, *array, 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(&longArrayBody(t, *array, 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(&floatArrayBody(t, *array, 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(&doubleArrayBody(t, *array, 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(*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(arguments[0]); return methodID(t, t->m->classpath->getVMMethod(t, *m)); } jmethodID JNICALL FromReflectedMethod(Thread* t, jobject method) { uintptr_t arguments[] = { reinterpret_cast(method) }; return static_cast(run(t, fromReflectedMethod, arguments)); } uint64_t toReflectedMethod(Thread* t, uintptr_t* arguments) { jmethodID m = arguments[1]; jboolean isStatic = arguments[2]; return reinterpret_cast (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(c), static_cast(method), static_cast(isStatic) }; return reinterpret_cast(run(t, toReflectedMethod, arguments)); } uint64_t fromReflectedField(Thread* t, uintptr_t* arguments) { jobject f = reinterpret_cast(arguments[0]); return fieldID(t, t->m->classpath->getVMField(t, *f)); } jfieldID JNICALL FromReflectedField(Thread* t, jobject field) { uintptr_t arguments[] = { reinterpret_cast(field) }; return static_cast(run(t, fromReflectedField, arguments)); } uint64_t toReflectedField(Thread* t, uintptr_t* arguments) { jfieldID f = arguments[1]; jboolean isStatic = arguments[2]; return reinterpret_cast (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(c), static_cast(field), static_cast(isStatic) }; return reinterpret_cast(run(t, toReflectedField, arguments)); } uint64_t registerNatives(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); const JNINativeMethod* methods = reinterpret_cast(arguments[1]); jint methodCount = arguments[2]; for (int i = 0; i < methodCount; ++i) { if (methods[i].function) { object method = findMethodOrNull (t, jclassVmClass(t, *c), methods[i].name, methods[i].signature); if (method == 0 or (methodFlags(t, method) & 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. } 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(c), reinterpret_cast(methods), static_cast(methodCount) }; return run(t, registerNatives, arguments) ? 0 : -1; } jint JNICALL UnregisterNatives(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); unregisterNatives(t, *c); return 0; } uint64_t monitorOp(Thread* t, uintptr_t* arguments) { void (*op)(Thread*, object) = reinterpret_cast(arguments[0]); jobject o = reinterpret_cast(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(voidPointer(acquire0)), reinterpret_cast(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(voidPointer(release0)), reinterpret_cast(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, root(t, Machine::OutOfMemoryError)); } } jint JNICALL PushLocalFrame(Thread* t, jint capacity) { uintptr_t arguments[] = { static_cast(capacity) }; return run(t, pushLocalFrame, arguments) ? 0 : -1; } uint64_t popLocalFrame(Thread* t, uintptr_t* arguments) { uint64_t r; jobject presult = reinterpret_cast(arguments[0]); if(presult != NULL) { object result = *presult; PROTECT(t, result); t->m->processor->popLocalFrame(t); r = reinterpret_cast(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(result) }; return reinterpret_cast(run(t, popLocalFrame, arguments)); } jobject JNICALL NewDirectByteBuffer(Thread* t, void* p, jlong capacity) { jclass c = FindClass(t, "java/nio/DirectByteBuffer"); return NewObject(t, c, GetMethodID(t, c, "", "(JI)V"), reinterpret_cast(p), static_cast(capacity)); } void* JNICALL GetDirectBufferAddress(Thread* t, jobject b) { return reinterpret_cast (GetLongField(t, b, GetFieldID(t, GetObjectClass(t, b), "address", "J"))); } jlong JNICALL GetDirectBufferCapacity(Thread* t, jobject b) { return GetIntField (t, b, GetFieldID(t, GetObjectClass(t, b), "capacity", "I")); } 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; } else if (s[length - 1] == 'k' or s[length - 1] == 'K') { memcpy(RUNTIME_ARRAY_BODY(buffer), s, length - 1); RUNTIME_ARRAY_BODY(buffer)[length - 1] = 0; return atoi(RUNTIME_ARRAY_BODY(buffer)) * 1024; } else if (s[length - 1] == 'm' or s[length - 1] == 'M') { memcpy(RUNTIME_ARRAY_BODY(buffer), s, length - 1); RUNTIME_ARRAY_BODY(buffer)[length - 1] = 0; return atoi(RUNTIME_ARRAY_BODY(buffer)) * 1024 * 1024; } else { 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*) { setRoot(t, Machine::NullPointerException, makeThrowable (t, Machine::NullPointerExceptionType)); setRoot(t, Machine::ArithmeticException, makeThrowable(t, Machine::ArithmeticExceptionType)); setRoot(t, Machine::ArrayIndexOutOfBoundsException, makeThrowable(t, Machine::ArrayIndexOutOfBoundsExceptionType)); setRoot(t, Machine::OutOfMemoryError, makeThrowable(t, Machine::OutOfMemoryErrorType)); setRoot(t, Machine::Shutdown, makeThrowable(t, Machine::ThrowableType)); setRoot(t, Machine::FinalizerThread, t->m->classpath->makeThread(t, t)); threadDaemon(t, root(t, Machine::FinalizerThread)) = true; t->m->classpath->boot(t); 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" JNIEXPORT jint JNICALL JNI_GetDefaultJavaVMInitArgs(void*) { return 0; } extern "C" JNIEXPORT jint JNICALL JNI_GetCreatedJavaVMs(Machine**, jsize, jsize*) { // todo return -1; } extern "C" JNIEXPORT jint JNICALL JNI_CreateJavaVM(Machine** m, Thread** t, void* args) { local::JavaVMInitArgs* a = static_cast(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, 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; if (classpath == 0) classpath = "."; System* s = makeSystem(crashDumpDirectory); 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, true); const char** properties = static_cast (h->allocate(sizeof(const char*) * propertyCount)); const char** propertyPointer = properties; const char** arguments = static_cast (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; } *m = new (h->allocate(sizeof(Machine))) Machine (s, h, bf, af, p, c, properties, propertyCount, arguments, a->nOptions, stackLimit); *t = p->makeThread(*m, 0, 0); enter(*t, Thread::ActiveState); enter(*t, Thread::IdleState); return run(*t, local::boot, 0) ? 0 : -1; }