diff --git a/jcl/src/java.base/share/classes/java/lang/invoke/MethodType.java b/jcl/src/java.base/share/classes/java/lang/invoke/MethodType.java index 7799198aea7..1791fe63636 100644 --- a/jcl/src/java.base/share/classes/java/lang/invoke/MethodType.java +++ b/jcl/src/java.base/share/classes/java/lang/invoke/MethodType.java @@ -51,7 +51,6 @@ import java.util.WeakHashMap; import com.ibm.oti.util.Msg; -import com.ibm.oti.vm.VM; /*[IF CRIU_SUPPORT]*/ import openj9.internal.criu.NotCheckpointSafe; @@ -337,43 +336,7 @@ public MethodType erase() { */ @VMCONSTANTPOOL_METHOD public static MethodType fromMethodDescriptorString(String methodDescriptor, ClassLoader loader) { - ClassLoader classLoader = loader; - if (classLoader == null) { - /*[IF JAVA_SPEC_VERSION >= 14]*/ - @SuppressWarnings("removal") - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkPermission(sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION); - } - /*[ENDIF] JAVA_SPEC_VERSION >= 14 */ - classLoader = ClassLoader.getSystemClassLoader(); - } - - // Check cache - Map classLoaderMethodTypeCache = VM.getVMLangAccess().getMethodTypeCache(classLoader); - MethodType mt = classLoaderMethodTypeCache != null ? classLoaderMethodTypeCache.get(methodDescriptor) : null; - - // MethodDescriptorString is not in cache - if (null == mt) { - // ensure '.' is not included in the descriptor - if (methodDescriptor.indexOf((int)'.') != -1) { - throw new IllegalArgumentException(methodDescriptor); - } - - // split descriptor into classes - last one is the return type - ArrayList> classes = parseIntoClasses(methodDescriptor, classLoader); - if (classes.size() == 0) { - throw new IllegalArgumentException(methodDescriptor); - } - - Class returnType = classes.remove(classes.size() - 1); - mt = methodType(returnType, classes); - if (classLoaderMethodTypeCache != null) { - classLoaderMethodTypeCache.put(mt.methodDescriptor, mt); - } - } - - return mt; + return MethodTypeHelper.fromMethodDescriptorStringInternal(methodDescriptor, loader); } /** @@ -385,7 +348,7 @@ public static MethodType fromMethodDescriptorString(String methodDescriptor, Cla */ @SuppressWarnings("unused") /* Used by native code */ private static final MethodType fromMethodDescriptorStringAppendArg(String methodDescriptor, ClassLoader loader, Class appendArgumentType) { - List> types = parseIntoClasses(methodDescriptor, loader); + List> types = MethodTypeHelper.parseIntoClasses(methodDescriptor, loader); Class returnType = types.remove(types.size() - 1); types.add(appendArgumentType); @@ -412,49 +375,6 @@ private static final Throwable throwNoClassDefFoundError(TypeNotPresentException } throw e; } - - /* - * Parse the MethodDescriptor string into a list of Class objects. The last class in the list - * is the return type. - */ - private static final ArrayList> parseIntoClasses(String methodDescriptor, ClassLoader classLoader) { - int length = methodDescriptor.length(); - if (length == 0) { - /*[MSG "K05d3", "invalid descriptor: {0}"]*/ - throw new IllegalArgumentException(Msg.getString("K05d3", methodDescriptor)); //$NON-NLS-1$ - } - - char[] signature = new char[length]; - methodDescriptor.getChars(0, length, signature, 0); - int index = 0; - boolean closeBracket = false; - - if (signature[index] != '(') { - /*[MSG "K05d4", "missing opening '(': {0}"]*/ - throw new IllegalArgumentException(Msg.getString("K05d4", methodDescriptor)); //$NON-NLS-1$ - } - index++; - - ArrayList> args = new ArrayList>(); - - while(index < length) { - /* Ensure we only see one ')' closing bracket */ - if ((signature[index] == ')')) { - if (closeBracket) { - /*[MSG "K05d5", "too many ')': {0}"]*/ - throw new IllegalArgumentException(Msg.getString("K05d5", methodDescriptor)); //$NON-NLS-1$ - } - closeBracket = true; - index++; - continue; - } - - index = MethodTypeHelper.parseIntoClass(signature, index, args, classLoader, methodDescriptor); - index++; - } - return args; - } - /** * Convenience method to convert all types to Object. diff --git a/jcl/src/java.base/share/classes/java/lang/invoke/MethodTypeHelper.java b/jcl/src/java.base/share/classes/java/lang/invoke/MethodTypeHelper.java index fe1b48cf752..8d8fd7cc4a3 100644 --- a/jcl/src/java.base/share/classes/java/lang/invoke/MethodTypeHelper.java +++ b/jcl/src/java.base/share/classes/java/lang/invoke/MethodTypeHelper.java @@ -32,7 +32,10 @@ import jdk.internal.value.PrimitiveClass; /*[ENDIF] INLINE-TYPES */ +import java.util.Map; + import com.ibm.oti.util.Msg; +import com.ibm.oti.vm.VM; /** * MethodTypeHelper - static methods @@ -270,6 +273,116 @@ static final int parseIntoClass(char[] signature, int index, ArrayList> return index; } + /** + * Parse the MethodDescriptor string into a list of Class objects. The last class in the list + * is the return type. + * + * @param methodDescriptor the method descriptor string + * @param classLoader the ClassLoader to be used or null for System ClassLoader + * @return list of classes representing the parameters and return type + * @throws IllegalArgumentException if the string is not well-formed + */ + static final ArrayList> parseIntoClasses(String methodDescriptor, ClassLoader classLoader) { + int length = methodDescriptor.length(); + if (length == 0) { + /*[MSG "K05d3", "invalid descriptor: {0}"]*/ + throw new IllegalArgumentException(Msg.getString("K05d3", methodDescriptor)); //$NON-NLS-1$ + } + + char[] signature = new char[length]; + methodDescriptor.getChars(0, length, signature, 0); + int index = 0; + boolean closeBracket = false; + + if (signature[index] != '(') { + /*[MSG "K05d4", "missing opening '(': {0}"]*/ + throw new IllegalArgumentException(Msg.getString("K05d4", methodDescriptor)); //$NON-NLS-1$ + } + index++; + + ArrayList> args = new ArrayList>(); + + while(index < length) { + /* Ensure we only see one ')' closing bracket */ + if ((signature[index] == ')')) { + if (closeBracket) { + /*[MSG "K05d5", "too many ')': {0}"]*/ + throw new IllegalArgumentException(Msg.getString("K05d5", methodDescriptor)); //$NON-NLS-1$ + } + closeBracket = true; + index++; + continue; + } + + index = parseIntoClass(signature, index, args, classLoader, methodDescriptor); + index++; + } + return args; + } + + /** + * Convenience Method to create a MethodType from bytecode-level method descriptor. + * (See JVM Spec 2nd Ed. section 4.4.3). + * + * All of the classes used in the method descriptor string must be reachable from a + * common ClassLoader or an exception will result. + * + * The ClassLoader parameter may be null, in which case the System ClassLoader will be used. + * + * Note, the Class names must use JVM syntax in the method descriptor String and therefore + * java.lang.Class will be represented as Ljava/lang/Class; + * + * Example method descriptors: + * (II)V - method taking two ints and return void + * (I)Ljava/lang/Integer; - method taking an int and returning an Integer + * ([I)I - method taking an array of ints and returning an int + * + * @param methodDescriptor the method descriptor string + * @param loader the ClassLoader to be used or null for System ClassLoader + * @return a MethodType object representing the method descriptor string + * @throws IllegalArgumentException if the string is not well-formed + * @throws TypeNotPresentException if a named type cannot be found + */ + static MethodType fromMethodDescriptorStringInternal(String methodDescriptor, ClassLoader loader) { + ClassLoader classLoader = loader; + if (classLoader == null) { + /*[IF JAVA_SPEC_VERSION >= 14]*/ + @SuppressWarnings("removal") + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkPermission(sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION); + } + /*[ENDIF] JAVA_SPEC_VERSION >= 14 */ + classLoader = ClassLoader.getSystemClassLoader(); + } + + // Check cache + Map classLoaderMethodTypeCache = VM.getVMLangAccess().getMethodTypeCache(classLoader); + MethodType mt = classLoaderMethodTypeCache != null ? classLoaderMethodTypeCache.get(methodDescriptor) : null; + + // MethodDescriptorString is not in cache + if (null == mt) { + // ensure '.' is not included in the descriptor + if (methodDescriptor.indexOf((int)'.') != -1) { + throw new IllegalArgumentException(methodDescriptor); + } + + // split descriptor into classes - last one is the return type + ArrayList> classes = parseIntoClasses(methodDescriptor, classLoader); + if (classes.size() == 0) { + throw new IllegalArgumentException(methodDescriptor); + } + + Class returnType = classes.remove(classes.size() - 1); + mt = MethodType.methodType(returnType, classes); + if (classLoaderMethodTypeCache != null) { + classLoaderMethodTypeCache.put(mt.toMethodDescriptorString(), mt); + } + } + + return mt; + } + /** * This helper calls MethodType.fromMethodDescriptorString(...) or * MethodType.fromMethodDescriptorStringAppendArg(...) but throws @@ -287,7 +400,7 @@ static final int parseIntoClass(char[] signature, int index, ArrayList> */ static final MethodType vmResolveFromMethodDescriptorString(String methodDescriptor, ClassLoader loader, Class appendArgumentType) throws Throwable { try { - MethodType result = MethodType.fromMethodDescriptorString(methodDescriptor, loader); + MethodType result = fromMethodDescriptorStringInternal(methodDescriptor, loader); if (null != appendArgumentType) { result = result.appendParameterTypes(appendArgumentType); }