1 /* 2 * Copyright (c) 2018, 2022, 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 package java.lang.runtime; 27 28 import java.lang.invoke.MethodHandle; 29 import java.lang.invoke.MethodHandles; 30 import java.lang.invoke.MethodType; 31 import java.lang.reflect.Modifier; 32 import java.util.ArrayDeque; 33 import java.util.ArrayList; 34 import java.util.Arrays; 35 import java.util.Comparator; 36 import java.util.Deque; 37 import java.util.HashMap; 38 import java.util.HashSet; 39 import java.util.List; 40 import java.util.Map; 41 import java.util.Objects; 42 import java.util.Set; 43 import java.util.concurrent.ConcurrentHashMap; 44 import java.util.concurrent.atomic.AtomicInteger; 45 import java.util.stream.Collectors; 46 import java.util.stream.Stream; 47 import jdk.internal.access.JavaLangInvokeAccess; 48 import jdk.internal.access.SharedSecrets; 49 import jdk.internal.value.PrimitiveClass; 50 import sun.invoke.util.Wrapper; 51 import sun.security.action.GetIntegerAction; 52 import sun.security.action.GetPropertyAction; 53 54 import static java.lang.invoke.MethodHandles.constant; 55 import static java.lang.invoke.MethodHandles.countedLoop; 56 import static java.lang.invoke.MethodHandles.dropArguments; 57 import static java.lang.invoke.MethodHandles.filterArguments; 58 import static java.lang.invoke.MethodHandles.filterReturnValue; 59 import static java.lang.invoke.MethodHandles.guardWithTest; 60 import static java.lang.invoke.MethodHandles.permuteArguments; 61 import static java.lang.invoke.MethodType.methodType; 62 import static java.lang.runtime.ObjectMethods.primitiveEquals; 63 64 /** 65 * Implementation for Object::equals and Object::hashCode for value objects. 66 * 67 * ValueObjectMethods::isSubstitutable and valueObjectHashCode are 68 * private entry points called by VM. 69 */ 70 final class ValueObjectMethods { 71 private ValueObjectMethods() {} 72 private static final boolean VERBOSE = 73 GetPropertyAction.privilegedGetProperty("value.bsm.debug") != null; 74 private static final int THRESHOLD = 75 GetIntegerAction.privilegedGetProperty("jdk.value.recursion.threshold", Integer.MAX_VALUE); 76 private static final JavaLangInvokeAccess JLIA = SharedSecrets.getJavaLangInvokeAccess(); 77 78 static class MethodHandleBuilder { 79 static Stream<MethodHandle> getterStream(Class<?> type, Comparator<MethodHandle> comparator) { 80 // filter static fields 81 Stream<MethodHandle> s = Arrays.stream(type.getDeclaredFields()) 82 .filter(f -> !Modifier.isStatic(f.getModifiers())) 83 .map(f -> { 84 try { 85 return JLIA.unreflectField(f, false); 86 } catch (IllegalAccessException e) { 87 throw newLinkageError(e); 88 } 89 }); 90 if (comparator != null) { 91 s = s.sorted(comparator); 92 } 93 return s; 94 } 95 96 static List<MethodHandle> getters(Class<?> type, Comparator<MethodHandle> comparator) { 97 return getterStream(type, comparator).toList(); 98 } 99 100 static MethodHandle hashCodeForType(Class<?> type) { 101 if (type.isPrimitive()) { 102 int index = Wrapper.forPrimitiveType(type).ordinal(); 103 return HASHCODE[index]; 104 } else { 105 return HASHCODE[Wrapper.OBJECT.ordinal()].asType(methodType(int.class, type)); 106 } 107 } 108 109 static MethodHandle builtinPrimitiveEquals(Class<?> type) { 110 return primitiveEquals.get(type); 111 } 112 113 /* 114 * Produces a MethodHandle that returns boolean if two instances 115 * of the given reference type are substitutable. 116 * 117 * Two values of reference type are substitutable i== iff 118 * 1. if o1 and o2 are both reference objects then o1 r== o2; or 119 * 2. if o1 and o2 are both values then o1 v== o2 120 * 121 * At invocation time, it needs a dynamic check on the objects and 122 * do the substitutability test if they are of a value class. 123 */ 124 static MethodHandle referenceTypeEquals(Class<?> type) { 125 return OBJECT_EQUALS.asType(methodType(boolean.class, type, type)); 126 } 127 128 static Class<?> fieldType(MethodHandle getter) { 129 Class<?> ftype = getter.type().returnType(); 130 return ftype; 131 } 132 133 /** 134 * A base method for testing substitutability on a recursive data type, 135 * a value class with cyclic membership. 136 * 137 * This method will first invoke a method handle to test the substitutability 138 * of fields whose type is not recursively-typed. If true, then compares the 139 * value of the fields whose type is a recursive data type. 140 * For a field of its own type {@code f}, invoke the method handle for 141 * this base method on the field value of the given objects. 142 * For a field of other recursive data type, invoke {@link #isSubstitutable(Object, Object)} 143 * on the field value of the given objects. 144 * 145 * @param type a value class 146 * @param mh a MethodHandle that tests substitutability of all fields whose type 147 * is not recursively-typed. The method type is (V, V)boolean 148 * @param getters all getters for the fields whose type is a recursive data type 149 * @param recur MethodHandle that is capable of recursively calling itself 150 * to test if two objects of the given value class are substitutable. 151 * The method type is (Object, Object, AtomicInteger)boolean. 152 * @param o1 an object 153 * @param o2 an object to be compared for substitutability 154 * @param counter an AtomicInteger counter to keep track of the traversal count 155 * @return 156 * @param <V> a value class 157 */ 158 private static <V> boolean substitutableBase(Class<V> type, MethodHandle mh, MethodHandle[] getters, 159 MethodHandle recur, Object o1, Object o2, 160 AtomicInteger counter) throws Throwable { 161 assert isValueClass(type) : type.getName() + " not a value class"; 162 163 if (o1 == null && o2 == null) return true; 164 if (o1 == null || o2 == null) return false; 165 166 if (counter.getAndDecrement() == 0) { 167 throw new StackOverflowError("fail to evaluate == for value class " + type.getName()); 168 } 169 170 // test if the substitutability of all fields whose type is not recursively-typed 171 var result = (boolean) mh.invoke(o1, o2); 172 if (result) { 173 assert o1.getClass() == type && o2.getClass() == type; 174 175 // test if the fields of a recursive data type are substitutable 176 for (MethodHandle getter : getters) { 177 Class<?> ftype = fieldType(getter); 178 var f1 = getter.invoke(o1); 179 var f2 = getter.invoke(o2); 180 181 boolean substitutable; 182 if (ftype == type) { 183 substitutable = (boolean)recur.invokeExact(f1, f2, counter); 184 } else { 185 MethodHandle recur2 = RECUR_SUBST_METHOD_HANDLES.get(ftype); 186 substitutable = (boolean)recur2.invokeExact(f1, f2, counter); 187 } 188 if (!substitutable) { 189 return false; 190 } 191 } 192 } 193 return result; 194 } 195 196 197 /** 198 * A base method for computing the hashcode for a recursive data type, 199 * a value class with cyclic membership. 200 * 201 * This method will first invoke a method handle to compute the hash code 202 * of the fields whose type is not recursively-typed. Then compute the 203 * hash code of the remaining fields whose type is a recursive data type. 204 * For a field of its own type {@code f}, invoke the method handle for 205 * this base method on the field value of the given object. 206 * For a field of other recursive data type, invoke {@link Object#hashCode()} 207 * on the field value of the given object. 208 * 209 * @param type a value class 210 * @param mh a MethodHandle that computes the hash code of all fields whose 211 * type is not recursively-typed. The method type is (V)int 212 * @param getters all getters for the fields whose type is a recursive data type 213 * @param recur MethodHandle that is capable of recursively calling itself 214 * to compute the hash code of a field of the same type. 215 * The method type is (Object, AtomicInteger)int. 216 * @param obj an object 217 * @param counter an AtomicInteger counter to keep track of the traversal count 218 * @return the hash code of a value object of the given type 219 * @param <V> a value class 220 */ 221 private static <V> int hashCodeBase(Class<V> type, MethodHandle mh, MethodHandle[] getters, 222 MethodHandle recur, Object obj, 223 AtomicInteger counter) throws Throwable { 224 assert isValueClass(type) : type.getName() + " not a value class"; 225 226 if (obj == null) return 0; 227 228 if (counter.getAndDecrement() == 0) { 229 throw new StackOverflowError("fail to evaluate hashCode of a value object: " + type.getName()); 230 } 231 232 // compute the hash code of all fields whose type is not recursively-typed 233 var result = (int) mh.invoke(obj); 234 if (obj != null) { 235 assert obj.getClass() == type; 236 237 // test if the fields of a recursive data type are substitutable 238 for (MethodHandle getter : getters) { 239 Class<?> ftype = fieldType(getter); 240 var f = getter.invoke(obj); 241 242 int hc; 243 if (ftype == type) { 244 hc = (int)recur.invokeExact(f, counter); 245 } else { 246 MethodHandle recur2 = RECUR_HASHCODE_METHOD_HANDLES.get(ftype); 247 hc = (int)recur2.invokeExact(f, counter); 248 } 249 result = hashCombiner(result, hc); 250 } 251 } 252 return result; 253 } 254 255 /* 256 * Finds all value class memberships of the given type involved in cycles 257 */ 258 private static Set<Class<?>> recursiveValueTypes(Class<?> type) { 259 if (!isValueClass(type)) { 260 return Set.of(); 261 } 262 263 Deque<Class<?>> deque = new ArrayDeque<>(); 264 Set<Class<?>> visited = new HashSet<>(); 265 Set<Class<?>> recursiveTypes = new HashSet<>(); 266 Map<Class<?>, List<Class<?>>> unvisitedEdges = new HashMap<>(); 267 268 Class<?> c; 269 deque.add(type); 270 while ((c = deque.peek()) != null) { 271 if (visited.contains(c)) { 272 // remove the current node being visited 273 deque.pop(); 274 if (deque.contains(c)) { 275 // include all types in the cycle 276 for (Class<?> n : deque) { 277 recursiveTypes.add(n); 278 if (n == c) { 279 break; 280 } 281 } 282 } 283 284 // continue the depth-first search from the parent of c 285 if ((c = deque.peek()) == null) 286 continue; 287 } else { 288 visited.add(c); 289 } 290 291 // depth-first search on the field types of type c that are value classes 292 List<Class<?>> nodes = unvisitedEdges.computeIfAbsent(c, (k) -> fieldTypes(k)); 293 if (nodes.isEmpty()) { 294 // all field types are traversed 295 deque.pop(); 296 } else { 297 Class<?> n = nodes.remove(0); 298 deque.push(n); 299 } 300 } 301 302 if (recursiveTypes.isEmpty()) 303 return Set.of(); 304 305 return Arrays.stream(type.getDeclaredFields()) 306 .filter(f -> !Modifier.isStatic(f.getModifiers())) 307 .map(f -> f.getType()) 308 .filter(recursiveTypes::contains) 309 .collect(Collectors.toSet()); 310 } 311 312 private static List<Class<?>> fieldTypes(Class<?> type) { 313 List<Class<?>> result = new ArrayList<>(); 314 Arrays.stream(type.getDeclaredFields()) 315 .filter(f -> !Modifier.isStatic(f.getModifiers())) 316 .map(f -> f.getType()) 317 .filter(ft -> isValueClass(ft) && !result.contains(ft)) 318 .forEach(result::add); 319 return result; 320 } 321 322 private static final ClassValue<MethodHandle> RECUR_SUBST_METHOD_HANDLES = new ClassValue<>() { 323 /* 324 * Produces a MethodHandle that returns boolean if two value objects of 325 * a recursive data type are substitutable. This method is invoked by 326 * the substitutableBase method. 327 * 328 * The method type is (Object, Object, AtomicInteger)boolean. 329 */ 330 @Override protected MethodHandle computeValue(Class<?> type) { 331 return recurValueTypeEquals(type, recursiveValueTypes(type)); 332 } 333 }; 334 335 /* 336 * Produces a MethodHandle that returns boolean if two value objects 337 * are substitutable. The method type is (V, V)boolean. 338 */ 339 static MethodHandle valueTypeEquals(Class<?> type) { 340 // ensure the reference type of a primitive class not used in the method handle 341 assert isValueClass(type) || PrimitiveClass.isPrimitiveValueType(type); 342 343 Set<Class<?>> recursiveTypes = recursiveValueTypes(type); 344 if (recursiveTypes.isEmpty()) { 345 return valueTypeEquals(type, getters(type, TYPE_SORTER)); 346 } else { 347 MethodHandle target = recurValueTypeEquals(type, recursiveTypes); 348 return MethodHandles.insertArguments(target, 2, new AtomicInteger(THRESHOLD)) 349 .asType(methodType(boolean.class, type, type)); 350 } 351 } 352 353 /* 354 * Produces a MethodHandle that returns boolean if the given fields 355 * of the two value objects are substitutable. The method type is (V, V)boolean 356 */ 357 static MethodHandle valueTypeEquals(Class<?> type, List<MethodHandle> getters) { 358 // ensure the reference type of a primitive class not used in the method handle 359 assert isValueClass(type) || PrimitiveClass.isPrimitiveValueType(type); 360 361 MethodType mt = methodType(boolean.class, type, type); 362 MethodHandle instanceTrue = dropArguments(TRUE, 0, type, Object.class).asType(mt); 363 MethodHandle instanceFalse = dropArguments(FALSE, 0, type, Object.class).asType(mt); 364 MethodHandle accumulator = dropArguments(TRUE, 0, type, type); 365 for (MethodHandle getter : getters) { 366 Class<?> ftype = fieldType(getter); 367 MethodHandle eq = substitutableInvoker(ftype).asType(methodType(boolean.class, ftype, ftype)); 368 MethodHandle thisFieldEqual = filterArguments(eq, 0, getter, getter); 369 accumulator = guardWithTest(thisFieldEqual, accumulator, instanceFalse); 370 } 371 372 // if both arguments are null, return true; 373 // otherwise return accumulator; 374 return guardWithTest(IS_NULL.asType(mt), 375 instanceTrue, 376 guardWithTest(IS_SAME_VALUE_CLASS.asType(mt), 377 accumulator, 378 instanceFalse)); 379 } 380 381 /* 382 * Produces a MethodHandle that returns boolean if two value objects of 383 * a recursive data type are substitutable. 384 * 385 * The method type is (Object, Object, AtomicInteger)boolean. 386 */ 387 static MethodHandle recurValueTypeEquals(Class<?> type, Set<Class<?>> recursiveTypes) { 388 Stream<MethodHandle> getterStream = getterStream(type, TYPE_SORTER);; 389 List<MethodHandle> nonRecurTypeGetters = new ArrayList<>(); 390 List<MethodHandle> recurTypeGetters = new ArrayList<>(); 391 getterStream.forEach(getter -> { 392 Class<?> ftype = fieldType(getter); 393 if (recursiveTypes.contains(ftype)) { 394 // skip the value class that is involved in a cyclic membership 395 recurTypeGetters.add(getter); 396 } else { 397 nonRecurTypeGetters.add(getter); 398 } 399 }); 400 401 if (recurTypeGetters.isEmpty()) { 402 throw new InternalError("must be a recursive data type: " + type.getName()); 403 } 404 405 MethodHandle target = valueTypeEquals(type, nonRecurTypeGetters); 406 // This value class contains cyclic membership 407 // Create a method handle that is capable of calling itself. 408 // - the substitutableBase method first calls the method handle that tests 409 // the substitutability of all fields that are not a recursive data type 410 // - for a field of its own type, call the recursive method 411 // - for a field of a recursive data type, call isSubstitutable 412 Object[] arguments = new Object[]{type, target, recurTypeGetters.toArray(MethodHandle[]::new)}; 413 target = MethodHandles.insertArguments(RECUR_EQUALS, 0, arguments); 414 return recursive(target); 415 } 416 417 private static final ClassValue<MethodHandle> RECUR_HASHCODE_METHOD_HANDLES = new ClassValue<>() { 418 /* 419 * Produces a MethodHandle that returns the hashcode of a value object of 420 * a recursive data type. This method is invoked by the hashCodeBase method. 421 * 422 * The method type is (Object, AtomicInteger)int. 423 */ 424 @Override protected MethodHandle computeValue(Class<?> type) { 425 return recurValueTypeHashCode(type, recursiveValueTypes(type)); 426 } 427 }; 428 429 /* 430 * Produces a MethodHandle that computes the hash code of a value object. 431 * The method type of the return MethodHandle is (V)int. 432 */ 433 static MethodHandle valueTypeHashCode(Class<?> type) { 434 // ensure the reference type of a primitive class not used in the method handle 435 assert isValueClass(type) || PrimitiveClass.isPrimitiveValueType(type); 436 437 Set<Class<?>> recursiveTypes = recursiveValueTypes(type); 438 if (recursiveTypes.isEmpty()) { 439 return valueTypeHashCode(type, getterStream(type, null).toList()); 440 } else { 441 MethodHandle target = recurValueTypeHashCode(type, recursiveTypes); 442 return MethodHandles.insertArguments(target, 1, new AtomicInteger(THRESHOLD)) 443 .asType(methodType(int.class, type)); 444 } 445 } 446 447 /* 448 * Produces a MethodHandle that returns the hash code computed from 449 * the given fields of a value object. The method type is (V)int. 450 */ 451 static MethodHandle valueTypeHashCode(Class<?> type, List<MethodHandle> getters) { 452 // ensure the reference type of a primitive class not used in the method handle 453 assert isValueClass(type) || PrimitiveClass.isPrimitiveValueType(type); 454 455 MethodHandle target = dropArguments(constant(int.class, SALT), 0, type); 456 MethodHandle cls = dropArguments(constant(Class.class, type),0, type); 457 MethodHandle classHashCode = filterReturnValue(cls, hashCodeForType(Class.class)); 458 MethodHandle combiner = filterArguments(HASH_COMBINER, 0, target, classHashCode); 459 // int v = SALT * 31 + type.hashCode(); 460 MethodHandle init = permuteArguments(combiner, target.type(), 0, 0); 461 int length = getters.size(); 462 MethodHandle iterations = dropArguments(constant(int.class, length), 0, type); 463 MethodHandle[] hashers = new MethodHandle[length]; 464 for (int i=0; i < length; i++) { 465 MethodHandle getter = getters.get(i); 466 Class<?> ftype = fieldType(getter); 467 468 // For primitive types or reference types, this calls Objects::hashCode. 469 // For value objects and the hashCode method is not overridden, 470 // VM will call valueObjectHashCode to compute the hash code. 471 MethodHandle hasher = hashCodeForType(ftype); 472 hashers[i] = filterReturnValue(getter, hasher); 473 } 474 475 // for (int i=0; i < getters.length; i++) { 476 // v = computeHash(v, i, a); 477 // } 478 MethodHandle body = COMPUTE_HASH.bindTo(hashers) 479 .asType(methodType(int.class, int.class, int.class, type)); 480 return countedLoop(iterations, init, body); 481 } 482 483 /* 484 * Produces a MethodHandle that returns the hashcode of a value object of 485 * a recursive data type. This method is invoked by the hashCodeBase method. 486 * 487 * The method type is (Object, AtomicInteger)int. 488 */ 489 static MethodHandle recurValueTypeHashCode(Class<?> type, Set<Class<?>> recursiveTypes) { 490 Stream<MethodHandle> getterStream = getterStream(type, null);; 491 List<MethodHandle> nonRecurTypeGetters = new ArrayList<>(); 492 List<MethodHandle> recurTypeGetters = new ArrayList<>(); 493 getterStream.forEach(getter -> { 494 Class<?> ftype = fieldType(getter); 495 if (recursiveTypes.contains(ftype)) { 496 // skip the value class that is involved in a cyclic membership 497 recurTypeGetters.add(getter); 498 } else { 499 nonRecurTypeGetters.add(getter); 500 } 501 }); 502 503 if (recurTypeGetters.isEmpty()) { 504 throw new InternalError("must be a recursive data type: " + type.getName()); 505 } 506 507 MethodHandle target = valueTypeHashCode(type, nonRecurTypeGetters); 508 System.out.println(type.getName() + " valueHashCode " + nonRecurTypeGetters + " " + recurTypeGetters); 509 510 // This value class contains cyclic membership 511 // Create a method handle that is capable of calling itself. 512 // - the hashCodeBase method first calls the method handle that computes the hash code 513 // of all fields whose type is not recursively-typed 514 // - for a field of its own type, call the recursive method 515 // - for a field of a recursive data type, call valueObjectHashCode 516 Object[] arguments = new Object[]{type, target, recurTypeGetters.toArray(MethodHandle[]::new)}; 517 target = MethodHandles.insertArguments(RECUR_HASHCODE, 0, arguments); 518 return recursive(target); 519 } 520 521 // ------ utility methods ------ 522 private static boolean eq(Object a, Object b) { 523 if (a == null && b == null) return true; 524 if (a == null || b == null) return false; 525 if (a.getClass() != b.getClass()) return false; 526 return a.getClass().isValue() ? valueEquals(a, b) : (a == b); 527 } 528 529 /* 530 * Returns true if two value objects are substitutable. 531 */ 532 private static boolean valueEquals(Object a, Object b) { 533 assert a != null && b != null && isSameValueClass(a, b); 534 try { 535 Class<?> type = a.getClass(); 536 if (PrimitiveClass.isPrimitiveClass(type)) { 537 type = PrimitiveClass.asValueType(type); 538 } 539 return (boolean) substitutableInvoker(type).invoke(type.cast(a), type.cast(b)); 540 } catch (Error|RuntimeException e) { 541 throw e; 542 } catch (Throwable e) { 543 throw new InternalError(e); 544 } 545 } 546 547 private static boolean isNull(Object a, Object b) { 548 // avoid acmp that will call isSubstitutable 549 if (a != null) return false; 550 if (b != null) return false; 551 return true; 552 } 553 554 /* 555 * Returns true if the given objects are of the same value class. 556 * 557 * Two objects are of the same value class iff: 558 * 1. a != null and b != null 559 * 2. the declaring class of a and b is the same value class 560 */ 561 private static boolean isSameValueClass(Object a, Object b) { 562 if (a == null || b == null) return false; 563 564 return a.getClass().isValue() && a.getClass() == b.getClass(); 565 } 566 567 private static int hashCombiner(int accumulator, int value) { 568 return accumulator * 31 + value; 569 } 570 571 private static int computeHashCode(MethodHandle[] hashers, int v, int i, Object o) { 572 try { 573 int hc = (int)hashers[i].invoke(o); 574 return hashCombiner(v, hc); 575 } catch (Error|RuntimeException e) { 576 throw e; 577 } catch (Throwable e) { 578 throw new InternalError(e); 579 } 580 } 581 582 private static final MethodHandle FALSE = constant(boolean.class, false); 583 private static final MethodHandle TRUE = constant(boolean.class, true); 584 private static final MethodHandle OBJECT_EQUALS = 585 findStatic("eq", methodType(boolean.class, Object.class, Object.class)); 586 private static final MethodHandle IS_SAME_VALUE_CLASS = 587 findStatic("isSameValueClass", methodType(boolean.class, Object.class, Object.class)); 588 private static final MethodHandle IS_NULL = 589 findStatic("isNull", methodType(boolean.class, Object.class, Object.class)); 590 private static final MethodHandle HASH_COMBINER = 591 findStatic("hashCombiner", methodType(int.class, int.class, int.class)); 592 private static final MethodHandle COMPUTE_HASH = 593 findStatic("computeHashCode", methodType(int.class, MethodHandle[].class, int.class, int.class, Object.class)); 594 private static final MethodHandle[] HASHCODE = initHashCode(); 595 private static final MethodHandle RECUR_EQUALS = 596 findStatic("substitutableBase", 597 methodType(boolean.class, Class.class, MethodHandle.class, MethodHandle[].class, 598 MethodHandle.class, Object.class, Object.class, AtomicInteger.class)); 599 private static final MethodHandle RECUR_HASHCODE = 600 findStatic("hashCodeBase", 601 methodType(int.class, Class.class, MethodHandle.class, MethodHandle[].class, 602 MethodHandle.class, Object.class, AtomicInteger.class)); 603 604 private static MethodHandle[] initHashCode() { 605 MethodHandle[] mhs = new MethodHandle[Wrapper.COUNT]; 606 for (Wrapper wrapper : Wrapper.values()) { 607 if (wrapper == Wrapper.VOID) continue; 608 Class<?> cls = wrapper == Wrapper.OBJECT ? Objects.class : wrapper.wrapperType(); 609 mhs[wrapper.ordinal()] = findStatic(cls, "hashCode", 610 methodType(int.class, wrapper.primitiveType())); 611 } 612 return mhs; 613 } 614 615 private static MethodHandle findStatic(String name, MethodType methodType) { 616 return findStatic(MethodHandleBuilder.class, name, methodType); 617 } 618 private static MethodHandle findStatic(Class<?> cls, String name, MethodType methodType) { 619 try { 620 return JLIA.findStatic(cls, name, methodType); 621 } catch (IllegalAccessException e) { 622 throw newLinkageError(e); 623 } 624 } 625 626 /** 627 * A "salt" value used for this internal hashcode implementation that 628 * needs to vary sufficiently from one run to the next so that 629 * the default hashcode for value classes will vary between JVM runs. 630 */ 631 static final int SALT; 632 static { 633 long nt = System.nanoTime(); 634 int value = (int)((nt >>> 32) ^ nt); 635 SALT = GetIntegerAction.privilegedGetProperty("value.bsm.salt", value); 636 } 637 } 638 639 private static LinkageError newLinkageError(Throwable e) { 640 return (LinkageError) new LinkageError().initCause(e); 641 } 642 643 /** 644 * Returns {@code true} if the arguments are <em>substitutable</em> to each 645 * other and {@code false} otherwise. 646 * <em>Substitutability</em> means that they cannot be distinguished from 647 * each other in any data-dependent way, meaning that it is safe to substitute 648 * one for the other. 649 * 650 * <ul> 651 * <li>If {@code a} and {@code b} are both {@code null}, this method returns 652 * {@code true}. 653 * <li>If {@code a} and {@code b} are both instances of the same value class 654 * {@code V}, this method returns {@code true} if, for all fields {@code f} 655 * declared in {@code V}, {@code a.f} and {@code b.f} are substitutable. 656 * <li>If {@code a} and {@code b} are both values of the same builtin primitive type, 657 * this method returns {@code a == b} with the following exception: 658 * <ul> 659 * <li> If {@code a} and {@code b} both represent {@code NaN}, 660 * this method returns {@code true}, even though {@code NaN == NaN} 661 * has the value {@code false}. 662 * <li> If {@code a} is floating point positive zero while {@code b} is 663 * floating point negative zero, or vice versa, this method 664 * returns {@code false}, even though {@code +0.0 == -0.0} has 665 * the value {@code true}. 666 * </ul> 667 * <li>If {@code a} and {@code b} are both instances of the same reference type, 668 * this method returns {@code a == b}. 669 * <li>Otherwise this method returns {@code false}. 670 * </ul> 671 * 672 * <p>For example, 673 * <pre>{@code interface Number { ... } 674 * // ordinary reference class 675 * class IntNumber implements Number { ... } 676 * // value class 677 * value class IntValue implements Number { 678 * int i; 679 * : 680 * public static IntValue of(int i) {...} // IntValue::of creates a new value instance 681 * } 682 * // value class with an Object field 683 * value class RefValue { 684 * Object o; 685 * : 686 * } 687 * 688 * var val1 = IntValue.of(10); 689 * var val2 = IntValue.of(10); // val1 and val2 have the same value 690 * var ref1 = new IntNumber(10); // ref1 and ref2 are two reference instances 691 * var ref2 = new IntNumber(10); 692 * assertTrue(isSubstitutable(val1, val2)); // val1 and val2 are both value instances of IntValue 693 * assertFalse(isSubstitutable(ref1, ref2)); // ref1 and ref2 are two reference instances that are not substitutable 694 * assertTrue(isSubstitutable(ref1, ref1)); // a reference instance is substitutable with itself 695 * 696 * var rval1 = RefValue.of(List.of("list")); // rval1.o and rval2.o both contain a list of one-single element "list" 697 * var rval2 = RefValue.of(List.of("list"); 698 * var rval3 = RefValue.of(rval1.o); 699 * 700 * assertFalse(isSubstitutable(rval1, rval2)); // rval1.o and rval2.o are two different List instances and hence not substitutable 701 * assertTrue(isSubstitutable(rval1, rval3 )); // rval1.o and rval3.o are the same reference instance 702 * }</pre> 703 * 704 * @param a an object 705 * @param b an object to be compared with {@code a} for substitutability 706 * @return {@code true} if the arguments are substitutable to each other; 707 * {@code false} otherwise. 708 * @param <T> type 709 * @see Float#equals(Object) 710 * @see Double#equals(Object) 711 */ 712 private static <T> boolean isSubstitutable(T a, Object b) { 713 if (VERBOSE) { 714 System.out.println("substitutable " + a + " vs " + b); 715 } 716 717 // Called directly from the VM. 718 // 719 // DO NOT use "==" or "!=" on args "a" and "b", with this code or any of 720 // its callees. Could be inside of if_acmp<eq|ne> bytecode implementation. 721 722 if (a == null && b == null) return true; 723 if (a == null || b == null) return false; 724 if (a.getClass() != b.getClass()) return false; 725 726 try { 727 Class<?> type = a.getClass(); 728 if (PrimitiveClass.isPrimitiveClass(type)) { 729 type = PrimitiveClass.asValueType(type); 730 } 731 return (boolean) substitutableInvoker(type).invoke(a, b); 732 } catch (Error|RuntimeException e) { 733 if (VERBOSE) e.printStackTrace(); 734 throw e; 735 } catch (Throwable e) { 736 if (VERBOSE) e.printStackTrace(); 737 throw new InternalError(e); 738 } 739 } 740 741 /** 742 * Produces a method handle which tests if two arguments are 743 * {@linkplain #isSubstitutable(Object, Object) substitutable}. 744 * 745 * <ul> 746 * <li>If {@code T} is a non-floating point primitive type, this method 747 * returns a method handle testing the two arguments are the same value, 748 * i.e. {@code a == b}. 749 * <li>If {@code T} is {@code float} or {@code double}, this method 750 * returns a method handle representing {@link Float#equals(Object)} or 751 * {@link Double#equals(Object)} respectively. 752 * <li>If {@code T} is a reference type that is not {@code Object} and not an 753 * interface, this method returns a method handle testing 754 * the two arguments are the same reference, i.e. {@code a == b}. 755 * <li>If {@code T} is a value class, this method returns 756 * a method handle that returns {@code true} if 757 * for all fields {@code f} declared in {@code T}, where {@code U} is 758 * the type of {@code f}, if {@code a.f} and {@code b.f} are substitutable 759 * with respect to {@code U}. 760 * <li>If {@code T} is an interface or {@code Object}, and 761 * {@code a} and {@code b} are of the same value class {@code V}, 762 * this method returns a method handle that returns {@code true} if 763 * {@code a} and {@code b} are substitutable with respect to {@code V}. 764 * </ul> 765 * 766 * @param type class type 767 * @param <T> type 768 * @return a method handle for substitutability test 769 */ 770 private static <T> MethodHandle substitutableInvoker(Class<T> type) { 771 if (type.isPrimitive()) 772 return MethodHandleBuilder.builtinPrimitiveEquals(type); 773 774 if (isValueClass(type) || PrimitiveClass.isPrimitiveValueType(type)) { 775 return SUBST_TEST_METHOD_HANDLES.get(type); 776 } 777 return MethodHandleBuilder.referenceTypeEquals(type); 778 } 779 780 // store the method handle for value classes in ClassValue 781 private static final ClassValue<MethodHandle> SUBST_TEST_METHOD_HANDLES = new ClassValue<>() { 782 @Override protected MethodHandle computeValue(Class<?> type) { 783 return MethodHandleBuilder.valueTypeEquals(type); 784 } 785 }; 786 787 /** 788 * Invoke the hashCode method for the given value object. 789 * @param o the instance to hash. 790 * @return the hash code of the given value object. 791 */ 792 private static int valueObjectHashCode(Object o) { 793 Class<?> c = o.getClass(); 794 try { 795 // Note: javac disallows user to call super.hashCode if user implemented 796 // risk for recursion for experts crafting byte-code 797 if (!c.isValue()) 798 throw new InternalError("must be value or primitive class: " + c.getName()); 799 800 Class<?> type = PrimitiveClass.isPrimitiveClass(c) ? PrimitiveClass.asValueType(c) : c; 801 return (int) HASHCODE_METHOD_HANDLES.get(type).invoke(o); 802 } catch (Error|RuntimeException e) { 803 throw e; 804 } catch (Throwable e) { 805 if (VERBOSE) e.printStackTrace(); 806 throw new InternalError(e); 807 } 808 } 809 810 /** 811 * Returns true if the given type is a value class. 812 */ 813 private static boolean isValueClass(Class<?> type) { 814 return type.isValue() && !PrimitiveClass.isPrimitiveClass(type); 815 } 816 817 private static final ClassValue<MethodHandle> HASHCODE_METHOD_HANDLES = new ClassValue<>() { 818 @Override protected MethodHandle computeValue(Class<?> type) { 819 return MethodHandleBuilder.valueTypeHashCode(type); 820 } 821 }; 822 823 private static final Comparator<MethodHandle> TYPE_SORTER = (mh1, mh2) -> { 824 // sort the getters with the return type 825 Class<?> t1 = mh1.type().returnType(); 826 Class<?> t2 = mh2.type().returnType(); 827 if (t1 == t2) return 0; 828 829 if (t1.isPrimitive()) { 830 if (!t2.isPrimitive()) { 831 return 1; 832 } 833 } else { 834 if (t2.isPrimitive()) { 835 return -1; 836 } 837 } 838 return -1; 839 }; 840 841 842 /** 843 * Constructs a method handle that is capable of recursively 844 * calling itself, whose behavior is determined by a non-recursive 845 * base method handle which gets both the original arguments and a 846 * reference to the recursive method handle. 847 * <p> 848 * Here is pseudocode for the resulting loop handle, plus a sketch 849 * of the behavior of the base function. The symbols {@code A}, 850 * {@code a}, and {@code R} represent arguments and return value 851 * for both the recursive function and the base function. 852 * 853 * <blockquote><pre>{@code 854 * R recursive(A... a) { 855 * MethodHandle recur = &recursive; 856 * return base(recur, a...); 857 * } 858 * R base(MethodHandle recur, A... a) { 859 * ... if (no recursion) return f(a); ... 860 * var r2 = recur.invokeExact(a2...); 861 * var r3 = recur.invokeExact(a3...); 862 * ... do stuff with r2, r3, etc. ... 863 * } 864 * }</pre></blockquote> 865 * <p> 866 * To make several functions mutually recursive, additional base 867 * arguments can be passed to this combinator. For each base 868 * function, a recursive adapter is formed (like {@code recur} 869 * above). The sequence of recursive adapters is passed as 870 * initial arguments to each base function. Here is pseudocode 871 * that corresponds to three base functions: 872 * <blockquote><pre>{@code 873 * R recursive(A... a) { 874 * return base(&recursive, &recursive2, &recursive3, a...); 875 * } 876 * R2 recursive2(A2... a2) { 877 * return base2(&recursive, &recursive2, &recursive3, a2...); 878 * } 879 * R3 recursive3(A3... a3) { 880 * return base2(&recursive, &recursive2, &recursive3, a3...); 881 * } 882 * R base(MethodHandle recur, MethodHandle recur2, 883 * MethodHandle recur3, A... a) { 884 * ... if (no recursion) return f(a); ... 885 * var r2 = recur2.invokeExact(a2...); 886 * var r3 = recur3.invokeExact(a3...); 887 * ... do stuff with r2, r3, etc. ... 888 * } 889 * R2 base2(MethodHandle recur, MethodHandle recur2, 890 * MethodHandle recur3, A2... a2) { ... } 891 * R3 base3(MethodHandle recur, MethodHandle recur2, 892 * MethodHandle recur3, A3... a3) { ... } 893 * }</pre></blockquote> 894 * 895 * @apiNote Example: 896 * {@snippet lang="java" : 897 * // classic recursive implementation of the factorial function 898 * static int base(MethodHandle recur, int k) throws Throwable { 899 * if (k <= 1) return 1; 900 * return k * (int) recur.invokeExact(k - 1); 901 * } 902 * // assume MH_base is a handle to the above method 903 * MethodHandle recur = MethodHandles.recursive(MH_base); 904 * assertEquals(120, recur.invoke(5)); 905 * } 906 * <p> 907 * A constructed recursive method handle is made varargs 908 * if its corresponding base method handle is varargs. 909 * @implSpec 910 * For a single base function, this produces a result equivalent to: 911 * <pre>{@code 912 * class Holder { 913 * final MethodHandle recur; 914 * static final MH_recur = ...; //field getter 915 * Holder(MethodHandle base) { 916 * recur = filterArguments(base, 0, MH_recur).bindTo(this); 917 * } 918 * } 919 * return new Holder(base).recur; 920 * }</pre> 921 * @param base the logic of the function to make recursive 922 * @param moreBases additional base functions to be made mutually recursive 923 * @throws NullPointerException if any argument is null 924 * @throws IllegalArgumentException if any base function does not accept 925 * the required leading arguments of type {@code MethodHandle} 926 * 927 * @return a method handle which invokes the (first) base function 928 * on the incoming arguments, with recursive versions of the 929 * base function (or functions) prepended as extra arguments 930 * 931 * @since Valhalla 932 */ 933 static MethodHandle recursive(MethodHandle base, MethodHandle... moreBases) { 934 // freeze the varargs and check for nulls: 935 List<MethodHandle> bases2 = List.of(moreBases); 936 int baseCount = 1 + bases2.size(); 937 recursiveChecks(base, baseCount); 938 for (var base2 : bases2) { recursiveChecks(base2, baseCount); } 939 class Holder { 940 final MethodHandle recur; 941 final List<MethodHandle> recurs2; 942 MethodHandle recurs2(int i) { return recurs2.get(i); } 943 Holder() { 944 // Feed the first baseCount parameters of each base 945 // with a fetch of each recur, so we can bind to this: 946 var fetchers = new MethodHandle[baseCount]; 947 fetchers[0] = MH_recur; 948 for (int pos = 1; pos < fetchers.length; pos++) { 949 int i = pos-1; // index into recurs2 950 fetchers[pos] = MethodHandles.insertArguments(MH_recurs2, 1, i); 951 } 952 this.recur = makeRecur(base, fetchers); 953 if (baseCount == 1) { 954 this.recurs2 = List.of(); 955 } else { 956 var recurs2 = new MethodHandle[baseCount-1]; 957 for (int i = 0; i < recurs2.length; i++) { 958 recurs2[i] = makeRecur(bases2.get(i), fetchers); 959 } 960 this.recurs2 = List.of(recurs2); 961 } 962 } 963 MethodHandle makeRecur(MethodHandle base, MethodHandle[] fetchers) { 964 var adapt = filterArguments(base, 0, fetchers); 965 for (int pos = 0; pos < fetchers.length; pos++) { 966 adapt = adapt.bindTo(this); 967 } 968 return adapt.withVarargs(base.isVarargsCollector()); 969 } 970 static final MethodHandle MH_recur, MH_recurs2; 971 static { 972 try { 973 MH_recur = MethodHandles.lookup() 974 .findGetter(Holder.class, "recur", MethodHandle.class); 975 MH_recurs2 = MethodHandles.lookup() 976 .findVirtual(Holder.class, "recurs2", 977 methodType(MethodHandle.class, int.class)); 978 } catch (ReflectiveOperationException ex) { 979 throw new InternalError(ex); 980 } 981 } 982 } 983 return new Holder().recur; 984 } 985 986 private static void recursiveChecks(MethodHandle base, int baseCount) { 987 MethodType mt = base.type(); // implicit null check 988 boolean wrong = (mt.parameterCount() < baseCount); 989 for (int i = 0; i < baseCount && !wrong; i++) { 990 if (mt.parameterType(i) != MethodHandle.class) { 991 wrong = true; 992 } 993 } 994 if (!wrong) return; 995 throw new IllegalArgumentException("missing leading MethodHandle parameters: " + mt); 996 } 997 998 }