From 201473cf8722585bff7c644178e660a08706da96 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 22 Feb 2013 11:06:49 -0700 Subject: [PATCH] more work on Android classpath port --- src/android/icu.cpp | 12 + src/builtin.cpp | 7 + src/classpath-android.cpp | 520 +++++++++++++++++++++++++++++++------- src/classpath-avian.cpp | 7 - src/jnienv.cpp | 8 +- src/machine.cpp | 4 - 6 files changed, 447 insertions(+), 111 deletions(-) create mode 100644 src/android/icu.cpp diff --git a/src/android/icu.cpp b/src/android/icu.cpp new file mode 100644 index 0000000000..15b661e4c7 --- /dev/null +++ b/src/android/icu.cpp @@ -0,0 +1,12 @@ +void +register_libcore_icu_ICU(JNIEnv* e) +{ + UErrorCode status = U_ZERO_ERROR; + udata_setFileAccess(UDATA_NO_FILES, &status); + if (status != U_ZERO_ERROR) abort(); + + u_init(&status); + if (status != U_ZERO_ERROR) abort(); + + jniRegisterNativeMethods(e, "libcore/icu/ICU", gMethods, NELEM(gMethods)); +} diff --git a/src/builtin.cpp b/src/builtin.cpp index 8ec81eec14..35a576725d 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -615,3 +615,10 @@ Avian_sun_misc_Unsafe_compareAndSwapInt return atomicCompareAndSwap32 (&fieldAtOffset(target, offset), expect, update); } + +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_Classes_primitiveClass +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast(primitiveClass(t, arguments[0])); +} diff --git a/src/classpath-android.cpp b/src/classpath-android.cpp index 6cbb5a68b2..fbb1dad75e 100644 --- a/src/classpath-android.cpp +++ b/src/classpath-android.cpp @@ -44,6 +44,118 @@ appLoader(Thread* t, object, uintptr_t*) return reinterpret_cast(root(t, Machine::AppLoader)); } +object +makeMethodOrConstructor(Thread* t, object c, unsigned index) +{ + PROTECT(t, c); + + object method = arrayBody + (t, classMethodTable(t, jclassVmClass(t, c)), index); + PROTECT(t, method); + + unsigned parameterCount; + unsigned returnTypeSpec; + object parameterTypes = resolveParameterJTypes + (t, classLoader(t, methodClass(t, method)), methodSpec(t, method), + ¶meterCount, &returnTypeSpec); + PROTECT(t, parameterTypes); + + object returnType = resolveJType + (t, classLoader(t, methodClass(t, method)), reinterpret_cast + (&byteArrayBody(t, methodSpec(t, method), returnTypeSpec)), + byteArrayLength(t, methodSpec(t, method)) - 1 - returnTypeSpec); + PROTECT(t, returnType); + + object exceptionTypes = resolveExceptionJTypes + (t, classLoader(t, methodClass(t, method)), methodAddendum(t, method)); + + if (byteArrayBody(t, methodName(t, method), 0) == '<') { + return makeJconstructor + (t, 0, c, parameterTypes, exceptionTypes, 0, 0, 0, 0, index); + } else { + PROTECT(t, exceptionTypes); + + object name = t->m->classpath->makeString + (t, methodName(t, method), 0, + byteArrayLength(t, methodName(t, method)) - 1); + + return makeJmethod + (t, 0, index, c, name, parameterTypes, exceptionTypes, returnType, 0, 0, + 0, 0, 0); + } +} + +object +makeField(Thread* t, object c, unsigned index) +{ + PROTECT(t, c); + + object field = arrayBody + (t, classFieldTable(t, jclassVmClass(t, c)), index); + + PROTECT(t, field); + + object type = resolveClassBySpec + (t, classLoader(t, fieldClass(t, field)), + reinterpret_cast + (&byteArrayBody(t, fieldSpec(t, field), 0)), + byteArrayLength(t, fieldSpec(t, field)) - 1); + PROTECT(t, type); + + object name = t->m->classpath->makeString + (t, fieldName(t, field), 0, + byteArrayLength(t, fieldName(t, field)) - 1); + + return makeJfield(t, 0, c, type, 0, 0, name, index); +} + +void +initVmThread(Thread* t, object thread) +{ + PROTECT(t, thread); + + object field = resolveField + (t, objectClass(t, thread), "vmThread", "Ljava/lang/VMThread;"); + + if (fieldAtOffset(thread, fieldOffset(t, field)) == 0) { + PROTECT(t, field); + + object c = resolveClass + (t, root(t, Machine::BootLoader), "java/lang/VMThread"); + PROTECT(t, c); + + object instance = makeNew(t, c); + PROTECT(t, instance); + + object constructor = resolveMethod + (t, c, "", "(Ljava/lang/Thread;)V"); + + t->m->processor->invoke(t, constructor, instance, thread); + + set(t, thread, fieldOffset(t, field), instance); + } +} + +object +translateStackTrace(Thread* t, object raw) +{ + PROTECT(t, raw); + + object array = makeObjectArray + (t, resolveClass + (t, root(t, Machine::BootLoader), "java/lang/StackTraceElement"), + objectArrayLength(t, raw)); + PROTECT(t, array); + + for (unsigned i = 0; i < objectArrayLength(t, array); ++i) { + object e = makeStackTraceElement(t, objectArrayBody(t, raw, i)); + + set(t, array, ArrayBody + (i * BytesPerWord), e); + } + + return array; +} + class MyClasspath : public Classpath { public: MyClasspath(Allocator* allocator): @@ -86,64 +198,90 @@ class MyClasspath : public Classpath { virtual object makeThread(Thread* t, Thread* parent) { - const unsigned MaxPriority = 10; const unsigned NormalPriority = 5; - object group; + object group = 0; + PROTECT(t, group); if (parent) { group = threadGroup(t, parent->javaThread); } else { - group = allocate(t, FixedSizeOfThreadGroup, true); - setObjectClass(t, group, type(t, Machine::ThreadGroupType)); - threadGroupMaxPriority(t, group) = MaxPriority; + resolveSystemClass + (t, root(t, Machine::BootLoader), + className(t, type(t, Machine::ThreadGroupType)), false); + + group = makeNew(t, type(t, Machine::ThreadGroupType)); + + object constructor = resolveMethod + (t, type(t, Machine::ThreadGroupType), "", "()V"); + + t->m->processor->invoke(t, constructor, group); } - PROTECT(t, group); - object thread = allocate(t, FixedSizeOfThread, true); - setObjectClass(t, thread, type(t, Machine::ThreadType)); - threadPriority(t, thread) = NormalPriority; - threadGroup(t, thread) = group; + resolveSystemClass + (t, root(t, Machine::BootLoader), + className(t, type(t, Machine::ThreadType)), false); + + object thread = makeNew(t, type(t, Machine::ThreadType)); PROTECT(t, thread); - { object listClass = resolveClass - (t, root(t, Machine::BootLoader), "java/util/ArrayList"); - PROTECT(t, listClass); + object constructor = resolveMethod + (t, type(t, Machine::ThreadType), "", + "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V"); - object instance = makeNew(t, listClass); - PROTECT(t, instance); + t->m->processor->invoke + (t, constructor, thread, group, 0, NormalPriority, false); - object constructor = resolveMethod(t, listClass, "", "()V"); - - t->m->processor->invoke(t, constructor, instance); - - set(t, thread, ThreadInterruptActions, instance); - } + initVmThread(t, thread); return thread; } virtual object - makeJMethod(Thread* t, object) + makeJMethod(Thread* t, object vmMethod) { - abort(t); // todo + object table = classMethodTable(t, methodClass(t, vmMethod)); + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + if (vmMethod == arrayBody(t, table, i)) { + return makeMethodOrConstructor + (t, getJClass(t, methodClass(t, vmMethod)), i); + } + } + abort(t); } virtual object - getVMMethod(Thread* t, object) + getVMMethod(Thread* t, object jmethod) { - abort(t); // todo + return objectClass(t, jmethod) == type(t, Machine::JmethodType) + ? arrayBody + (t, classMethodTable + (t, jclassVmClass(t, jmethodDeclaringClass(t, jmethod))), + jmethodSlot(t, jmethod)) + : arrayBody + (t, classMethodTable + (t, jclassVmClass(t, jconstructorDeclaringClass(t, jmethod))), + jconstructorSlot(t, jmethod)); } virtual object - makeJField(Thread* t, object) + makeJField(Thread* t, object vmField) { - abort(t); // todo + object table = classFieldTable(t, fieldClass(t, vmField)); + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + if (vmField == arrayBody(t, table, i)) { + return makeField(t, getJClass(t, fieldClass(t, vmField)), i); + } + } + abort(t); } virtual object - getVMField(Thread* t, object) + getVMField(Thread* t, object jfield) { - abort(t); // todo + return arrayBody + (t, classFieldTable + (t, jclassVmClass(t, jfieldDeclaringClass(t, jfield))), + jfieldSlot(t, jfield)); } virtual void @@ -155,11 +293,23 @@ class MyClasspath : public Classpath { virtual void runThread(Thread* t) { - object method = resolveMethod - (t, root(t, Machine::BootLoader), "java/lang/Thread", "run", - "(Ljava/lang/Thread;)V"); + // force monitor creation so we don't get an OutOfMemory error + // later when we try to acquire it: + objectMonitor(t, t->javaThread, true); - t->m->processor->invoke(t, method, 0, t->javaThread); + THREAD_RESOURCE0(t, { + vm::acquire(t, t->javaThread); + t->flags &= ~Thread::ActiveFlag; + vm::notifyAll(t, t->javaThread); + vm::release(t, t->javaThread); + }); + + initVmThread(t, t->javaThread); + + object method = resolveMethod + (t, root(t, Machine::BootLoader), "java/lang/Thread", "run", "()V"); + + t->m->processor->invoke(t, method, t->javaThread); } virtual void @@ -261,47 +411,6 @@ class MyClasspath : public Classpath { Allocator* allocator; }; -object -makeMethodOrConstructor(Thread* t, object c, unsigned index) -{ - PROTECT(t, c); - - object method = arrayBody - (t, classMethodTable(t, jclassVmClass(t, c)), index); - PROTECT(t, method); - - unsigned parameterCount; - unsigned returnTypeSpec; - object parameterTypes = resolveParameterJTypes - (t, classLoader(t, methodClass(t, method)), methodSpec(t, method), - ¶meterCount, &returnTypeSpec); - PROTECT(t, parameterTypes); - - object returnType = resolveJType - (t, classLoader(t, methodClass(t, method)), reinterpret_cast - (&byteArrayBody(t, methodSpec(t, method), returnTypeSpec)), - byteArrayLength(t, methodSpec(t, method)) - 1 - returnTypeSpec); - PROTECT(t, returnType); - - object exceptionTypes = resolveExceptionJTypes - (t, classLoader(t, methodClass(t, method)), methodAddendum(t, method)); - - if (byteArrayBody(t, methodName(t, method), 0) == '<') { - return makeJconstructor - (t, 0, c, parameterTypes, exceptionTypes, 0, 0, 0, 0, index); - } else { - PROTECT(t, exceptionTypes); - - object name = t->m->classpath->makeString - (t, methodName(t, method), 0, - byteArrayLength(t, methodName(t, method)) - 1); - - return makeJmethod - (t, 0, index, c, name, parameterTypes, exceptionTypes, returnType, 0, 0, - 0, 0, 0); - } -} - } // namespace local } // namespace @@ -440,6 +549,28 @@ register_org_apache_harmony_dalvik_NativeTestTarget(_JNIEnv*) return 0; } +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_String_compareTo +(Thread* t, object, uintptr_t* arguments) +{ + object a = reinterpret_cast(arguments[0]); + object b = reinterpret_cast(arguments[1]); + + unsigned length = stringLength(t, a); + if (length > stringLength(t, b)) { + length = stringLength(t, b); + } + + for (unsigned i = 0; i < length; ++i) { + int d = stringCharAt(t, a, i) - stringCharAt(t, b, i); + if (d) { + return d; + } + } + + return stringLength(t, a) - stringLength(t, b); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_java_lang_String_isEmpty (Thread* t, object, uintptr_t* arguments) @@ -486,6 +617,34 @@ Avian_java_lang_String_fastIndexOf return -1; } +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Class_getInterfaces +(Thread* t, object, uintptr_t* arguments) +{ + object c = reinterpret_cast(arguments[0]); + + object addendum = classAddendum(t, jclassVmClass(t, c)); + if (addendum) { + object table = classAddendumInterfaceTable(t, addendum); + if (table) { + PROTECT(t, table); + + object array = makeObjectArray(t, arrayLength(t, table)); + PROTECT(t, array); + + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + object c = getJClass(t, arrayBody(t, table, i)); + set(t, array, ArrayBody + (i * BytesPerWord), c); + } + + return reinterpret_cast(array); + } + } + + return reinterpret_cast + (makeObjectArray(t, type(t, Machine::JclassType), 0)); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_java_lang_Class_newInstanceImpl (Thread* t, object, uintptr_t* arguments) @@ -561,29 +720,7 @@ Avian_java_lang_Class_getDeclaredField (t, method, 0, jclassVmClass(t, c), name)); if (index >= 0) { - object field = arrayBody - (t, classFieldTable(t, jclassVmClass(t, c)), index); - - PROTECT(t, field); - - object type = resolveClassBySpec - (t, classLoader(t, fieldClass(t, field)), - reinterpret_cast - (&byteArrayBody(t, fieldSpec(t, field), 0)), - byteArrayLength(t, fieldSpec(t, field)) - 1); - PROTECT(t, type); - - unsigned index = 0xFFFFFFFF; - object table = classFieldTable(t, fieldClass(t, field)); - for (unsigned i = 0; i < arrayLength(t, table); ++i) { - if (field == arrayBody(t, table, i)) { - index = i; - break; - } - } - - return reinterpret_cast - (makeJfield(t, 0, c, type, 0, 0, name, index)); + return reinterpret_cast(local::makeField(t, c, index)); } else { return 0; } @@ -687,6 +824,13 @@ Avian_dalvik_system_VMRuntime_properties (makeObjectArray(t, type(t, Machine::StringType), 0)); } +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Runtime_gc +(Thread* t, object, uintptr_t*) +{ + collect(t, Heap::MajorCollection); +} + extern "C" JNIEXPORT void JNICALL Avian_java_lang_System_arraycopy (Thread* t, object, uintptr_t* arguments) @@ -710,6 +854,50 @@ Avian_sun_misc_Unsafe_objectFieldOffset jfieldSlot(t, jfield))); } +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_VMThread_interrupt +(Thread* t, object, uintptr_t* arguments) +{ + object vmThread = reinterpret_cast(arguments[0]); + PROTECT(t, vmThread); + + object field = resolveField + (t, objectClass(t, vmThread), "thread", "Ljava/lang/Thread;"); + + interrupt + (t, reinterpret_cast + (threadPeer(t, fieldAtOffset(vmThread, fieldOffset(t, field))))); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_VMThread_interrupted +(Thread* t, object, uintptr_t*) +{ + return getAndClearInterrupted(t, t); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_VMThread_isInterrupted +(Thread* t, object, uintptr_t* arguments) +{ + object vmThread = reinterpret_cast(arguments[0]); + PROTECT(t, vmThread); + + object field = resolveField + (t, objectClass(t, vmThread), "thread", "Ljava/lang/Thread;"); + + return threadInterrupted + (t, fieldAtOffset(vmThread, fieldOffset(t, field))); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_VMThread_getStatus +(Thread*, object, uintptr_t*) +{ + // todo + return -1; +} + extern "C" JNIEXPORT int64_t JNICALL Avian_java_lang_VMThread_currentThread (Thread* t, object, uintptr_t*) @@ -717,6 +905,45 @@ Avian_java_lang_VMThread_currentThread return reinterpret_cast(t->javaThread); } +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_VMThread_create +(Thread* t, object, uintptr_t* arguments) +{ + startThread(t, reinterpret_cast(arguments[0])); +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_VMThread_sleep +(Thread* t, object, uintptr_t* arguments) +{ + int64_t milliseconds; memcpy(&milliseconds, arguments, 8); + if (arguments[2] > 0) ++ milliseconds; + if (milliseconds <= 0) milliseconds = 1; + + if (threadSleepLock(t, t->javaThread) == 0) { + object lock = makeJobject(t); + set(t, t->javaThread, ThreadSleepLock, lock); + } + + acquire(t, threadSleepLock(t, t->javaThread)); + vm::wait(t, threadSleepLock(t, t->javaThread), milliseconds); + release(t, threadSleepLock(t, t->javaThread)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_dalvik_system_VMStack_getThreadStackTrace +(Thread* t, object, uintptr_t* arguments) +{ + Thread* p = reinterpret_cast + (threadPeer(t, reinterpret_cast(arguments[0]))); + + return reinterpret_cast + (local::translateStackTrace + (t, p == t + ? makeTrace(t) + : t->m->processor->getStackTrace(t, p))); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_dalvik_system_VMStack_getCallingClassLoader (Thread* t, object, uintptr_t*) @@ -760,6 +987,50 @@ Avian_java_lang_Math_max return max(static_cast(arguments[0]), static_cast(arguments[1])); } +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Math_floor +(Thread*, object, uintptr_t* arguments) +{ + int64_t v; memcpy(&v, arguments, 8); + return doubleToBits(floor(bitsToDouble(v))); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Float_intBitsToFloat +(Thread*, object, uintptr_t* arguments) +{ + return arguments[0]; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Float_floatToIntBits +(Thread*, object, uintptr_t* arguments) +{ + if (((arguments[0] & 0x7F800000) == 0x7F800000) + and ((arguments[0] & 0x007FFFFF) != 0)) + { + return 0x7fc00000; + } else { + return arguments[0]; + } +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Object_wait +(Thread* t, object, uintptr_t* arguments) +{ + jlong milliseconds; memcpy(&milliseconds, arguments + 1, sizeof(jlong)); + + wait(t, reinterpret_cast(arguments[0]), milliseconds); +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Object_notifyAll +(Thread* t, object, uintptr_t* arguments) +{ + notifyAll(t, reinterpret_cast(arguments[0])); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_java_lang_Object_getClass (Thread* t, object, uintptr_t* arguments) @@ -857,13 +1128,27 @@ Avian_java_lang_Class_isAssignableFrom object that = reinterpret_cast(arguments[1]); if (LIKELY(that)) { - return vm::isAssignableFrom + return isAssignableFrom (t, jclassVmClass(t, this_), jclassVmClass(t, that)); } else { throwNew(t, Machine::NullPointerExceptionType); } } +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Class_isInstance +(Thread* t, object, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + object o = reinterpret_cast(arguments[1]); + + if (o) { + return instanceOf(t, jclassVmClass(t, this_), o); + } else { + return 0; + } +} + extern "C" JNIEXPORT int64_t JNICALL Avian_java_lang_reflect_Method_invokeNative (Thread* t, object, uintptr_t* arguments) @@ -1019,6 +1304,37 @@ Avian_java_lang_reflect_Constructor_constructNative return reinterpret_cast(instance); } +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Field_getField +(Thread* t, object, uintptr_t* arguments) +{ + object field = arrayBody + (t, classFieldTable + (t, jclassVmClass(t, reinterpret_cast(arguments[2]))), + arguments[4]); + + if (fieldFlags(t, field) & ACC_STATIC) { + return reinterpret_cast + (fieldAtOffset + (classStaticTable(t, fieldClass(t, field)), fieldOffset(t, field))); + } else { + return reinterpret_cast + (fieldAtOffset + (reinterpret_cast(arguments[1]), fieldOffset(t, field))); + } +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Field_getFieldModifiers +(Thread* t, object, uintptr_t* arguments) +{ + return fieldFlags + (t, arrayBody + (t, classFieldTable + (t, jclassVmClass(t, reinterpret_cast(arguments[1]))), + arguments[2])); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_java_lang_Throwable_nativeFillInStackTrace (Thread* t, object, uintptr_t*) @@ -1026,6 +1342,14 @@ Avian_java_lang_Throwable_nativeFillInStackTrace return reinterpret_cast(getTrace(t, 2)); } +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Throwable_nativeGetStackTrace +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast + (local::translateStackTrace(t, reinterpret_cast(arguments[0]))); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_avian_Classes_makeMethod (Thread* t, object, uintptr_t* arguments) diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index d5a6ba367a..58ab70e792 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -677,13 +677,6 @@ Avian_avian_Atomic_compareAndSwapObject return success; } -extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_Classes_primitiveClass -(Thread* t, object, uintptr_t* arguments) -{ - return reinterpret_cast(primitiveClass(t, arguments[0])); -} - extern "C" JNIEXPORT int64_t JNICALL Avian_avian_Classes_isAssignableFrom (Thread* t, object, uintptr_t* arguments) diff --git a/src/jnienv.cpp b/src/jnienv.cpp index b563993369..1a761659b4 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -3513,12 +3513,16 @@ boot(Thread* t, uintptr_t*) setRoot(t, Machine::Shutdown, makeThrowable(t, Machine::ThrowableType)); + t->m->classpath->boot(t); + + t->javaThread = t->m->classpath->makeThread(t, 0); + + threadPeer(t, t->javaThread) = reinterpret_cast(t); + 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; diff --git a/src/machine.cpp b/src/machine.cpp index ff3fdf814d..85174ca93c 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -3209,10 +3209,6 @@ Thread::init() setRoot(this, Machine::JNIFieldTable, makeVector(this, 0, 0)); m->localThread->set(this); - - javaThread = m->classpath->makeThread(this, 0); - - threadPeer(this, javaThread) = reinterpret_cast(this); } expect(this, m->system->success(m->system->make(&lock)));