diff --git a/classpath/avian/Android.java b/classpath/avian/Android.java deleted file mode 100644 index 720f82341c..0000000000 --- a/classpath/avian/Android.java +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (c) 2013, 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. */ - -package avian; - -public class Android { - public static VMField findField(VMClass vmClass, String name) { - if (vmClass.fieldTable != null) { - Classes.link(vmClass); - - for (int i = 0; i < vmClass.fieldTable.length; ++i) { - if (getName(vmClass.fieldTable[i]).equals(name)) { - return vmClass.fieldTable[i]; - } - } - } - return null; - } - - public static String getName(VMField vmField) { - return new String(vmField.name, 0, vmField.name.length - 1); - } -} diff --git a/classpath/avian/Classes.java b/classpath/avian/Classes.java index a445114022..e5c3d9fa69 100644 --- a/classpath/avian/Classes.java +++ b/classpath/avian/Classes.java @@ -16,6 +16,8 @@ import static avian.Stream.read2; import java.lang.reflect.Modifier; import java.lang.reflect.Method; import java.lang.reflect.Field; +import java.lang.reflect.Proxy; +import java.lang.annotation.Annotation; import java.io.InputStream; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -262,6 +264,158 @@ public class Classes { link(c, c.loader); } + public static Class forName(String name, boolean initialize, + ClassLoader loader) + throws ClassNotFoundException + { + if (loader == null) { + loader = Class.class.getClassLoader(); + } + Class c = loader.loadClass(name); + VMClass vmc = SystemClassLoader.vmClass(c); + Classes.link(vmc, loader); + if (initialize) { + Classes.initialize(vmc); + } + return c; + } + + public static Class forCanonicalName(String name) { + return forCanonicalName(null, name); + } + + public static Class forCanonicalName(ClassLoader loader, String name) { + try { + if (name.startsWith("[")) { + return forName(name, true, loader); + } else if (name.startsWith("L")) { + return forName(name.substring(1, name.length() - 1), true, loader); + } else { + if (name.length() == 1) { + return SystemClassLoader.getClass + (Classes.primitiveClass(name.charAt(0))); + } else { + throw new ClassNotFoundException(name); + } + } + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + private static int next(char c, String s, int start) { + for (int i = start; i < s.length(); ++i) { + if (s.charAt(i) == c) return i; + } + throw new RuntimeException(); + } + + public static Class[] getParameterTypes(VMMethod vmMethod) { + int count = vmMethod.parameterCount; + + Class[] types = new Class[count]; + int index = 0; + + String spec = new String + (vmMethod.spec, 1, vmMethod.spec.length - 1); + + try { + for (int i = 0; i < spec.length(); ++i) { + char c = spec.charAt(i); + if (c == ')') { + break; + } else if (c == 'L') { + int start = i + 1; + i = next(';', spec, start); + String name = spec.substring(start, i).replace('/', '.'); + types[index++] = Class.forName(name, true, vmMethod.class_.loader); + } else if (c == '[') { + int start = i; + while (spec.charAt(i) == '[') ++i; + + if (spec.charAt(i) == 'L') { + i = next(';', spec, i + 1); + String name = spec.substring(start, i).replace('/', '.'); + types[index++] = Class.forName + (name, true, vmMethod.class_.loader); + } else { + String name = spec.substring(start, i + 1); + types[index++] = forCanonicalName(vmMethod.class_.loader, name); + } + } else { + String name = spec.substring(i, i + 1); + types[index++] = forCanonicalName(vmMethod.class_.loader, name); + } + } + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + + return types; + } + public static int findField(VMClass vmClass, String name) { + if (vmClass.fieldTable != null) { + Classes.link(vmClass); + + for (int i = 0; i < vmClass.fieldTable.length; ++i) { + if (toString(vmClass.fieldTable[i].name).equals(name)) { + return i; + } + } + } + return -1; + } + + public static String toString(byte[] array) { + return new String(array, 0, array.length - 1); + } + + private static boolean match(Class[] a, Class[] b) { + if (a.length == b.length) { + for (int i = 0; i < a.length; ++i) { + if (! a[i].isAssignableFrom(b[i])) { + return false; + } + } + return true; + } else { + return false; + } + } + + private static int findMethod(VMClass vmClass, String name, + Class[] parameterTypes) + { + if (vmClass.methodTable != null) { + Classes.link(vmClass); + + if (parameterTypes == null) { + parameterTypes = new Class[0]; + } + + for (int i = 0; i < vmClass.methodTable.length; ++i) { + if (toString(vmClass.methodTable[i].name).equals(name) + && match(parameterTypes, + getParameterTypes(vmClass.methodTable[i]))) + { + return i; + } + } + } + return -1; + } + + public static Annotation getAnnotation(ClassLoader loader, Object[] a) { + if (a[0] == null) { + a[0] = Proxy.newProxyInstance + (loader, new Class[] { (Class) a[1] }, + new AnnotationInvocationHandler(a)); + } + return (Annotation) a[0]; + } + + public static native Method makeMethod(Class c, int slot); + private static native void acquireClassLock(); private static native void releaseClassLock(); diff --git a/classpath/avian/SystemClassLoader.java b/classpath/avian/SystemClassLoader.java index 5c228cd9c1..db704c6c26 100644 --- a/classpath/avian/SystemClassLoader.java +++ b/classpath/avian/SystemClassLoader.java @@ -28,6 +28,8 @@ public class SystemClassLoader extends ClassLoader { public static native Class getClass(VMClass vmClass); + public static native VMClass vmClass(Class jClass); + private native VMClass findLoadedVMClass(String name); protected Class reallyFindLoadedClass(String name){ @@ -35,6 +37,30 @@ public class SystemClassLoader extends ClassLoader { return c == null ? null : getClass(c); } + protected Class loadClass(String name, boolean resolve) + throws ClassNotFoundException + { + Class c = findLoadedClass(name); + if (c == null) { + ClassLoader parent = getParent(); + if (parent != null) { + try { + c = parent.loadClass(name); + } catch (ClassNotFoundException ok) { } + } + + if (c == null) { + c = findClass(name); + } + } + + if (resolve) { + resolveClass(c); + } + + return c; + } + private native String resourceURLPrefix(String name); protected URL findResource(String name) { diff --git a/classpath/java/lang/Class.java b/classpath/java/lang/Class.java index dcef601f12..a37fb96e59 100644 --- a/classpath/java/lang/Class.java +++ b/classpath/java/lang/Class.java @@ -145,38 +145,7 @@ public final class Class implements Type, AnnotatedElement { ClassLoader loader) throws ClassNotFoundException { - if (loader == null) { - loader = Class.class.vmClass.loader; - } - Class c = loader.loadClass(name); - Classes.link(c.vmClass, loader); - if (initialize) { - Classes.initialize(c.vmClass); - } - return c; - } - - public static Class forCanonicalName(String name) { - return forCanonicalName(null, name); - } - - public static Class forCanonicalName(ClassLoader loader, String name) { - try { - if (name.startsWith("[")) { - return forName(name, true, loader); - } else if (name.startsWith("L")) { - return forName(name.substring(1, name.length() - 1), true, loader); - } else { - if (name.length() == 1) { - return SystemClassLoader.getClass - (Classes.primitiveClass(name.charAt(0))); - } else { - throw new ClassNotFoundException(name); - } - } - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } + return Classes.forName(name, initialize, loader); } public Class getComponentType() { @@ -211,84 +180,36 @@ public final class Class implements Type, AnnotatedElement { return Classes.isAssignableFrom(vmClass, c.vmClass); } - private static Field findField(VMClass vmClass, String name) { - if (vmClass.fieldTable != null) { - Classes.link(vmClass); - - for (int i = 0; i < vmClass.fieldTable.length; ++i) { - if (Field.getName(vmClass.fieldTable[i]).equals(name)) { - return new Field(vmClass.fieldTable[i]); - } - } - } - return null; - } - public Field getDeclaredField(String name) throws NoSuchFieldException { - Field f = findField(vmClass, name); - if (f == null) { + int index = Classes.findField(vmClass, name); + if (index < 0) { throw new NoSuchFieldException(name); } else { - return f; + return new Field(vmClass.fieldTable[index]); } } public Field getField(String name) throws NoSuchFieldException { for (VMClass c = vmClass; c != null; c = c.super_) { - Field f = findField(c, name); - if (f != null) { - return f; + int index = findField(c, name); + if (index >= 0) { + return new Field(vmClass.fieldTable[index]); } } throw new NoSuchFieldException(name); } - private static boolean match(Class[] a, Class[] b) { - if (a.length == b.length) { - for (int i = 0; i < a.length; ++i) { - if (! a[i].isAssignableFrom(b[i])) { - return false; - } - } - return true; - } else { - return false; - } - } - - private static Method findMethod(VMClass vmClass, String name, - Class[] parameterTypes) - { - if (vmClass.methodTable != null) { - Classes.link(vmClass); - - if (parameterTypes == null) { - parameterTypes = new Class[0]; - } - - for (int i = 0; i < vmClass.methodTable.length; ++i) { - if (Method.getName(vmClass.methodTable[i]).equals(name) - && match(parameterTypes, - Method.getParameterTypes(vmClass.methodTable[i]))) - { - return new Method(vmClass.methodTable[i]); - } - } - } - return null; - } - public Method getDeclaredMethod(String name, Class ... parameterTypes) throws NoSuchMethodException { if (name.startsWith("<")) { throw new NoSuchMethodException(name); } - Method m = findMethod(vmClass, name, parameterTypes); - if (m == null) { + int index = Classes.findMethod(vmClass, name, parameterTypes); + if (index < 0) { throw new NoSuchMethodException(name); } else { - return m; + return new Method(vmClass.methodTable[index]); } } @@ -299,9 +220,9 @@ public final class Class implements Type, AnnotatedElement { throw new NoSuchMethodException(name); } for (VMClass c = vmClass; c != null; c = c.super_) { - Method m = findMethod(c, name, parameterTypes); - if (m != null) { - return m; + int index = findMethod(c, name, parameterTypes); + if (index >= 0) { + return new Method(vmClass.methodTable[index]); } } throw new NoSuchMethodException(name); diff --git a/classpath/java/lang/reflect/Method.java b/classpath/java/lang/reflect/Method.java index f90ed311a5..a572f3eb49 100644 --- a/classpath/java/lang/reflect/Method.java +++ b/classpath/java/lang/reflect/Method.java @@ -58,61 +58,8 @@ public class Method extends AccessibleObject implements Member { return new String(vmMethod.spec, 0, vmMethod.spec.length - 1, false); } - private static int next(char c, String s, int start) { - for (int i = start; i < s.length(); ++i) { - if (s.charAt(i) == c) return i; - } - throw new RuntimeException(); - } - public Class[] getParameterTypes() { - return getParameterTypes(vmMethod); - } - - public static Class[] getParameterTypes(VMMethod vmMethod) { - int count = vmMethod.parameterCount; - - Class[] types = new Class[count]; - int index = 0; - - String spec = new String - (vmMethod.spec, 1, vmMethod.spec.length - 1, false); - - try { - for (int i = 0; i < spec.length(); ++i) { - char c = spec.charAt(i); - if (c == ')') { - break; - } else if (c == 'L') { - int start = i + 1; - i = next(';', spec, start); - String name = spec.substring(start, i).replace('/', '.'); - types[index++] = Class.forName(name, true, vmMethod.class_.loader); - } else if (c == '[') { - int start = i; - while (spec.charAt(i) == '[') ++i; - - if (spec.charAt(i) == 'L') { - i = next(';', spec, i + 1); - String name = spec.substring(start, i).replace('/', '.'); - types[index++] = Class.forName - (name, true, vmMethod.class_.loader); - } else { - String name = spec.substring(start, i + 1); - types[index++] = Class.forCanonicalName - (vmMethod.class_.loader, name); - } - } else { - String name = spec.substring(i, i + 1); - types[index++] = Class.forCanonicalName - (vmMethod.class_.loader, name); - } - } - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } - - return types; + return Classes.getParameterTypes(vmMethod); } public Object invoke(Object instance, Object ... arguments) @@ -160,22 +107,13 @@ public class Method extends AccessibleObject implements Member { throw new RuntimeException(); } - private Annotation getAnnotation(Object[] a) { - if (a[0] == null) { - a[0] = Proxy.newProxyInstance - (vmMethod.class_.loader, new Class[] { (Class) a[1] }, - new AnnotationInvocationHandler(a)); - } - return (Annotation) a[0]; - } - public T getAnnotation(Class class_) { if (vmMethod.hasAnnotations()) { Object[] table = (Object[]) vmMethod.addendum.annotationTable; for (int i = 0; i < table.length; ++i) { Object[] a = (Object[]) table[i]; if (a[1] == class_) { - return (T) getAnnotation(a); + return (T) Classes.getAnnotation(vmMethod.class_.loader, a); } } } @@ -187,7 +125,8 @@ public class Method extends AccessibleObject implements Member { Object[] table = (Object[]) vmMethod.addendum.annotationTable; Annotation[] array = new Annotation[table.length]; for (int i = 0; i < table.length; ++i) { - array[i] = getAnnotation((Object[]) table[i]); + array[i] = Classes.getAnnotation + (vmMethod.class_.loader, (Object[]) table[i]); } return array; } else { diff --git a/classpath/java/lang/reflect/Proxy.java b/classpath/java/lang/reflect/Proxy.java index cfc35a6077..f3db1434b5 100644 --- a/classpath/java/lang/reflect/Proxy.java +++ b/classpath/java/lang/reflect/Proxy.java @@ -16,6 +16,9 @@ import static avian.Stream.write4; import static avian.Stream.set4; import static avian.Assembler.*; +import avian.SystemClassLoader; +import avian.Classes; + import avian.ConstantPool; import avian.ConstantPool.PoolEntry; @@ -87,26 +90,15 @@ public class Proxy { write1(out, aload_0); - write1(out, new_); - write2(out, ConstantPool.addClass(pool, "java/lang/reflect/Method") + 1); - write1(out, dup); write1(out, ldc_w); write2(out, ConstantPool.addClass(pool, className) + 1); - write1(out, getfield); - write2(out, ConstantPool.addFieldRef - (pool, "java/lang/Class", - "vmClass", "Lavian/VMClass;") + 1); - write1(out, getfield); - write2(out, ConstantPool.addFieldRef - (pool, "avian/VMClass", - "methodTable", "[Lavian/VMMethod;") + 1); write1(out, ldc_w); write2(out, ConstantPool.addInteger(pool, index) + 1); - write1(out, aaload); - write1(out, invokespecial); + write1(out, invokestatic); write2(out, ConstantPool.addMethodRef - (pool, "java/lang/reflect/Method", - "", "(Lavian/VMMethod;)V") + 1); + (pool, "avian/Classes", + "makeMethod", "(Ljava/lang/Class;I)Ljava/lang/reflect/Method;") + + 1); write1(out, ldc_w); write2(out, ConstantPool.addInteger(pool, parameterCount) + 1); @@ -363,10 +355,11 @@ public class Proxy { Map virtualMap = new HashMap(); for (Class c: interfaces) { - avian.VMMethod[] ivtable = c.vmClass.virtualTable; + avian.VMMethod[] ivtable = SystemClassLoader.vmClass(c).virtualTable; if (ivtable != null) { for (avian.VMMethod m: ivtable) { - virtualMap.put(Method.getName(m) + Method.getSpec(m), m); + virtualMap.put + (Classes.toString(m.name) + Classes.toString(m.spec), m); } } } @@ -376,15 +369,15 @@ public class Proxy { for (avian.VMMethod m: virtualMap.values()) { methodTable[i] = new MethodData (0, - ConstantPool.addUtf8(pool, Method.getName(m)), - ConstantPool.addUtf8(pool, Method.getSpec(m)), + ConstantPool.addUtf8(pool, Classes.toString(m.name)), + ConstantPool.addUtf8(pool, Classes.toString(m.spec)), makeInvokeCode(pool, name, m.spec, m.parameterCount, m.parameterFootprint, i)); ++ i; } methodTable[i++] = new MethodData - (0, + (Modifier.PUBLIC, ConstantPool.addUtf8(pool, ""), ConstantPool.addUtf8 (pool, "(Ljava/lang/reflect/InvocationHandler;)V"), diff --git a/makefile b/makefile index a023f4b6f2..61b3f9b920 100755 --- a/makefile +++ b/makefile @@ -163,7 +163,6 @@ ifneq ($(android),) -I$(android)/libcore/include \ -I$(build)/android-src/external/fdlibm \ -I$(build)/android-src \ - -fpermissive \ -fno-exceptions \ -DHAVE_SYS_UIO_H \ -D_FILE_OFFSET_BITS=64 \ @@ -1200,6 +1199,7 @@ ifneq ($(classpath),avian) # them to synthesize a class: classpath-sources := \ $(classpath-src)/avian/Addendum.java \ + $(classpath-src)/avian/AnnotationInvocationHandler.java \ $(classpath-src)/avian/Assembler.java \ $(classpath-src)/avian/Callback.java \ $(classpath-src)/avian/CallbackReceiver.java \ @@ -1230,7 +1230,7 @@ ifneq ($(classpath),avian) $(classpath-src)/java/net/StandardProtocolFamily.java \ $(classpath-src)/sun/misc/Cleaner.java \ $(classpath-src)/sun/misc/Unsafe.java \ - $(classpath-src)/avian/Android.java + $(classpath-src)/java/lang/reflect/Proxy.java endif else classpath-sources := $(shell find $(classpath-src) -name '*.java') @@ -1432,7 +1432,8 @@ $(build)/android.dep: $(luni-javas) $(dalvik-javas) $(xml-javas) find $(build)/android-src -name '*.java' > $(build)/android.txt $(javac) -Xmaxerrs 1000 -d $(build)/android -sourcepath $(luni-java) \ @$(build)/android.txt - rm $(build)/android/sun/misc/Unsafe* + rm $(build)/android/sun/misc/Unsafe* \ + $(build)/android/java/lang/reflect/Proxy* cp -r $(build)/android/* $(classpath-build) @touch $(@) diff --git a/src/builtin.cpp b/src/builtin.cpp index b9cfde971d..8ec81eec14 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -50,6 +50,15 @@ resolveSystemClassThrow(Thread* t, object loader, object spec) } // namespace +extern "C" JNIEXPORT void JNICALL +Avian_avian_Classes_initialize +(Thread* t, object, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + + initClass(t, this_); +} + extern "C" JNIEXPORT void JNICALL Avian_avian_Classes_acquireClassLock (Thread* t, object, uintptr_t*) @@ -75,6 +84,26 @@ Avian_avian_Classes_resolveVMClass (resolveClass(t, loader, spec, true, Machine::ClassNotFoundExceptionType)); } +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_Classes_defineVMClass +(Thread* t, object, uintptr_t* arguments) +{ + object loader = reinterpret_cast(arguments[0]); + object b = reinterpret_cast(arguments[1]); + int offset = arguments[2]; + int length = arguments[3]; + + uint8_t* buffer = static_cast + (t->m->heap->allocate(length)); + + THREAD_RESOURCE2(t, uint8_t*, buffer, int, length, + t->m->heap->free(buffer, length)); + + memcpy(buffer, &byteArrayBody(t, b, offset), length); + + return reinterpret_cast(defineClass(t, loader, buffer, length)); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_avian_SystemClassLoader_findLoadedVMClass (Thread* t, object, uintptr_t* arguments) @@ -85,6 +114,14 @@ Avian_avian_SystemClassLoader_findLoadedVMClass return search(t, loader, name, findLoadedClass, true); } +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_SystemClassLoader_vmClass +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast + (jclassVmClass(t, reinterpret_cast(arguments[0]))); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_avian_SystemClassLoader_findVMClass (Thread* t, object, uintptr_t* arguments) diff --git a/src/classpath-android.cpp b/src/classpath-android.cpp index ef26c514ca..6cbb5a68b2 100644 --- a/src/classpath-android.cpp +++ b/src/classpath-android.cpp @@ -26,6 +26,24 @@ namespace { namespace local { +void JNICALL +loadLibrary(Thread* t, object, uintptr_t* arguments) +{ + object name = reinterpret_cast(arguments[1]); + + unsigned length = stringLength(t, name); + THREAD_RUNTIME_ARRAY(t, char, n, length + 1); + stringChars(t, name, RUNTIME_ARRAY_BODY(n)); + + loadLibrary(t, "", RUNTIME_ARRAY_BODY(n), true, true); +} + +int64_t JNICALL +appLoader(Thread* t, object, uintptr_t*) +{ + return reinterpret_cast(root(t, Machine::AppLoader)); +} + class MyClasspath : public Classpath { public: MyClasspath(Allocator* allocator): @@ -85,6 +103,21 @@ class MyClasspath : public Classpath { setObjectClass(t, thread, type(t, Machine::ThreadType)); threadPriority(t, thread) = NormalPriority; threadGroup(t, thread) = group; + PROTECT(t, thread); + + { object listClass = resolveClass + (t, root(t, Machine::BootLoader), "java/util/ArrayList"); + PROTECT(t, listClass); + + object instance = makeNew(t, listClass); + PROTECT(t, instance); + + object constructor = resolveMethod(t, listClass, "", "()V"); + + t->m->processor->invoke(t, constructor, instance); + + set(t, thread, ThreadInterruptActions, instance); + } return thread; } @@ -138,6 +171,30 @@ class MyClasspath : public Classpath { virtual void boot(Thread* t) { + { object runtimeClass = resolveClass + (t, root(t, Machine::BootLoader), "java/lang/Runtime", false); + + if (runtimeClass) { + PROTECT(t, runtimeClass); + + intercept(t, runtimeClass, "loadLibrary", + "(Ljava/lang/String;Ljava/lang/ClassLoader;)V", + voidPointer(loadLibrary)); + } + } + + { object classLoaderClass = resolveClass + (t, root(t, Machine::BootLoader), "java/lang/ClassLoader", false); + + if (classLoaderClass) { + PROTECT(t, classLoaderClass); + + intercept(t, classLoaderClass, "createSystemClassLoader", + "()Ljava/lang/ClassLoader;", + voidPointer(appLoader)); + } + } + JNI_OnLoad(reinterpret_cast< ::JavaVM*>(t->m), 0); } @@ -153,6 +210,48 @@ class MyClasspath : public Classpath { // ignore } + virtual object + makeDirectByteBuffer(Thread* t, void* p, jlong capacity) + { + object c = resolveClass + (t, root(t, Machine::BootLoader), "java/nio/ReadWriteDirectByteBuffer"); + PROTECT(t, c); + + object instance = makeNew(t, c); + PROTECT(t, instance); + + object constructor = resolveMethod(t, c, "", "(II)V"); + + t->m->processor->invoke + (t, constructor, instance, reinterpret_cast(p), + static_cast(capacity)); + + return instance; + } + + virtual void* + getDirectBufferAddress(Thread* t, object b) + { + PROTECT(t, b); + + object field = resolveField + (t, objectClass(t, b), "effectiveDirectAddress", "I"); + + return reinterpret_cast + (fieldAtOffset(b, fieldOffset(t, field))); + } + + virtual int64_t + getDirectBufferCapacity(Thread* t, object b) + { + PROTECT(t, b); + + object field = resolveField + (t, objectClass(t, b), "capacity", "I"); + + return fieldAtOffset(b, fieldOffset(t, field)); + } + virtual void dispose() { @@ -162,6 +261,47 @@ 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 @@ -346,6 +486,23 @@ Avian_java_lang_String_fastIndexOf return -1; } +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Class_newInstanceImpl +(Thread* t, object, uintptr_t* arguments) +{ + object c = jclassVmClass(t, reinterpret_cast(arguments[0])); + + object method = resolveMethod(t, c, "", "()V"); + PROTECT(t, method); + + object instance = makeNew(t, c); + PROTECT(t, instance); + + t->m->processor->invoke(t, method, instance); + + return reinterpret_cast(instance); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_java_lang_Class_getComponentType (Thread* t, object, uintptr_t* arguments) @@ -366,6 +523,25 @@ Avian_java_lang_Class_getComponentType } } +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Class_classForName +(Thread* t, object, uintptr_t* arguments) +{ + object name = reinterpret_cast(arguments[0]); + PROTECT(t, name); + + object loader = reinterpret_cast(arguments[2]); + PROTECT(t, loader); + + object method = resolveMethod + (t, root(t, Machine::BootLoader), "avian/Classes", "forName", + "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"); + + return reinterpret_cast + (t->m->processor->invoke + (t, method, 0, name, static_cast(arguments[1]), loader)); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_java_lang_Class_getDeclaredField (Thread* t, object, uintptr_t* arguments) @@ -377,13 +553,17 @@ Avian_java_lang_Class_getDeclaredField PROTECT(t, name); object method = resolveMethod - (t, root(t, Machine::BootLoader), "avian/Android", "findField", - "(Lavian/VMClass;Ljava/lang/String;)Lavian/VMField;"); + (t, root(t, Machine::BootLoader), "avian/Classes", "findField", + "(Lavian/VMClass;Ljava/lang/String;)I"); - object field = t->m->processor->invoke - (t, method, 0, jclassVmClass(t, c), name); + int index = intValue + (t, t->m->processor->invoke + (t, method, 0, jclassVmClass(t, c), name)); + + if (index >= 0) { + object field = arrayBody + (t, classFieldTable(t, jclassVmClass(t, c)), index); - if (field) { PROTECT(t, field); object type = resolveClassBySpec @@ -409,6 +589,75 @@ Avian_java_lang_Class_getDeclaredField } } +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Class_getDeclaredConstructorOrMethod +(Thread* t, object, uintptr_t* arguments) +{ + object c = reinterpret_cast(arguments[0]); + PROTECT(t, c); + + object name = reinterpret_cast(arguments[1]); + PROTECT(t, name); + + object parameterTypes = reinterpret_cast(arguments[2]); + PROTECT(t, parameterTypes); + + object method = resolveMethod + (t, root(t, Machine::BootLoader), "avian/Classes", "findMethod", + "(Lavian/VMClass;Ljava/lang/String;[Ljava/lang/Class;)I"); + + int index = intValue + (t, t->m->processor->invoke + (t, method, 0, jclassVmClass(t, c), name, parameterTypes)); + + if (index >= 0) { + return reinterpret_cast + (local::makeMethodOrConstructor(t, c, index)); + } else { + return 0; + } +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_SystemClassLoader_findLoadedVMClass +(Thread*, object, uintptr_t*); + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_VMClassLoader_findLoadedClass +(Thread* t, object method, uintptr_t* arguments) +{ + int64_t v = Avian_avian_SystemClassLoader_findLoadedVMClass + (t, method, arguments); + + if (v) { + return reinterpret_cast + (getJClass(t, reinterpret_cast(v))); + } else { + return 0; + } +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_Classes_defineVMClass +(Thread*, object, uintptr_t*); + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_VMClassLoader_defineClass__Ljava_lang_ClassLoader_2Ljava_lang_String_2_3BII +(Thread* t, object method, uintptr_t* arguments) +{ + uintptr_t args[] + = { arguments[0], arguments[2], arguments[3], arguments[4] }; + + int64_t v = Avian_avian_Classes_defineVMClass(t, method, args); + + if (v) { + return reinterpret_cast + (getJClass(t, reinterpret_cast(v))); + } else { + return 0; + } +} + extern "C" JNIEXPORT int64_t JNICALL Avian_dalvik_system_VMRuntime_bootClassPath (Thread* t, object, uintptr_t*) @@ -467,3 +716,456 @@ Avian_java_lang_VMThread_currentThread { return reinterpret_cast(t->javaThread); } + +extern "C" JNIEXPORT int64_t JNICALL +Avian_dalvik_system_VMStack_getCallingClassLoader +(Thread* t, object, uintptr_t*) +{ + class Visitor: public Processor::StackVisitor { + public: + Visitor(Thread* t): + t(t), loader(0), counter(2) + { } + + virtual bool visit(Processor::StackWalker* walker) { + if (counter--) { + return true; + } else { + this->loader = classLoader(t, methodClass(t, walker->method())); + return false; + } + } + + Thread* t; + object loader; + unsigned counter; + } v(t); + + t->m->processor->walkStack(t, &v); + + return reinterpret_cast(v.loader); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Math_min +(Thread*, object, uintptr_t* arguments) +{ + return min(static_cast(arguments[0]), static_cast(arguments[1])); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Math_max +(Thread*, object, uintptr_t* arguments) +{ + return max(static_cast(arguments[0]), static_cast(arguments[1])); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Object_getClass +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast + (getJClass(t, objectClass(t, reinterpret_cast(arguments[0])))); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Object_hashCode +(Thread* t, object, uintptr_t* arguments) +{ + return objectHash(t, reinterpret_cast(arguments[0])); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Object_internalClone +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast + (clone(t, reinterpret_cast(arguments[1]))); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Class_getModifiers +(Thread* t, object, uintptr_t* arguments) +{ + return classFlags + (t, jclassVmClass(t, reinterpret_cast(arguments[0]))); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Class_getSuperclass +(Thread* t, object, uintptr_t* arguments) +{ + object c = jclassVmClass(t, reinterpret_cast(arguments[0])); + if (classFlags(t, c) & ACC_INTERFACE) { + return 0; + } else { + object s = classSuper(t, c); + return s ? reinterpret_cast(getJClass(t, s)) : 0; + } +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Class_desiredAssertionStatus +(Thread*, object, uintptr_t*) +{ + return 1; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Class_getNameNative +(Thread* t, object, uintptr_t* arguments) +{ + object name = className + (t, jclassVmClass(t, reinterpret_cast(arguments[0]))); + + return reinterpret_cast + (t->m->classpath->makeString(t, name, 0, byteArrayLength(t, name) - 1)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Class_isInterface +(Thread* t, object, uintptr_t* arguments) +{ + return (classFlags + (t, jclassVmClass(t, reinterpret_cast(arguments[0]))) + & ACC_INTERFACE) != 0; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Class_isPrimitive +(Thread* t, object, uintptr_t* arguments) +{ + return (classVmFlags + (t, jclassVmClass(t, reinterpret_cast(arguments[0]))) + & PrimitiveFlag) != 0; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Class_getClassLoader +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast + (classLoader + (t, jclassVmClass(t, reinterpret_cast(arguments[0])))); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Class_isAssignableFrom +(Thread* t, object, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + object that = reinterpret_cast(arguments[1]); + + if (LIKELY(that)) { + return vm::isAssignableFrom + (t, jclassVmClass(t, this_), jclassVmClass(t, that)); + } else { + throwNew(t, Machine::NullPointerExceptionType); + } +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Method_invokeNative +(Thread* t, object, uintptr_t* arguments) +{ + object instance = reinterpret_cast(arguments[1]); + object args = reinterpret_cast(arguments[2]); + object method = arrayBody + (t, classMethodTable + (t, jclassVmClass(t, reinterpret_cast(arguments[3]))), + arguments[6]); + + return reinterpret_cast(invoke(t, method, instance, args)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Method_getMethodModifiers +(Thread* t, object, uintptr_t* arguments) +{ + return methodFlags + (t, arrayBody + (t, classMethodTable + (t, jclassVmClass(t, reinterpret_cast(arguments[0]))), + arguments[1])); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Method_isAnnotationPresent +(Thread* t, object, uintptr_t* arguments) +{ + object method = arrayBody + (t, classMethodTable + (t, jclassVmClass(t, reinterpret_cast(arguments[0]))), + arguments[1]); + + object addendum = methodAddendum(t, method); + if (addendum) { + object table = addendumAnnotationTable(t, addendum); + if (table) { + for (unsigned i = 0; i < objectArrayLength(t, table); ++i) { + if (objectArrayBody(t, objectArrayBody(t, table, i), 1) + == reinterpret_cast(arguments[2])) + { + return true; + } + } + } + } + + return false; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Method_getAnnotation +(Thread* t, object, uintptr_t* arguments) +{ + object method = arrayBody + (t, classMethodTable + (t, jclassVmClass(t, reinterpret_cast(arguments[0]))), + arguments[1]); + + object addendum = methodAddendum(t, method); + if (addendum) { + object table = addendumAnnotationTable(t, addendum); + if (table) { + for (unsigned i = 0; i < objectArrayLength(t, table); ++i) { + if (objectArrayBody(t, objectArrayBody(t, table, i), 1) + == reinterpret_cast(arguments[2])) + { + PROTECT(t, method); + PROTECT(t, table); + + object get = resolveMethod + (t, root(t, Machine::BootLoader), "avian/Classes", "getAnnotation", + "(Ljava/lang/ClassLoader;[Ljava/lang/Object;)" + "Ljava/lang/annotation/Annotation;"); + + return reinterpret_cast + (t->m->processor->invoke + (t, get, 0, classLoader(t, methodClass(t, method)), + objectArrayBody(t, table, i))); + } + } + } + } + + return false; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Method_getDeclaredAnnotations +(Thread* t, object, uintptr_t* arguments) +{ + object method = arrayBody + (t, classMethodTable + (t, jclassVmClass(t, reinterpret_cast(arguments[0]))), + arguments[1]); + + object addendum = methodAddendum(t, method); + if (addendum) { + object table = addendumAnnotationTable(t, addendum); + if (table) { + PROTECT(t, method); + PROTECT(t, table); + + object array = makeObjectArray + (t, resolveClass + (t, root(t, Machine::BootLoader), "java/lang/annotation/Annotation"), + objectArrayLength(t, table)); + PROTECT(t, array); + + object get = resolveMethod + (t, root(t, Machine::BootLoader), "avian/Classes", "getAnnotation", + "(Ljava/lang/ClassLoader;[Ljava/lang/Object;)" + "Ljava/lang/annotation/Annotation;"); + PROTECT(t, get); + + for (unsigned i = 0; i < objectArrayLength(t, table); ++i) { + object a = t->m->processor->invoke + (t, get, 0, classLoader(t, methodClass(t, method)), + objectArrayBody(t, table, i)); + + set(t, array, ArrayBody + (i * BytesPerWord), a); + } + + return reinterpret_cast(array); + } + } + + return reinterpret_cast + (makeObjectArray + (t, resolveClass + (t, root(t, Machine::BootLoader), "java/lang/annotation/Annotation"), + 0)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Constructor_constructNative +(Thread* t, object, uintptr_t* arguments) +{ + object args = reinterpret_cast(arguments[1]); + PROTECT(t, args); + + object c = jclassVmClass(t, reinterpret_cast(arguments[2])); + + object method = arrayBody(t, classMethodTable(t, c), arguments[4]); + PROTECT(t, method); + + object instance = makeNew(t, c); + PROTECT(t, instance); + + t->m->processor->invokeArray(t, method, instance, args); + + return reinterpret_cast(instance); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Throwable_nativeFillInStackTrace +(Thread* t, object, uintptr_t*) +{ + return reinterpret_cast(getTrace(t, 2)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_Classes_makeMethod +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast + (local::makeMethodOrConstructor + (t, reinterpret_cast(arguments[0]), arguments[1])); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Array_createObjectArray +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast + (makeObjectArray + (t, jclassVmClass(t, reinterpret_cast(arguments[0])), + arguments[1])); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_nio_ByteOrder_isLittleEndian +(Thread*, object, uintptr_t*) +{ +#ifdef ARCH_powerpc + return false; +#else + return true; +#endif +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_dalvik_system_VMRuntime_newNonMovableArray +(Thread* t, object, uintptr_t* arguments) +{ + if (jclassVmClass(t, reinterpret_cast(arguments[1])) + == type(t, Machine::JbyteType)) + { + object array = allocate3 + (t, t->m->heap, Machine::FixedAllocation, + ArrayBody + arguments[2], false); + + setObjectClass(t, array, type(t, Machine::ByteArrayType)); + byteArrayLength(t, array) = arguments[2]; + + return reinterpret_cast(array); + } else { + // todo + abort(t); + } +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_dalvik_system_VMRuntime_addressOf +(Thread*, object, uintptr_t* arguments) +{ + return arguments[1] + ArrayBody; +} + +extern "C" JNIEXPORT void JNICALL +Avian_libcore_io_Memory_pokeLong +(Thread*, object, uintptr_t* arguments) +{ + int64_t v; memcpy(&v, arguments + 1, 8); + if (arguments[3]) { + v = swapV8(v); + } + memcpy(reinterpret_cast(arguments[0]), &v, 8); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_libcore_io_Memory_peekLong +(Thread*, object, uintptr_t* arguments) +{ + int64_t v; memcpy(&v, reinterpret_cast(arguments[0]), 8); + return arguments[1] ? swapV8(v) : v; +} + +extern "C" JNIEXPORT void JNICALL +Avian_libcore_io_Memory_pokeInt +(Thread*, object, uintptr_t* arguments) +{ + int32_t v = arguments[2] ? swapV4(arguments[1]) : arguments[1]; + memcpy(reinterpret_cast(arguments[0]), &v, 4); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_libcore_io_Memory_peekInt +(Thread*, object, uintptr_t* arguments) +{ + int32_t v; memcpy(&v, reinterpret_cast(arguments[0]), 4); + return arguments[1] ? swapV4(v) : v; +} + +extern "C" JNIEXPORT void JNICALL +Avian_libcore_io_Memory_pokeShort +(Thread*, object, uintptr_t* arguments) +{ + int16_t v = arguments[2] ? swapV2(arguments[1]) : arguments[1]; + memcpy(reinterpret_cast(arguments[0]), &v, 2); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_libcore_io_Memory_peekShort +(Thread*, object, uintptr_t* arguments) +{ + int16_t v; memcpy(&v, reinterpret_cast(arguments[0]), 2); + return arguments[1] ? swapV2(v) : v; +} + +extern "C" JNIEXPORT void JNICALL +Avian_libcore_io_Memory_pokeByte +(Thread*, object, uintptr_t* arguments) +{ + *reinterpret_cast(arguments[0]) = arguments[1]; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_libcore_io_Memory_peekByte +(Thread*, object, uintptr_t* arguments) +{ + return *reinterpret_cast(arguments[0]); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_System_nanoTime +(Thread* t, object, uintptr_t*) +{ + return t->m->system->now() * 1000 * 1000; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_System_currentTimeMillis +(Thread* t, object, uintptr_t*) +{ + return t->m->system->now(); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_System_identityHashCode +(Thread* t, object, uintptr_t* arguments) +{ + return objectHash(t, reinterpret_cast(arguments[0])); +} diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index f313bffa01..d5a6ba367a 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -684,35 +684,6 @@ Avian_avian_Classes_primitiveClass return reinterpret_cast(primitiveClass(t, arguments[0])); } -extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_Classes_defineVMClass -(Thread* t, object, uintptr_t* arguments) -{ - object loader = reinterpret_cast(arguments[0]); - object b = reinterpret_cast(arguments[1]); - int offset = arguments[2]; - int length = arguments[3]; - - uint8_t* buffer = static_cast - (t->m->heap->allocate(length)); - - THREAD_RESOURCE2(t, uint8_t*, buffer, int, length, - t->m->heap->free(buffer, length)); - - memcpy(buffer, &byteArrayBody(t, b, offset), length); - - return reinterpret_cast(defineClass(t, loader, buffer, length)); -} - -extern "C" JNIEXPORT void JNICALL -Avian_avian_Classes_initialize -(Thread* t, object, uintptr_t* arguments) -{ - object this_ = reinterpret_cast(arguments[0]); - - initClass(t, this_); -} - extern "C" JNIEXPORT int64_t JNICALL Avian_avian_Classes_isAssignableFrom (Thread* t, object, uintptr_t* arguments) diff --git a/src/classpath-common.h b/src/classpath-common.h index ca6649a01e..20b631d8a7 100644 --- a/src/classpath-common.h +++ b/src/classpath-common.h @@ -355,6 +355,260 @@ resolveClassBySpec(Thread* t, object loader, const char* spec, } } +object +resolveJType(Thread* t, object loader, const char* spec, unsigned specLength) +{ + return getJClass(t, resolveClassBySpec(t, loader, spec, specLength)); +} + +object +resolveParameterTypes(Thread* t, object loader, object spec, + unsigned* parameterCount, unsigned* returnTypeSpec) +{ + PROTECT(t, loader); + PROTECT(t, spec); + + object list = 0; + PROTECT(t, list); + + unsigned offset = 1; + unsigned count = 0; + while (byteArrayBody(t, spec, offset) != ')') { + switch (byteArrayBody(t, spec, offset)) { + case 'L': { + unsigned start = offset; + ++ offset; + while (byteArrayBody(t, spec, offset) != ';') ++ offset; + ++ offset; + + object type = resolveClassBySpec + (t, loader, reinterpret_cast(&byteArrayBody(t, spec, start)), + offset - start); + + list = makePair(t, type, list); + + ++ count; + } break; + + case '[': { + unsigned start = offset; + while (byteArrayBody(t, spec, offset) == '[') ++ offset; + switch (byteArrayBody(t, spec, offset)) { + case 'L': + ++ offset; + while (byteArrayBody(t, spec, offset) != ';') ++ offset; + ++ offset; + break; + + default: + ++ offset; + break; + } + + object type = resolveClassBySpec + (t, loader, reinterpret_cast(&byteArrayBody(t, spec, start)), + offset - start); + + list = makePair(t, type, list); + ++ count; + } break; + + default: + list = makePair + (t, primitiveClass(t, byteArrayBody(t, spec, offset)), list); + ++ offset; + ++ count; + break; + } + } + + *parameterCount = count; + *returnTypeSpec = offset + 1; + return list; +} + +object +resolveParameterJTypes(Thread* t, object loader, object spec, + unsigned* parameterCount, unsigned* returnTypeSpec) +{ + object list = resolveParameterTypes + (t, loader, spec, parameterCount, returnTypeSpec); + + PROTECT(t, list); + + object array = makeObjectArray + (t, type(t, Machine::JclassType), *parameterCount); + PROTECT(t, array); + + for (int i = *parameterCount - 1; i >= 0; --i) { + object c = getJClass(t, pairFirst(t, list)); + set(t, array, ArrayBody + (i * BytesPerWord), c); + list = pairSecond(t, list); + } + + return array; +} + +object +resolveExceptionJTypes(Thread* t, object loader, object addendum) +{ + if (addendum == 0 or methodAddendumExceptionTable(t, addendum) == 0) { + return makeObjectArray(t, type(t, Machine::JclassType), 0); + } + + PROTECT(t, loader); + PROTECT(t, addendum); + + object array = makeObjectArray + (t, type(t, Machine::JclassType), + shortArrayLength(t, methodAddendumExceptionTable(t, addendum))); + PROTECT(t, array); + + for (unsigned i = 0; i < shortArrayLength + (t, methodAddendumExceptionTable(t, addendum)); ++i) + { + uint16_t index = shortArrayBody + (t, methodAddendumExceptionTable(t, addendum), i) - 1; + + object o = singletonObject(t, addendumPool(t, addendum), index); + + if (objectClass(t, o) == type(t, Machine::ReferenceType)) { + o = resolveClass(t, loader, referenceName(t, o)); + + set(t, addendumPool(t, addendum), SingletonBody + (index * BytesPerWord), + o); + } + + o = getJClass(t, o); + + set(t, array, ArrayBody + (i * BytesPerWord), o); + } + + return array; +} + +object +invoke(Thread* t, object method, object instance, object args) +{ + PROTECT(t, method); + PROTECT(t, instance); + PROTECT(t, args); + + if (methodFlags(t, method) & ACC_STATIC) { + instance = 0; + } + + if ((args == 0 ? 0 : objectArrayLength(t, args)) + != methodParameterCount(t, method)) + { + throwNew(t, Machine::IllegalArgumentExceptionType); + } + + if (methodParameterCount(t, method)) { + PROTECT(t, method); + + unsigned specLength = byteArrayLength(t, methodSpec(t, method)); + THREAD_RUNTIME_ARRAY(t, char, spec, specLength); + memcpy(spec, &byteArrayBody(t, methodSpec(t, method), 0), specLength); + unsigned i = 0; + for (MethodSpecIterator it(t, spec); it.hasNext();) { + object type; + bool objectType = false; + const char* p = it.next(); + switch (*p) { + case 'Z': type = vm::type(t, Machine::BooleanType); break; + case 'B': type = vm::type(t, Machine::ByteType); break; + case 'S': type = vm::type(t, Machine::ShortType); break; + case 'C': type = vm::type(t, Machine::CharType); break; + case 'I': type = vm::type(t, Machine::IntType); break; + case 'F': type = vm::type(t, Machine::FloatType); break; + case 'J': type = vm::type(t, Machine::LongType); break; + case 'D': type = vm::type(t, Machine::DoubleType); break; + + case 'L': ++ p; + case '[': { + objectType = true; + unsigned nameLength = it.s - p; + THREAD_RUNTIME_ARRAY(t, char, name, nameLength); + memcpy(name, p, nameLength - 1); + name[nameLength - 1] = 0; + type = resolveClass + (t, classLoader(t, methodClass(t, method)), name); + } break; + + default: + abort(); + } + + object arg = objectArrayBody(t, args, i++); + if ((arg == 0 and (not objectType)) + or (arg and (not instanceOf(t, type, arg)))) + { + // fprintf(stderr, "%s is not a %s\n", arg ? &byteArrayBody(t, className(t, objectClass(t, arg)), 0) : reinterpret_cast(""), &byteArrayBody(t, className(t, type), 0)); + + throwNew(t, Machine::IllegalArgumentExceptionType); + } + } + } + + unsigned returnCode = methodReturnCode(t, method); + + THREAD_RESOURCE0(t, { + if (t->exception) { + object exception = t->exception; + t->exception = makeThrowable + (t, Machine::InvocationTargetExceptionType, 0, 0, exception); + } + }); + + object result; + if (args) { + result = t->m->processor->invokeArray(t, method, instance, args); + } else { + result = t->m->processor->invoke(t, method, instance); + } + + return translateInvokeResult(t, returnCode, result); +} + +// only safe to call during bootstrap when there's only one thread +// running: +void +intercept(Thread* t, object c, const char* name, const char* spec, + void* function) +{ + object m = findMethodOrNull(t, c, name, spec); + if (m) { + PROTECT(t, m); + + object clone = methodClone(t, m); + + // make clone private to prevent vtable updates at compilation + // time. Otherwise, our interception might be bypassed by calls + // through the vtable. + methodFlags(t, clone) |= ACC_PRIVATE; + + methodFlags(t, m) |= ACC_NATIVE; + + object native = makeNativeIntercept(t, function, true, clone); + + PROTECT(t, native); + + object runtimeData = getMethodRuntimeData(t, m); + + set(t, runtimeData, MethodRuntimeDataNative, native); + } else { + // If we can't find the method, just ignore it, since ProGuard may + // have stripped it out as unused. Otherwise, the code below can + // be uncommented for debugging purposes. + + // fprintf(stderr, "unable to find %s%s in %s\n", + // name, spec, &byteArrayBody(t, className(t, c), 0)); + + // abort(t); + } +} + } // namespace vm #endif//CLASSPATH_COMMON_H diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index df37efceaf..ba49a5f009 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -1918,44 +1918,6 @@ loadLibrary(Thread* t, object, uintptr_t* arguments) RUNTIME_ARRAY_BODY(n), not absolute, true); } -// only safe to call during bootstrap when there's only one thread -// running: -void -intercept(Thread* t, object c, const char* name, const char* spec, - void* function) -{ - object m = findMethodOrNull(t, c, name, spec); - if (m) { - PROTECT(t, m); - - object clone = methodClone(t, m); - - // make clone private to prevent vtable updates at compilation - // time. Otherwise, our interception might be bypassed by calls - // through the vtable. - methodFlags(t, clone) |= ACC_PRIVATE; - - methodFlags(t, m) |= ACC_NATIVE; - - object native = makeNativeIntercept(t, function, true, clone); - - PROTECT(t, native); - - object runtimeData = getMethodRuntimeData(t, m); - - set(t, runtimeData, MethodRuntimeDataNative, native); - } else { - // If we can't find the method, just ignore it, since ProGuard may - // have stripped it out as unused. Otherwise, the code below can - // be uncommented for debugging purposes. - - // fprintf(stderr, "unable to find %s%s in %s\n", - // name, spec, &byteArrayBody(t, className(t, c), 0)); - - // abort(t); - } -} - void interceptFileOperations(Thread* t) { @@ -2185,138 +2147,6 @@ countConstructors(Thread* t, object c, bool publicOnly) return count; } -object -resolveJType(Thread* t, object loader, const char* spec, unsigned specLength) -{ - return getJClass(t, resolveClassBySpec(t, loader, spec, specLength)); -} - -object -resolveParameterTypes(Thread* t, object loader, object spec, - unsigned* parameterCount, unsigned* returnTypeSpec) -{ - PROTECT(t, loader); - PROTECT(t, spec); - - object list = 0; - PROTECT(t, list); - - unsigned offset = 1; - unsigned count = 0; - while (byteArrayBody(t, spec, offset) != ')') { - switch (byteArrayBody(t, spec, offset)) { - case 'L': { - unsigned start = offset; - ++ offset; - while (byteArrayBody(t, spec, offset) != ';') ++ offset; - ++ offset; - - object type = resolveClassBySpec - (t, loader, reinterpret_cast(&byteArrayBody(t, spec, start)), - offset - start); - - list = makePair(t, type, list); - - ++ count; - } break; - - case '[': { - unsigned start = offset; - while (byteArrayBody(t, spec, offset) == '[') ++ offset; - switch (byteArrayBody(t, spec, offset)) { - case 'L': - ++ offset; - while (byteArrayBody(t, spec, offset) != ';') ++ offset; - ++ offset; - break; - - default: - ++ offset; - break; - } - - object type = resolveClassBySpec - (t, loader, reinterpret_cast(&byteArrayBody(t, spec, start)), - offset - start); - - list = makePair(t, type, list); - ++ count; - } break; - - default: - list = makePair - (t, primitiveClass(t, byteArrayBody(t, spec, offset)), list); - ++ offset; - ++ count; - break; - } - } - - *parameterCount = count; - *returnTypeSpec = offset + 1; - return list; -} - -object -resolveParameterJTypes(Thread* t, object loader, object spec, - unsigned* parameterCount, unsigned* returnTypeSpec) -{ - object list = resolveParameterTypes - (t, loader, spec, parameterCount, returnTypeSpec); - - PROTECT(t, list); - - object array = makeObjectArray - (t, type(t, Machine::JclassType), *parameterCount); - PROTECT(t, array); - - for (int i = *parameterCount - 1; i >= 0; --i) { - object c = getJClass(t, pairFirst(t, list)); - set(t, array, ArrayBody + (i * BytesPerWord), c); - list = pairSecond(t, list); - } - - return array; -} - -object -resolveExceptionJTypes(Thread* t, object loader, object addendum) -{ - if (addendum == 0 or methodAddendumExceptionTable(t, addendum) == 0) { - return makeObjectArray(t, type(t, Machine::JclassType), 0); - } - - PROTECT(t, loader); - PROTECT(t, addendum); - - object array = makeObjectArray - (t, type(t, Machine::JclassType), - shortArrayLength(t, methodAddendumExceptionTable(t, addendum))); - PROTECT(t, array); - - for (unsigned i = 0; i < shortArrayLength - (t, methodAddendumExceptionTable(t, addendum)); ++i) - { - uint16_t index = shortArrayBody - (t, methodAddendumExceptionTable(t, addendum), i) - 1; - - object o = singletonObject(t, addendumPool(t, addendum), index); - - if (objectClass(t, o) == type(t, Machine::ReferenceType)) { - o = resolveClass(t, loader, referenceName(t, o)); - - set(t, addendumPool(t, addendum), SingletonBody + (index * BytesPerWord), - o); - } - - o = getJClass(t, o); - - set(t, array, ArrayBody + (i * BytesPerWord), o); - } - - return array; -} - object makeJmethod(Thread* t, object vmMethod, int index) { @@ -2330,18 +2160,18 @@ makeJmethod(Thread* t, object vmMethod, int index) unsigned parameterCount; unsigned returnTypeSpec; - object parameterTypes = local::resolveParameterJTypes + object parameterTypes = resolveParameterJTypes (t, classLoader(t, methodClass(t, vmMethod)), methodSpec(t, vmMethod), ¶meterCount, &returnTypeSpec); PROTECT(t, parameterTypes); - object returnType = local::resolveJType + object returnType = resolveJType (t, classLoader(t, methodClass(t, vmMethod)), reinterpret_cast (&byteArrayBody(t, methodSpec(t, vmMethod), returnTypeSpec)), byteArrayLength(t, methodSpec(t, vmMethod)) - 1 - returnTypeSpec); PROTECT(t, returnType); - object exceptionTypes = local::resolveExceptionJTypes + object exceptionTypes = resolveExceptionJTypes (t, classLoader(t, methodClass(t, vmMethod)), methodAddendum(t, vmMethod)); PROTECT(t, exceptionTypes); @@ -2406,12 +2236,12 @@ makeJconstructor(Thread* t, object vmMethod, int index) unsigned parameterCount; unsigned returnTypeSpec; - object parameterTypes = local::resolveParameterJTypes + object parameterTypes = resolveParameterJTypes (t, classLoader(t, methodClass(t, vmMethod)), methodSpec(t, vmMethod), ¶meterCount, &returnTypeSpec); PROTECT(t, parameterTypes); - object exceptionTypes = local::resolveExceptionJTypes + object exceptionTypes = resolveExceptionJTypes (t, classLoader(t, methodClass(t, vmMethod)), methodAddendum(t, vmMethod)); PROTECT(t, exceptionTypes); @@ -4777,83 +4607,10 @@ jvmInvokeMethod(Thread* t, uintptr_t* arguments) (t, jclassVmClass(t, jmethodClazz(t, *method))), jmethodSlot(t, *method)); - if (methodFlags(t, vmMethod) & ACC_STATIC) { - instance = 0; - } - - if ((args == 0 ? 0 : objectArrayLength(t, *args)) - != methodParameterCount(t, vmMethod)) - { - throwNew(t, Machine::IllegalArgumentExceptionType); - } - - if (methodParameterCount(t, vmMethod)) { - PROTECT(t, vmMethod); - - unsigned specLength = byteArrayLength(t, methodSpec(t, vmMethod)); - THREAD_RUNTIME_ARRAY(t, char, spec, specLength); - memcpy(spec, &byteArrayBody(t, methodSpec(t, vmMethod), 0), specLength); - unsigned i = 0; - for (MethodSpecIterator it(t, spec); it.hasNext();) { - object type; - bool objectType = false; - const char* p = it.next(); - switch (*p) { - case 'Z': type = vm::type(t, Machine::BooleanType); break; - case 'B': type = vm::type(t, Machine::ByteType); break; - case 'S': type = vm::type(t, Machine::ShortType); break; - case 'C': type = vm::type(t, Machine::CharType); break; - case 'I': type = vm::type(t, Machine::IntType); break; - case 'F': type = vm::type(t, Machine::FloatType); break; - case 'J': type = vm::type(t, Machine::LongType); break; - case 'D': type = vm::type(t, Machine::DoubleType); break; - - case 'L': ++ p; - case '[': { - objectType = true; - unsigned nameLength = it.s - p; - THREAD_RUNTIME_ARRAY(t, char, name, nameLength); - memcpy(name, p, nameLength - 1); - name[nameLength - 1] = 0; - type = resolveClass - (t, classLoader(t, methodClass(t, vmMethod)), name); - } break; - - default: - abort(); - } - - object arg = objectArrayBody(t, *args, i++); - if ((arg == 0 and (not objectType)) - or (arg and (not instanceOf(t, type, arg)))) - { - // fprintf(stderr, "%s is not a %s\n", arg ? &byteArrayBody(t, className(t, objectClass(t, arg)), 0) : reinterpret_cast(""), &byteArrayBody(t, className(t, type), 0)); - - throwNew(t, Machine::IllegalArgumentExceptionType); - } - } - } - - unsigned returnCode = methodReturnCode(t, vmMethod); - - THREAD_RESOURCE0(t, { - if (t->exception) { - object exception = t->exception; - t->exception = makeThrowable - (t, Machine::InvocationTargetExceptionType, 0, 0, exception); - } - }); - - object result; - if (args) { - result = t->m->processor->invokeArray - (t, vmMethod, instance ? *instance : 0, *args); - } else { - result = t->m->processor->invoke(t, vmMethod, instance ? *instance : 0); - } - return reinterpret_cast - (makeLocalReference(t, translateInvokeResult(t, returnCode, result))); + (makeLocalReference + (t, invoke + (t, vmMethod, instance ? *instance : 0, args ? *args : 0))); } extern "C" JNIEXPORT jobject JNICALL diff --git a/src/jnienv.cpp b/src/jnienv.cpp index bcd2c2f05c..b563993369 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -3401,27 +3401,56 @@ PopLocalFrame(Thread* t, jobject result) return reinterpret_cast(run(t, popLocalFrame, arguments)); } +uint64_t +newDirectByteBuffer(Thread* t, uintptr_t* arguments) +{ + jlong capacity; memcpy(&capacity, arguments + 1, sizeof(jlong)); + + return reinterpret_cast + (makeLocalReference + (t, t->m->classpath->makeDirectByteBuffer + (t, reinterpret_cast(arguments[0]), capacity))); +} + 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)); + uintptr_t arguments[1 + (sizeof(jlong) / BytesPerWord)]; + arguments[0] = reinterpret_cast(p); + memcpy(arguments + 1, &capacity, sizeof(jlong)); + + return reinterpret_cast(run(t, newDirectByteBuffer, arguments)); +} + +uint64_t +getDirectBufferAddress(Thread* t, uintptr_t* arguments) +{ + return reinterpret_cast + (t->m->classpath->getDirectBufferAddress + (t, *reinterpret_cast(arguments[0]))); } void* JNICALL GetDirectBufferAddress(Thread* t, jobject b) { - return reinterpret_cast - (GetLongField(t, b, GetFieldID(t, GetObjectClass(t, b), "address", "J"))); + uintptr_t arguments[] = { reinterpret_cast(b) }; + + return reinterpret_cast(run(t, getDirectBufferAddress, arguments)); +} + +uint64_t +getDirectBufferCapacity(Thread* t, uintptr_t* arguments) +{ + return t->m->classpath->getDirectBufferCapacity + (t, *reinterpret_cast(arguments[0])); } jlong JNICALL GetDirectBufferCapacity(Thread* t, jobject b) { - return GetIntField - (t, b, GetFieldID(t, GetObjectClass(t, b), "capacity", "I")); + uintptr_t arguments[] = { reinterpret_cast(b) }; + + return run(t, getDirectBufferCapacity, arguments); } struct JavaVMOption { diff --git a/src/machine.cpp b/src/machine.cpp index 8555878c41..ff3fdf814d 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -2369,8 +2369,6 @@ object makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec, object elementClass) { - // todo: arrays should implement Cloneable and Serializable - if (classVmFlags(t, type(t, Machine::JobjectType)) & BootstrapFlag) { PROTECT(t, loader); PROTECT(t, spec); @@ -2398,7 +2396,7 @@ makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec, spec, 0, type(t, Machine::JobjectType), - 0, + root(t, Machine::ArrayInterfaceTable), vtable, 0, 0, @@ -2733,6 +2731,33 @@ boot(Thread* t) setRoot(t, Machine::StringMap, makeWeakHashMap(t, 0, 0)); + { object interfaceTable = makeArray(t, 4); + + set(t, interfaceTable, ArrayBody, type(t, Machine::SerializableType)); + + set(t, interfaceTable, ArrayBody + (2 * BytesPerWord), + type(t, Machine::CloneableType)); + + setRoot(t, Machine::ArrayInterfaceTable, interfaceTable); + } + + set(t, type(t, Machine::BooleanArrayType), ClassInterfaceTable, + root(t, Machine::ArrayInterfaceTable)); + set(t, type(t, Machine::ByteArrayType), ClassInterfaceTable, + root(t, Machine::ArrayInterfaceTable)); + set(t, type(t, Machine::CharArrayType), ClassInterfaceTable, + root(t, Machine::ArrayInterfaceTable)); + set(t, type(t, Machine::ShortArrayType), ClassInterfaceTable, + root(t, Machine::ArrayInterfaceTable)); + set(t, type(t, Machine::IntArrayType), ClassInterfaceTable, + root(t, Machine::ArrayInterfaceTable)); + set(t, type(t, Machine::LongArrayType), ClassInterfaceTable, + root(t, Machine::ArrayInterfaceTable)); + set(t, type(t, Machine::FloatArrayType), ClassInterfaceTable, + root(t, Machine::ArrayInterfaceTable)); + set(t, type(t, Machine::DoubleArrayType), ClassInterfaceTable, + root(t, Machine::ArrayInterfaceTable)); + m->processor->boot(t, 0, 0); { object bootCode = makeCode(t, 0, 0, 0, 0, 0, 0, 0, 1); diff --git a/src/machine.h b/src/machine.h index 1d29cbc88a..1d79cea6d8 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1227,10 +1227,11 @@ class Machine { OutOfMemoryError, Shutdown, VirtualFileFinders, - VirtualFiles + VirtualFiles, + ArrayInterfaceTable }; - static const unsigned RootCount = VirtualFiles + 1; + static const unsigned RootCount = ArrayInterfaceTable + 1; Machine(System* system, Heap* heap, Finder* bootFinder, Finder* appFinder, Processor* processor, Classpath* classpath, const char** properties, @@ -1569,6 +1570,15 @@ class Classpath { virtual void updatePackageMap(Thread* t, object class_) = 0; + virtual object + makeDirectByteBuffer(Thread* t, void* p, jlong capacity) = 0; + + virtual void* + getDirectBufferAddress(Thread* t, object buffer) = 0; + + virtual int64_t + getDirectBufferCapacity(Thread* t, object buffer) = 0; + virtual void dispose() = 0; }; diff --git a/src/target.h b/src/target.h index f75e575eef..42b07b1dc4 100644 --- a/src/target.h +++ b/src/target.h @@ -23,11 +23,9 @@ targetV1(T v) return v; } -#ifdef TARGET_OPPOSITE_ENDIAN - template inline T -targetV2(T v) +swapV2(T v) { return (((v >> 8) & 0xFF) | ((v << 8))); @@ -35,7 +33,7 @@ targetV2(T v) template inline T -targetV4(T v) +swapV4(T v) { return (((v >> 24) & 0x000000FF) | ((v >> 8) & 0x0000FF00) | @@ -45,7 +43,7 @@ targetV4(T v) template inline T -targetV8(T v) +swapV8(T v) { return (((static_cast(v) >> 56) & UINT64_C(0x00000000000000FF)) | ((static_cast(v) >> 40) & UINT64_C(0x000000000000FF00)) | @@ -57,6 +55,29 @@ targetV8(T v) ((static_cast(v) << 56))); } +#ifdef TARGET_OPPOSITE_ENDIAN + +template +inline T +targetV2(T v) +{ + return swapV2(v); +} + +template +inline T +targetV4(T v) +{ + return swapV4(v); +} + +template +inline T +targetV8(T v) +{ + return swapV8(v); +} + #else template inline T diff --git a/src/types.def b/src/types.def index 36f345e4c4..faf1d1341c 100644 --- a/src/types.def +++ b/src/types.def @@ -16,6 +16,10 @@ (type constantPool sun/reflect/ConstantPool) +(type serializable java/io/Serializable) + +(type cloneable java/lang/Cloneable) + (type singleton (array uintptr_t body))