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
equal deleted inserted replaced
48860:5bce1b7e7800 48861:47f19ff9903c
    33 import java.util.Arrays;
    33 import java.util.Arrays;
    34 import java.util.Collections;
    34 import java.util.Collections;
    35 import java.util.List;
    35 import java.util.List;
    36 import java.util.Map;
    36 import java.util.Map;
    37 
    37 
       
    38 import org.graalvm.collections.EconomicMap;
       
    39 import org.graalvm.collections.Equivalence;
       
    40 import org.graalvm.collections.MapCursor;
       
    41 import org.graalvm.collections.Pair;
       
    42 import org.graalvm.collections.UnmodifiableEconomicMap;
       
    43 import org.graalvm.collections.UnmodifiableMapCursor;
    38 import org.graalvm.compiler.api.replacements.MethodSubstitution;
    44 import org.graalvm.compiler.api.replacements.MethodSubstitution;
    39 import org.graalvm.compiler.api.replacements.MethodSubstitutionRegistry;
    45 import org.graalvm.compiler.api.replacements.MethodSubstitutionRegistry;
    40 import org.graalvm.compiler.bytecode.BytecodeProvider;
    46 import org.graalvm.compiler.bytecode.BytecodeProvider;
    41 import org.graalvm.compiler.debug.Assertions;
    47 import org.graalvm.compiler.debug.Assertions;
    42 import org.graalvm.compiler.debug.GraalError;
    48 import org.graalvm.compiler.debug.GraalError;
    43 import org.graalvm.compiler.graph.Node;
    49 import org.graalvm.compiler.graph.Node;
    44 import org.graalvm.compiler.graph.iterators.NodeIterable;
    50 import org.graalvm.compiler.graph.iterators.NodeIterable;
    45 import org.graalvm.compiler.nodes.ValueNode;
    51 import org.graalvm.compiler.nodes.ValueNode;
    46 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
    52 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
    47 import org.graalvm.util.EconomicMap;
       
    48 import org.graalvm.util.Equivalence;
       
    49 import org.graalvm.util.MapCursor;
       
    50 import org.graalvm.util.Pair;
       
    51 import org.graalvm.util.UnmodifiableEconomicMap;
       
    52 import org.graalvm.util.UnmodifiableMapCursor;
       
    53 
    53 
    54 import jdk.vm.ci.meta.MetaUtil;
    54 import jdk.vm.ci.meta.MetaUtil;
    55 import jdk.vm.ci.meta.ResolvedJavaMethod;
    55 import jdk.vm.ci.meta.ResolvedJavaMethod;
    56 import jdk.vm.ci.meta.ResolvedJavaType;
    56 import jdk.vm.ci.meta.ResolvedJavaType;
    57 import jdk.vm.ci.meta.Signature;
    57 import jdk.vm.ci.meta.Signature;
   106                 this.args = newArgs;
   106                 this.args = newArgs;
   107                 this.value = null;
   107                 this.value = null;
   108                 return this;
   108                 return this;
   109             }
   109             }
   110             return null;
   110             return null;
       
   111         }
       
   112     }
       
   113 
       
   114     /**
       
   115      * A symbol for an already resolved method.
       
   116      */
       
   117     public static class ResolvedJavaSymbol implements Type {
       
   118         private final ResolvedJavaType resolved;
       
   119 
       
   120         public ResolvedJavaSymbol(ResolvedJavaType type) {
       
   121             this.resolved = type;
       
   122         }
       
   123 
       
   124         public ResolvedJavaType getResolved() {
       
   125             return resolved;
       
   126         }
       
   127 
       
   128         @Override
       
   129         public String toString() {
       
   130             return resolved.toJavaName();
   111         }
   131         }
   112     }
   132     }
   113 
   133 
   114     /**
   134     /**
   115      * A symbol that is lazily {@linkplain OptionalLazySymbol#resolve() resolved} to a {@link Type}.
   135      * A symbol that is lazily {@linkplain OptionalLazySymbol#resolve() resolved} to a {@link Type}.
   694     /**
   714     /**
   695      * Determines if methods in a given class can have invocation plugins.
   715      * Determines if methods in a given class can have invocation plugins.
   696      *
   716      *
   697      * @param declaringClass the class to test
   717      * @param declaringClass the class to test
   698      */
   718      */
   699     protected boolean canBeIntrinsified(ResolvedJavaType declaringClass) {
   719     public boolean canBeIntrinsified(ResolvedJavaType declaringClass) {
   700         return true;
   720         return true;
   701     }
   721     }
   702 
   722 
   703     LateClassPlugins findLateClassPlugins(String internalClassName) {
   723     LateClassPlugins findLateClassPlugins(String internalClassName) {
   704         for (LateClassPlugins lcp = lateRegistrations; lcp != null; lcp = lcp.next) {
   724         for (LateClassPlugins lcp = lateRegistrations; lcp != null; lcp = lcp.next) {
  1148             }
  1168             }
  1149             throw new AssertionError(format("graph builder plugin for %s not found", binding));
  1169             throw new AssertionError(format("graph builder plugin for %s not found", binding));
  1150         }
  1170         }
  1151 
  1171 
  1152         static boolean checkResolvable(boolean isOptional, Type declaringType, Binding binding) {
  1172         static boolean checkResolvable(boolean isOptional, Type declaringType, Binding binding) {
       
  1173             if (declaringType instanceof ResolvedJavaSymbol) {
       
  1174                 return checkResolvable(isOptional, ((ResolvedJavaSymbol) declaringType).getResolved(), binding);
       
  1175             }
  1153             Class<?> declaringClass = InvocationPlugins.resolveType(declaringType, isOptional);
  1176             Class<?> declaringClass = InvocationPlugins.resolveType(declaringType, isOptional);
  1154             if (declaringClass == null) {
  1177             if (declaringClass == null) {
  1155                 return true;
  1178                 return true;
  1156             }
  1179             }
  1157             if (binding.name.equals("<init>")) {
  1180             if (binding.name.equals("<init>")) {
  1160                 }
  1183                 }
  1161             } else {
  1184             } else {
  1162                 if (resolveMethod(declaringClass, binding) == null && !isOptional) {
  1185                 if (resolveMethod(declaringClass, binding) == null && !isOptional) {
  1163                     throw new AssertionError(String.format("Method not found: %s.%s%s", declaringClass.getName(), binding.name, binding.argumentsDescriptor));
  1186                     throw new AssertionError(String.format("Method not found: %s.%s%s", declaringClass.getName(), binding.name, binding.argumentsDescriptor));
  1164                 }
  1187                 }
       
  1188             }
       
  1189             return true;
       
  1190         }
       
  1191 
       
  1192         private static boolean checkResolvable(boolean isOptional, ResolvedJavaType declaringType, Binding binding) {
       
  1193             if (resolveJavaMethod(declaringType, binding) == null && !isOptional) {
       
  1194                 throw new AssertionError(String.format("Method not found: %s.%s%s", declaringType.toJavaName(), binding.name, binding.argumentsDescriptor));
  1165             }
  1195             }
  1166             return true;
  1196             return true;
  1167         }
  1197         }
  1168     }
  1198     }
  1169 
  1199 
  1233      * parameter types matching {@code binding} is found and the return types of all the matching
  1263      * parameter types matching {@code binding} is found and the return types of all the matching
  1234      * methods form an inheritance chain, the one with the most specific type is returned; otherwise
  1264      * methods form an inheritance chain, the one with the most specific type is returned; otherwise
  1235      * {@link NoSuchMethodError} is thrown.
  1265      * {@link NoSuchMethodError} is thrown.
  1236      *
  1266      *
  1237      * @param declaringClass the class to search for a method matching {@code binding}
  1267      * @param declaringClass the class to search for a method matching {@code binding}
  1238      * @return the method (if any) in {@code declaringClass} matching binding
  1268      * @return the method (if any) in {@code declaringClass} matching {@code binding}
  1239      */
  1269      */
  1240     public static Method resolveMethod(Class<?> declaringClass, Binding binding) {
  1270     public static Method resolveMethod(Class<?> declaringClass, Binding binding) {
  1241         if (binding.name.equals("<init>")) {
  1271         if (binding.name.equals("<init>")) {
  1242             return null;
  1272             return null;
  1243         }
  1273         }
  1244         Method[] methods = declaringClass.getDeclaredMethods();
  1274         Method[] methods = declaringClass.getDeclaredMethods();
  1245         List<String> parameterTypeNames = parseParameters(binding.argumentsDescriptor);
  1275         List<String> parameterTypeNames = parseParameters(binding.argumentsDescriptor);
       
  1276         Method match = null;
  1246         for (int i = 0; i < methods.length; ++i) {
  1277         for (int i = 0; i < methods.length; ++i) {
  1247             Method m = methods[i];
  1278             Method m = methods[i];
  1248             if (binding.isStatic == Modifier.isStatic(m.getModifiers()) && m.getName().equals(binding.name)) {
  1279             if (binding.isStatic == Modifier.isStatic(m.getModifiers()) &&
  1249                 if (parameterTypeNames.equals(toInternalTypeNames(m.getParameterTypes()))) {
  1280                             m.getName().equals(binding.name) &&
  1250                     for (int j = i + 1; j < methods.length; ++j) {
  1281                             parameterTypeNames.equals(toInternalTypeNames(m.getParameterTypes()))) {
  1251                         Method other = methods[j];
  1282                 if (match == null) {
  1252                         if (binding.isStatic == Modifier.isStatic(other.getModifiers()) && other.getName().equals(binding.name)) {
  1283                     match = m;
  1253                             if (parameterTypeNames.equals(toInternalTypeNames(other.getParameterTypes()))) {
  1284                 } else if (match.getReturnType().isAssignableFrom(m.getReturnType())) {
  1254                                 if (m.getReturnType().isAssignableFrom(other.getReturnType())) {
  1285                     // `m` has a more specific return type - choose it
  1255                                     // `other` has a more specific return type - choose it
  1286                     // (`match` is most likely a bridge method)
  1256                                     // (m is most likely a bridge method)
  1287                     match = m;
  1257                                     m = other;
  1288                 } else {
  1258                                 } else {
  1289                     if (!m.getReturnType().isAssignableFrom(match.getReturnType())) {
  1259                                     if (!other.getReturnType().isAssignableFrom(m.getReturnType())) {
  1290                         throw new NoSuchMethodError(String.format(
  1260                                         throw new NoSuchMethodError(String.format(
  1291                                         "Found 2 methods with same name and parameter types but unrelated return types:%n %s%n %s", match, m));
  1261                                                         "Found 2 methods with same name and parameter types but unrelated return types:%n %s%n %s", m, other));
  1292                     }
  1262                                     }
  1293                 }
  1263                                 }
  1294             }
  1264                             }
  1295         }
       
  1296         return match;
       
  1297     }
       
  1298 
       
  1299     /**
       
  1300      * Same as {@link #resolveMethod(Class, Binding)} and
       
  1301      * {@link #resolveConstructor(Class, Binding)} except in terms of {@link ResolvedJavaType} and
       
  1302      * {@link ResolvedJavaMethod}.
       
  1303      */
       
  1304     public static ResolvedJavaMethod resolveJavaMethod(ResolvedJavaType declaringClass, Binding binding) {
       
  1305         ResolvedJavaMethod[] methods = declaringClass.getDeclaredMethods();
       
  1306         if (binding.name.equals("<init>")) {
       
  1307             for (ResolvedJavaMethod m : methods) {
       
  1308                 if (m.getName().equals("<init>") && m.getSignature().toMethodDescriptor().startsWith(binding.argumentsDescriptor)) {
       
  1309                     return m;
       
  1310                 }
       
  1311             }
       
  1312             return null;
       
  1313         }
       
  1314 
       
  1315         ResolvedJavaMethod match = null;
       
  1316         for (int i = 0; i < methods.length; ++i) {
       
  1317             ResolvedJavaMethod m = methods[i];
       
  1318             if (binding.isStatic == m.isStatic() &&
       
  1319                             m.getName().equals(binding.name) &&
       
  1320                             m.getSignature().toMethodDescriptor().startsWith(binding.argumentsDescriptor)) {
       
  1321                 if (match == null) {
       
  1322                     match = m;
       
  1323                 } else {
       
  1324                     final ResolvedJavaType matchReturnType = (ResolvedJavaType) match.getSignature().getReturnType(declaringClass);
       
  1325                     final ResolvedJavaType mReturnType = (ResolvedJavaType) m.getSignature().getReturnType(declaringClass);
       
  1326                     if (matchReturnType.isAssignableFrom(mReturnType)) {
       
  1327                         // `m` has a more specific return type - choose it
       
  1328                         // (`match` is most likely a bridge method)
       
  1329                         match = m;
       
  1330                     } else {
       
  1331                         if (!mReturnType.isAssignableFrom(matchReturnType)) {
       
  1332                             throw new NoSuchMethodError(String.format(
       
  1333                                             "Found 2 methods with same name and parameter types but unrelated return types:%n %s%n %s", match, m));
  1265                         }
  1334                         }
  1266                     }
  1335                     }
  1267                     return m;
  1336                 }
  1268                 }
  1337             }
  1269             }
  1338         }
  1270         }
  1339         return match;
  1271         return null;
       
  1272     }
  1340     }
  1273 
  1341 
  1274     /**
  1342     /**
  1275      * Resolves a given binding to a constructor in a given class.
  1343      * Resolves a given binding to a constructor in a given class.
  1276      *
  1344      *