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 package java.lang.invoke;
27
28 import java.lang.constant.ClassDesc;
29 import java.lang.constant.Constable;
30 import java.lang.constant.MethodTypeDesc;
31 import java.lang.ref.Reference;
32 import java.lang.ref.ReferenceQueue;
33 import java.lang.ref.WeakReference;
34 import java.util.Arrays;
35 import java.util.Collections;
36 import java.util.function.Supplier;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.NoSuchElementException;
40 import java.util.Objects;
41 import java.util.Optional;
42 import java.util.StringJoiner;
43 import java.util.concurrent.ConcurrentHashMap;
44 import java.util.concurrent.ConcurrentMap;
45 import java.util.stream.Stream;
46
47 import jdk.internal.util.ReferencedKeySet;
48 import jdk.internal.util.ReferenceKey;
49 import jdk.internal.vm.annotation.Stable;
50 import sun.invoke.util.BytecodeDescriptor;
51 import sun.invoke.util.VerifyType;
52 import sun.invoke.util.Wrapper;
53 import sun.security.util.SecurityConstants;
54
55 import static java.lang.invoke.MethodHandleStatics.UNSAFE;
56 import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException;
57
58 /**
59 * A method type represents the arguments and return type accepted and
60 * returned by a method handle, or the arguments and return type passed
61 * and expected by a method handle caller. Method types must be properly
62 * matched between a method handle and all its callers,
63 * and the JVM's operations enforce this matching at, specifically
64 * during calls to {@link MethodHandle#invokeExact MethodHandle.invokeExact}
65 * and {@link MethodHandle#invoke MethodHandle.invoke}, and during execution
66 * of {@code invokedynamic} instructions.
137 */
138 public final
139 class MethodType
140 implements Constable,
141 TypeDescriptor.OfMethod<Class<?>, MethodType>,
142 java.io.Serializable {
143 @java.io.Serial
144 private static final long serialVersionUID = 292L; // {rtype, {ptype...}}
145
146 // The rtype and ptypes fields define the structural identity of the method type:
147 private final @Stable Class<?> rtype;
148 private final @Stable Class<?>[] ptypes;
149
150 // The remaining fields are caches of various sorts:
151 private @Stable MethodTypeForm form; // erased form, plus cached data about primitives
152 private @Stable Object wrapAlt; // alternative wrapped/unwrapped version and
153 // private communication for readObject and readResolve
154 private @Stable Invokers invokers; // cache of handy higher-order adapters
155 private @Stable String methodDescriptor; // cache for toMethodDescriptorString
156
157 /**
158 * Constructor that performs no copying or validation.
159 * Should only be called from the factory method makeImpl
160 */
161 private MethodType(Class<?> rtype, Class<?>[] ptypes) {
162 this.rtype = rtype;
163 this.ptypes = ptypes;
164 }
165
166 /*trusted*/ MethodTypeForm form() { return form; }
167 /*trusted*/ Class<?> rtype() { return rtype; }
168 /*trusted*/ Class<?>[] ptypes() { return ptypes; }
169
170 void setForm(MethodTypeForm f) { form = f; }
171
172 /** This number, mandated by the JVM spec as 255,
173 * is the maximum number of <em>slots</em>
174 * that any Java method can receive in its argument list.
175 * It limits both JVM signatures and method type objects.
176 * The longest possible invocation will look like
177 * {@code staticMethod(arg1, arg2, ..., arg255)} or
178 * {@code x.virtualMethod(arg1, arg2, ..., arg254)}.
179 */
180 /*non-public*/
181 static final int MAX_JVM_ARITY = 255; // this is mandated by the JVM spec.
223 }
224 static void checkSlotCount(int count) {
225 if ((count & MAX_JVM_ARITY) != count)
226 throw newIllegalArgumentException("bad parameter count "+count);
227 }
228 private static IndexOutOfBoundsException newIndexOutOfBoundsException(Object num) {
229 if (num instanceof Integer) num = "bad index: "+num;
230 return new IndexOutOfBoundsException(num.toString());
231 }
232
233 static final ReferencedKeySet<MethodType> internTable =
234 ReferencedKeySet.create(false, true, new Supplier<>() {
235 @Override
236 public Map<ReferenceKey<MethodType>, ReferenceKey<MethodType>> get() {
237 return new ConcurrentHashMap<>(512);
238 }
239 });
240
241 static final Class<?>[] NO_PTYPES = {};
242
243 /**
244 * Finds or creates an instance of the given method type.
245 * @param rtype the return type
246 * @param ptypes the parameter types
247 * @return a method type with the given components
248 * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
249 * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
250 */
251 public static MethodType methodType(Class<?> rtype, Class<?>[] ptypes) {
252 return methodType(rtype, ptypes, false);
253 }
254
255 /**
256 * Finds or creates a method type with the given components.
257 * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
258 * @param rtype the return type
259 * @param ptypes the parameter types
260 * @return a method type with the given components
261 * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
262 * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
381 }
382 return makeImpl(rtype, ptypes, trusted);
383 }
384
385 /**
386 * Sole factory method to find or create an interned method type. Will perform
387 * input validation on behalf of factory methods
388 *
389 * @param rtype desired return type
390 * @param ptypes desired parameter types
391 * @param trusted whether the ptypes can be used without cloning
392 * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
393 * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
394 * @return the unique method type of the desired structure
395 */
396 private static MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
397 if (ptypes.length == 0) {
398 ptypes = NO_PTYPES; trusted = true;
399 }
400 MethodType primordialMT = new MethodType(rtype, ptypes);
401 MethodType mt = internTable.get(primordialMT);
402 if (mt != null)
403 return mt;
404
405 // promote the object to the Real Thing, and reprobe
406 Objects.requireNonNull(rtype);
407 if (trusted) {
408 MethodType.checkPtypes(ptypes);
409 mt = primordialMT;
410 } else {
411 // Make defensive copy then validate
412 ptypes = Arrays.copyOf(ptypes, ptypes.length);
413 MethodType.checkPtypes(ptypes);
414 mt = new MethodType(rtype, ptypes);
415 }
416 mt.form = MethodTypeForm.findForm(mt);
417 return internTable.intern(mt);
418 }
419 private static final @Stable MethodType[] objectOnlyTypes = new MethodType[20];
420
421 /**
422 * Finds or creates a method type whose components are {@code Object} with an optional trailing {@code Object[]} array.
423 * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
424 * All parameters and the return type will be {@code Object},
425 * except the final array parameter if any, which will be {@code Object[]}.
426 * @param objectArgCount number of parameters (excluding the final array parameter if any)
427 * @param finalArray whether there will be a trailing array parameter, of type {@code Object[]}
428 * @return a generally applicable method type, for all calls of the given fixed argument count and a collected array of further arguments
429 * @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255 (or 254, if {@code finalArray} is true)
430 * @see #genericMethodType(int)
431 */
432 public static MethodType genericMethodType(int objectArgCount, boolean finalArray) {
433 MethodType mt;
434 checkSlotCount(objectArgCount);
435 int ivarargs = (!finalArray ? 0 : 1);
436 int ootIndex = objectArgCount*2 + ivarargs;
437 if (ootIndex < objectOnlyTypes.length) {
438 mt = objectOnlyTypes[ootIndex];
439 if (mt != null) return mt;
1374
1375 static final long ptypesOffset
1376 = UNSAFE.objectFieldOffset(MethodType.class, "ptypes");
1377 }
1378
1379 /**
1380 * Resolves and initializes a {@code MethodType} object
1381 * after serialization.
1382 * @return the fully initialized {@code MethodType} object
1383 */
1384 @java.io.Serial
1385 private Object readResolve() {
1386 // Do not use a trusted path for deserialization:
1387 // return makeImpl(rtype, ptypes, true);
1388 // Verify all operands, and make sure ptypes is unshared:
1389 // Return a new validated MethodType for the rtype and ptypes passed from readObject.
1390 MethodType mt = ((MethodType[])wrapAlt)[0];
1391 wrapAlt = null;
1392 return mt;
1393 }
1394 }
|
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 package java.lang.invoke;
27
28 import java.lang.constant.ClassDesc;
29 import java.lang.constant.Constable;
30 import java.lang.constant.MethodTypeDesc;
31 import java.lang.ref.Reference;
32 import java.lang.ref.ReferenceQueue;
33 import java.lang.ref.WeakReference;
34 import java.util.Arrays;
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.function.Supplier;
38 import java.util.HashMap;
39 import java.util.Iterator;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.NoSuchElementException;
43 import java.util.Objects;
44 import java.util.Optional;
45 import java.util.StringJoiner;
46 import java.util.concurrent.ConcurrentHashMap;
47 import java.util.concurrent.ConcurrentMap;
48 import java.util.stream.Stream;
49
50 import jdk.internal.misc.CDS;
51 import jdk.internal.util.ReferencedKeySet;
52 import jdk.internal.util.ReferenceKey;
53 import jdk.internal.vm.annotation.Stable;
54 import sun.invoke.util.BytecodeDescriptor;
55 import sun.invoke.util.VerifyType;
56 import sun.invoke.util.Wrapper;
57 import sun.security.util.SecurityConstants;
58
59 import static java.lang.invoke.MethodHandleStatics.UNSAFE;
60 import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException;
61
62 /**
63 * A method type represents the arguments and return type accepted and
64 * returned by a method handle, or the arguments and return type passed
65 * and expected by a method handle caller. Method types must be properly
66 * matched between a method handle and all its callers,
67 * and the JVM's operations enforce this matching at, specifically
68 * during calls to {@link MethodHandle#invokeExact MethodHandle.invokeExact}
69 * and {@link MethodHandle#invoke MethodHandle.invoke}, and during execution
70 * of {@code invokedynamic} instructions.
141 */
142 public final
143 class MethodType
144 implements Constable,
145 TypeDescriptor.OfMethod<Class<?>, MethodType>,
146 java.io.Serializable {
147 @java.io.Serial
148 private static final long serialVersionUID = 292L; // {rtype, {ptype...}}
149
150 // The rtype and ptypes fields define the structural identity of the method type:
151 private final @Stable Class<?> rtype;
152 private final @Stable Class<?>[] ptypes;
153
154 // The remaining fields are caches of various sorts:
155 private @Stable MethodTypeForm form; // erased form, plus cached data about primitives
156 private @Stable Object wrapAlt; // alternative wrapped/unwrapped version and
157 // private communication for readObject and readResolve
158 private @Stable Invokers invokers; // cache of handy higher-order adapters
159 private @Stable String methodDescriptor; // cache for toMethodDescriptorString
160
161 private final boolean checkArchivable = CDS.isDumpingArchive();
162 /**
163 * Constructor that performs no copying or validation.
164 * Should only be called from the factory method makeImpl
165 */
166 private MethodType(Class<?> rtype, Class<?>[] ptypes) {
167 if (checkArchivable) {
168 MethodHandleNatives.checkArchivable(rtype);
169 for (var p : ptypes) {
170 MethodHandleNatives.checkArchivable(p);
171 }
172 }
173
174 this.rtype = rtype;
175 this.ptypes = ptypes;
176 }
177
178 /*trusted*/ MethodTypeForm form() { return form; }
179 /*trusted*/ Class<?> rtype() { return rtype; }
180 /*trusted*/ Class<?>[] ptypes() { return ptypes; }
181
182 void setForm(MethodTypeForm f) { form = f; }
183
184 /** This number, mandated by the JVM spec as 255,
185 * is the maximum number of <em>slots</em>
186 * that any Java method can receive in its argument list.
187 * It limits both JVM signatures and method type objects.
188 * The longest possible invocation will look like
189 * {@code staticMethod(arg1, arg2, ..., arg255)} or
190 * {@code x.virtualMethod(arg1, arg2, ..., arg254)}.
191 */
192 /*non-public*/
193 static final int MAX_JVM_ARITY = 255; // this is mandated by the JVM spec.
235 }
236 static void checkSlotCount(int count) {
237 if ((count & MAX_JVM_ARITY) != count)
238 throw newIllegalArgumentException("bad parameter count "+count);
239 }
240 private static IndexOutOfBoundsException newIndexOutOfBoundsException(Object num) {
241 if (num instanceof Integer) num = "bad index: "+num;
242 return new IndexOutOfBoundsException(num.toString());
243 }
244
245 static final ReferencedKeySet<MethodType> internTable =
246 ReferencedKeySet.create(false, true, new Supplier<>() {
247 @Override
248 public Map<ReferenceKey<MethodType>, ReferenceKey<MethodType>> get() {
249 return new ConcurrentHashMap<>(512);
250 }
251 });
252
253 static final Class<?>[] NO_PTYPES = {};
254
255 private static Object[] archivedObjects;
256
257 private static @Stable HashMap<MethodType,MethodType> archivedMethodTypes;
258
259 private static @Stable MethodType[] objectOnlyTypes;
260
261 @SuppressWarnings("unchecked")
262 static void doit() {
263 CDS.initializeFromArchive(MethodType.class);
264 if (archivedObjects != null) {
265 archivedMethodTypes = (HashMap<MethodType,MethodType>)archivedObjects[0];
266 objectOnlyTypes = (MethodType[])archivedObjects[1];
267 } else {
268 objectOnlyTypes = new MethodType[20];
269 }
270 }
271 static {
272 doit();
273 }
274
275 /**
276 * Finds or creates an instance of the given method type.
277 * @param rtype the return type
278 * @param ptypes the parameter types
279 * @return a method type with the given components
280 * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
281 * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
282 */
283 public static MethodType methodType(Class<?> rtype, Class<?>[] ptypes) {
284 return methodType(rtype, ptypes, false);
285 }
286
287 /**
288 * Finds or creates a method type with the given components.
289 * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
290 * @param rtype the return type
291 * @param ptypes the parameter types
292 * @return a method type with the given components
293 * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
294 * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
413 }
414 return makeImpl(rtype, ptypes, trusted);
415 }
416
417 /**
418 * Sole factory method to find or create an interned method type. Will perform
419 * input validation on behalf of factory methods
420 *
421 * @param rtype desired return type
422 * @param ptypes desired parameter types
423 * @param trusted whether the ptypes can be used without cloning
424 * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
425 * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
426 * @return the unique method type of the desired structure
427 */
428 private static MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
429 if (ptypes.length == 0) {
430 ptypes = NO_PTYPES; trusted = true;
431 }
432 MethodType primordialMT = new MethodType(rtype, ptypes);
433 if (archivedMethodTypes != null) {
434 MethodType mt = archivedMethodTypes.get(primordialMT);
435 if (mt != null) {
436 return mt;
437 }
438 }
439
440 MethodType mt = internTable.get(primordialMT);
441 if (mt != null)
442 return mt;
443
444 // promote the object to the Real Thing, and reprobe
445 Objects.requireNonNull(rtype);
446 if (trusted) {
447 MethodType.checkPtypes(ptypes);
448 mt = primordialMT;
449 } else {
450 // Make defensive copy then validate
451 ptypes = Arrays.copyOf(ptypes, ptypes.length);
452 MethodType.checkPtypes(ptypes);
453 mt = new MethodType(rtype, ptypes);
454 }
455 mt.form = MethodTypeForm.findForm(mt);
456 return internTable.intern(mt);
457 }
458
459 /**
460 * Finds or creates a method type whose components are {@code Object} with an optional trailing {@code Object[]} array.
461 * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
462 * All parameters and the return type will be {@code Object},
463 * except the final array parameter if any, which will be {@code Object[]}.
464 * @param objectArgCount number of parameters (excluding the final array parameter if any)
465 * @param finalArray whether there will be a trailing array parameter, of type {@code Object[]}
466 * @return a generally applicable method type, for all calls of the given fixed argument count and a collected array of further arguments
467 * @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255 (or 254, if {@code finalArray} is true)
468 * @see #genericMethodType(int)
469 */
470 public static MethodType genericMethodType(int objectArgCount, boolean finalArray) {
471 MethodType mt;
472 checkSlotCount(objectArgCount);
473 int ivarargs = (!finalArray ? 0 : 1);
474 int ootIndex = objectArgCount*2 + ivarargs;
475 if (ootIndex < objectOnlyTypes.length) {
476 mt = objectOnlyTypes[ootIndex];
477 if (mt != null) return mt;
1412
1413 static final long ptypesOffset
1414 = UNSAFE.objectFieldOffset(MethodType.class, "ptypes");
1415 }
1416
1417 /**
1418 * Resolves and initializes a {@code MethodType} object
1419 * after serialization.
1420 * @return the fully initialized {@code MethodType} object
1421 */
1422 @java.io.Serial
1423 private Object readResolve() {
1424 // Do not use a trusted path for deserialization:
1425 // return makeImpl(rtype, ptypes, true);
1426 // Verify all operands, and make sure ptypes is unshared:
1427 // Return a new validated MethodType for the rtype and ptypes passed from readObject.
1428 MethodType mt = ((MethodType[])wrapAlt)[0];
1429 wrapAlt = null;
1430 return mt;
1431 }
1432
1433 static HashMap<MethodType,MethodType> archive(Archiver archiver) {
1434 HashMap<MethodType,MethodType> archivedSet = new HashMap<>();
1435
1436 for (Iterator<MethodType> i = internTable.iterator(); i.hasNext(); ) {
1437 MethodType t = i.next();
1438 MethodType a = archiver.clean(t);
1439 if (a != null) {
1440 archivedSet.put(a, a);
1441 }
1442 }
1443
1444 return archivedSet;
1445 }
1446
1447 static class Archiver {
1448 ArrayList<MethodType> archived = new ArrayList<>();
1449
1450 MethodType clean(MethodType t) {
1451 if (t == null || t.form == null) { // HACK!
1452 return null;
1453 }
1454 if (archived.contains(t)) {
1455 return t;
1456 }
1457
1458 archived.add(t);
1459 return t;
1460 }
1461 }
1462
1463 // This is called from C code.
1464 static void dumpSharedArchive() {
1465 Archiver archiver = new Archiver();
1466
1467 MethodType[] objectOnlyTypesCopy = new MethodType[objectOnlyTypes.length];
1468 for (int i = 0; i < objectOnlyTypes.length; i++) {
1469 MethodType t = archiver.clean(objectOnlyTypes[i]);
1470 if (t != null) {
1471 objectOnlyTypesCopy[i] = t;
1472 }
1473 }
1474
1475 archivedObjects = new Object[2];
1476 archivedObjects[0] = archive(archiver);
1477 archivedObjects[1] = objectOnlyTypesCopy;
1478
1479 DirectMethodHandle.dumpSharedArchive();
1480 LambdaForm.NamedFunction.dumpSharedArchive();
1481 }
1482 }
|