55 private ObjectMethods() { }
56
57 private static final int MAX_STRING_CONCAT_SLOTS = 20;
58
59 private static final MethodType DESCRIPTOR_MT = MethodType.methodType(MethodType.class);
60 private static final MethodType NAMES_MT = MethodType.methodType(List.class);
61 private static final MethodHandle FALSE = MethodHandles.constant(boolean.class, false);
62 private static final MethodHandle TRUE = MethodHandles.constant(boolean.class, true);
63 private static final MethodHandle ZERO = MethodHandles.constant(int.class, 0);
64 private static final MethodHandle CLASS_IS_INSTANCE;
65 private static final MethodHandle OBJECT_EQUALS;
66 private static final MethodHandle OBJECTS_EQUALS;
67 private static final MethodHandle OBJECTS_HASHCODE;
68 private static final MethodHandle OBJECTS_TOSTRING;
69 private static final MethodHandle OBJECT_EQ;
70 private static final MethodHandle OBJECT_HASHCODE;
71 private static final MethodHandle OBJECT_TO_STRING;
72 private static final MethodHandle STRING_FORMAT;
73 private static final MethodHandle HASH_COMBINER;
74
75 private static final HashMap<Class<?>, MethodHandle> primitiveEquals = new HashMap<>();
76 private static final HashMap<Class<?>, MethodHandle> primitiveHashers = new HashMap<>();
77 private static final HashMap<Class<?>, MethodHandle> primitiveToString = new HashMap<>();
78
79 static {
80 try {
81 Class<ObjectMethods> OBJECT_METHODS_CLASS = ObjectMethods.class;
82 MethodHandles.Lookup publicLookup = MethodHandles.publicLookup();
83 MethodHandles.Lookup lookup = MethodHandles.lookup();
84
85 @SuppressWarnings("removal")
86 ClassLoader loader = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
87 @Override public ClassLoader run() { return ClassLoader.getPlatformClassLoader(); }
88 });
89
90 CLASS_IS_INSTANCE = publicLookup.findVirtual(Class.class, "isInstance",
91 MethodType.methodType(boolean.class, Object.class));
92 OBJECT_EQUALS = publicLookup.findVirtual(Object.class, "equals",
93 MethodType.methodType(boolean.class, Object.class));
94 OBJECT_HASHCODE = publicLookup.findVirtual(Object.class, "hashCode",
95 MethodType.fromMethodDescriptorString("()I", loader));
395 * @return a call site if invoked by indy, or a method handle
396 * if invoked by a condy
397 * @throws IllegalArgumentException if the bootstrap arguments are invalid
398 * or inconsistent
399 * @throws NullPointerException if any argument is {@code null} or if any element
400 * in the {@code getters} array is {@code null}
401 * @throws Throwable if any exception is thrown during call site construction
402 */
403 public static Object bootstrap(MethodHandles.Lookup lookup, String methodName, TypeDescriptor type,
404 Class<?> recordClass,
405 String names,
406 MethodHandle... getters) throws Throwable {
407 requireNonNull(lookup);
408 requireNonNull(methodName);
409 requireNonNull(type);
410 requireNonNull(recordClass);
411 requireNonNull(names);
412 requireNonNull(getters);
413 Arrays.stream(getters).forEach(Objects::requireNonNull);
414 MethodType methodType;
415 if (type instanceof MethodType mt)
416 methodType = mt;
417 else {
418 methodType = null;
419 if (!MethodHandle.class.equals(type))
420 throw new IllegalArgumentException(type.toString());
421 }
422 List<MethodHandle> getterList = List.of(getters);
423 MethodHandle handle = switch (methodName) {
424 case "equals" -> {
425 if (methodType != null && !methodType.equals(MethodType.methodType(boolean.class, recordClass, Object.class)))
426 throw new IllegalArgumentException("Bad method type: " + methodType);
427 yield makeEquals(recordClass, getterList);
428 }
429 case "hashCode" -> {
430 if (methodType != null && !methodType.equals(MethodType.methodType(int.class, recordClass)))
431 throw new IllegalArgumentException("Bad method type: " + methodType);
432 yield makeHashCode(recordClass, getterList);
433 }
434 case "toString" -> {
435 if (methodType != null && !methodType.equals(MethodType.methodType(String.class, recordClass)))
436 throw new IllegalArgumentException("Bad method type: " + methodType);
437 List<String> nameList = "".equals(names) ? List.of() : List.of(names.split(";"));
438 if (nameList.size() != getterList.size())
439 throw new IllegalArgumentException("Name list and accessor list do not match");
440 yield makeToString(lookup, recordClass, getters, nameList);
441 }
442 default -> throw new IllegalArgumentException(methodName);
|
55 private ObjectMethods() { }
56
57 private static final int MAX_STRING_CONCAT_SLOTS = 20;
58
59 private static final MethodType DESCRIPTOR_MT = MethodType.methodType(MethodType.class);
60 private static final MethodType NAMES_MT = MethodType.methodType(List.class);
61 private static final MethodHandle FALSE = MethodHandles.constant(boolean.class, false);
62 private static final MethodHandle TRUE = MethodHandles.constant(boolean.class, true);
63 private static final MethodHandle ZERO = MethodHandles.constant(int.class, 0);
64 private static final MethodHandle CLASS_IS_INSTANCE;
65 private static final MethodHandle OBJECT_EQUALS;
66 private static final MethodHandle OBJECTS_EQUALS;
67 private static final MethodHandle OBJECTS_HASHCODE;
68 private static final MethodHandle OBJECTS_TOSTRING;
69 private static final MethodHandle OBJECT_EQ;
70 private static final MethodHandle OBJECT_HASHCODE;
71 private static final MethodHandle OBJECT_TO_STRING;
72 private static final MethodHandle STRING_FORMAT;
73 private static final MethodHandle HASH_COMBINER;
74
75 /* package-private */
76 static final HashMap<Class<?>, MethodHandle> primitiveEquals = new HashMap<>();
77
78 private static final HashMap<Class<?>, MethodHandle> primitiveHashers = new HashMap<>();
79 private static final HashMap<Class<?>, MethodHandle> primitiveToString = new HashMap<>();
80
81 static {
82 try {
83 Class<ObjectMethods> OBJECT_METHODS_CLASS = ObjectMethods.class;
84 MethodHandles.Lookup publicLookup = MethodHandles.publicLookup();
85 MethodHandles.Lookup lookup = MethodHandles.lookup();
86
87 @SuppressWarnings("removal")
88 ClassLoader loader = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
89 @Override public ClassLoader run() { return ClassLoader.getPlatformClassLoader(); }
90 });
91
92 CLASS_IS_INSTANCE = publicLookup.findVirtual(Class.class, "isInstance",
93 MethodType.methodType(boolean.class, Object.class));
94 OBJECT_EQUALS = publicLookup.findVirtual(Object.class, "equals",
95 MethodType.methodType(boolean.class, Object.class));
96 OBJECT_HASHCODE = publicLookup.findVirtual(Object.class, "hashCode",
97 MethodType.fromMethodDescriptorString("()I", loader));
397 * @return a call site if invoked by indy, or a method handle
398 * if invoked by a condy
399 * @throws IllegalArgumentException if the bootstrap arguments are invalid
400 * or inconsistent
401 * @throws NullPointerException if any argument is {@code null} or if any element
402 * in the {@code getters} array is {@code null}
403 * @throws Throwable if any exception is thrown during call site construction
404 */
405 public static Object bootstrap(MethodHandles.Lookup lookup, String methodName, TypeDescriptor type,
406 Class<?> recordClass,
407 String names,
408 MethodHandle... getters) throws Throwable {
409 requireNonNull(lookup);
410 requireNonNull(methodName);
411 requireNonNull(type);
412 requireNonNull(recordClass);
413 requireNonNull(names);
414 requireNonNull(getters);
415 Arrays.stream(getters).forEach(Objects::requireNonNull);
416 MethodType methodType;
417 if (type instanceof MethodType mt) {
418 methodType = mt;
419 if (mt.parameterType(0) != recordClass) {
420 throw new IllegalArgumentException("Bad method type: " + mt);
421 }
422 } else {
423 methodType = null;
424 if (!MethodHandle.class.equals(type))
425 throw new IllegalArgumentException(type.toString());
426 }
427 List<MethodHandle> getterList = List.of(getters);
428 for (MethodHandle getter : getterList) {
429 if (getter.type().parameterType(0) != recordClass) {
430 throw new IllegalArgumentException("Bad receiver type: " + getter);
431 }
432 }
433 MethodHandle handle = switch (methodName) {
434 case "equals" -> {
435 if (methodType != null && !methodType.equals(MethodType.methodType(boolean.class, recordClass, Object.class)))
436 throw new IllegalArgumentException("Bad method type: " + methodType);
437 yield makeEquals(recordClass, getterList);
438 }
439 case "hashCode" -> {
440 if (methodType != null && !methodType.equals(MethodType.methodType(int.class, recordClass)))
441 throw new IllegalArgumentException("Bad method type: " + methodType);
442 yield makeHashCode(recordClass, getterList);
443 }
444 case "toString" -> {
445 if (methodType != null && !methodType.equals(MethodType.methodType(String.class, recordClass)))
446 throw new IllegalArgumentException("Bad method type: " + methodType);
447 List<String> nameList = "".equals(names) ? List.of() : List.of(names.split(";"));
448 if (nameList.size() != getterList.size())
449 throw new IllegalArgumentException("Name list and accessor list do not match");
450 yield makeToString(lookup, recordClass, getters, nameList);
451 }
452 default -> throw new IllegalArgumentException(methodName);
|