82 */ |
82 */ |
83 |
83 |
84 package jdk.internal.dynalink.beans; |
84 package jdk.internal.dynalink.beans; |
85 |
85 |
86 import java.lang.invoke.MethodHandle; |
86 import java.lang.invoke.MethodHandle; |
|
87 import java.lang.invoke.MethodHandles; |
87 import java.lang.invoke.MethodType; |
88 import java.lang.invoke.MethodType; |
|
89 import java.util.ArrayList; |
88 import java.util.Iterator; |
90 import java.util.Iterator; |
89 import java.util.LinkedList; |
91 import java.util.LinkedList; |
90 import java.util.List; |
92 import java.util.List; |
|
93 import jdk.internal.dynalink.CallSiteDescriptor; |
91 import jdk.internal.dynalink.beans.ApplicableOverloadedMethods.ApplicabilityTest; |
94 import jdk.internal.dynalink.beans.ApplicableOverloadedMethods.ApplicabilityTest; |
92 import jdk.internal.dynalink.linker.LinkerServices; |
95 import jdk.internal.dynalink.linker.LinkerServices; |
93 import jdk.internal.dynalink.support.TypeUtilities; |
96 import jdk.internal.dynalink.support.TypeUtilities; |
94 |
97 |
95 /** |
98 /** |
96 * Represents an overloaded method. |
99 * Represents a group of {@link SingleDynamicMethod} objects that represents all overloads of a particular name (or all |
|
100 * constructors) for a particular class. Correctly handles overload resolution, variable arity methods, and caller |
|
101 * sensitive methods within the overloads. |
97 * |
102 * |
98 * @author Attila Szegedi |
103 * @author Attila Szegedi |
99 */ |
104 */ |
100 class OverloadedDynamicMethod extends DynamicMethod { |
105 class OverloadedDynamicMethod extends DynamicMethod { |
101 /** |
106 /** |
102 * Holds a list of all methods. |
107 * Holds a list of all methods. |
103 */ |
108 */ |
104 private final LinkedList<MethodHandle> methods; |
109 private final LinkedList<SingleDynamicMethod> methods; |
105 private final ClassLoader classLoader; |
110 private final ClassLoader classLoader; |
106 |
111 |
107 /** |
112 /** |
108 * Creates a new overloaded dynamic method. |
113 * Creates a new overloaded dynamic method. |
109 * |
114 * |
110 * @param clazz the class this method belongs to |
115 * @param clazz the class this method belongs to |
111 * @param name the name of the method |
116 * @param name the name of the method |
112 */ |
117 */ |
113 OverloadedDynamicMethod(Class<?> clazz, String name) { |
118 OverloadedDynamicMethod(Class<?> clazz, String name) { |
114 this(new LinkedList<MethodHandle>(), clazz.getClassLoader(), getClassAndMethodName(clazz, name)); |
119 this(new LinkedList<SingleDynamicMethod>(), clazz.getClassLoader(), getClassAndMethodName(clazz, name)); |
115 } |
120 } |
116 |
121 |
117 private OverloadedDynamicMethod(LinkedList<MethodHandle> methods, ClassLoader classLoader, String name) { |
122 private OverloadedDynamicMethod(LinkedList<SingleDynamicMethod> methods, ClassLoader classLoader, String name) { |
118 super(name); |
123 super(name); |
119 this.methods = methods; |
124 this.methods = methods; |
120 this.classLoader = classLoader; |
125 this.classLoader = classLoader; |
121 } |
126 } |
122 |
127 |
123 @Override |
128 @Override |
124 SimpleDynamicMethod getMethodForExactParamTypes(String paramTypes) { |
129 SingleDynamicMethod getMethodForExactParamTypes(String paramTypes) { |
125 final LinkedList<MethodHandle> matchingMethods = new LinkedList<>(); |
130 final LinkedList<SingleDynamicMethod> matchingMethods = new LinkedList<>(); |
126 for(MethodHandle method: methods) { |
131 for(SingleDynamicMethod method: methods) { |
127 if(typeMatchesDescription(paramTypes, method.type())) { |
132 final SingleDynamicMethod matchingMethod = method.getMethodForExactParamTypes(paramTypes); |
128 matchingMethods.add(method); |
133 if(matchingMethod != null) { |
|
134 matchingMethods.add(matchingMethod); |
129 } |
135 } |
130 } |
136 } |
131 switch(matchingMethods.size()) { |
137 switch(matchingMethods.size()) { |
132 case 0: { |
138 case 0: { |
133 return null; |
139 return null; |
134 } |
140 } |
135 case 1: { |
141 case 1: { |
136 final MethodHandle target = matchingMethods.get(0); |
142 return matchingMethods.getFirst(); |
137 return new SimpleDynamicMethod(target, SimpleDynamicMethod.getMethodNameWithSignature(target, getName())); |
|
138 } |
143 } |
139 default: { |
144 default: { |
140 throw new BootstrapMethodError("Can't choose among " + matchingMethods + " for argument types " |
145 throw new BootstrapMethodError("Can't choose among " + matchingMethods + " for argument types " |
141 + paramTypes + " for method " + getName()); |
146 + paramTypes + " for method " + getName()); |
142 } |
147 } |
143 } |
148 } |
144 } |
149 } |
145 |
150 |
146 @Override |
151 @Override |
147 public MethodHandle getInvocation(final MethodType callSiteType, final LinkerServices linkerServices) { |
152 public MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) { |
|
153 final MethodType callSiteType = callSiteDescriptor.getMethodType(); |
148 // First, find all methods applicable to the call site by subtyping (JLS 15.12.2.2) |
154 // First, find all methods applicable to the call site by subtyping (JLS 15.12.2.2) |
149 final ApplicableOverloadedMethods subtypingApplicables = getApplicables(callSiteType, |
155 final ApplicableOverloadedMethods subtypingApplicables = getApplicables(callSiteType, |
150 ApplicableOverloadedMethods.APPLICABLE_BY_SUBTYPING); |
156 ApplicableOverloadedMethods.APPLICABLE_BY_SUBTYPING); |
151 // Next, find all methods applicable by method invocation conversion to the call site (JLS 15.12.2.3). |
157 // Next, find all methods applicable by method invocation conversion to the call site (JLS 15.12.2.3). |
152 final ApplicableOverloadedMethods methodInvocationApplicables = getApplicables(callSiteType, |
158 final ApplicableOverloadedMethods methodInvocationApplicables = getApplicables(callSiteType, |
154 // Finally, find all methods applicable by variable arity invocation. (JLS 15.12.2.4). |
160 // Finally, find all methods applicable by variable arity invocation. (JLS 15.12.2.4). |
155 final ApplicableOverloadedMethods variableArityApplicables = getApplicables(callSiteType, |
161 final ApplicableOverloadedMethods variableArityApplicables = getApplicables(callSiteType, |
156 ApplicableOverloadedMethods.APPLICABLE_BY_VARIABLE_ARITY); |
162 ApplicableOverloadedMethods.APPLICABLE_BY_VARIABLE_ARITY); |
157 |
163 |
158 // Find the methods that are maximally specific based on the call site signature |
164 // Find the methods that are maximally specific based on the call site signature |
159 List<MethodHandle> maximallySpecifics = subtypingApplicables.findMaximallySpecificMethods(); |
165 List<SingleDynamicMethod> maximallySpecifics = subtypingApplicables.findMaximallySpecificMethods(); |
160 if(maximallySpecifics.isEmpty()) { |
166 if(maximallySpecifics.isEmpty()) { |
161 maximallySpecifics = methodInvocationApplicables.findMaximallySpecificMethods(); |
167 maximallySpecifics = methodInvocationApplicables.findMaximallySpecificMethods(); |
162 if(maximallySpecifics.isEmpty()) { |
168 if(maximallySpecifics.isEmpty()) { |
163 maximallySpecifics = variableArityApplicables.findMaximallySpecificMethods(); |
169 maximallySpecifics = variableArityApplicables.findMaximallySpecificMethods(); |
164 } |
170 } |
169 // might match more concrete types passed in invocations. That's why we provisionally call them "invokables". |
175 // might match more concrete types passed in invocations. That's why we provisionally call them "invokables". |
170 // This is typical for very generic signatures at call sites. Typical example: call site specifies |
176 // This is typical for very generic signatures at call sites. Typical example: call site specifies |
171 // (Object, Object), and we have a method whose parameter types are (String, int). None of the JLS applicability |
177 // (Object, Object), and we have a method whose parameter types are (String, int). None of the JLS applicability |
172 // rules will trigger, but we must consider the method, as it can be the right match for a concrete invocation. |
178 // rules will trigger, but we must consider the method, as it can be the right match for a concrete invocation. |
173 @SuppressWarnings({ "unchecked", "rawtypes" }) |
179 @SuppressWarnings({ "unchecked", "rawtypes" }) |
174 final List<MethodHandle> invokables = (List)methods.clone(); |
180 final List<SingleDynamicMethod> invokables = (List)methods.clone(); |
175 invokables.removeAll(subtypingApplicables.getMethods()); |
181 invokables.removeAll(subtypingApplicables.getMethods()); |
176 invokables.removeAll(methodInvocationApplicables.getMethods()); |
182 invokables.removeAll(methodInvocationApplicables.getMethods()); |
177 invokables.removeAll(variableArityApplicables.getMethods()); |
183 invokables.removeAll(variableArityApplicables.getMethods()); |
178 for(final Iterator<MethodHandle> it = invokables.iterator(); it.hasNext();) { |
184 for(final Iterator<SingleDynamicMethod> it = invokables.iterator(); it.hasNext();) { |
179 final MethodHandle m = it.next(); |
185 final SingleDynamicMethod m = it.next(); |
180 if(!isApplicableDynamically(linkerServices, callSiteType, m)) { |
186 if(!isApplicableDynamically(linkerServices, callSiteType, m)) { |
181 it.remove(); |
187 it.remove(); |
182 } |
188 } |
183 } |
189 } |
184 |
190 |
197 // No overloads can ever match the call site type |
203 // No overloads can ever match the call site type |
198 return null; |
204 return null; |
199 } |
205 } |
200 case 1: { |
206 case 1: { |
201 // Very lucky, we ended up with a single candidate method handle based on the call site signature; we |
207 // Very lucky, we ended up with a single candidate method handle based on the call site signature; we |
202 // can link it very simply by delegating to a SimpleDynamicMethod. |
208 // can link it very simply by delegating to the SingleDynamicMethod. |
203 final MethodHandle mh = invokables.iterator().next(); |
209 invokables.iterator().next().getInvocation(callSiteDescriptor, linkerServices); |
204 return new SimpleDynamicMethod(mh).getInvocation(callSiteType, linkerServices); |
|
205 } |
210 } |
206 default: { |
211 default: { |
207 // We have more than one candidate. We have no choice but to link to a method that resolves overloads on |
212 // We have more than one candidate. We have no choice but to link to a method that resolves overloads on |
208 // every invocation (alternatively, we could opportunistically link the one method that resolves for the |
213 // every invocation (alternatively, we could opportunistically link the one method that resolves for the |
209 // current arguments, but we'd need to install a fairly complex guard for that and when it'd fail, we'd |
214 // current arguments, but we'd need to install a fairly complex guard for that and when it'd fail, we'd |
210 // go back all the way to candidate selection. |
215 // go back all the way to candidate selection. Note that we're resolving any potential caller sensitive |
211 // TODO: cache per call site type |
216 // methods here to their handles, as the OverloadedMethod instance is specific to a call site, so it |
212 return new OverloadedMethod(invokables, this, callSiteType, linkerServices).getInvoker(); |
217 // has an already determined Lookup. |
|
218 final List<MethodHandle> methodHandles = new ArrayList<>(invokables.size()); |
|
219 final MethodHandles.Lookup lookup = callSiteDescriptor.getLookup(); |
|
220 for(SingleDynamicMethod method: invokables) { |
|
221 methodHandles.add(method.getTarget(lookup)); |
|
222 } |
|
223 return new OverloadedMethod(methodHandles, this, callSiteType, linkerServices).getInvoker(); |
213 } |
224 } |
214 } |
225 } |
215 |
226 |
216 } |
227 } |
217 |
228 |
218 @Override |
229 @Override |
219 public boolean contains(MethodHandle mh) { |
230 public boolean contains(SingleDynamicMethod m) { |
220 final MethodType type = mh.type(); |
231 for(SingleDynamicMethod method: methods) { |
221 for(MethodHandle method: methods) { |
232 if(method.contains(m)) { |
222 if(typesEqualNoReceiver(type, method.type())) { |
|
223 return true; |
233 return true; |
224 } |
234 } |
225 } |
235 } |
226 return false; |
236 return false; |
227 } |
|
228 |
|
229 private static boolean typesEqualNoReceiver(MethodType type1, MethodType type2) { |
|
230 final int pc = type1.parameterCount(); |
|
231 if(pc != type2.parameterCount()) { |
|
232 return false; |
|
233 } |
|
234 for(int i = 1; i < pc; ++i) { // i = 1: ignore receiver |
|
235 if(type1.parameterType(i) != type2.parameterType(i)) { |
|
236 return false; |
|
237 } |
|
238 } |
|
239 return true; |
|
240 } |
237 } |
241 |
238 |
242 ClassLoader getClassLoader() { |
239 ClassLoader getClassLoader() { |
243 return classLoader; |
240 return classLoader; |
244 } |
241 } |
245 |
242 |
246 private static boolean isApplicableDynamically(LinkerServices linkerServices, MethodType callSiteType, |
243 private static boolean isApplicableDynamically(LinkerServices linkerServices, MethodType callSiteType, |
247 MethodHandle m) { |
244 SingleDynamicMethod m) { |
248 final MethodType methodType = m.type(); |
245 final MethodType methodType = m.getMethodType(); |
249 final boolean varArgs = m.isVarargsCollector(); |
246 final boolean varArgs = m.isVarArgs(); |
250 final int fixedArgLen = methodType.parameterCount() - (varArgs ? 1 : 0); |
247 final int fixedArgLen = methodType.parameterCount() - (varArgs ? 1 : 0); |
251 final int callSiteArgLen = callSiteType.parameterCount(); |
248 final int callSiteArgLen = callSiteType.parameterCount(); |
252 |
249 |
253 // Arity checks |
250 // Arity checks |
254 if(varArgs) { |
251 if(varArgs) { |