89 import java.util.LinkedList; |
89 import java.util.LinkedList; |
90 import java.util.List; |
90 import java.util.List; |
91 import jdk.internal.dynalink.beans.ApplicableOverloadedMethods.ApplicabilityTest; |
91 import jdk.internal.dynalink.beans.ApplicableOverloadedMethods.ApplicabilityTest; |
92 import jdk.internal.dynalink.linker.LinkerServices; |
92 import jdk.internal.dynalink.linker.LinkerServices; |
93 import jdk.internal.dynalink.support.TypeUtilities; |
93 import jdk.internal.dynalink.support.TypeUtilities; |
94 |
|
95 |
94 |
96 /** |
95 /** |
97 * Represents an overloaded method. |
96 * Represents an overloaded method. |
98 * |
97 * |
99 * @author Attila Szegedi |
98 * @author Attila Szegedi |
202 // Very lucky, we ended up with a single candidate method handle based on the call site signature; we |
201 // Very lucky, we ended up with a single candidate method handle based on the call site signature; we |
203 // can link it very simply by delegating to a SimpleDynamicMethod. |
202 // can link it very simply by delegating to a SimpleDynamicMethod. |
204 final MethodHandle mh = invokables.iterator().next(); |
203 final MethodHandle mh = invokables.iterator().next(); |
205 return new SimpleDynamicMethod(mh).getInvocation(callSiteType, linkerServices); |
204 return new SimpleDynamicMethod(mh).getInvocation(callSiteType, linkerServices); |
206 } |
205 } |
207 } |
206 default: { |
208 |
207 // We have more than one candidate. We have no choice but to link to a method that resolves overloads on |
209 // We have more than one candidate. We have no choice but to link to a method that resolves overloads on every |
208 // every invocation (alternatively, we could opportunistically link the one method that resolves for the |
210 // invocation (alternatively, we could opportunistically link the one method that resolves for the current |
209 // current arguments, but we'd need to install a fairly complex guard for that and when it'd fail, we'd |
211 // arguments, but we'd need to install a fairly complex guard for that and when it'd fail, we'd go back all the |
210 // go back all the way to candidate selection. |
212 // way to candidate selection. |
211 // TODO: cache per call site type |
213 // TODO: cache per call site type |
212 return new OverloadedMethod(invokables, this, callSiteType, linkerServices).getInvoker(); |
214 return new OverloadedMethod(invokables, this, callSiteType, linkerServices).getInvoker(); |
213 } |
|
214 } |
|
215 |
215 } |
216 } |
216 |
217 |
217 @Override |
218 @Override |
218 public boolean contains(MethodHandle mh) { |
219 public boolean contains(MethodHandle mh) { |
219 final MethodType type = mh.type(); |
220 final MethodType type = mh.type(); |
246 MethodHandle m) { |
247 MethodHandle m) { |
247 final MethodType methodType = m.type(); |
248 final MethodType methodType = m.type(); |
248 final boolean varArgs = m.isVarargsCollector(); |
249 final boolean varArgs = m.isVarargsCollector(); |
249 final int fixedArgLen = methodType.parameterCount() - (varArgs ? 1 : 0); |
250 final int fixedArgLen = methodType.parameterCount() - (varArgs ? 1 : 0); |
250 final int callSiteArgLen = callSiteType.parameterCount(); |
251 final int callSiteArgLen = callSiteType.parameterCount(); |
|
252 |
|
253 // Arity checks |
251 if(varArgs) { |
254 if(varArgs) { |
252 if(callSiteArgLen < fixedArgLen) { |
255 if(callSiteArgLen < fixedArgLen) { |
253 return false; |
256 return false; |
254 } |
257 } |
255 } else if(callSiteArgLen != fixedArgLen) { |
258 } else if(callSiteArgLen != fixedArgLen) { |
256 return false; |
259 return false; |
257 } |
260 } |
258 // Starting from 1, as receiver type doesn't participate |
261 |
|
262 // Fixed arguments type checks, starting from 1, as receiver type doesn't participate |
259 for(int i = 1; i < fixedArgLen; ++i) { |
263 for(int i = 1; i < fixedArgLen; ++i) { |
260 if(!isApplicableDynamically(linkerServices, callSiteType.parameterType(i), methodType.parameterType(i))) { |
264 if(!isApplicableDynamically(linkerServices, callSiteType.parameterType(i), methodType.parameterType(i))) { |
261 return false; |
265 return false; |
262 } |
266 } |
263 } |
267 } |
264 if(varArgs) { |
268 if(!varArgs) { |
265 final Class<?> varArgArrayType = methodType.parameterType(fixedArgLen); |
269 // Not vararg; both arity and types matched. |
266 final Class<?> varArgType = varArgArrayType.getComponentType(); |
|
267 if(fixedArgLen == callSiteArgLen - 1) { |
|
268 final Class<?> callSiteArgType = callSiteType.parameterType(fixedArgLen); |
|
269 // Exactly one vararg; check both exact matching and component |
|
270 // matching. |
|
271 return isApplicableDynamically(linkerServices, callSiteArgType, varArgArrayType) |
|
272 || isApplicableDynamically(linkerServices, callSiteArgType, varArgType); |
|
273 } else { |
|
274 for(int i = fixedArgLen; i < callSiteArgLen; ++i) { |
|
275 if(!isApplicableDynamically(linkerServices, callSiteType.parameterType(i), varArgType)) { |
|
276 return false; |
|
277 } |
|
278 } |
|
279 return true; |
|
280 } |
|
281 } else { |
|
282 return true; |
270 return true; |
283 } |
271 } |
|
272 |
|
273 final Class<?> varArgArrayType = methodType.parameterType(fixedArgLen); |
|
274 final Class<?> varArgType = varArgArrayType.getComponentType(); |
|
275 |
|
276 if(fixedArgLen == callSiteArgLen - 1) { |
|
277 // Exactly one vararg; check both array type matching and array component type matching. |
|
278 final Class<?> callSiteArgType = callSiteType.parameterType(fixedArgLen); |
|
279 return isApplicableDynamically(linkerServices, callSiteArgType, varArgArrayType) |
|
280 || isApplicableDynamically(linkerServices, callSiteArgType, varArgType); |
|
281 } |
|
282 |
|
283 // Either zero, or more than one vararg; check if all actual vararg types match the vararg array component type. |
|
284 for(int i = fixedArgLen; i < callSiteArgLen; ++i) { |
|
285 if(!isApplicableDynamically(linkerServices, callSiteType.parameterType(i), varArgType)) { |
|
286 return false; |
|
287 } |
|
288 } |
|
289 |
|
290 return true; |
284 } |
291 } |
285 |
292 |
286 private static boolean isApplicableDynamically(LinkerServices linkerServices, Class<?> callSiteType, |
293 private static boolean isApplicableDynamically(LinkerServices linkerServices, Class<?> callSiteType, |
287 Class<?> methodType) { |
294 Class<?> methodType) { |
288 return TypeUtilities.isPotentiallyConvertible(callSiteType, methodType) |
295 return TypeUtilities.isPotentiallyConvertible(callSiteType, methodType) |