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