< prev index next >

src/java.base/share/classes/java/lang/runtime/ObjectMethods.java

Print this page

 59 public final class ObjectMethods {
 60 
 61     private ObjectMethods() { }
 62 
 63     private static final int MAX_STRING_CONCAT_SLOTS = 20;
 64 
 65     private static final MethodHandle FALSE = MethodHandles.zero(boolean.class);
 66     private static final MethodHandle TRUE = MethodHandles.constant(boolean.class, true);
 67     private static final MethodHandle ZERO = MethodHandles.zero(int.class);
 68     private static final MethodHandle CLASS_IS_INSTANCE;
 69     private static final MethodHandle IS_NULL;
 70     private static final MethodHandle IS_ARG0_NULL;
 71     private static final MethodHandle IS_ARG1_NULL;
 72     private static final MethodHandle OBJECT_EQ;
 73     private static final MethodHandle HASH_COMBINER;
 74     private static final MethodType MT_OBJECT_BOOLEAN = MethodType.methodType(boolean.class, Object.class);
 75     private static final MethodType MT_INT = MethodType.methodType(int.class);
 76     private static final MethodTypeDesc MTD_OBJECT_BOOLEAN = MethodTypeDesc.of(CD_boolean, CD_Object);
 77     private static final MethodTypeDesc MTD_INT = MethodTypeDesc.of(CD_int);
 78 
 79     private static final HashMap<Class<?>, MethodHandle> primitiveEquals = new HashMap<>();


 80     private static final HashMap<Class<?>, MethodHandle> primitiveHashers = new HashMap<>();
 81 
 82     static {
 83         try {
 84             Class<ObjectMethods> OBJECT_METHODS_CLASS = ObjectMethods.class;
 85             MethodHandles.Lookup publicLookup = MethodHandles.publicLookup();
 86             MethodHandles.Lookup lookup = MethodHandles.lookup();
 87 
 88             CLASS_IS_INSTANCE = publicLookup.findVirtual(Class.class, "isInstance",
 89                                                          MethodType.methodType(boolean.class, Object.class));
 90 
 91             var objectsIsNull = publicLookup.findStatic(Objects.class, "isNull",
 92                                                         MethodType.methodType(boolean.class, Object.class));
 93             IS_NULL = objectsIsNull;
 94             IS_ARG0_NULL = MethodHandles.dropArguments(objectsIsNull, 1, Object.class);
 95             IS_ARG1_NULL = MethodHandles.dropArguments(objectsIsNull, 0, Object.class);
 96 
 97             OBJECT_EQ = lookup.findStatic(OBJECT_METHODS_CLASS, "eq",
 98                                           MethodType.methodType(boolean.class, Object.class, Object.class));
 99             HASH_COMBINER = lookup.findStatic(OBJECT_METHODS_CLASS, "hashCombiner",

502      * @return             a call site if invoked by indy, or a method handle
503      *                     if invoked by a condy
504      * @throws IllegalArgumentException if the bootstrap arguments are invalid
505      *                                  or inconsistent
506      * @throws NullPointerException if any argument is {@code null} or if any element
507      *                              in the {@code getters} array is {@code null}
508      * @throws Throwable if any exception is thrown during call site construction
509      */
510     public static Object bootstrap(MethodHandles.Lookup lookup, String methodName, TypeDescriptor type,
511                                    Class<?> recordClass,
512                                    String names,
513                                    MethodHandle... getters) throws Throwable {
514         requireNonNull(lookup);
515         requireNonNull(methodName);
516         requireNonNull(type);
517         requireNonNull(recordClass);
518         requireNonNull(names);
519         requireNonNull(getters);
520         Arrays.stream(getters).forEach(Objects::requireNonNull);
521         MethodType methodType;
522         if (type instanceof MethodType mt)
523             methodType = mt;
524         else {



525             methodType = null;
526             if (!MethodHandle.class.equals(type))
527                 throw new IllegalArgumentException(type.toString());
528         }
529         List<MethodHandle> getterList = List.of(getters);





530         MethodHandle handle = switch (methodName) {
531             case "equals"   -> {
532                 if (methodType != null && !methodType.equals(MethodType.methodType(boolean.class, recordClass, Object.class)))
533                     throw new IllegalArgumentException("Bad method type: " + methodType);
534                 yield makeEquals(lookup, recordClass, getterList);
535             }
536             case "hashCode" -> {
537                 if (methodType != null && !methodType.equals(MethodType.methodType(int.class, recordClass)))
538                     throw new IllegalArgumentException("Bad method type: " + methodType);
539                 yield makeHashCode(lookup, recordClass, getterList);
540             }
541             case "toString" -> {
542                 if (methodType != null && !methodType.equals(MethodType.methodType(String.class, recordClass)))
543                     throw new IllegalArgumentException("Bad method type: " + methodType);
544                 List<String> nameList = "".equals(names) ? List.of() : List.of(names.split(";"));
545                 if (nameList.size() != getterList.size())
546                     throw new IllegalArgumentException("Name list and accessor list do not match");
547                 yield makeToString(lookup, recordClass, getters, nameList);
548             }
549             default -> throw new IllegalArgumentException(methodName);

 59 public final class ObjectMethods {
 60 
 61     private ObjectMethods() { }
 62 
 63     private static final int MAX_STRING_CONCAT_SLOTS = 20;
 64 
 65     private static final MethodHandle FALSE = MethodHandles.zero(boolean.class);
 66     private static final MethodHandle TRUE = MethodHandles.constant(boolean.class, true);
 67     private static final MethodHandle ZERO = MethodHandles.zero(int.class);
 68     private static final MethodHandle CLASS_IS_INSTANCE;
 69     private static final MethodHandle IS_NULL;
 70     private static final MethodHandle IS_ARG0_NULL;
 71     private static final MethodHandle IS_ARG1_NULL;
 72     private static final MethodHandle OBJECT_EQ;
 73     private static final MethodHandle HASH_COMBINER;
 74     private static final MethodType MT_OBJECT_BOOLEAN = MethodType.methodType(boolean.class, Object.class);
 75     private static final MethodType MT_INT = MethodType.methodType(int.class);
 76     private static final MethodTypeDesc MTD_OBJECT_BOOLEAN = MethodTypeDesc.of(CD_boolean, CD_Object);
 77     private static final MethodTypeDesc MTD_INT = MethodTypeDesc.of(CD_int);
 78 
 79     /* package-private */
 80     static final HashMap<Class<?>, MethodHandle> primitiveEquals = new HashMap<>();
 81 
 82     private static final HashMap<Class<?>, MethodHandle> primitiveHashers = new HashMap<>();
 83 
 84     static {
 85         try {
 86             Class<ObjectMethods> OBJECT_METHODS_CLASS = ObjectMethods.class;
 87             MethodHandles.Lookup publicLookup = MethodHandles.publicLookup();
 88             MethodHandles.Lookup lookup = MethodHandles.lookup();
 89 
 90             CLASS_IS_INSTANCE = publicLookup.findVirtual(Class.class, "isInstance",
 91                                                          MethodType.methodType(boolean.class, Object.class));
 92 
 93             var objectsIsNull = publicLookup.findStatic(Objects.class, "isNull",
 94                                                         MethodType.methodType(boolean.class, Object.class));
 95             IS_NULL = objectsIsNull;
 96             IS_ARG0_NULL = MethodHandles.dropArguments(objectsIsNull, 1, Object.class);
 97             IS_ARG1_NULL = MethodHandles.dropArguments(objectsIsNull, 0, Object.class);
 98 
 99             OBJECT_EQ = lookup.findStatic(OBJECT_METHODS_CLASS, "eq",
100                                           MethodType.methodType(boolean.class, Object.class, Object.class));
101             HASH_COMBINER = lookup.findStatic(OBJECT_METHODS_CLASS, "hashCombiner",

504      * @return             a call site if invoked by indy, or a method handle
505      *                     if invoked by a condy
506      * @throws IllegalArgumentException if the bootstrap arguments are invalid
507      *                                  or inconsistent
508      * @throws NullPointerException if any argument is {@code null} or if any element
509      *                              in the {@code getters} array is {@code null}
510      * @throws Throwable if any exception is thrown during call site construction
511      */
512     public static Object bootstrap(MethodHandles.Lookup lookup, String methodName, TypeDescriptor type,
513                                    Class<?> recordClass,
514                                    String names,
515                                    MethodHandle... getters) throws Throwable {
516         requireNonNull(lookup);
517         requireNonNull(methodName);
518         requireNonNull(type);
519         requireNonNull(recordClass);
520         requireNonNull(names);
521         requireNonNull(getters);
522         Arrays.stream(getters).forEach(Objects::requireNonNull);
523         MethodType methodType;
524         if (type instanceof MethodType mt) {
525             methodType = mt;
526             if (mt.parameterType(0) != recordClass) {
527                 throw new IllegalArgumentException("Bad method type: " + mt);
528             }
529         } else {
530             methodType = null;
531             if (!MethodHandle.class.equals(type))
532                 throw new IllegalArgumentException(type.toString());
533         }
534         List<MethodHandle> getterList = List.of(getters);
535         for (MethodHandle getter : getterList) {
536             if (getter.type().parameterType(0) != recordClass) {
537                 throw new IllegalArgumentException("Bad receiver type: " + getter);
538             }
539         }
540         MethodHandle handle = switch (methodName) {
541             case "equals"   -> {
542                 if (methodType != null && !methodType.equals(MethodType.methodType(boolean.class, recordClass, Object.class)))
543                     throw new IllegalArgumentException("Bad method type: " + methodType);
544                 yield makeEquals(lookup, recordClass, getterList);
545             }
546             case "hashCode" -> {
547                 if (methodType != null && !methodType.equals(MethodType.methodType(int.class, recordClass)))
548                     throw new IllegalArgumentException("Bad method type: " + methodType);
549                 yield makeHashCode(lookup, recordClass, getterList);
550             }
551             case "toString" -> {
552                 if (methodType != null && !methodType.equals(MethodType.methodType(String.class, recordClass)))
553                     throw new IllegalArgumentException("Bad method type: " + methodType);
554                 List<String> nameList = "".equals(names) ? List.of() : List.of(names.split(";"));
555                 if (nameList.size() != getterList.size())
556                     throw new IllegalArgumentException("Name list and accessor list do not match");
557                 yield makeToString(lookup, recordClass, getters, nameList);
558             }
559             default -> throw new IllegalArgumentException(methodName);
< prev index next >