implement JNI reflection methods

These include FromReflectedMethod, ToReflectedMethod,
FromReflectedField, and ToReflectedField.
This commit is contained in:
Joel Dice 2012-12-19 12:39:33 -07:00
parent 7b07b5b9a3
commit d200019d10
6 changed files with 476 additions and 145 deletions

View File

@ -54,6 +54,37 @@ class MyClasspath : public Classpath {
root(t, Machine::BootLoader), 0, 0, group, 0); 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 virtual void
clearInterrupted(Thread*) clearInterrupted(Thread*)
{ {

View File

@ -341,6 +341,15 @@ makeClassNameString(Thread* t, object name)
return makeString(t, "%s", s); 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 void
interceptFileOperations(Thread*); interceptFileOperations(Thread*);
@ -537,6 +546,44 @@ class MyClasspath : public Classpath {
return thread; 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 virtual void
clearInterrupted(Thread* t) clearInterrupted(Thread* t)
{ {
@ -2260,6 +2307,213 @@ resolveExceptionJTypes(Thread* t, object loader, object addendum)
return array; 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),
&parameterCount, &returnTypeSpec);
PROTECT(t, parameterTypes);
object returnType = local::resolveJType
(t, classLoader(t, methodClass(t, vmMethod)), reinterpret_cast<char*>
(&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),
&parameterCount, &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<char*>
(&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 void
setProperty(Thread* t, object method, object properties, setProperty(Thread* t, object method, object properties,
const char* name, const void* value, const char* format = "%s") 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)) if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC))
and byteArrayBody(t, methodName(t, vmMethod), 0) != '<') and byteArrayBody(t, methodName(t, vmMethod), 0) != '<')
{ {
object name = intern object method = makeJmethod(t, vmMethod, i);
(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),
&parameterCount, &returnTypeSpec);
PROTECT(t, parameterTypes);
object returnType = local::resolveJType
(t, classLoader(t, jclassVmClass(t, *c)), reinterpret_cast<char*>
(&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);
assert(t, ai < objectArrayLength(t, array)); assert(t, ai < objectArrayLength(t, array));
@ -4483,50 +4679,7 @@ jvmGetClassDeclaredFields(Thread* t, uintptr_t* arguments)
PROTECT(t, vmField); PROTECT(t, vmField);
if ((not publicOnly) or (fieldFlags(t, vmField) & ACC_PUBLIC)) { if ((not publicOnly) or (fieldFlags(t, vmField) & ACC_PUBLIC)) {
object name = intern object field = makeJfield(t, vmField, i);
(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<char*>
(&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);
assert(t, ai < objectArrayLength(t, array)); assert(t, ai < objectArrayLength(t, array));
@ -4577,47 +4730,7 @@ jvmGetClassDeclaredConstructors(Thread* t, uintptr_t* arguments)
(&byteArrayBody(t, methodName(t, vmMethod), 0)), (&byteArrayBody(t, methodName(t, vmMethod), 0)),
"<init>") == 0) "<init>") == 0)
{ {
unsigned parameterCount; object method = makeJconstructor(t, vmMethod, i);
unsigned returnTypeSpec;
object parameterTypes = local::resolveParameterJTypes
(t, classLoader(t, jclassVmClass(t, *c)), methodSpec(t, vmMethod),
&parameterCount, &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);
assert(t, ai < objectArrayLength(t, array)); assert(t, ai < objectArrayLength(t, array));

View File

@ -3154,6 +3154,82 @@ ReleasePrimitiveArrayCritical(Thread* t, jarray, void*, jint)
} }
} }
uint64_t
fromReflectedMethod(Thread* t, uintptr_t* arguments)
{
jobject m = reinterpret_cast<jobject>(arguments[0]);
return methodID(t, t->m->classpath->getVMMethod(t, *m));
}
jmethodID JNICALL
FromReflectedMethod(Thread* t, jobject method)
{
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(method) };
return reinterpret_cast<jmethodID>(run(t, fromReflectedMethod, arguments));
}
uint64_t
toReflectedMethod(Thread* t, uintptr_t* arguments)
{
jmethodID m = arguments[1];
jboolean isStatic = arguments[2];
return reinterpret_cast<uintptr_t>
(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<uintptr_t>(c),
reinterpret_cast<uintptr_t>(method),
static_cast<uintptr_t>(isStatic) };
return reinterpret_cast<jobject>(run(t, toReflectedMethod, arguments));
}
uint64_t
fromReflectedField(Thread* t, uintptr_t* arguments)
{
jobject f = reinterpret_cast<jobject>(arguments[0]);
return fieldID(t, t->m->classpath->getVMField(t, *f));
}
jfieldID JNICALL
FromReflectedField(Thread* t, jobject field)
{
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(field) };
return reinterpret_cast<jfieldID>(run(t, fromReflectedField, arguments));
}
uint64_t
toReflectedField(Thread* t, uintptr_t* arguments)
{
jfieldID f = arguments[1];
jboolean isStatic = arguments[2];
return reinterpret_cast<uintptr_t>
(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<uintptr_t>(c),
reinterpret_cast<uintptr_t>(field),
static_cast<uintptr_t>(isStatic) };
return reinterpret_cast<jobject>(run(t, toReflectedField, arguments));
}
uint64_t uint64_t
registerNatives(Thread* t, uintptr_t* arguments) registerNatives(Thread* t, uintptr_t* arguments)
{ {
@ -3607,6 +3683,10 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable)
envTable->IsSameObject = local::IsSameObject; envTable->IsSameObject = local::IsSameObject;
envTable->PushLocalFrame = local::PushLocalFrame; envTable->PushLocalFrame = local::PushLocalFrame;
envTable->PopLocalFrame = local::PopLocalFrame; envTable->PopLocalFrame = local::PopLocalFrame;
envTable->FromReflectedMethod = local::FromReflectedMethod;
envTable->ToReflectedMethod = local::ToReflectedMethod;
envTable->FromReflectedField = local::FromReflectedField;
envTable->ToReflectedField = local::ToReflectedField;
} }
} // namespace vm } // namespace vm

