Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-aarch32-jdk8u
Path: blob/jdk8u272-b10-aarch32-20201026/nashorn/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java
48797 views
1
/*
2
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
/*
27
* This file is available under and governed by the GNU General Public
28
* License version 2 only, as published by the Free Software Foundation.
29
* However, the following notice accompanied the original version of this
30
* file, and Oracle licenses the original version of this file under the BSD
31
* license:
32
*/
33
/*
34
Copyright 2009-2013 Attila Szegedi
35
36
Licensed under both the Apache License, Version 2.0 (the "Apache License")
37
and the BSD License (the "BSD License"), with licensee being free to
38
choose either of the two at their discretion.
39
40
You may not use this file except in compliance with either the Apache
41
License or the BSD License.
42
43
If you choose to use this file in compliance with the Apache License, the
44
following notice applies to you:
45
46
You may obtain a copy of the Apache License at
47
48
http://www.apache.org/licenses/LICENSE-2.0
49
50
Unless required by applicable law or agreed to in writing, software
51
distributed under the License is distributed on an "AS IS" BASIS,
52
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
53
implied. See the License for the specific language governing
54
permissions and limitations under the License.
55
56
If you choose to use this file in compliance with the BSD License, the
57
following notice applies to you:
58
59
Redistribution and use in source and binary forms, with or without
60
modification, are permitted provided that the following conditions are
61
met:
62
* Redistributions of source code must retain the above copyright
63
notice, this list of conditions and the following disclaimer.
64
* Redistributions in binary form must reproduce the above copyright
65
notice, this list of conditions and the following disclaimer in the
66
documentation and/or other materials provided with the distribution.
67
* Neither the name of the copyright holder nor the names of
68
contributors may be used to endorse or promote products derived from
69
this software without specific prior written permission.
70
71
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
72
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
73
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
74
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
75
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
76
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
77
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
78
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
79
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
80
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
81
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
82
*/
83
84
package jdk.internal.dynalink.beans;
85
86
import java.lang.invoke.MethodHandle;
87
import java.lang.invoke.MethodHandles;
88
import java.lang.invoke.MethodType;
89
import java.text.Collator;
90
import java.util.ArrayList;
91
import java.util.Collections;
92
import java.util.Iterator;
93
import java.util.LinkedList;
94
import java.util.List;
95
import jdk.internal.dynalink.CallSiteDescriptor;
96
import jdk.internal.dynalink.beans.ApplicableOverloadedMethods.ApplicabilityTest;
97
import jdk.internal.dynalink.linker.LinkerServices;
98
import jdk.internal.dynalink.support.TypeUtilities;
99
100
/**
101
* Represents a group of {@link SingleDynamicMethod} objects that represents all overloads of a particular name (or all
102
* constructors) for a particular class. Correctly handles overload resolution, variable arity methods, and caller
103
* sensitive methods within the overloads.
104
*
105
* @author Attila Szegedi
106
*/
107
class OverloadedDynamicMethod extends DynamicMethod {
108
/**
109
* Holds a list of all methods.
110
*/
111
private final LinkedList<SingleDynamicMethod> methods;
112
private final ClassLoader classLoader;
113
114
/**
115
* Creates a new overloaded dynamic method.
116
*
117
* @param clazz the class this method belongs to
118
* @param name the name of the method
119
*/
120
OverloadedDynamicMethod(final Class<?> clazz, final String name) {
121
this(new LinkedList<SingleDynamicMethod>(), clazz.getClassLoader(), getClassAndMethodName(clazz, name));
122
}
123
124
private OverloadedDynamicMethod(final LinkedList<SingleDynamicMethod> methods, final ClassLoader classLoader, final String name) {
125
super(name);
126
this.methods = methods;
127
this.classLoader = classLoader;
128
}
129
130
@Override
131
SingleDynamicMethod getMethodForExactParamTypes(final String paramTypes) {
132
final LinkedList<SingleDynamicMethod> matchingMethods = new LinkedList<>();
133
for(final SingleDynamicMethod method: methods) {
134
final SingleDynamicMethod matchingMethod = method.getMethodForExactParamTypes(paramTypes);
135
if(matchingMethod != null) {
136
matchingMethods.add(matchingMethod);
137
}
138
}
139
switch(matchingMethods.size()) {
140
case 0: {
141
return null;
142
}
143
case 1: {
144
return matchingMethods.getFirst();
145
}
146
default: {
147
throw new BootstrapMethodError("Can't choose among " + matchingMethods + " for argument types "
148
+ paramTypes + " for method " + getName());
149
}
150
}
151
}
152
153
@Override
154
public MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) {
155
final MethodType callSiteType = callSiteDescriptor.getMethodType();
156
// First, find all methods applicable to the call site by subtyping (JLS 15.12.2.2)
157
final ApplicableOverloadedMethods subtypingApplicables = getApplicables(callSiteType,
158
ApplicableOverloadedMethods.APPLICABLE_BY_SUBTYPING);
159
// Next, find all methods applicable by method invocation conversion to the call site (JLS 15.12.2.3).
160
final ApplicableOverloadedMethods methodInvocationApplicables = getApplicables(callSiteType,
161
ApplicableOverloadedMethods.APPLICABLE_BY_METHOD_INVOCATION_CONVERSION);
162
// Finally, find all methods applicable by variable arity invocation. (JLS 15.12.2.4).
163
final ApplicableOverloadedMethods variableArityApplicables = getApplicables(callSiteType,
164
ApplicableOverloadedMethods.APPLICABLE_BY_VARIABLE_ARITY);
165
166
// Find the methods that are maximally specific based on the call site signature
167
List<SingleDynamicMethod> maximallySpecifics = subtypingApplicables.findMaximallySpecificMethods();
168
if(maximallySpecifics.isEmpty()) {
169
maximallySpecifics = methodInvocationApplicables.findMaximallySpecificMethods();
170
if(maximallySpecifics.isEmpty()) {
171
maximallySpecifics = variableArityApplicables.findMaximallySpecificMethods();
172
}
173
}
174
175
// Now, get a list of the rest of the methods; those that are *not* applicable to the call site signature based
176
// on JLS rules. As paradoxical as that might sound, we have to consider these for dynamic invocation, as they
177
// might match more concrete types passed in invocations. That's why we provisionally call them "invokables".
178
// This is typical for very generic signatures at call sites. Typical example: call site specifies
179
// (Object, Object), and we have a method whose parameter types are (String, int). None of the JLS applicability
180
// rules will trigger, but we must consider the method, as it can be the right match for a concrete invocation.
181
@SuppressWarnings({ "unchecked", "rawtypes" })
182
final List<SingleDynamicMethod> invokables = (List)methods.clone();
183
invokables.removeAll(subtypingApplicables.getMethods());
184
invokables.removeAll(methodInvocationApplicables.getMethods());
185
invokables.removeAll(variableArityApplicables.getMethods());
186
for(final Iterator<SingleDynamicMethod> it = invokables.iterator(); it.hasNext();) {
187
final SingleDynamicMethod m = it.next();
188
if(!isApplicableDynamically(linkerServices, callSiteType, m)) {
189
it.remove();
190
}
191
}
192
193
// If no additional methods can apply at invocation time, and there's more than one maximally specific method
194
// based on call site signature, that is a link-time ambiguity. In a static scenario, javac would report an
195
// ambiguity error.
196
if(invokables.isEmpty() && maximallySpecifics.size() > 1) {
197
throw new BootstrapMethodError("Can't choose among " + maximallySpecifics + " for argument types "
198
+ callSiteType);
199
}
200
201
// Merge them all.
202
invokables.addAll(maximallySpecifics);
203
switch(invokables.size()) {
204
case 0: {
205
// No overloads can ever match the call site type
206
return null;
207
}
208
case 1: {
209
// Very lucky, we ended up with a single candidate method handle based on the call site signature; we
210
// can link it very simply by delegating to the SingleDynamicMethod.
211
return invokables.iterator().next().getInvocation(callSiteDescriptor, linkerServices);
212
}
213
default: {
214
// We have more than one candidate. We have no choice but to link to a method that resolves overloads on
215
// every invocation (alternatively, we could opportunistically link the one method that resolves for the
216
// current arguments, but we'd need to install a fairly complex guard for that and when it'd fail, we'd
217
// go back all the way to candidate selection. Note that we're resolving any potential caller sensitive
218
// methods here to their handles, as the OverloadedMethod instance is specific to a call site, so it
219
// has an already determined Lookup.
220
final List<MethodHandle> methodHandles = new ArrayList<>(invokables.size());
221
final MethodHandles.Lookup lookup = callSiteDescriptor.getLookup();
222
for(final SingleDynamicMethod method: invokables) {
223
methodHandles.add(method.getTarget(lookup));
224
}
225
return new OverloadedMethod(methodHandles, this, callSiteType, linkerServices).getInvoker();
226
}
227
}
228
229
}
230
231
@Override
232
public boolean contains(final SingleDynamicMethod m) {
233
for(final SingleDynamicMethod method: methods) {
234
if(method.contains(m)) {
235
return true;
236
}
237
}
238
return false;
239
}
240
241
@Override
242
public boolean isConstructor() {
243
assert !methods.isEmpty();
244
return methods.getFirst().isConstructor();
245
}
246
247
@Override
248
public String toString() {
249
// First gather the names and sort them. This makes it consistent and easier to read.
250
final List<String> names = new ArrayList<>(methods.size());
251
int len = 0;
252
for (final SingleDynamicMethod m: methods) {
253
final String name = m.getName();
254
len += name.length();
255
names.add(name);
256
}
257
// Case insensitive sorting, so e.g. "Object" doesn't come before "boolean".
258
final Collator collator = Collator.getInstance();
259
collator.setStrength(Collator.SECONDARY);
260
Collections.sort(names, collator);
261
262
final String className = getClass().getName();
263
// Class name length + length of signatures + 2 chars/per signature for indentation and newline +
264
// 3 for brackets and initial newline
265
final int totalLength = className.length() + len + 2 * names.size() + 3;
266
final StringBuilder b = new StringBuilder(totalLength);
267
b.append('[').append(className).append('\n');
268
for(final String name: names) {
269
b.append(' ').append(name).append('\n');
270
}
271
b.append(']');
272
assert b.length() == totalLength;
273
return b.toString();
274
};
275
276
ClassLoader getClassLoader() {
277
return classLoader;
278
}
279
280
private static boolean isApplicableDynamically(final LinkerServices linkerServices, final MethodType callSiteType,
281
final SingleDynamicMethod m) {
282
final MethodType methodType = m.getMethodType();
283
final boolean varArgs = m.isVarArgs();
284
final int fixedArgLen = methodType.parameterCount() - (varArgs ? 1 : 0);
285
final int callSiteArgLen = callSiteType.parameterCount();
286
287
// Arity checks
288
if(varArgs) {
289
if(callSiteArgLen < fixedArgLen) {
290
return false;
291
}
292
} else if(callSiteArgLen != fixedArgLen) {
293
return false;
294
}
295
296
// Fixed arguments type checks, starting from 1, as receiver type doesn't participate
297
for(int i = 1; i < fixedArgLen; ++i) {
298
if(!isApplicableDynamically(linkerServices, callSiteType.parameterType(i), methodType.parameterType(i))) {
299
return false;
300
}
301
}
302
if(!varArgs) {
303
// Not vararg; both arity and types matched.
304
return true;
305
}
306
307
final Class<?> varArgArrayType = methodType.parameterType(fixedArgLen);
308
final Class<?> varArgType = varArgArrayType.getComponentType();
309
310
if(fixedArgLen == callSiteArgLen - 1) {
311
// Exactly one vararg; check both array type matching and array component type matching.
312
final Class<?> callSiteArgType = callSiteType.parameterType(fixedArgLen);
313
return isApplicableDynamically(linkerServices, callSiteArgType, varArgArrayType)
314
|| isApplicableDynamically(linkerServices, callSiteArgType, varArgType);
315
}
316
317
// Either zero, or more than one vararg; check if all actual vararg types match the vararg array component type.
318
for(int i = fixedArgLen; i < callSiteArgLen; ++i) {
319
if(!isApplicableDynamically(linkerServices, callSiteType.parameterType(i), varArgType)) {
320
return false;
321
}
322
}
323
324
return true;
325
}
326
327
private static boolean isApplicableDynamically(final LinkerServices linkerServices, final Class<?> callSiteType,
328
final Class<?> methodType) {
329
return TypeUtilities.isPotentiallyConvertible(callSiteType, methodType)
330
|| linkerServices.canConvert(callSiteType, methodType);
331
}
332
333
private ApplicableOverloadedMethods getApplicables(final MethodType callSiteType, final ApplicabilityTest test) {
334
return new ApplicableOverloadedMethods(methods, callSiteType, test);
335
}
336
337
/**
338
* Add a method to this overloaded method's set.
339
*
340
* @param method a method to add
341
*/
342
public void addMethod(final SingleDynamicMethod method) {
343
assert constructorFlagConsistent(method);
344
methods.add(method);
345
}
346
347
private boolean constructorFlagConsistent(final SingleDynamicMethod method) {
348
return methods.isEmpty()? true : (methods.getFirst().isConstructor() == method.isConstructor());
349
}
350
}
351
352