From e8eba94cecfa09bbc531a67ff94594ace402c742 Mon Sep 17 00:00:00 2001 From: Rahmadi Trimananda Date: Tue, 18 Jun 2019 20:01:33 -0700 Subject: [PATCH] A proper implementation for getGenericParameterTypes using the class ParameterizedTypeImpl. --- examples/Reflection.java | 8 +- src/main/gov/nasa/jpf/vm/Types.java | 59 +++++++++++++-- .../jpf/vm/JPF_java_lang_reflect_Method.java | 73 +++++++++++++++---- 3 files changed, 117 insertions(+), 23 deletions(-) diff --git a/examples/Reflection.java b/examples/Reflection.java index ae0e853..fe2927c 100644 --- a/examples/Reflection.java +++ b/examples/Reflection.java @@ -42,25 +42,25 @@ public class Reflection { public static void main(String[] args) { - /*Method[] methods = SampleClass.class.getMethods(); + Method[] methods = SampleClass.class.getMethods(); Type[] parameters = methods[0].getGenericParameterTypes(); //Type[] parameters = methods[0].getGenericParameterTypes(); for (int i = 0; i < parameters.length; i++) { System.out.println(parameters[i]); } System.out.println(); - Class[] parameterTypes = methods[0].getParameterTypes(); + /*Class[] parameterTypes = methods[0].getParameterTypes(); for(Class parameterType: parameterTypes){ System.out.println(parameterType.getName()); } System.out.println();*/ - TypeVariable[] typeParameters = GenericShort.class.getTypeParameters(); + /*TypeVariable[] typeParameters = GenericShort.class.getTypeParameters(); //TypeVariable[] typeParameters = SampleClass.class.getTypeParameters(); for(TypeVariable typeVar: typeParameters){ System.out.println(typeVar); - } + }*/ System.out.println(); /* Type returnType = methods[0].getGenericReturnType(); diff --git a/src/main/gov/nasa/jpf/vm/Types.java b/src/main/gov/nasa/jpf/vm/Types.java index 873b065..2e98b25 100644 --- a/src/main/gov/nasa/jpf/vm/Types.java +++ b/src/main/gov/nasa/jpf/vm/Types.java @@ -1177,21 +1177,22 @@ public class Types { throw new JPFException("invalid method declaration: " + methodDecl); } + // TODO: Fix for Groovy's model-checking public static String[] getGenericTypeVariableNames(String signature) { int pos = 0; - int opening = 0; + int marker = 0; ArrayList typeVarNames = new ArrayList<>(); while (pos < signature.length()) { if (pos > 0) { // Start from ';' if this is not the first type variable name - opening = signature.indexOf(';', pos); + marker = signature.indexOf(';', pos); // Break if this is the end of the type variable names - if (signature.charAt(opening + 1) == '>') + if (signature.charAt(marker + 1) == '>') break; } int colon = signature.indexOf(':', pos); - String typeVarName = signature.substring(opening + 1, colon); + String typeVarName = signature.substring(marker + 1, colon); typeVarNames.add(typeVarName); pos = colon + 1; } @@ -1201,5 +1202,53 @@ public class Types { return arrTypeVarNames; } - + + // TODO: Fix for Groovy's model-checking + public static String[] getParameterizedTypesFromArgumentTypeNames(String signature) { + int pos = signature.indexOf('<', 0); + if (pos == -1) + return new String[0]; + ArrayList typeVarNames = new ArrayList<>(); + + while (pos < signature.length()) { + String typeVarName = ""; + int comma = signature.indexOf(',', pos); + if (comma == -1) { + int closing = signature.indexOf('>', pos); + typeVarName = signature.substring(pos + 1, closing); + pos = signature.length(); + } else { + typeVarName = signature.substring(pos + 1, comma); + pos = comma + 1; + } + typeVarNames.add(typeVarName); + } + + String[] arrTypeVarNames = new String[typeVarNames.size()]; + typeVarNames.toArray(arrTypeVarNames); + + return arrTypeVarNames; + } + + public static String getGenericClassName(String signature) { + int opening = signature.indexOf('<'); + if (opening == -1) + return signature; + else + return signature.substring(0, opening); + } + + public static String getOwnerClassName(String signature) { + int marker = signature.indexOf('$'); + if (marker == -1) + return null; + else + return signature.substring(0, marker); + } + + public static boolean isGenericSignature(String signature) { + int opening = signature.indexOf('<'); + return (opening != -1); + } + // TODO: Fix for Groovy's model-checking } diff --git a/src/peers/gov/nasa/jpf/vm/JPF_java_lang_reflect_Method.java b/src/peers/gov/nasa/jpf/vm/JPF_java_lang_reflect_Method.java index 4e1987b..efb46e8 100644 --- a/src/peers/gov/nasa/jpf/vm/JPF_java_lang_reflect_Method.java +++ b/src/peers/gov/nasa/jpf/vm/JPF_java_lang_reflect_Method.java @@ -115,27 +115,72 @@ public class JPF_java_lang_reflect_Method extends NativePeer { } // TODO: Fix for Groovy's model-checking - // TODO: We have been able to only register the generic class and not yet the parameterized types - static int getGenericParameterTypes( MJIEnv env, MethodInfo mi) { + private static int getParameterizedTypeImplObj(String signature, MJIEnv env) { + + ThreadInfo ti = env.getThreadInfo(); + ClassLoaderInfo cli = env.getSystemClassLoaderInfo(); + ClassInfo ci = cli.getResolvedClassInfo("sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl"); + // Create a new object of type ParameterizedTypeImpl + int paramTypeRef = env.newObject(ci); + ElementInfo ei = env.getModifiableElementInfo(paramTypeRef); + // Get field information and fill out the fields + // rawType field + String className = Types.getGenericClassName(signature); + ClassInfo gci = cli.getResolvedClassInfo(className); + if (!gci.isRegistered()) { + gci.registerClass(ti); + } + ei.setReferenceField("rawType", gci.getClassObjectRef()); + + // actualTypeArguments + String[] parameterizedTypes = Types.getParameterizedTypesFromArgumentTypeNames(signature); + int[] types = new int[parameterizedTypes.length]; + for(int j = 0; j < parameterizedTypes.length; j++) { + ClassInfo pci = cli.getResolvedClassInfo(parameterizedTypes[j]); + if (!pci.isRegistered()) { + pci.registerClass(ti); + } + types[j] = pci.getClassObjectRef(); + } + int aRef = env.newObjectArray("Ljava/lang/reflect/Type;", parameterizedTypes.length); + // Set references for every array element + for (int j = 0; j < parameterizedTypes.length; j++) { + env.setReferenceArrayElement(aRef, j, types[j]); + } + ei.setReferenceField("actualTypeArguments", aRef); + + // ownerType + String ownerType = Types.getOwnerClassName(signature); + if (ownerType != null) { + ClassInfo oci = ClassLoaderInfo.getCurrentResolvedClassInfo(ownerType); + if (!oci.isRegistered()) { + oci.registerClass(ti); + } + ei.setReferenceField("ownerType", oci.getClassObjectRef()); + } else { + ei.setReferenceField("ownerType", MJIEnv.NULL); + } + + return paramTypeRef; + } + + static int getGenericParameterTypes( MJIEnv env, int objRef, MethodInfo mi) { ThreadInfo ti = env.getThreadInfo(); String[] argTypeNames = mi.getArgumentGenericTypeNames(); int[] ar = new int[argTypeNames.length]; for (int i = 0; i < argTypeNames.length; i++) { // Change this into just the generic class type if it is a generic class - String genericTypeName = argTypeNames[i]; - int startOfGenericParameter = argTypeNames[i].indexOf('<'); - if (startOfGenericParameter != -1) { - genericTypeName = argTypeNames[i].substring(0, startOfGenericParameter); - } - ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(genericTypeName); - if (!ci.isRegistered()) { - ci.registerClass(ti); + if (Types.isGenericSignature(argTypeNames[i])) { + ar[i] = getParameterizedTypeImplObj(argTypeNames[i], env); + } else { + ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(argTypeNames[i]); + if (!ci.isRegistered()) { + ci.registerClass(ti); + } + ar[i] = ci.getClassObjectRef(); } - - ar[i] = ci.getClassObjectRef(); } - int aRef = env.newObjectArray("Ljava/lang/reflect/Type;", argTypeNames.length); for (int i = 0; i < argTypeNames.length; i++) { env.setReferenceArrayElement(aRef, i, ar[i]); @@ -146,7 +191,7 @@ public class JPF_java_lang_reflect_Method extends NativePeer { @MJI public int getGenericParameterTypes_____3Ljava_lang_reflect_Type_2 (MJIEnv env, int objRef){ - return getGenericParameterTypes(env, getMethodInfo(env, objRef)); + return getGenericParameterTypes(env, objRef, getMethodInfo(env, objRef)); } @MJI -- 2.34.1