#include "machine.h" #include "constants.h" #include "processor.h" using namespace vm; namespace { inline void replace(char a, char b, char* c) { for (; *c; ++c) if (*c == a) *c = b; } jclass search(Thread* t, jstring name, object (*op)(Thread*, object), bool replaceDots) { if (LIKELY(name)) { object n = makeByteArray(t, stringLength(t, *name) + 1, false); char* s = reinterpret_cast(&byteArrayBody(t, n, 0)); stringChars(t, *name, s); if (replaceDots) { replace('.', '/', s); } object r = op(t, n); if (t->exception) { return 0; } return makeLocalReference(t, r); } else { t->exception = makeNullPointerException(t); return 0; } } } // namespace extern "C" JNIEXPORT jstring JNICALL Java_java_lang_Object_toString(Thread* t, jobject this_) { ENTER(t, Thread::ActiveState); unsigned hash = objectHash(t, *this_); object s = makeString (t, "%s@0x%x", &byteArrayBody(t, className(t, objectClass(t, *this_)), 0), hash); return makeLocalReference(t, s); } extern "C" JNIEXPORT jclass JNICALL Java_java_lang_Object_getClass(Thread* t, jobject this_) { ENTER(t, Thread::ActiveState); return makeLocalReference(t, objectClass(t, *this_)); } extern "C" JNIEXPORT void JNICALL Java_java_lang_Object_wait(Thread* t, jobject this_, jlong milliseconds) { ENTER(t, Thread::ActiveState); vm::wait(t, *this_, milliseconds); } extern "C" JNIEXPORT void JNICALL Java_java_lang_Object_notify(Thread* t, jobject this_) { ENTER(t, Thread::ActiveState); notify(t, *this_); } extern "C" JNIEXPORT void JNICALL Java_java_lang_Object_notifyAll(Thread* t, jobject this_) { ENTER(t, Thread::ActiveState); notifyAll(t, *this_); } extern "C" JNIEXPORT jint JNICALL Java_java_lang_Object_hashCode(Thread* t, jobject this_) { ENTER(t, Thread::ActiveState); return objectHash(t, *this_); } extern "C" JNIEXPORT jobject JNICALL Java_java_lang_Object_clone(Thread* t, jclass, jobject o) { ENTER(t, Thread::ActiveState); object class_ = objectClass(t, *o); unsigned size = baseSize(t, *o, class_) * BytesPerWord; object clone; if (classArrayElementSize(t, class_)) { clone = static_cast(allocate(t, size, classObjectMask(t, class_))); memcpy(clone, *o, size); // clear any object header flags: setObjectClass(t, *o, objectClass(t, *o)); } else { clone = make(t, objectClass(t, *o)); memcpy(reinterpret_cast(clone) + 1, reinterpret_cast(*o) + 1, size - BytesPerWord); } return makeLocalReference(t, clone); } extern "C" JNIEXPORT jclass JNICALL Java_java_lang_ClassLoader_defineClass (Thread* t, jclass, jbyteArray b, jint offset, jint length) { ENTER(t, Thread::ActiveState); uint8_t* buffer = static_cast(t->m->system->allocate(length)); memcpy(buffer, &byteArrayBody(t, *b, offset), length); object c = parseClass(t, buffer, length); t->m->system->free(buffer); return makeLocalReference(t, c); } extern "C" JNIEXPORT jclass JNICALL Java_java_lang_SystemClassLoader_findLoadedClass (Thread* t, jclass, jstring name) { ENTER(t, Thread::ActiveState); return search(t, name, findLoadedClass, true); } extern "C" JNIEXPORT jclass JNICALL Java_java_lang_SystemClassLoader_findClass(Thread* t, jclass, jstring name) { ENTER(t, Thread::ActiveState); return search(t, name, resolveClass, true); } extern "C" JNIEXPORT jboolean JNICALL Java_java_lang_SystemClassLoader_resourceExists (Thread* t, jclass, jstring name) { ENTER(t, Thread::ActiveState); if (LIKELY(name)) { char n[stringLength(t, *name) + 1]; stringChars(t, *name, n); return t->m->finder->exists(n); } else { t->exception = makeNullPointerException(t); return 0; } } extern "C" JNIEXPORT jobject JNICALL Java_java_io_ObjectInputStream_makeInstance(Thread* t, jclass, jclass c) { ENTER(t, Thread::ActiveState); return makeLocalReference(t, make(t, *c)); } extern "C" JNIEXPORT jclass JNICALL Java_java_lang_Class_primitiveClass(Thread* t, jclass, jchar name) { ENTER(t, Thread::ActiveState); switch (name) { case 'B': return makeLocalReference(t, arrayBody(t, t->m->types, Machine::JbyteType)); case 'C': return makeLocalReference(t, arrayBody(t, t->m->types, Machine::JcharType)); case 'D': return makeLocalReference(t, arrayBody(t, t->m->types, Machine::JdoubleType)); case 'F': return makeLocalReference(t, arrayBody(t, t->m->types, Machine::JfloatType)); case 'I': return makeLocalReference(t, arrayBody(t, t->m->types, Machine::JintType)); case 'J': return makeLocalReference(t, arrayBody(t, t->m->types, Machine::JlongType)); case 'S': return makeLocalReference(t, arrayBody(t, t->m->types, Machine::JshortType)); case 'V': return makeLocalReference(t, arrayBody(t, t->m->types, Machine::JvoidType)); case 'Z': return makeLocalReference(t, arrayBody(t, t->m->types, Machine::JbooleanType)); default: t->exception = makeIllegalArgumentException(t); return 0; } } extern "C" JNIEXPORT void JNICALL Java_java_lang_Class_initialize(Thread* t, jobject this_) { ENTER(t, Thread::ActiveState); initClass(t, *this_); } extern "C" JNIEXPORT jboolean JNICALL Java_java_lang_Class_isAssignableFrom(Thread* t, jobject this_, jclass that) { ENTER(t, Thread::ActiveState); if (LIKELY(that)) { return vm::isAssignableFrom(t, *this_, *that); } else { t->exception = makeNullPointerException(t); return 0; } } extern "C" JNIEXPORT jlong JNICALL Java_java_lang_reflect_Field_getPrimitive (Thread* t, jclass, jobject instance, jint code, jint offset) { ENTER(t, Thread::ActiveState); switch (code) { case ByteField: return cast(*instance, offset); case BooleanField: return cast(*instance, offset); case CharField: return cast(*instance, offset); case ShortField: return cast(*instance, offset); case IntField: return cast(*instance, offset); case LongField: return cast(*instance, offset); case FloatField: return cast(*instance, offset); case DoubleField: return cast(*instance, offset); default: abort(t); } } extern "C" JNIEXPORT jobject JNICALL Java_java_lang_reflect_Field_getObject (Thread* t, jclass, jobject instance, jint offset) { ENTER(t, Thread::ActiveState); return makeLocalReference(t, cast(*instance, offset)); } extern "C" JNIEXPORT void JNICALL Java_java_lang_reflect_Field_setPrimitive (Thread* t, jclass, jobject instance, jint code, jint offset, jlong value) { ENTER(t, Thread::ActiveState); switch (code) { case ByteField: cast(*instance, offset) = static_cast(value); break; case BooleanField: cast(*instance, offset) = static_cast(value); break; case CharField: cast(*instance, offset) = static_cast(value); break; case ShortField: cast(*instance, offset) = static_cast(value); break; case IntField: cast(*instance, offset) = static_cast(value); break; case LongField: cast(*instance, offset) = static_cast(value); break; case FloatField: cast(*instance, offset) = static_cast(value); break; case DoubleField: cast(*instance, offset) = static_cast(value); break; default: abort(t); } } extern "C" JNIEXPORT void JNICALL Java_java_lang_reflect_Field_setObject (Thread* t, jclass, jobject instance, jint offset, jobject value) { ENTER(t, Thread::ActiveState); set(t, *instance, offset, (value ? *value : 0)); } extern "C" JNIEXPORT jobject JNICALL Java_java_lang_reflect_Constructor_make(Thread* t, jclass, jclass c) { ENTER(t, Thread::ActiveState); return makeLocalReference(t, make(t, *c)); } extern "C" JNIEXPORT jobject JNICALL Java_java_lang_reflect_Method_getCaller(Thread* t, jclass) { ENTER(t, Thread::ActiveState); Processor* p = t->m->processor; uintptr_t frame = p->frameStart(t); frame = p->frameNext(t, frame); frame = p->frameNext(t, frame); return makeLocalReference(t, p->frameMethod(t, frame)); } extern "C" JNIEXPORT jobject JNICALL Java_java_lang_reflect_Method_invoke (Thread* t, jclass, jobject method, jobject instance, jobjectArray arguments) { ENTER(t, Thread::ActiveState); object v = t->m->processor->invokeArray (t, *method, (instance ? *instance : 0), *arguments); if (t->exception) { t->exception = makeInvocationTargetException(t, t->exception); } return makeLocalReference(t, v); } extern "C" JNIEXPORT jint JNICALL Java_java_lang_reflect_Array_getLength(Thread* t, jclass, jobject array) { ENTER(t, Thread::ActiveState); if (LIKELY(array)) { object a = *array; unsigned elementSize = classArrayElementSize(t, objectClass(t, a)); if (LIKELY(elementSize)) { return cast(a, BytesPerWord); } else { t->exception = makeIllegalArgumentException(t); } } else { t->exception = makeNullPointerException(t); } return 0; } extern "C" JNIEXPORT jobject JNICALL Java_java_lang_reflect_Array_makeObjectArray (Thread* t, jclass, jclass elementType, jint length) { ENTER(t, Thread::ActiveState); return makeLocalReference(t, makeObjectArray(t, *elementType, length, true)); } extern "C" JNIEXPORT jint JNICALL Java_java_lang_Float_floatToRawIntBits(Thread*, jclass, jfloat v) { return floatToBits(v); } extern "C" JNIEXPORT jfloat JNICALL Java_java_lang_Float_intBitsToFloat(Thread*, jclass, jint v) { return bitsToFloat(v); } extern "C" JNIEXPORT jlong JNICALL Java_java_lang_Double_doubleToRawLongBits(Thread*, jclass, jdouble v) { return doubleToBits(v); } extern "C" JNIEXPORT jdouble JNICALL Java_java_lang_Double_longBitsToDouble(Thread*, jclass, jlong v) { return bitsToDouble(v); } extern "C" JNIEXPORT jobject JNICALL Java_java_lang_String_intern(Thread* t, jobject this_) { ENTER(t, Thread::ActiveState); return makeLocalReference(t, intern(t, *this_)); } extern "C" JNIEXPORT jstring JNICALL Java_java_lang_System_getVMProperty(Thread* t, jclass, jstring name, jbooleanArray found) { ENTER(t, Thread::ActiveState); unsigned length = stringLength(t, *name); char n[length + 1]; stringChars(t, *name, n); jstring r = 0; if (strcmp(n, "java.lang.classpath") == 0) { r = makeLocalReference(t, makeString(t, "%s", t->m->finder->path())); } else if (strcmp(n, "avium.version") == 0) { r = makeLocalReference(t, makeString(t, "0.0")); } if (r) { booleanArrayBody(t, *found, 0) = true; } return r; } extern "C" JNIEXPORT void JNICALL Java_java_lang_System_arraycopy (Thread* t, jclass, jobject src, jint srcOffset, jobject dst, jint dstOffset, jint length) { ENTER(t, Thread::ActiveState); if (LIKELY(src and dst)) { object s = *src; object d = *dst; if (LIKELY(objectClass(t, s) == objectClass(t, d))) { unsigned elementSize = classArrayElementSize(t, objectClass(t, s)); if (LIKELY(elementSize)) { intptr_t sl = cast(s, BytesPerWord); intptr_t dl = cast(d, BytesPerWord); if (LIKELY(srcOffset >= 0 and srcOffset + length <= sl and dstOffset >= 0 and dstOffset + length <= dl)) { uint8_t* sbody = &cast(s, ArrayBody); uint8_t* dbody = &cast(d, ArrayBody); if (s == d) { memmove(dbody + (dstOffset * elementSize), sbody + (srcOffset * elementSize), length * elementSize); } else { memcpy(dbody + (dstOffset * elementSize), sbody + (srcOffset * elementSize), length * elementSize); } if (classObjectMask(t, objectClass(t, d))) { mark(t, d, ArrayBody + (dstOffset * BytesPerWord), length); } return; } } } } else { t->exception = makeNullPointerException(t); return; } t->exception = makeArrayStoreException(t); } extern "C" JNIEXPORT jint JNICALL Java_java_lang_System_identityHashCode(Thread* t, jclass, jobject o) { ENTER(t, Thread::ActiveState); if (LIKELY(o)) { return objectHash(t, *o); } else { t->exception = makeNullPointerException(t); return 0; } } extern "C" JNIEXPORT void JNICALL Java_java_lang_Runtime_load(Thread* t, jclass, jstring name, jboolean mapName) { ENTER(t, Thread::ActiveState); ACQUIRE(t, t->m->classLock); unsigned length = stringLength(t, *name); char n[length + 1]; stringChars(t, *name, n); if (mapName and t->m->builtins) { const char* s = t->m->builtins; while (*s) { if (strncmp(s, n, length) == 0 and (s[length] == ',' or s[length] == 0)) { // library is built in to this executable return; } else { while (*s and *s != ',') ++ s; if (*s) ++ s; } } } for (System::Library* lib = t->m->libraries; lib; lib = lib->next()) { if (lib->name() and strcmp(lib->name(), n) == 0 and lib->mapName() == mapName) { // already loaded return; } } System::Library* lib; if (LIKELY(t->m->system->success (t->m->system->load(&lib, n, mapName, t->m->libraries)))) { t->m->libraries = lib; } else { object message = makeString(t, "library not found: %s", n); t->exception = makeUnsatisfiedLinkError(t, message); } } extern "C" JNIEXPORT void JNICALL Java_java_lang_Runtime_gc(Thread* t, jobject) { ENTER(t, Thread::ActiveState); ENTER(t, Thread::ExclusiveState); collect(t, Heap::MajorCollection); } extern "C" JNIEXPORT void JNICALL Java_java_lang_Runtime_exit(Thread* t, jobject, jint code) { ENTER(t, Thread::ActiveState); t->m->system->exit(code); } extern "C" JNIEXPORT jlong JNICALL Java_java_lang_Runtime_freeMemory(Thread*, jobject) { // todo return 0; } extern "C" JNIEXPORT jlong JNICALL Java_java_lang_Runtime_totalMemory(Thread*, jobject) { // todo return 0; } extern "C" JNIEXPORT jobject JNICALL Java_java_lang_Throwable_trace(Thread* t, jclass, jint skipCount) { ENTER(t, Thread::ActiveState); Processor* p = t->m->processor; uintptr_t frame = p->frameStart(t); while (skipCount-- and p->frameValid(t, frame)) { frame = p->frameNext(t, frame); } // skip Throwable constructors while (p->frameValid(t, frame) and isAssignableFrom (t, arrayBody(t, t->m->types, Machine::ThrowableType), methodClass(t, p->frameMethod(t, frame))) and strcmp(reinterpret_cast(""), &byteArrayBody (t, methodName(t, p->frameMethod(t, frame)), 0)) == 0) { frame = p->frameNext(t, frame); } return makeLocalReference(t, makeTrace(t, frame)); } extern "C" JNIEXPORT jarray JNICALL Java_java_lang_Throwable_resolveTrace(Thread* t, jclass, jobject trace) { ENTER(t, Thread::ActiveState); unsigned length = arrayLength(t, *trace); object array = makeObjectArray (t, arrayBody(t, t->m->types, Machine::StackTraceElementType), length, true); PROTECT(t, array); object e = 0; PROTECT(t, e); object class_ = 0; PROTECT(t, class_); for (unsigned i = 0; i < length; ++i) { e = arrayBody(t, *trace, i); class_ = className(t, methodClass(t, traceElementMethod(t, e))); class_ = makeString(t, class_, 0, byteArrayLength(t, class_) - 1, 0); object method = methodName(t, traceElementMethod(t, e)); method = makeString(t, method, 0, byteArrayLength(t, method) - 1, 0); unsigned line = t->m->processor->lineNumber (t, traceElementMethod(t, e), traceElementIp(t, e)); object ste = makeStackTraceElement(t, class_, method, 0, line); set(t, array, ArrayBody + (i * BytesPerWord), ste); } return makeLocalReference(t, array); } extern "C" JNIEXPORT jobject JNICALL Java_java_lang_Thread_currentThread(Thread* t, jclass) { ENTER(t, Thread::ActiveState); return makeLocalReference(t, t->javaThread); } extern "C" JNIEXPORT jlong JNICALL Java_java_lang_Thread_doStart(Thread* t, jobject this_) { ENTER(t, Thread::ActiveState); Thread* p = t->m->processor->makeThread(t->m, *this_, t); if (t->m->system->success(t->m->system->start(&(p->runnable)))) { return reinterpret_cast(p); } else { p->exit(); return 0; } } extern "C" JNIEXPORT void JNICALL Java_java_lang_Thread_interrupt(Thread* t, jclass, jlong peer) { interrupt(t, reinterpret_cast(peer)); } extern "C" JNIEXPORT jlong JNICALL Java_java_net_URL_00024ResourceInputStream_open (Thread* t, jclass, jstring path) { ENTER(t, Thread::ActiveState); if (LIKELY(path)) { char p[stringLength(t, *path) + 1]; stringChars(t, *path, p); return reinterpret_cast(t->m->finder->find(p)); } else { t->exception = makeNullPointerException(t); return 0; } } extern "C" JNIEXPORT jint JNICALL Java_java_net_URL_00024ResourceInputStream_read__JI (Thread*, jclass, jlong peer, jint position) { System::Region* region = reinterpret_cast(peer); if (position >= static_cast(region->length())) { return -1; } else { return region->start()[position]; } } extern "C" JNIEXPORT jint JNICALL Java_java_net_URL_00024ResourceInputStream_read__JI_3BII (Thread* t, jclass, jlong peer, jint position, jbyteArray b, jint offset, jint length) { ENTER(t, Thread::ActiveState); if (length == 0) return 0; System::Region* region = reinterpret_cast(peer); if (length > static_cast(region->length()) - position) { length = static_cast(region->length()) - position; } if (length <= 0) { return -1; } else { memcpy(&byteArrayBody(t, *b, offset), region->start() + position, length); return length; } } extern "C" JNIEXPORT void JNICALL Java_java_net_URL_00024ResourceInputStream_close(Thread*, jclass, jlong peer) { reinterpret_cast(peer)->dispose(); }