Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/jdk.dynalink/share/classes/jdk/dynalink/beans/OverloadedMethod.java
41161 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
Redistribution and use in source and binary forms, with or without
37
modification, are permitted provided that the following conditions are
38
met:
39
* Redistributions of source code must retain the above copyright
40
notice, this list of conditions and the following disclaimer.
41
* Redistributions in binary form must reproduce the above copyright
42
notice, this list of conditions and the following disclaimer in the
43
documentation and/or other materials provided with the distribution.
44
* Neither the name of the copyright holder nor the names of
45
contributors may be used to endorse or promote products derived from
46
this software without specific prior written permission.
47
48
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
49
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
50
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
51
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
52
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
53
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
54
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
55
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
56
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
57
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
58
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59
*/
60
61
package jdk.dynalink.beans;
62
63
import java.lang.invoke.MethodHandle;
64
import java.lang.invoke.MethodHandles;
65
import java.lang.invoke.MethodType;
66
import java.util.ArrayList;
67
import java.util.Iterator;
68
import java.util.List;
69
import java.util.Map;
70
import java.util.concurrent.ConcurrentHashMap;
71
import jdk.dynalink.SecureLookupSupplier;
72
import jdk.dynalink.internal.InternalTypeUtilities;
73
import jdk.dynalink.linker.LinkerServices;
74
import jdk.dynalink.linker.support.Lookup;
75
76
/**
77
* Represents a subset of overloaded methods for a certain method name on a certain class. It can be either a fixarg or
78
* a vararg subset depending on the subclass. The method is for a fixed number of arguments though (as it is generated
79
* for a concrete call site). As such, all methods in the subset can be invoked with the specified number of arguments
80
* (exactly matching for fixargs, or having less than or equal fixed arguments, for varargs).
81
*/
82
class OverloadedMethod {
83
private final Map<ClassString, MethodHandle> argTypesToMethods = new ConcurrentHashMap<>();
84
private final OverloadedDynamicMethod parent;
85
private final ClassLoader callSiteClassLoader;
86
private final MethodType callSiteType;
87
private final MethodHandle invoker;
88
private final LinkerServices linkerServices;
89
private final SecureLookupSupplier lookupSupplier;
90
private final ArrayList<MethodHandle> fixArgMethods;
91
private final ArrayList<MethodHandle> varArgMethods;
92
93
OverloadedMethod(final List<MethodHandle> methodHandles,
94
final OverloadedDynamicMethod parent,
95
final ClassLoader callSiteClassLoader,
96
final MethodType callSiteType,
97
final LinkerServices linkerServices,
98
final SecureLookupSupplier lookupSupplier) {
99
this.parent = parent;
100
this.callSiteClassLoader = callSiteClassLoader;
101
final Class<?> commonRetType = getCommonReturnType(methodHandles);
102
this.callSiteType = callSiteType.changeReturnType(commonRetType);
103
this.linkerServices = linkerServices;
104
this.lookupSupplier = lookupSupplier;
105
106
fixArgMethods = new ArrayList<>(methodHandles.size());
107
varArgMethods = new ArrayList<>(methodHandles.size());
108
final int argNum = callSiteType.parameterCount();
109
for(final MethodHandle mh: methodHandles) {
110
if(mh.isVarargsCollector()) {
111
final MethodHandle asFixed = mh.asFixedArity();
112
if(argNum == asFixed.type().parameterCount()) {
113
fixArgMethods.add(asFixed);
114
}
115
varArgMethods.add(mh);
116
} else {
117
fixArgMethods.add(mh);
118
}
119
}
120
fixArgMethods.trimToSize();
121
varArgMethods.trimToSize();
122
123
final MethodHandle bound = SELECT_METHOD.bindTo(this);
124
final MethodHandle collecting = SingleDynamicMethod.collectArguments(bound, argNum).asType(
125
callSiteType.changeReturnType(MethodHandle.class));
126
invoker = linkerServices.asTypeLosslessReturn(MethodHandles.foldArguments(
127
MethodHandles.exactInvoker(this.callSiteType), collecting), callSiteType);
128
}
129
130
MethodHandle getInvoker() {
131
return invoker;
132
}
133
134
private static final MethodHandle SELECT_METHOD = Lookup.findOwnSpecial(MethodHandles.lookup(), "selectMethod",
135
MethodHandle.class, Object[].class);
136
137
@SuppressWarnings("unused")
138
private MethodHandle selectMethod(final Object[] args) {
139
final Class<?>[] argTypes = new Class<?>[args.length];
140
for(int i = 0; i < argTypes.length; ++i) {
141
final Object arg = args[i];
142
argTypes[i] = arg == null ? ClassString.NULL_CLASS : arg.getClass();
143
}
144
final ClassString classString = new ClassString(argTypes);
145
MethodHandle method = argTypesToMethods.get(classString);
146
if(method == null) {
147
List<MethodHandle> methods = classString.getMaximallySpecifics(fixArgMethods, linkerServices, false);
148
if(methods.isEmpty()) {
149
methods = classString.getMaximallySpecifics(varArgMethods, linkerServices, true);
150
}
151
switch(methods.size()) {
152
case 0: {
153
method = getNoSuchMethodThrower(argTypes);
154
break;
155
}
156
case 1: {
157
final List<MethodHandle> fmethods = methods;
158
method = linkerServices.getWithLookup(
159
()->SingleDynamicMethod.getInvocation(fmethods.get(0), callSiteType, linkerServices),
160
lookupSupplier);
161
break;
162
}
163
default: {
164
// This is unfortunate - invocation time ambiguity.
165
method = getAmbiguousMethodThrower(argTypes, methods);
166
break;
167
}
168
}
169
// Avoid keeping references to unrelated classes; this ruins the
170
// performance a bit, but avoids class loader memory leaks.
171
if(classString.isVisibleFrom(callSiteClassLoader)) {
172
argTypesToMethods.put(classString, method);
173
}
174
}
175
return method;
176
}
177
178
private MethodHandle getNoSuchMethodThrower(final Class<?>[] argTypes) {
179
return adaptThrower(MethodHandles.insertArguments(THROW_NO_SUCH_METHOD, 0, this, argTypes));
180
}
181
182
private static final MethodHandle THROW_NO_SUCH_METHOD = Lookup.findOwnSpecial(MethodHandles.lookup(),
183
"throwNoSuchMethod", void.class, Class[].class);
184
185
@SuppressWarnings("unused")
186
private void throwNoSuchMethod(final Class<?>[] argTypes) throws NoSuchMethodException {
187
if(varArgMethods.isEmpty()) {
188
throw new NoSuchMethodException("None of the fixed arity signatures " + getSignatureList(fixArgMethods) +
189
" of method " + parent.getName() + " match the argument types " + argTypesString(argTypes));
190
}
191
throw new NoSuchMethodException("None of the fixed arity signatures " + getSignatureList(fixArgMethods) +
192
" or the variable arity signatures " + getSignatureList(varArgMethods) + " of the method " +
193
parent.getName() + " match the argument types " + argTypesString(argTypes));
194
}
195
196
private MethodHandle getAmbiguousMethodThrower(final Class<?>[] argTypes, final List<MethodHandle> methods) {
197
return adaptThrower(MethodHandles.insertArguments(THROW_AMBIGUOUS_METHOD, 0, this, argTypes, methods));
198
}
199
200
private MethodHandle adaptThrower(final MethodHandle rawThrower) {
201
return MethodHandles.dropArguments(rawThrower, 0, callSiteType.parameterList()).asType(callSiteType);
202
}
203
204
private static final MethodHandle THROW_AMBIGUOUS_METHOD = Lookup.findOwnSpecial(MethodHandles.lookup(),
205
"throwAmbiguousMethod", void.class, Class[].class, List.class);
206
207
@SuppressWarnings("unused")
208
private void throwAmbiguousMethod(final Class<?>[] argTypes, final List<MethodHandle> methods) throws NoSuchMethodException {
209
final String arity = methods.get(0).isVarargsCollector() ? "variable" : "fixed";
210
throw new NoSuchMethodException("Can't unambiguously select between " + arity + " arity signatures " +
211
getSignatureList(methods) + " of the method " + parent.getName() + " for argument types " +
212
argTypesString(argTypes));
213
}
214
215
private static String argTypesString(final Class<?>[] classes) {
216
final StringBuilder b = new StringBuilder().append('[');
217
appendTypes(b, classes, false);
218
return b.append(']').toString();
219
}
220
221
private static String getSignatureList(final List<MethodHandle> methods) {
222
final StringBuilder b = new StringBuilder().append('[');
223
final Iterator<MethodHandle> it = methods.iterator();
224
if(it.hasNext()) {
225
appendSig(b, it.next());
226
while(it.hasNext()) {
227
appendSig(b.append(", "), it.next());
228
}
229
}
230
return b.append(']').toString();
231
}
232
233
private static void appendSig(final StringBuilder b, final MethodHandle m) {
234
b.append('(');
235
appendTypes(b, m.type().parameterArray(), m.isVarargsCollector());
236
b.append(')');
237
}
238
239
private static void appendTypes(final StringBuilder b, final Class<?>[] classes, final boolean varArg) {
240
final int l = classes.length;
241
if(!varArg) {
242
if(l > 1) {
243
b.append(classes[1].getCanonicalName());
244
for(int i = 2; i < l; ++i) {
245
b.append(", ").append(classes[i].getCanonicalName());
246
}
247
}
248
} else {
249
for(int i = 1; i < l - 1; ++i) {
250
b.append(classes[i].getCanonicalName()).append(", ");
251
}
252
b.append(classes[l - 1].getComponentType().getCanonicalName()).append("...");
253
}
254
}
255
256
private static Class<?> getCommonReturnType(final List<MethodHandle> methodHandles) {
257
final Iterator<MethodHandle> it = methodHandles.iterator();
258
Class<?> retType = it.next().type().returnType();
259
while(it.hasNext()) {
260
retType = InternalTypeUtilities.getCommonLosslessConversionType(retType, it.next().type().returnType());
261
}
262
return retType;
263
}
264
}
265
266