src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java
changeset 48861 47f19ff9903c
parent 47216 71c04702a3d5
child 49873 26ebfe8ce852
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java	Fri Feb 02 10:37:48 2018 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java	Fri Feb 02 17:28:17 2018 -0800
@@ -35,6 +35,12 @@
 import java.util.List;
 import java.util.Map;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.MapCursor;
+import org.graalvm.collections.Pair;
+import org.graalvm.collections.UnmodifiableEconomicMap;
+import org.graalvm.collections.UnmodifiableMapCursor;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
 import org.graalvm.compiler.api.replacements.MethodSubstitutionRegistry;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
@@ -44,12 +50,6 @@
 import org.graalvm.compiler.graph.iterators.NodeIterable;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.MapCursor;
-import org.graalvm.util.Pair;
-import org.graalvm.util.UnmodifiableEconomicMap;
-import org.graalvm.util.UnmodifiableMapCursor;
 
 import jdk.vm.ci.meta.MetaUtil;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -112,6 +112,26 @@
     }
 
     /**
+     * A symbol for an already resolved method.
+     */
+    public static class ResolvedJavaSymbol implements Type {
+        private final ResolvedJavaType resolved;
+
+        public ResolvedJavaSymbol(ResolvedJavaType type) {
+            this.resolved = type;
+        }
+
+        public ResolvedJavaType getResolved() {
+            return resolved;
+        }
+
+        @Override
+        public String toString() {
+            return resolved.toJavaName();
+        }
+    }
+
+    /**
      * A symbol that is lazily {@linkplain OptionalLazySymbol#resolve() resolved} to a {@link Type}.
      */
     static class OptionalLazySymbol implements Type {
@@ -696,7 +716,7 @@
      *
      * @param declaringClass the class to test
      */
-    protected boolean canBeIntrinsified(ResolvedJavaType declaringClass) {
+    public boolean canBeIntrinsified(ResolvedJavaType declaringClass) {
         return true;
     }
 
@@ -1150,6 +1170,9 @@
         }
 
         static boolean checkResolvable(boolean isOptional, Type declaringType, Binding binding) {
+            if (declaringType instanceof ResolvedJavaSymbol) {
+                return checkResolvable(isOptional, ((ResolvedJavaSymbol) declaringType).getResolved(), binding);
+            }
             Class<?> declaringClass = InvocationPlugins.resolveType(declaringType, isOptional);
             if (declaringClass == null) {
                 return true;
@@ -1165,6 +1188,13 @@
             }
             return true;
         }
+
+        private static boolean checkResolvable(boolean isOptional, ResolvedJavaType declaringType, Binding binding) {
+            if (resolveJavaMethod(declaringType, binding) == null && !isOptional) {
+                throw new AssertionError(String.format("Method not found: %s.%s%s", declaringType.toJavaName(), binding.name, binding.argumentsDescriptor));
+            }
+            return true;
+        }
     }
 
     /**
@@ -1235,7 +1265,7 @@
      * {@link NoSuchMethodError} is thrown.
      *
      * @param declaringClass the class to search for a method matching {@code binding}
-     * @return the method (if any) in {@code declaringClass} matching binding
+     * @return the method (if any) in {@code declaringClass} matching {@code binding}
      */
     public static Method resolveMethod(Class<?> declaringClass, Binding binding) {
         if (binding.name.equals("<init>")) {
@@ -1243,32 +1273,70 @@
         }
         Method[] methods = declaringClass.getDeclaredMethods();
         List<String> parameterTypeNames = parseParameters(binding.argumentsDescriptor);
+        Method match = null;
         for (int i = 0; i < methods.length; ++i) {
             Method m = methods[i];
-            if (binding.isStatic == Modifier.isStatic(m.getModifiers()) && m.getName().equals(binding.name)) {
-                if (parameterTypeNames.equals(toInternalTypeNames(m.getParameterTypes()))) {
-                    for (int j = i + 1; j < methods.length; ++j) {
-                        Method other = methods[j];
-                        if (binding.isStatic == Modifier.isStatic(other.getModifiers()) && other.getName().equals(binding.name)) {
-                            if (parameterTypeNames.equals(toInternalTypeNames(other.getParameterTypes()))) {
-                                if (m.getReturnType().isAssignableFrom(other.getReturnType())) {
-                                    // `other` has a more specific return type - choose it
-                                    // (m is most likely a bridge method)
-                                    m = other;
-                                } else {
-                                    if (!other.getReturnType().isAssignableFrom(m.getReturnType())) {
-                                        throw new NoSuchMethodError(String.format(
-                                                        "Found 2 methods with same name and parameter types but unrelated return types:%n %s%n %s", m, other));
-                                    }
-                                }
-                            }
-                        }
+            if (binding.isStatic == Modifier.isStatic(m.getModifiers()) &&
+                            m.getName().equals(binding.name) &&
+                            parameterTypeNames.equals(toInternalTypeNames(m.getParameterTypes()))) {
+                if (match == null) {
+                    match = m;
+                } else if (match.getReturnType().isAssignableFrom(m.getReturnType())) {
+                    // `m` has a more specific return type - choose it
+                    // (`match` is most likely a bridge method)
+                    match = m;
+                } else {
+                    if (!m.getReturnType().isAssignableFrom(match.getReturnType())) {
+                        throw new NoSuchMethodError(String.format(
+                                        "Found 2 methods with same name and parameter types but unrelated return types:%n %s%n %s", match, m));
                     }
+                }
+            }
+        }
+        return match;
+    }
+
+    /**
+     * Same as {@link #resolveMethod(Class, Binding)} and
+     * {@link #resolveConstructor(Class, Binding)} except in terms of {@link ResolvedJavaType} and
+     * {@link ResolvedJavaMethod}.
+     */
+    public static ResolvedJavaMethod resolveJavaMethod(ResolvedJavaType declaringClass, Binding binding) {
+        ResolvedJavaMethod[] methods = declaringClass.getDeclaredMethods();
+        if (binding.name.equals("<init>")) {
+            for (ResolvedJavaMethod m : methods) {
+                if (m.getName().equals("<init>") && m.getSignature().toMethodDescriptor().startsWith(binding.argumentsDescriptor)) {
                     return m;
                 }
             }
+            return null;
         }
-        return null;
+
+        ResolvedJavaMethod match = null;
+        for (int i = 0; i < methods.length; ++i) {
+            ResolvedJavaMethod m = methods[i];
+            if (binding.isStatic == m.isStatic() &&
+                            m.getName().equals(binding.name) &&
+                            m.getSignature().toMethodDescriptor().startsWith(binding.argumentsDescriptor)) {
+                if (match == null) {
+                    match = m;
+                } else {
+                    final ResolvedJavaType matchReturnType = (ResolvedJavaType) match.getSignature().getReturnType(declaringClass);
+                    final ResolvedJavaType mReturnType = (ResolvedJavaType) m.getSignature().getReturnType(declaringClass);
+                    if (matchReturnType.isAssignableFrom(mReturnType)) {
+                        // `m` has a more specific return type - choose it
+                        // (`match` is most likely a bridge method)
+                        match = m;
+                    } else {
+                        if (!mReturnType.isAssignableFrom(matchReturnType)) {
+                            throw new NoSuchMethodError(String.format(
+                                            "Found 2 methods with same name and parameter types but unrelated return types:%n %s%n %s", match, m));
+                        }
+                    }
+                }
+            }
+        }
+        return match;
     }
 
     /**