View File

@ -1536,6 +1536,18 @@ class Classpath {
virtual object virtual object
makeThread(Thread* t, Thread* parent) = 0; 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 virtual void
clearInterrupted(Thread* t) = 0; clearInterrupted(Thread* t) = 0;

View File

@ -1,3 +1,7 @@
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class JNI { public class JNI {
static { static {
System.loadLibrary("test"); System.loadLibrary("test");
@ -37,7 +41,27 @@ public class JNI {
float a13, float a14, float a15, double a16, float a17, float a18, float a13, float a14, float a15, double a16, float a17, float a18,
float a19, float a20); 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 expect(addDoubles
(1.0d, 2.0d, 3.0d, 4.0d, 5.0d, 6.0d, 7.0d, 8.0d, 9.0d, 10.0d, 11.0d, (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) 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.0f) == 42.0f);
expect(doEcho(42.0d) == 42.0d); 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"));
} }
} }

View File

@ -57,6 +57,50 @@ Java_JNI_doEcho__D(JNIEnv* e, jclass c, jdouble f)
(c, e->GetStaticMethodID(c, "echo", "(D)D"), array); (c, e->GetStaticMethodID(c, "echo", "(D)D"), array);
} }
extern "C" JNIEXPORT jlong JNICALL
Java_JNI_fromReflectedMethod(JNIEnv* e, jclass, jobject method)
{
return reinterpret_cast<uintptr_t>(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<jmethodID>(id), isStatic);
}
extern "C" JNIEXPORT jint JNICALL
Java_JNI_callStaticIntMethod(JNIEnv* e, jclass, jclass c, jlong id)
{
return e->CallStaticIntMethod(c, reinterpret_cast<jmethodID>(id));
}
extern "C" JNIEXPORT jobject JNICALL
Java_JNI_newObject(JNIEnv* e, jclass, jclass c, jlong id)
{
return e->NewObject(c, reinterpret_cast<jmethodID>(id));
}
extern "C" JNIEXPORT jlong JNICALL
Java_JNI_fromReflectedField(JNIEnv* e, jclass, jobject field)
{
return reinterpret_cast<uintptr_t>(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<jfieldID>(id), isStatic);
}
extern "C" JNIEXPORT jint JNICALL
Java_JNI_getStaticIntField(JNIEnv* e, jclass, jclass c, jlong id)
{
return e->GetStaticIntField(c, reinterpret_cast<jfieldID>(id));
}
extern "C" JNIEXPORT jobject JNICALL extern "C" JNIEXPORT jobject JNICALL
Java_Buffers_allocateNative(JNIEnv* e, jclass, jint capacity) Java_Buffers_allocateNative(JNIEnv* e, jclass, jint capacity)
{ {