diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index ddef6c36de..703332c518 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -54,6 +54,37 @@ class MyClasspath : public Classpath { root(t, Machine::BootLoader), 0, 0, group, 0); } + virtual object + makeJMethod(Thread* t, object vmMethod) + { + PROTECT(t, vmMethod); + + object jmethod = makeJmethod(t, vmMethod, false); + + return byteArrayBody(t, methodName(t, vmMethod), 0) == '<' + ? makeJconstructor(t, jmethod) : jmethod; + } + + virtual object + getVMMethod(Thread* t, object jmethod) + { + return objectClass(t, jmethod) == type(t, Machine::JmethodType) + ? jmethodVmMethod(t, jmethod) + : jmethodVmMethod(t, jconstructorMethod(t, jmethod)); + } + + virtual object + makeJField(Thread* t, object vmField) + { + return makeJfield(t, vmField, false); + } + + virtual object + getVMField(Thread* t, object jfield) + { + return jfieldVmField(t, jfield); + } + virtual void clearInterrupted(Thread*) { diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index bb505051d9..b06211777f 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -341,6 +341,15 @@ makeClassNameString(Thread* t, object name) return makeString(t, "%s", s); } +object +makeJmethod(Thread* t, object vmMethod, int index = -1); + +object +makeJconstructor(Thread* t, object vmMethod, int index = -1); + +object +makeJfield(Thread* t, object vmField, int index = -1); + void interceptFileOperations(Thread*); @@ -537,6 +546,44 @@ class MyClasspath : public Classpath { return thread; } + virtual object + makeJMethod(Thread* t, object vmMethod) + { + PROTECT(t, vmMethod); + + return byteArrayBody(t, methodName(t, vmMethod), 0) == '<' + ? makeJconstructor(t, vmMethod) + : makeJmethod(t, vmMethod); + } + + virtual object + getVMMethod(Thread* t, object jmethod) + { + return objectClass(t, jmethod) == type(t, Machine::JmethodType) + ? arrayBody + (t, classMethodTable + (t, jclassVmClass(t, jmethodClazz(t, jmethod))), + jmethodSlot(t, jmethod)) + : arrayBody + (t, classMethodTable + (t, jclassVmClass(t, jconstructorClazz(t, jmethod))), + jconstructorSlot(t, jmethod)); + } + + virtual object + makeJField(Thread* t, object vmField) + { + return makeJfield(t, vmField); + } + + virtual object + getVMField(Thread* t, object jfield) + { + return arrayBody + (t, classFieldTable + (t, jclassVmClass(t, jfieldClazz(t, jfield))), jfieldSlot(t, jfield)); + } + virtual void clearInterrupted(Thread* t) { @@ -2260,6 +2307,213 @@ resolveExceptionJTypes(Thread* t, object loader, object addendum) return array; } +object +makeJmethod(Thread* t, object vmMethod, int index) +{ + PROTECT(t, vmMethod); + + object name = intern + (t, t->m->classpath->makeString + (t, methodName(t, vmMethod), 0, byteArrayLength + (t, methodName(t, vmMethod)) - 1)); + PROTECT(t, name); + + unsigned parameterCount; + unsigned returnTypeSpec; + object parameterTypes = local::resolveParameterJTypes + (t, classLoader(t, methodClass(t, vmMethod)), methodSpec(t, vmMethod), + ¶meterCount, &returnTypeSpec); + PROTECT(t, parameterTypes); + + object returnType = local::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 + (t, classLoader(t, methodClass(t, vmMethod)), + methodAddendum(t, vmMethod)); + PROTECT(t, exceptionTypes); + + object signature; + object annotationTable; + object annotationDefault; + object addendum = methodAddendum(t, vmMethod); + if (addendum) { + signature = addendumSignature(t, addendum); + if (signature) { + signature = t->m->classpath->makeString + (t, signature, 0, byteArrayLength(t, signature) - 1); + } + + annotationTable = addendumAnnotationTable(t, addendum); + + annotationDefault = methodAddendumAnnotationDefault(t, addendum); + } else { + signature = 0; + annotationTable = 0; + annotationDefault = 0; + } + + PROTECT(t, signature); + PROTECT(t, annotationTable); + PROTECT(t, annotationDefault); + + if (annotationTable or annotationDefault) { + object runtimeData = getClassRuntimeData(t, methodClass(t, vmMethod)); + + set(t, runtimeData, ClassRuntimeDataPool, + addendumPool(t, methodAddendum(t, vmMethod))); + } + + if (index == -1) { + object table = classMethodTable(t, methodClass(t, vmMethod)); + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + if (vmMethod == arrayBody(t, table, i)) { + index = i; + break; + } + } + } + + expect(t, index != -1); + + object jclass = getJClass(t, methodClass(t, vmMethod)); + + return makeJmethod + (t, true, 0, jclass, index, name, returnType, parameterTypes, + exceptionTypes, methodFlags(t, vmMethod), signature, 0, annotationTable, + 0, annotationDefault, 0, 0, 0); +} + +object +makeJconstructor(Thread* t, object vmMethod, int index) +{ + PROTECT(t, vmMethod); + + unsigned parameterCount; + unsigned returnTypeSpec; + object parameterTypes = local::resolveParameterJTypes + (t, classLoader(t, methodClass(t, vmMethod)), methodSpec(t, vmMethod), + ¶meterCount, &returnTypeSpec); + PROTECT(t, parameterTypes); + + object exceptionTypes = local::resolveExceptionJTypes + (t, classLoader(t, methodClass(t, vmMethod)), + methodAddendum(t, vmMethod)); + PROTECT(t, exceptionTypes); + + object signature; + object annotationTable; + object addendum = methodAddendum(t, vmMethod); + if (addendum) { + signature = addendumSignature(t, addendum); + if (signature) { + signature = t->m->classpath->makeString + (t, signature, 0, byteArrayLength(t, signature) - 1); + } + + annotationTable = addendumAnnotationTable(t, addendum); + } else { + signature = 0; + annotationTable = 0; + } + + PROTECT(t, signature); + PROTECT(t, annotationTable); + + if (annotationTable) { + object runtimeData = getClassRuntimeData(t, methodClass(t, vmMethod)); + + set(t, runtimeData, ClassRuntimeDataPool, + addendumPool(t, methodAddendum(t, vmMethod))); + } + + if (index == -1) { + object table = classMethodTable(t, methodClass(t, vmMethod)); + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + if (vmMethod == arrayBody(t, table, i)) { + index = i; + break; + } + } + } + + expect(t, index != -1); + + object jclass = getJClass(t, methodClass(t, vmMethod)); + + return makeJconstructor + (t, true, 0, jclass, index, parameterTypes, exceptionTypes, methodFlags + (t, vmMethod), signature, 0, annotationTable, 0, 0, 0, 0); +} + +object +makeJfield(Thread* t, object vmField, int index) +{ + PROTECT(t, vmField); + + object name = intern + (t, t->m->classpath->makeString + (t, fieldName(t, vmField), 0, byteArrayLength + (t, fieldName(t, vmField)) - 1)); + PROTECT(t, name); + + object type = local::resolveClassBySpec + (t, classLoader(t, fieldClass(t, vmField)), + reinterpret_cast + (&byteArrayBody(t, fieldSpec(t, vmField), 0)), + byteArrayLength(t, fieldSpec(t, vmField)) - 1); + PROTECT(t, type); + + type = getJClass(t, type); + + object signature; + object annotationTable; + object addendum = fieldAddendum(t, vmField); + if (addendum) { + signature = addendumSignature(t, addendum); + if (signature) { + signature = t->m->classpath->makeString + (t, signature, 0, byteArrayLength(t, signature) - 1); + } + + annotationTable = addendumAnnotationTable(t, addendum); + } else { + signature = 0; + annotationTable = 0; + } + + PROTECT(t, signature); + PROTECT(t, annotationTable); + + if (annotationTable) { + object runtimeData = getClassRuntimeData(t, fieldClass(t, vmField)); + + set(t, runtimeData, ClassRuntimeDataPool, + addendumPool(t, fieldAddendum(t, vmField))); + } + + if (index == -1) { + object table = classFieldTable(t, fieldClass(t, vmField)); + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + if (vmField == arrayBody(t, table, i)) { + index = i; + break; + } + } + } + + expect(t, index != -1); + + object jclass = getJClass(t, fieldClass(t, vmField)); + + return makeJfield + (t, true, 0, jclass, index, name, type, fieldFlags + (t, vmField), signature, 0, annotationTable, 0, 0, 0, 0); +} + void setProperty(Thread* t, object method, object properties, const char* name, const void* value, const char* format = "%s") @@ -4380,65 +4634,7 @@ jvmGetClassDeclaredMethods(Thread* t, uintptr_t* arguments) if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC)) and byteArrayBody(t, methodName(t, vmMethod), 0) != '<') { - object name = intern - (t, t->m->classpath->makeString - (t, methodName(t, vmMethod), 0, byteArrayLength - (t, methodName(t, vmMethod)) - 1)); - PROTECT(t, name); - - unsigned parameterCount; - unsigned returnTypeSpec; - object parameterTypes = local::resolveParameterJTypes - (t, classLoader(t, jclassVmClass(t, *c)), methodSpec(t, vmMethod), - ¶meterCount, &returnTypeSpec); - PROTECT(t, parameterTypes); - - object returnType = local::resolveJType - (t, classLoader(t, jclassVmClass(t, *c)), reinterpret_cast - (&byteArrayBody(t, methodSpec(t, vmMethod), returnTypeSpec)), - byteArrayLength(t, methodSpec(t, vmMethod)) - 1 - returnTypeSpec); - PROTECT(t, returnType); - - object exceptionTypes = local::resolveExceptionJTypes - (t, classLoader(t, jclassVmClass(t, *c)), - methodAddendum(t, vmMethod)); - PROTECT(t, exceptionTypes); - - object signature; - object annotationTable; - object annotationDefault; - object addendum = methodAddendum(t, vmMethod); - if (addendum) { - signature = addendumSignature(t, addendum); - if (signature) { - signature = t->m->classpath->makeString - (t, signature, 0, byteArrayLength(t, signature) - 1); - } - - annotationTable = addendumAnnotationTable(t, addendum); - - annotationDefault = methodAddendumAnnotationDefault(t, addendum); - } else { - signature = 0; - annotationTable = 0; - annotationDefault = 0; - } - - if (annotationTable or annotationDefault) { - PROTECT(t, signature); - PROTECT(t, annotationTable); - PROTECT(t, annotationDefault); - - object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c)); - - set(t, runtimeData, ClassRuntimeDataPool, - addendumPool(t, methodAddendum(t, vmMethod))); - } - - object method = makeJmethod - (t, true, 0, *c, i, name, returnType, parameterTypes, exceptionTypes, - methodFlags(t, vmMethod), signature, 0, annotationTable, 0, - annotationDefault, 0, 0, 0); + object method = makeJmethod(t, vmMethod, i); assert(t, ai < objectArrayLength(t, array)); @@ -4483,50 +4679,7 @@ jvmGetClassDeclaredFields(Thread* t, uintptr_t* arguments) PROTECT(t, vmField); if ((not publicOnly) or (fieldFlags(t, vmField) & ACC_PUBLIC)) { - object name = intern - (t, t->m->classpath->makeString - (t, fieldName(t, vmField), 0, byteArrayLength - (t, fieldName(t, vmField)) - 1)); - PROTECT(t, name); - - object type = local::resolveClassBySpec - (t, classLoader(t, jclassVmClass(t, *c)), - reinterpret_cast - (&byteArrayBody(t, fieldSpec(t, vmField), 0)), - byteArrayLength(t, fieldSpec(t, vmField)) - 1); - PROTECT(t, type); - - type = getJClass(t, type); - - object signature; - object annotationTable; - object addendum = fieldAddendum(t, vmField); - if (addendum) { - signature = addendumSignature(t, addendum); - if (signature) { - signature = t->m->classpath->makeString - (t, signature, 0, byteArrayLength(t, signature) - 1); - } - - annotationTable = addendumAnnotationTable(t, addendum); - } else { - signature = 0; - annotationTable = 0; - } - - if (annotationTable) { - PROTECT(t, signature); - PROTECT(t, annotationTable); - - object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c)); - - set(t, runtimeData, ClassRuntimeDataPool, - addendumPool(t, fieldAddendum(t, vmField))); - } - - object field = makeJfield - (t, true, 0, *c, i, name, type, fieldFlags - (t, vmField), signature, 0, annotationTable, 0, 0, 0, 0); + object field = makeJfield(t, vmField, i); assert(t, ai < objectArrayLength(t, array)); @@ -4577,47 +4730,7 @@ jvmGetClassDeclaredConstructors(Thread* t, uintptr_t* arguments) (&byteArrayBody(t, methodName(t, vmMethod), 0)), "") == 0) { - unsigned parameterCount; - unsigned returnTypeSpec; - object parameterTypes = local::resolveParameterJTypes - (t, classLoader(t, jclassVmClass(t, *c)), methodSpec(t, vmMethod), - ¶meterCount, &returnTypeSpec); - PROTECT(t, parameterTypes); - - object exceptionTypes = local::resolveExceptionJTypes - (t, classLoader(t, jclassVmClass(t, *c)), - methodAddendum(t, vmMethod)); - PROTECT(t, exceptionTypes); - - object signature; - object annotationTable; - object addendum = methodAddendum(t, vmMethod); - if (addendum) { - signature = addendumSignature(t, addendum); - if (signature) { - signature = t->m->classpath->makeString - (t, signature, 0, byteArrayLength(t, signature) - 1); - } - - annotationTable = addendumAnnotationTable(t, addendum); - } else { - signature = 0; - annotationTable = 0; - } - - if (annotationTable) { - PROTECT(t, signature); - PROTECT(t, annotationTable); - - object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c)); - - set(t, runtimeData, ClassRuntimeDataPool, - addendumPool(t, methodAddendum(t, vmMethod))); - } - - object method = makeJconstructor - (t, true, 0, *c, i, parameterTypes, exceptionTypes, methodFlags - (t, vmMethod), signature, 0, annotationTable, 0, 0, 0, 0); + object method = makeJconstructor(t, vmMethod, i); assert(t, ai < objectArrayLength(t, array)); diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 12a32fb3f5..289c955bc3 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -3154,6 +3154,82 @@ ReleasePrimitiveArrayCritical(Thread* t, jarray, void*, jint) } } +uint64_t +fromReflectedMethod(Thread* t, uintptr_t* arguments) +{ + jobject m = reinterpret_cast(arguments[0]); + + return methodID(t, t->m->classpath->getVMMethod(t, *m)); +} + +jmethodID JNICALL +FromReflectedMethod(Thread* t, jobject method) +{ + uintptr_t arguments[] = { reinterpret_cast(method) }; + + return reinterpret_cast(run(t, fromReflectedMethod, arguments)); +} + +uint64_t +toReflectedMethod(Thread* t, uintptr_t* arguments) +{ + jmethodID m = arguments[1]; + jboolean isStatic = arguments[2]; + + return reinterpret_cast + (makeLocalReference + (t, t->m->classpath->makeJMethod + (t, isStatic ? getStaticMethod(t, m) : getMethod(t, m)))); +} + +jobject JNICALL +ToReflectedMethod(Thread* t, jclass c, jmethodID method, jboolean isStatic) +{ + uintptr_t arguments[] = { reinterpret_cast(c), + reinterpret_cast(method), + static_cast(isStatic) }; + + return reinterpret_cast(run(t, toReflectedMethod, arguments)); +} + +uint64_t +fromReflectedField(Thread* t, uintptr_t* arguments) +{ + jobject f = reinterpret_cast(arguments[0]); + + return fieldID(t, t->m->classpath->getVMField(t, *f)); +} + +jfieldID JNICALL +FromReflectedField(Thread* t, jobject field) +{ + uintptr_t arguments[] = { reinterpret_cast(field) }; + + return reinterpret_cast(run(t, fromReflectedField, arguments)); +} + +uint64_t +toReflectedField(Thread* t, uintptr_t* arguments) +{ + jfieldID f = arguments[1]; + jboolean isStatic = arguments[2]; + + return reinterpret_cast + (makeLocalReference + (t, t->m->classpath->makeJField + (t, isStatic ? getStaticField(t, f) : getField(t, f)))); +} + +jobject JNICALL +ToReflectedField(Thread* t, jclass c, jfieldID field, jboolean isStatic) +{ + uintptr_t arguments[] = { reinterpret_cast(c), + reinterpret_cast(field), + static_cast(isStatic) }; + + return reinterpret_cast(run(t, toReflectedField, arguments)); +} + uint64_t registerNatives(Thread* t, uintptr_t* arguments) { @@ -3607,6 +3683,10 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) envTable->IsSameObject = local::IsSameObject; envTable->PushLocalFrame = local::PushLocalFrame; envTable->PopLocalFrame = local::PopLocalFrame; + envTable->FromReflectedMethod = local::FromReflectedMethod; + envTable->ToReflectedMethod = local::ToReflectedMethod; + envTable->FromReflectedField = local::FromReflectedField; + envTable->ToReflectedField = local::ToReflectedField; } } // namespace vm diff --git a/src/machine.h b/src/machine.h index 52233cab3c..f71788572d 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1536,6 +1536,18 @@ class Classpath { virtual object makeThread(Thread* t, Thread* parent) = 0; + virtual object + makeJMethod(Thread* t, object vmMethod) = 0; + + virtual object + getVMMethod(Thread* t, object jmethod) = 0; + + virtual object + makeJField(Thread* t, object vmField) = 0; + + virtual object + getVMField(Thread* t, object jfield) = 0; + virtual void clearInterrupted(Thread* t) = 0; diff --git a/test/JNI.java b/test/JNI.java index b4e93c0f75..cbb17cc925 100644 --- a/test/JNI.java +++ b/test/JNI.java @@ -1,3 +1,7 @@ +import java.lang.reflect.Method; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; + public class JNI { static { System.loadLibrary("test"); @@ -37,7 +41,27 @@ public class JNI { float a13, float a14, float a15, double a16, float a17, float a18, float a19, float a20); - public static void main(String[] args) { + private static native long fromReflectedMethod(Object m); + + private static native Object toReflectedMethod(Class c, long id, + boolean isStatic); + + private static native int callStaticIntMethod(Class c, long id); + + private static native Object newObject(Class c, long id); + + private static native long fromReflectedField(Field f); + + private static native Field toReflectedField(Class c, long id, + boolean isStatic); + + private static native int getStaticIntField(Class c, long id); + + public static int method242() { return 242; } + + public static final int field950 = 950; + + public static void main(String[] args) throws Exception { expect(addDoubles (1.0d, 2.0d, 3.0d, 4.0d, 5.0d, 6.0d, 7.0d, 8.0d, 9.0d, 10.0d, 11.0d, 12.0d, 13.0d, 14.0d, 15.0d, 16.0d, 17.0d, 18.0d, 19.0d, 20.0d) @@ -55,5 +79,32 @@ public class JNI { expect(doEcho(42.0f) == 42.0f); expect(doEcho(42.0d) == 42.0d); + + expect(callStaticIntMethod + (JNI.class, fromReflectedMethod + (JNI.class.getMethod("method242"))) == 242); + + expect(((Method) toReflectedMethod + (JNI.class, fromReflectedMethod + (JNI.class.getMethod("method242")), true)) + .getName().equals("method242")); + + expect(newObject + (JNI.class, fromReflectedMethod + (JNI.class.getConstructor())) instanceof JNI); + + expect(((Constructor) toReflectedMethod + (JNI.class, fromReflectedMethod + (JNI.class.getConstructor()), false)) + .getDeclaringClass().equals(JNI.class)); + + expect(getStaticIntField + (JNI.class, fromReflectedField + (JNI.class.getField("field950"))) == 950); + + expect(toReflectedField + (JNI.class, fromReflectedField + (JNI.class.getField("field950")), true) + .getName().equals("field950")); } } diff --git a/test/jni.cpp b/test/jni.cpp index fe174edec9..eacf9e31bc 100644 --- a/test/jni.cpp +++ b/test/jni.cpp @@ -57,6 +57,50 @@ Java_JNI_doEcho__D(JNIEnv* e, jclass c, jdouble f) (c, e->GetStaticMethodID(c, "echo", "(D)D"), array); } +extern "C" JNIEXPORT jlong JNICALL +Java_JNI_fromReflectedMethod(JNIEnv* e, jclass, jobject method) +{ + return reinterpret_cast(e->FromReflectedMethod(method)); +} + +extern "C" JNIEXPORT jobject JNICALL +Java_JNI_toReflectedMethod(JNIEnv* e, jclass, jclass c, jlong id, + jboolean isStatic) +{ + return e->ToReflectedMethod(c, reinterpret_cast(id), isStatic); +} + +extern "C" JNIEXPORT jint JNICALL +Java_JNI_callStaticIntMethod(JNIEnv* e, jclass, jclass c, jlong id) +{ + return e->CallStaticIntMethod(c, reinterpret_cast(id)); +} + +extern "C" JNIEXPORT jobject JNICALL +Java_JNI_newObject(JNIEnv* e, jclass, jclass c, jlong id) +{ + return e->NewObject(c, reinterpret_cast(id)); +} + +extern "C" JNIEXPORT jlong JNICALL +Java_JNI_fromReflectedField(JNIEnv* e, jclass, jobject field) +{ + return reinterpret_cast(e->FromReflectedField(field)); +} + +extern "C" JNIEXPORT jobject JNICALL +Java_JNI_toReflectedField(JNIEnv* e, jclass, jclass c, jlong id, + jboolean isStatic) +{ + return e->ToReflectedField(c, reinterpret_cast(id), isStatic); +} + +extern "C" JNIEXPORT jint JNICALL +Java_JNI_getStaticIntField(JNIEnv* e, jclass, jclass c, jlong id) +{ + return e->GetStaticIntField(c, reinterpret_cast(id)); +} + extern "C" JNIEXPORT jobject JNICALL Java_Buffers_allocateNative(JNIEnv* e, jclass, jint capacity) {