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);
}
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*)
{

View File

@ -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),
&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
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),
&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);
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<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);
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)),
"<init>") == 0)
{
unsigned parameterCount;
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);
object method = makeJconstructor(t, vmMethod, i);
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
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

View File

@ -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;

View File

@ -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"));
}
}

View File

@ -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<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
Java_Buffers_allocateNative(JNIEnv* e, jclass, jint capacity)
{