1 /*
   2  * Copyright (c) 2018, 2025, 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.invoke.VarHandle;
  32 import java.lang.reflect.Modifier;
  33 import java.util.ArrayDeque;
  34 import java.util.ArrayList;
  35 import java.util.Arrays;
  36 import java.util.Comparator;
  37 import java.util.Deque;
  38 import java.util.HashMap;
  39 import java.util.HashSet;
  40 import java.util.Iterator;
  41 import java.util.LinkedHashMap;
  42 import java.util.LinkedList;
  43 import java.util.List;
  44 import java.util.Map;
  45 import java.util.Objects;
  46 import java.util.Set;
  47 import java.util.concurrent.ConcurrentHashMap;
  48 import java.util.concurrent.atomic.AtomicBoolean;
  49 import java.util.function.Function;
  50 import java.util.function.Predicate;
  51 import java.util.stream.Stream;
  52 
  53 import jdk.internal.access.JavaLangInvokeAccess;
  54 import jdk.internal.access.SharedSecrets;
  55 import jdk.internal.value.LayoutIteration;
  56 import sun.invoke.util.Wrapper;
  57 
  58 import static java.lang.invoke.MethodHandles.constant;
  59 import static java.lang.invoke.MethodHandles.dropArguments;
  60 import static java.lang.invoke.MethodHandles.filterArguments;
  61 import static java.lang.invoke.MethodHandles.foldArguments;
  62 import static java.lang.invoke.MethodHandles.guardWithTest;
  63 import static java.lang.invoke.MethodHandles.permuteArguments;
  64 import static java.lang.invoke.MethodType.methodType;
  65 import static java.lang.runtime.ObjectMethods.primitiveEquals;
  66 import static java.util.stream.Collectors.joining;
  67 import static java.util.stream.Collectors.toList;
  68 import static java.util.stream.Collectors.toMap;
  69 
  70 /**
  71  * Implementation for Object::equals and Object::hashCode for value objects.
  72  *
  73  * ValueObjectMethods::isSubstitutable and valueObjectHashCode are
  74  * private entry points called by VM.
  75  */
  76 final class ValueObjectMethods {
  77     private ValueObjectMethods() {}
  78     private static final boolean VERBOSE =
  79             System.getProperty("value.bsm.debug") != null;
  80     private static final int MAX_NODE_VISITS =
  81             Integer.getInteger("jdk.value.recursion.threshold", Integer.MAX_VALUE);
  82     private static final JavaLangInvokeAccess JLIA = SharedSecrets.getJavaLangInvokeAccess();
  83 
  84     static class MethodHandleBuilder {
  85         private static final HashMap<Class<?>, MethodHandle> primitiveSubstitutable = new HashMap<>();
  86 
  87         static {
  88             primitiveSubstitutable.putAll(primitiveEquals); // adopt all the primitive eq methods
  89             primitiveSubstitutable.put(float.class,
  90                     findStatic("eqValue", methodType(boolean.class, float.class, float.class)));
  91             primitiveSubstitutable.put(double.class,
  92                     findStatic("eqValue", methodType(boolean.class, double.class, double.class)));
  93         }
  94 
  95         static Stream<MethodHandle> getterStream(Class<?> type, Comparator<MethodHandle> comparator) {
  96             // filter static fields
  97             List<MethodHandle> mhs = LayoutIteration.ELEMENTS.get(type);
  98             if (comparator != null) {
  99                 mhs = new ArrayList<>(mhs);
 100                 mhs.sort(comparator);
 101             }
 102             return mhs.stream();
 103         }
 104 
 105         static MethodHandle hashCodeForType(Class<?> type) {
 106             if (type.isPrimitive()) {
 107                 int index = Wrapper.forPrimitiveType(type).ordinal();
 108                 return HASHCODE[index];
 109             } else {
 110                 return HASHCODE[Wrapper.OBJECT.ordinal()].asType(methodType(int.class, type));
 111             }
 112         }
 113 
 114         static MethodHandle builtinPrimitiveSubstitutable(Class<?> type) {
 115             return primitiveSubstitutable.get(type);
 116         }
 117 
 118         /*
 119          * Produces a MethodHandle that returns boolean if two instances
 120          * of the given reference type are substitutable.
 121          *
 122          * Two values of reference type are substitutable i== iff
 123          * 1. if o1 and o2 are both reference objects then o1 r== o2; or
 124          * 2. if o1 and o2 are both values then o1 v== o2
 125          *
 126          * At invocation time, it needs a dynamic check on the objects and
 127          * do the substitutability test if they are of a value class.
 128          */
 129         static MethodHandle referenceTypeEquals(Class<?> type) {
 130             return OBJECT_EQUALS.asType(methodType(boolean.class, type, type));
 131         }
 132 
 133         static Class<?> fieldType(MethodHandle getter) {
 134             Class<?> ftype = getter.type().returnType();
 135             return ftype;
 136         }
 137 
 138         private static List<Class<?>> valueTypeFields(Class<?> type) {
 139             return LayoutIteration.ELEMENTS.get(type).stream()
 140                     .<Class<?>>map(mh -> mh.type().returnType())
 141                     .filter(Class::isValue)
 142                     .distinct()
 143                     .toList();
 144         }
 145 
 146         /*
 147          * Produces a MethodHandle that returns boolean if two value objects
 148          * are substitutable.  The method type is (V, V)boolean.
 149          */
 150         static MethodHandle valueTypeEquals(Class<?> type) {
 151             var builder = METHOD_HANDLE_BUILDERS.get(type);
 152             if (builder == null) {
 153                 builder = newBuilder(type);
 154             }
 155             return builder.equalsTarget();
 156         }
 157 
 158         /*
 159          * Produces a MethodHandle that computes the hash code of a value object.
 160          * The method type of the return MethodHandle is (V)int.
 161          */
 162         static MethodHandle valueTypeHashCode(Class<?> type) {
 163             var builder = METHOD_HANDLE_BUILDERS.get(type);
 164             if (builder == null) {
 165                 builder = newBuilder(type);
 166             }
 167             return builder.hashCodeTarget();
 168         }
 169 
 170         /*
 171          * Produces a MethodHandle that returns boolean if the given non-recursively typed
 172          * fields of the two value objects are substitutable. The method type is (V, V)boolean
 173          */
 174         static MethodHandle valueTypeEquals(Class<?> type, List<MethodHandle> getters) {
 175             assert type.isValue();
 176 
 177             MethodType mt = methodType(boolean.class, type, type);
 178             MethodHandle instanceTrue = dropArguments(TRUE, 0, type, Object.class).asType(mt);
 179             MethodHandle instanceFalse = dropArguments(FALSE, 0, type, Object.class).asType(mt);
 180             MethodHandle accumulator = dropArguments(TRUE, 0, type, type);
 181             for (MethodHandle getter : getters) {
 182                 Class<?> ftype = fieldType(getter);
 183                 var eq = substitutableInvoker(ftype).asType(methodType(boolean.class, ftype, ftype));
 184                 var thisFieldEqual = filterArguments(eq, 0, getter, getter);
 185                 accumulator = guardWithTest(thisFieldEqual, accumulator, instanceFalse);
 186             }
 187 
 188             // if both arguments are null, return true;
 189             // otherwise return accumulator;
 190             return guardWithTest(IS_NULL.asType(mt),
 191                                  instanceTrue,
 192                                  guardWithTest(IS_SAME_VALUE_CLASS.asType(mt),
 193                                                accumulator,
 194                                                instanceFalse));
 195         }
 196 
 197         /*
 198          * Produces a MethodHandle that returns the hash code computed from
 199          * the given non-recursively-typed fields of a value object.
 200          * The method type is (V)int.
 201          */
 202         static MethodHandle valueTypeHashCode(Class<?> type, List<MethodHandle> getters) {
 203             assert type.isValue();
 204 
 205             MethodHandle target = dropArguments(constant(int.class, SALT), 0, type);
 206             MethodHandle classHasher = dropArguments(hashCodeForType(Class.class).bindTo(type), 0, type);
 207             MethodHandle hashCombiner = dropArguments(HASH_COMBINER, 2, type);
 208             MethodHandle accumulator = foldArguments(foldArguments(hashCombiner, 1, classHasher), 0, target);
 209             for (MethodHandle getter : getters) {
 210                 Class<?> ft = fieldType(getter);
 211                 // For primitive types or reference types, this calls Objects::hashCode.
 212                 // For value objects and the hashCode method is not overridden,
 213                 // VM will call valueObjectHashCode to compute the hash code.
 214                 var hasher = hashCodeForType(ft);
 215                 var hashThisField = filterArguments(hasher, 0, getter);    // (R)I
 216                 var combineHashes = foldArguments(hashCombiner, 1, hashThisField);
 217                 accumulator = foldArguments(combineHashes, 0, accumulator);
 218             }
 219             return accumulator;
 220         }
 221 
 222         // ------ utility methods ------
 223         private static boolean eq(Object a, Object b)   {
 224             if (a == null && b == null) return true;
 225             if (a == null || b == null) return false;
 226             if (a.getClass() != b.getClass()) return false;
 227             return a.getClass().isValue() ? valueEquals(a, b) : (a == b);
 228         }
 229 
 230         /*
 231          * Returns true if two value objects are substitutable.
 232          */
 233         private static boolean valueEquals(Object a, Object b) {
 234             assert a != null && b != null && isSameValueClass(a, b);
 235             try {
 236                 Class<?> type = a.getClass();
 237                 return (boolean) substitutableInvoker(type).invoke(type.cast(a), type.cast(b));
 238             } catch (Error|RuntimeException e) {
 239                 throw e;
 240             } catch (Throwable e) {
 241                 throw new InternalError(e);
 242             }
 243         }
 244 
 245         private static boolean isNull(Object a, Object b) {
 246             // avoid acmp that will call isSubstitutable
 247             if (a != null) return false;
 248             if (b != null) return false;
 249             return true;
 250         }
 251 
 252         /*
 253          * Returns true if the given objects are of the same value class.
 254          *
 255          * Two objects are of the same value class iff:
 256          * 1. a != null and b != null
 257          * 2. the declaring class of a and b is the same value class
 258          */
 259         private static boolean isSameValueClass(Object a, Object b) {
 260             if (a == null || b == null) return false;
 261 
 262             return a.getClass().isValue() && a.getClass() == b.getClass();
 263         }
 264 
 265         private static int hashCombiner(int accumulator, int value) {
 266             return accumulator * 31 + value;
 267         }
 268 
 269         private static int[] newCounter(int[] counter) {
 270             return new int[] { counter[0] };
 271         }
 272 
 273         private static boolean recurValueEq(MethodHandle target, Object o1, Object o2, int[] counter) {
 274             assert counter[0] > 0;
 275 
 276             if (o1 == null && o2 == null) return true;
 277             if (o1 == null || o2 == null) return false;
 278             if (o1.getClass() != o2.getClass()) return false;
 279 
 280             if (--counter[0] == 0) {
 281                 throw new StackOverflowError("fail to evaluate == for value class " + o1.getClass().getName());
 282             }
 283 
 284             try {
 285                 return (boolean) target.invoke(o1, o2, counter);
 286             } catch (Error|RuntimeException e) {
 287                 throw e;
 288             } catch (Throwable e) {
 289                 throw new InternalError(e);
 290             }
 291         }
 292 
 293         private static int recurValueHashCode(MethodHandle target, Object o, int[] counter) {
 294             assert counter[0] > 0;
 295 
 296             if (o == null) return 0;
 297 
 298             if (--counter[0] == 0) {
 299                 throw new StackOverflowError("fail to evaluate hashCode for value class " + o.getClass().getName());
 300             }
 301 
 302             try {
 303                 return (int) target.invoke(o, counter);
 304             } catch (Error|RuntimeException e) {
 305                 throw e;
 306             } catch (Throwable e) {
 307                 throw new InternalError(e);
 308             }
 309         }
 310 
 311         private static final MethodHandle FALSE = constant(boolean.class, false);
 312         private static final MethodHandle TRUE = constant(boolean.class, true);
 313         // Substitutability test for float
 314         private static boolean eqValue(float a, float b) {
 315             return Float.floatToRawIntBits(a) == Float.floatToRawIntBits(b);
 316         }
 317         // Substitutability test for double
 318         private static boolean eqValue(double a, double b) {
 319             return Double.doubleToRawLongBits(a) == Double.doubleToRawLongBits(b);
 320         }
 321         private static final MethodHandle OBJECT_EQUALS =
 322                 findStatic("eq", methodType(boolean.class, Object.class, Object.class));
 323         private static final MethodHandle IS_SAME_VALUE_CLASS =
 324                 findStatic("isSameValueClass", methodType(boolean.class, Object.class, Object.class));
 325         private static final MethodHandle IS_NULL =
 326                 findStatic("isNull", methodType(boolean.class, Object.class, Object.class));
 327         private static final MethodHandle HASH_COMBINER =
 328                 findStatic("hashCombiner", methodType(int.class, int.class, int.class));
 329         private static final MethodHandle[] HASHCODE = initHashCode();
 330         private static final MethodHandle RECUR_VALUE_EQ =
 331                 findStatic("recurValueEq", methodType(boolean.class, MethodHandle.class, Object.class, Object.class, int[].class));
 332         private static final MethodHandle RECUR_VALUE_HASHCODE =
 333                 findStatic("recurValueHashCode", methodType(int.class, MethodHandle.class, Object.class, int[].class));
 334         private static final MethodHandle NEW_COUNTER =
 335                 findStatic("newCounter", methodType(int[].class, int[].class));
 336 
 337         private static MethodHandle[] initHashCode() {
 338             MethodHandle[] mhs = new MethodHandle[Wrapper.COUNT];
 339             for (Wrapper wrapper : Wrapper.values()) {
 340                 if (wrapper == Wrapper.VOID) continue;
 341                 Class<?> cls = wrapper == Wrapper.OBJECT ? Objects.class : wrapper.wrapperType();
 342                 mhs[wrapper.ordinal()] = findStatic(cls, "hashCode",
 343                                                     methodType(int.class, wrapper.primitiveType()));
 344             }
 345             return mhs;
 346         }
 347 
 348         private static MethodHandle findStatic(String name, MethodType methodType) {
 349             return findStatic(MethodHandleBuilder.class, name, methodType);
 350         }
 351         private static MethodHandle findStatic(Class<?> cls, String name, MethodType methodType) {
 352             try {
 353                 return JLIA.findStatic(cls, name, methodType);
 354             } catch (IllegalAccessException e) {
 355                 throw newLinkageError(e);
 356             }
 357         }
 358 
 359         /**
 360          * A "salt" value used for this internal hashcode implementation that
 361          * needs to vary sufficiently from one run to the next so that
 362          * the default hashcode for value classes will vary between JVM runs.
 363          */
 364         static final int SALT;
 365         static {
 366             long nt = System.nanoTime();
 367             int value = (int)((nt >>> 32) ^ nt);
 368             SALT = Integer.getInteger("value.bsm.salt", value);
 369         }
 370 
 371         static MethodHandleBuilder newBuilder(Class<?> type) {
 372             assert type.isValue();
 373 
 374             Deque<Class<?>> deque = new ArrayDeque<>();
 375             deque.add(type);
 376             Map<Class<?>, MethodHandleBuilder> visited = new HashMap<>();
 377             var builder = new MethodHandleBuilder(type, deque, visited);
 378             visited.put(type, builder);
 379             return builder;
 380         }
 381 
 382         enum Status {
 383             NOT_START,
 384             IN_PROGRESS,
 385             TRAVERSAL_DONE,
 386             READY
 387         }
 388 
 389         final Class<?> type;
 390         final List<Class<?>> fieldValueTypes;
 391         // a map of the type of a field T to a cycle of T -> ... -> V
 392         // where V is this builder's value type
 393         final Map<Class<?>, List<Class<?>>> cyclicMembers = new HashMap<>();
 394         // recursively-typed fields declared in this builder's value type
 395         final Set<Class<?>> recurFieldTypes = new HashSet<>();
 396         final Deque<Class<?>> path;
 397         final Map<Class<?>, MethodHandleBuilder> visited;;
 398         volatile Status status = Status.NOT_START;
 399         volatile MethodHandle equalsTarget;
 400         volatile MethodHandle hashCodeTarget;
 401 
 402         static final VarHandle STATUS_HANDLE;
 403         static {
 404             VarHandle vh = null;
 405             try {
 406                 vh = MethodHandles.lookup().findVarHandle(MethodHandleBuilder.class, "status", Status.class);
 407             } catch (ReflectiveOperationException e) {
 408                 throw new InternalError(e);
 409             }
 410             STATUS_HANDLE = vh;
 411         }
 412 
 413         /**
 414          * Constructs a new MethodHandleBuilder for the given value type.
 415          *
 416          * @param type a value class
 417          * @param path the graph traversal
 418          * @param visited a map of a visited type to a builder
 419          */
 420         private MethodHandleBuilder(Class<?> type, Deque<Class<?>> path, Map<Class<?>, MethodHandleBuilder> visited) {
 421             this.type = type;
 422             this.fieldValueTypes = valueTypeFields(type);
 423             this.path = path;
 424             this.visited = visited;
 425             if (VERBOSE) {
 426                 System.out.println("New builder for " + type.getName() + " " + path);
 427             }
 428         }
 429 
 430         /*
 431          * Returns a method handle that implements equals method for this builder's value class.
 432          */
 433         MethodHandle equalsTarget() {
 434             if (status != Status.READY)
 435                 throw new IllegalStateException(type.getName() + " not ready");
 436 
 437             var mh = equalsTarget;
 438             if (mh != null) return mh;
 439 
 440             generateMethodHandle();
 441             return equalsTarget;
 442         }
 443 
 444         /*
 445          * Returns a method handle that implements hashCode method for this builder's value class.
 446          */
 447         MethodHandle hashCodeTarget() {
 448             if (status != Status.READY)
 449                 throw new IllegalStateException(type.getName() + " not ready");
 450 
 451             var mh = hashCodeTarget;
 452             if (mh != null) return mh;
 453 
 454             generateMethodHandle();
 455             return hashCodeTarget;
 456         }
 457 
 458         /*
 459          * Build the graph for this builder's value type.  Detect all cycles.
 460          * This builder after this method returns is in DONE_TRAVERSAL or READY status.
 461          *
 462          * A builder for type V will change to READY status when the entire graph for V
 463          * is traversed (i.e. all builders in this graph are in DONE_TRAVERSAL or READY
 464          * status).
 465          */
 466         MethodHandleBuilder build() {
 467             if (status == Status.READY) return this;
 468 
 469             if (!STATUS_HANDLE.compareAndSet(this, Status.NOT_START, Status.IN_PROGRESS)) {
 470                 throw new RuntimeException(type.getName() + " in progress");
 471             }
 472 
 473             // traverse the graph and find all cycles
 474             detectCycles();
 475 
 476             if (!STATUS_HANDLE.compareAndSet(this, Status.IN_PROGRESS, Status.TRAVERSAL_DONE)) {
 477                 throw new RuntimeException(type.getName() + " failed to set done traversal. " + status);
 478             }
 479 
 480             // Check if this node V is ready for building equals/hashCode method handles.
 481             // V is ready if the types of all its fields are done traversal.
 482             if (ready()) {
 483                 // Do a pass on all the cycles containing V.  V is ready.
 484                 // If a node N in the cycle has completed the traversal (i.e. cycles are detected),
 485                 // call ready() on N to update its status if ready.
 486                 for (List<Class<?>> cycle : cyclicMembers.values()) {
 487                     cycle.stream().filter(c -> c != type)
 488                                   .map(visited::get)
 489                                   .filter(b -> b.status == Status.TRAVERSAL_DONE)
 490                                   .forEach(MethodHandleBuilder::ready);
 491                 }
 492             }
 493             return this;
 494         }
 495 
 496         /*
 497          * Traverses the graph and finds all cycles.
 498          */
 499         private void detectCycles() {
 500             LinkedList<Class<?>> deque = new LinkedList<>();
 501             deque.addAll(fieldValueTypes);
 502             while (!deque.isEmpty()) {
 503                 Class<?> n = deque.pop();
 504                 // detect cyclic membership
 505                 if (path.contains(n)) {
 506                     List<Class<?>> cycle = new ArrayList<>();
 507                     Iterator<Class<?>> iter = path.iterator();
 508                     while (iter.hasNext()) {
 509                         Class<?> c = iter.next();
 510                         cycle.add(c);
 511                         if (c == n) break;
 512                     }
 513                     cyclicMembers.put(n, cycle);
 514                     path.pop();
 515                     continue;
 516                 }
 517 
 518                 try {
 519                     path.push(n);
 520                     if (!visited.containsKey(n)) {
 521                         // Duplicate the path and pass it to an unvisited node
 522                         Deque<Class<?>> newPath = new ArrayDeque<>();
 523                         newPath.addAll(path);
 524                         visited.computeIfAbsent(n, c -> new MethodHandleBuilder(n, newPath, visited));
 525                     }
 526 
 527                     var builder = visited.get(n);
 528                     switch (builder.status) {
 529                         case NOT_START -> builder.build();
 530                         case TRAVERSAL_DONE -> builder.ready();
 531                     }
 532                 } finally {
 533                     path.pop();
 534                 }
 535             }
 536 
 537             // propagate the cycles to the recursively-typed value classes
 538             // For each cycle A -> B -> C -> A, the cycle is recorded in all
 539             // the nodes (A, B, and C) in this cycle.
 540             for (Map.Entry<Class<?>, List<Class<?>>> e : cyclicMembers.entrySet()) {
 541                 Class<?> c = e.getKey();
 542                 List<Class<?>> cycle = e.getValue();
 543                 var builder = visited.get(c);
 544                 for (Class<?> ft : cycle) {
 545                     if (ft != c && builder.fieldValueTypes.contains(ft)) {
 546                         var v = builder.cyclicMembers.put(ft, cycle);
 547                         assert v == null || cycle.equals(v) : "mismatched cycle: " + v + " vs " + cycle;
 548                     }
 549                 }
 550             }
 551         }
 552 
 553         /*
 554          * Tests if this builder is ready for generating equals and hashCode
 555          * method handles for the value class.
 556          *
 557          * This builder is ready if and only if the type graph of all its fields
 558          * are traversed and all cycles are detected.
 559          *
 560          * Before setting to READY, the recursively-typed fields are recorded
 561          * that includes all types in the cycles and the field types which
 562          * references recursive types
 563          */
 564         private boolean ready() {
 565             if (status == Status.READY) return true;
 566 
 567             boolean inProgress = fieldValueTypes.stream().map(visited::get)
 568                                                 .anyMatch(b -> b.status == Status.IN_PROGRESS);
 569             if (inProgress)
 570                 return false;
 571 
 572             // collect the recursively-typed value classes required by this method handle
 573             // all types in the cycles and the field types which references recursive types
 574             recurFieldTypes.addAll(cyclicMembers.keySet());
 575             for (Class<?> c : fieldValueTypes) {
 576                 if (c == type) continue;
 577 
 578                 // if this field type references a recursive type
 579                 var b = visited.get(c);
 580                 if (b.cyclicMembers.size() > 0 || b.recurFieldTypes.size() > 0)
 581                     recurFieldTypes.add(c);
 582             };
 583 
 584             // Finished recording recursively-typed fields.  Set to READY.
 585             if (!STATUS_HANDLE.compareAndSet(this, Status.TRAVERSAL_DONE, Status.READY)) {
 586                 throw new RuntimeException(type.getName() + " failed to set READY. " + status);
 587             }
 588             return true;
 589         }
 590 
 591         void generateMethodHandle() {
 592             if (status != Status.READY)
 593                 throw new IllegalStateException(type.getName() + " not ready");
 594 
 595             // non-recursive value type
 596             if (recurFieldTypes.isEmpty()) {
 597                 if (cyclicMembers.size() > 0)
 598                     throw new RuntimeException(type.getName() + " should not reach here");
 599 
 600                 this.equalsTarget = valueTypeEquals(type, getterStream(type, TYPE_SORTER).toList());
 601                 this.hashCodeTarget = valueTypeHashCode(type, getterStream(type, null).toList());
 602                 return;
 603             }
 604 
 605             if (VERBOSE) {
 606                 System.out.println(debugString());
 607             }
 608 
 609             // generate the base function for each recursive type
 610             // boolean base1(MethodHandle entry, MethodHandle base1, MethodHandle base2,....., Object o1, Object o2, int[] counter)
 611             // :
 612             // boolean baseN(MethodHandle entry, MethodHandle base1, MethodHandle base2,....., Object o1, Object o2, int[] counter)
 613             //
 614             List<Class<?>> recursiveTypes = aggregateRecursiveTypes();
 615             Map<Class<?>, MethodHandle> bases = new LinkedHashMap<>();
 616             Map<Class<?>, MethodHandle> hashCodeBases = new LinkedHashMap<>();
 617             for (Class<?> c : recursiveTypes) {
 618                 bases.put(c, visited.get(c).generateSubstBase(recursiveTypes));
 619                 hashCodeBases.put(c, visited.get(c).generateHashCodeBase(recursiveTypes));
 620             }
 621 
 622             var handles = bases.values().stream().toArray(MethodHandle[]::new);
 623             var hashCodeHandles = hashCodeBases.values().stream().toArray(MethodHandle[]::new);
 624 
 625             // The entry point for equals for this value type T looks like this:
 626             //
 627             // boolean entry(MethodHandle entry, MethodHandle base1, MethodHandle base2,....., Object o1, Object o2, int[] counter) {
 628             //    int[] newCounter = new int[] { counter[0] } ;
 629             //    return baseT(o1, o2, newCounter);
 630             // }
 631             this.equalsTarget = newValueEquals(recursiveTypes, handles);
 632             this.hashCodeTarget = newValueHashCode(recursiveTypes, hashCodeHandles);
 633 
 634             // Precompute the method handles for all recursive data types in the cycles
 635             // They share the generated base method handles.
 636             var cycles = cyclicMembers.values().stream().flatMap(List::stream)
 637                                 .filter(c -> c != type)
 638                                 .collect(toMap(Function.identity(), visited::get));
 639             for (Class<?> n : cycles.keySet()) {
 640                 var builder = cycles.get(n);
 641                 if (builder.status != Status.READY) {
 642                     throw new InternalError(type.getName() + " is not ready: " + status);
 643                 }
 644 
 645                 var mh = builder.equalsTarget;
 646                 var mh2 = builder.hashCodeTarget;
 647                 if (mh != null && mh2 != null) {
 648                     continue;
 649                 }
 650 
 651                 // precompute the method handles for each recursive type in the cycle
 652                 if (mh == null) {
 653                     builder.equalsTarget = builder.newValueEquals(recursiveTypes, handles);
 654                 }
 655                 if (mh2 == null) {
 656                     builder.hashCodeTarget = builder.newValueHashCode(recursiveTypes, hashCodeHandles);
 657                 }
 658             }
 659 
 660             // cache the builders with precomputed method handles in the cache
 661             synchronized (CACHED_METHOD_HANDLE_BUILDERS) {
 662                 for (Class<?> n : cycles.keySet()) {
 663                     try {
 664                         // the builder is added to the builder cache and propapate to
 665                         // the class value
 666                         CACHED_METHOD_HANDLE_BUILDERS.computeIfAbsent(n, cycles::get);
 667                         METHOD_HANDLE_BUILDERS.get(n);
 668                     } finally {
 669                         // Remove it from the builder cache once it's in class value
 670                         CACHED_METHOD_HANDLE_BUILDERS.remove(n);
 671                     }
 672                 }
 673             }
 674 
 675             // equals and hashCode are generated.  Clear the path and visited builders.
 676             clear();
 677         }
 678 
 679         private void clear() {
 680             path.clear();
 681             visited.clear();
 682         }
 683 
 684         /*
 685          * Aggregates all recursive data types for this builder's value types.
 686          * The result is used in generating a recursive method handle
 687          * for this builder's value type.
 688          *
 689          * A graph of V:
 690          * V -> P -> V
 691          *   -> N -> N (self-recursive)
 692          *   -> E -> F -> E
 693          *
 694          * V, P, N, E, F are the mutual recursive types for V. The recursive method handle
 695          * for V is created with the base functions for V, P, N, E, F and it can mutually
 696          * call the recursive method handle for these types.  Specifically, MH_V calls
 697          * MH_P which calls MH_V, MH_N which calls itself, and MH_E which calls MH_F.
 698          */
 699         private List<Class<?>> aggregateRecursiveTypes() {
 700             boolean ready = true;
 701             for (List<Class<?>> cycle : cyclicMembers.values()) {
 702                 // ensure all nodes in all cycles that are done traversal and ready for
 703                 // method handle generation
 704                 cycle.stream().filter(c -> c != type)
 705                               .map(visited::get)
 706                               .filter(b -> b.status == Status.TRAVERSAL_DONE)
 707                               .forEach(MethodHandleBuilder::ready);
 708 
 709                 // check the status
 710                 ready = ready && cycle.stream().filter(c -> c != type)
 711                                       .map(visited::get)
 712                                       .allMatch(b -> b.status == Status.READY);
 713             }
 714 
 715             if (!ready) {
 716                 throw new IllegalStateException(type.getName() + " " + status);
 717             }
 718 
 719             /*
 720              * Traverse the graph for V to find all mutual recursive types for V.
 721              *
 722              * Node T is a mutual recursive type for V if any of the following:
 723              * 1. T is a recursively-typed field in V
 724              * 2. T is a type involved the cycles from V ... -> T ... -> V
 725              * 3. T is a mutual recursive type for N where N is a mutual recursive type for V.
 726              */
 727             Deque<Class<?>> deque = new ArrayDeque<>();
 728             List<Class<?>> recurTypes = new ArrayList<>();
 729             recurTypes.add(type);
 730             Stream.concat(recurFieldTypes.stream(),
 731                           cyclicMembers.values().stream().flatMap(List::stream))
 732                   .filter(Predicate.not(deque::contains)).forEach(deque::add);
 733             while (!deque.isEmpty()) {
 734                 Class<?> c = deque.pop();
 735                 if (recurTypes.contains(c)) continue;
 736 
 737                 recurTypes.add(c);
 738 
 739                 var builder = visited.get(c);
 740                 Stream.concat(builder.recurFieldTypes.stream(),
 741                               builder.cyclicMembers.values().stream().flatMap(List::stream))
 742                       .filter(n -> !recurTypes.contains(n) && !deque.contains(n))
 743                       .forEach(deque::push);
 744             }
 745             return recurTypes;
 746         }
 747 
 748         /*
 749          * Create a new method handle that implements equals(T, Object) for value class T
 750          * for this builder using the given base method handles.  The return method handle
 751          * is capable of recursively calling itself for value class T whose entry point:
 752          *   boolean entry(MethodHandle entry, MethodHandle base1, MethodHandle base2, ..., Object o1, Object o2, int[] counter) {
 753          *       int[] newCounter = new int[] { counter[0] };
 754          *       return baseT(o1, o2, newCounter);
 755          *   }
 756          *
 757          * The counter is used to keep of node visits and throw StackOverflowError
 758          * if the counter gets "unreasonably" large of a cyclic value graph
 759          * (regardless of how many real stack frames were consumed.)
 760          */
 761         MethodHandle newValueEquals(List<Class<?>> recursiveTypes, MethodHandle[] bases) {
 762             var entry = equalsEntry(recursiveTypes);
 763             var mh = MethodHandles.insertArguments(recursive(entry, bases), 2, new int[] {MAX_NODE_VISITS});
 764             return mh.asType(methodType(boolean.class, type, type));
 765         }
 766 
 767         /*
 768          * Create a new method handle that implements hashCode(T) for value class T
 769          * for this builder using the given base method handles.  The return method handle
 770          * is capable of recursively calling itself for value class T whose entry point:
 771          *   boolean entry(MethodHandle entry, MethodHandle base1, MethodHandle base2, ..., Object o, int[] counter) {
 772          *       int[] newCounter = new int[] { counter[0] };
 773          *       return baseT(o, newCounter);
 774          *   }
 775          *
 776          * The counter is used to keep of node visits and throw StackOverflowError
 777          * if the counter gets "unreasonably" large of a cyclic value graph
 778          * (regardless of how many real stack frames were consumed.)
 779          */
 780         MethodHandle newValueHashCode(List<Class<?>> recursiveTypes, MethodHandle[] bases) {
 781             var entry = hashCodeEntry(recursiveTypes);
 782             var mh = MethodHandles.insertArguments(recursive(entry, bases), 1, new int[] {MAX_NODE_VISITS});
 783             return mh.asType(methodType(int.class, type));
 784         }
 785 
 786         /*
 787          * Create a method handle where the first N+1 parameters are MethodHandle and
 788          * N is the number of the recursive value types and followed with
 789          * Object, Object and int[] parameters.  The pseudo code looks like this:
 790          *
 791          * boolean eq(MethodHandle entry, MethodHandle base1, MethodHandle base2, ..., Object o1, Object o2, int[] counter) {
 792          *    if (o1 == null && o2 == null) return true;
 793          *    if (o1 == null || o2 == null) return false;
 794          *    if (o1.getClass() != o2. getClass()) return false;
 795          *
 796          *    int[] newCounter = new int[] { counter[0]; }
 797          *    return (boolean) baseT.invoke(o1, o2, newCounter);
 798          * }
 799          */
 800         MethodHandle equalsEntry(List<Class<?>> recursiveTypes) {
 801             List<Class<?>> leadingMHParams = new ArrayList<>();
 802             // the first MethodHandle parameter is this entry point
 803             // followed with MethodHandle parameter for each mutual exclusive value class
 804             int mhParamCount = recursiveTypes.size()+1;
 805             for (int i=0; i < mhParamCount; i++) {
 806                 leadingMHParams.add(MethodHandle.class);
 807             }
 808 
 809             MethodType mt = methodType(boolean.class, Stream.concat(leadingMHParams.stream(), Stream.of(type, type, int[].class))
 810                     .collect(toList()));
 811             var allParameters = mt.parameterList();
 812             MethodHandle instanceTrue = dropArguments(TRUE, 0, allParameters).asType(mt);
 813             MethodHandle instanceFalse = dropArguments(FALSE, 0, allParameters).asType(mt);
 814             MethodHandle isNull = dropArguments(dropArguments(IS_NULL, 0, leadingMHParams), mhParamCount+2, int[].class).asType(mt);
 815             MethodHandle isSameValueType = dropArguments(dropArguments(IS_SAME_VALUE_CLASS, 0, leadingMHParams), mhParamCount+2, int[].class).asType(mt);
 816 
 817             int index = recursiveTypes.indexOf(type);
 818             var mtype = methodType(boolean.class, Stream.concat(leadingMHParams.stream(), Stream.of(type, type, int[].class)).collect(toList()));
 819             var recurEq = RECUR_VALUE_EQ.asType(methodType(boolean.class, MethodHandle.class, type, type, int[].class));
 820             var eq = permuteArguments(recurEq, mtype, index+1, mhParamCount, mhParamCount+1, mhParamCount+2);
 821             eq = filterArguments(eq, mhParamCount+2, NEW_COUNTER);
 822 
 823             // if both arguments are null, return true;
 824             // otherwise return the method handle corresponding to this type
 825             return guardWithTest(isNull,
 826                                  instanceTrue,
 827                                  guardWithTest(isSameValueType, eq, instanceFalse));
 828         }
 829 
 830         /*
 831          * A base method for substitutability test for a recursive data type,
 832          * a value class with cyclic membership.
 833          *
 834          * The signature of this base method is:
 835          *    boolean base(MethodHandle entry, MethodHandle base1, MethodHandle base2, ..., V o1, V o2, int[] counter)
 836          *
 837          * where the first N+1 parameters are MethodHandle and N is the number of
 838          * the recursive value types and followed with Object, Object and int[] parameters.
 839          *
 840          * This method first calls the method handle that tests the substitutability
 841          * of all fields that are not recursively-typed, if any, and then test
 842          * the substitutability of the fields that are of each recursive value type.
 843          * The pseudo code looks like this:
 844          *
 845          * boolean base(MethodHandle entry, MethodHandle base1, MethodHandle base2, ..., V o1, V o2, int[] counter) {
 846          *    if (o1 == null && o2 == null) return true;
 847          *    if (o1 == null || o2 == null) return false;
 848          *    if (o1.getClass() != o2. getClass()) return false;
 849          *
 850          *    for each non-recursively-typed field {
 851          *        if (field value of o1 != field value of o2) return false;
 852          *    }
 853          *
 854          *    for each recursively-typed field of type T {
 855          *        if (--counter[0] == 0) throw new StackOverflowError();
 856          *        // baseT is the method handle corresponding to the recursive type T
 857          *        boolean rc = (boolean) baseT.invoke(o1, o2, counter);
 858          *        if (!rc) return false;
 859          *    }
 860          *    return true;
 861          * }
 862          */
 863         MethodHandle generateSubstBase(List<Class<?>> recursiveTypes) {
 864             List<MethodHandle> nonRecurGetters = new ArrayList<>();
 865             Map<Class<?>, List<MethodHandle>> recurGetters = new LinkedHashMap<>();
 866             getterStream(type, TYPE_SORTER).forEach(mh -> {
 867                 Class<?> ft = fieldType(mh);
 868                 if (!this.recurFieldTypes.contains(ft)) {
 869                     nonRecurGetters.add(mh);
 870                 } else {
 871                     assert recursiveTypes.contains(ft);
 872                     recurGetters.computeIfAbsent(ft, t -> new ArrayList<>()).add(mh);
 873                 }
 874             });
 875 
 876             // The first parameter is the method handle of the entry point
 877             // followed with one MethodHandle for each recursive value type
 878             List<Class<?>> leadingMHParams = new ArrayList<>();
 879             int mhParamCount = recursiveTypes.size()+1;
 880             for (int i=0; i < mhParamCount; i++) {
 881                 leadingMHParams.add(MethodHandle.class);
 882             }
 883 
 884             MethodType mt = methodType(boolean.class,
 885                                        Stream.concat(leadingMHParams.stream(), Stream.of(type, type, int[].class)).collect(toList()));
 886             var allParameters = mt.parameterList();
 887 
 888             var instanceTrue = dropArguments(TRUE, 0, allParameters).asType(mt);
 889             var instanceFalse = dropArguments(FALSE, 0, allParameters).asType(mt);
 890             var accumulator = dropArguments(TRUE, 0, allParameters).asType(mt);
 891             var isNull = dropArguments(dropArguments(IS_NULL, 0, leadingMHParams), mhParamCount+2, int[].class).asType(mt);
 892             var isSameValueType = dropArguments(dropArguments(IS_SAME_VALUE_CLASS, 0, leadingMHParams), mhParamCount+2, int[].class).asType(mt);
 893 
 894             // This value class contains cyclic membership.
 895             // Create a method handle that first calls the method handle that tests
 896             // the substitutability of all fields that are not recursively-typed, if any,
 897             // and then test the substitutability of the fields that are of each recursive
 898             // value type.
 899             //
 900             // Method handle for the substitutability test for recursive types is built
 901             // before that for non-recursive types.
 902             for (Map.Entry<Class<?>, List<MethodHandle>> e : recurGetters.entrySet()) {
 903                 Class<?> ft = e.getKey();
 904                 int index = recursiveTypes.indexOf(ft);
 905                 var mtype = methodType(boolean.class,
 906                                 Stream.concat(leadingMHParams.stream(), Stream.of(ft, ft, int[].class)).collect(toList()));
 907                 var recurEq = RECUR_VALUE_EQ.asType(methodType(boolean.class, MethodHandle.class, ft, ft, int[].class));
 908                 var eq = permuteArguments(recurEq, mtype, index+1, mhParamCount, mhParamCount+1, mhParamCount+2);
 909                 for (MethodHandle getter : e.getValue()) {
 910                     assert ft == fieldType(getter);
 911                     var thisFieldEqual = filterArguments(eq, mhParamCount, getter, getter);
 912                     accumulator = guardWithTest(thisFieldEqual, accumulator, instanceFalse);
 913                 }
 914             }
 915 
 916             if (nonRecurGetters.isEmpty()) {
 917                 // if both arguments are null, return true;
 918                 // otherwise return accumulator;
 919                 return guardWithTest(isNull,
 920                                      instanceTrue,
 921                                      guardWithTest(isSameValueType, accumulator, instanceFalse));
 922             } else {
 923                 // method handle for substitutability test of the non-recursive-typed fields
 924                 var mh = valueTypeEquals(type, nonRecurGetters);
 925                 mh = dropArguments(dropArguments(mh, 0, leadingMHParams), mhParamCount+2, int[].class).asType(mt);
 926                 return guardWithTest(mh, accumulator, instanceFalse);
 927             }
 928         }
 929 
 930         /*
 931          * Create a method handle where the first N+1 parameters are MethodHandle and
 932          * N is the number of the recursive value types and followed with
 933          * Object and int[] parameters.  The pseudo code looks like this:
 934          *
 935          * int hashCode(MethodHandle entry, MethodHandle base1, MethodHandle base2, ..., Object o, int[] counter) {
 936          *    int[] newCounter = new int[] { counter[0]; }
 937          *    return (int) baseT.invoke(o, newCounter);
 938          * }
 939          */
 940         MethodHandle hashCodeEntry(List<Class<?>> recursiveTypes) {
 941             List<Class<?>> leadingMHParams = new ArrayList<>();
 942             int mhParamCount = recursiveTypes.size()+1;
 943             // the first MethodHandle parameter is this entry point
 944             // followed with MethodHandle parameter for each mutual exclusive value class
 945             for (int i=0; i < mhParamCount; i++) {
 946                 leadingMHParams.add(MethodHandle.class);
 947             }
 948 
 949             int index = recursiveTypes.indexOf(type);
 950             var mtype = methodType(int.class, Stream.concat(leadingMHParams.stream(), Stream.of(type, int[].class)).collect(toList()));
 951             var recurHashCode = RECUR_VALUE_HASHCODE.asType(methodType(int.class, MethodHandle.class, type, int[].class));
 952             var mh = permuteArguments(recurHashCode, mtype, index+1, mhParamCount, mhParamCount+1);
 953             return filterArguments(mh, mhParamCount+1, NEW_COUNTER);
 954         }
 955 
 956         /**
 957          * A base method for computing the hashcode for a recursive data type,
 958          * a value class with cyclic membership.
 959          *
 960          * The signature of this base method is:
 961          *    int base(MethodHandle entry, MethodHandle base1, MethodHandle base2, ..., V o, int[] counter)
 962          *
 963          * where the first N+1 parameters are MethodHandle and N is the number of
 964          * the recursive value types and followed with Object and int[] parameters.
 965          *
 966          * This method will first invoke a method handle to compute the hash code
 967          * of the not recursively-typed fields.  Then compute the hash code of the
 968          * remaining recursively-typed fields.
 969          */
 970         MethodHandle generateHashCodeBase(List<Class<?>> recursiveTypes) {
 971             assert status == Status.READY;
 972 
 973             List<MethodHandle> nonRecurGetters = new ArrayList<>();
 974             Map<Class<?>, List<MethodHandle>> recurGetters = new LinkedHashMap<>();
 975             getterStream(type, null).forEach(mh -> {
 976                 Class<?> ft = fieldType(mh);
 977                 if (!this.recurFieldTypes.contains(ft)) {
 978                     nonRecurGetters.add(mh);
 979                 } else {
 980                     assert recursiveTypes.contains(ft);
 981                     recurGetters.computeIfAbsent(ft, t -> new ArrayList<>()).add(mh);
 982                 }
 983             });
 984 
 985             int mhParamCount = recursiveTypes.size()+1;
 986             List<Class<?>> leadingMHParams = new ArrayList<>();
 987             for (int i=0; i < mhParamCount; i++) {    // include entry point
 988                 leadingMHParams.add(MethodHandle.class);
 989             }
 990 
 991             MethodType mt = methodType(int.class,
 992                                        Stream.concat(leadingMHParams.stream(), Stream.of(type, int[].class)).collect(toList()));
 993             var allParameters = mt.parameterList();
 994             var hashCombiner = dropArguments(HASH_COMBINER, 2, allParameters);
 995             var salt = dropArguments(constant(int.class, SALT), 0, allParameters);
 996             var classHasher = dropArguments(hashCodeForType(Class.class).bindTo(type), 0, allParameters);
 997             var accumulator = foldArguments(foldArguments(hashCombiner, 1, classHasher), 0, salt);
 998             for (MethodHandle getter : nonRecurGetters) {
 999                 Class<?> ft = fieldType(getter);
1000                 var hasher = dropArguments(hashCodeForType(ft), 0, leadingMHParams);
1001                 var hashThisField = filterArguments(hasher, mhParamCount, getter);
1002                 var combineHashes = foldArguments(hashCombiner, 1, hashThisField);
1003                 accumulator = foldArguments(combineHashes, 0, accumulator);
1004             }
1005 
1006             for (Map.Entry<Class<?>, List<MethodHandle>> e : recurGetters.entrySet()) {
1007                 Class<?> ft = e.getKey();
1008                 int index = recursiveTypes.indexOf(ft);
1009                 var mtype = methodType(int.class, Stream.concat(leadingMHParams.stream(), Stream.of(ft, int[].class)).collect(toList()));
1010                 var recurHashCode = RECUR_VALUE_HASHCODE.asType(methodType(int.class, MethodHandle.class, ft, int[].class));
1011                 var hasher = permuteArguments(recurHashCode, mtype, index + 1, mhParamCount, mhParamCount + 1);
1012                 for (MethodHandle getter : e.getValue()) {
1013                     assert ft == fieldType(getter);
1014                     var hashThisField = filterArguments(hasher, mhParamCount, getter);
1015                     var combineHashes = foldArguments(hashCombiner, 1, hashThisField);
1016                     accumulator = foldArguments(combineHashes, 0, accumulator);
1017                 }
1018             }
1019             return accumulator;
1020         }
1021 
1022         private String debugString() {
1023             StringBuilder sb = new StringBuilder();
1024             sb.append(type.getName()).append(" ").append(status).append("\n");
1025             sb.append(fieldValueTypes.stream().filter(c -> !recurFieldTypes.contains(c))
1026                             .map(Class::getName)
1027                             .collect(joining(" ", "  non-recursive types: ", "\n")));
1028             sb.append(recurFieldTypes.stream().map(Class::getName)
1029                             .collect(joining(" ", "  recursive types: ", "\n")));
1030             for (var n : cyclicMembers.keySet()) {
1031                 List<Class<?>> cycle = cyclicMembers.get(n);
1032                 sb.append("  cycle: ");
1033                 int start = cycle.indexOf(n);
1034                 for (int i=start; i < cycle.size(); i++ ) {
1035                     sb.append(cycle.get(i).getName()).append(" -> ");
1036                 }
1037                 for (int i=0; i < start; i++) {
1038                     sb.append(cycle.get(i).getName()).append(" -> ");
1039                 }
1040                 sb.append(n.getName()).append("\n");
1041             };
1042             return sb.toString();
1043         }
1044     }
1045 
1046     private static LinkageError newLinkageError(Throwable e) {
1047         return (LinkageError) new LinkageError().initCause(e);
1048     }
1049 
1050     /**
1051      * Returns {@code true} if the arguments are <em>substitutable</em> to each
1052      * other and {@code false} otherwise.
1053      * <em>Substitutability</em> means that they cannot be distinguished from
1054      * each other in any data-dependent way, meaning that it is safe to substitute
1055      * one for the other.
1056      *
1057      * <ul>
1058      * <li>If {@code a} and {@code b} are both {@code null}, this method returns
1059      *     {@code true}.
1060      * <li>If {@code a} and {@code b} are both instances of the same value class
1061      *     {@code V}, this method returns {@code true} if, for all fields {@code f}
1062      *      declared in {@code V}, {@code a.f} and {@code b.f} are substitutable.
1063      * <li>If {@code a} and {@code b} are both values of the same builtin primitive type,
1064      *     this method returns {@code a == b} with the following exception:
1065      *     <ul>
1066      *     <li> For primitive types {@code float} and {@code double} the
1067      *          comparison uses the raw bits corresponding to {@link Float#floatToRawIntBits(float)}
1068      *          and {@link Double#doubleToRawLongBits(double)} respectively.
1069      *     </ul>
1070      * <li>If {@code a} and {@code b} are both instances of the same reference type,
1071      *     this method returns {@code a == b}.
1072      * <li>Otherwise this method returns {@code false}.
1073      * </ul>
1074      *
1075      * <p>For example,
1076      * <pre>{@code interface Number { ... }
1077      * // ordinary reference class
1078      * class IntNumber implements Number { ... }
1079      * // value class
1080      * value class IntValue implements Number {
1081      *     int i;
1082      *     :
1083      *     public static IntValue of(int i) {...}     // IntValue::of creates a new value instance
1084      * }
1085      * // value class with an Object field
1086      * value class RefValue {
1087      *     Object o;
1088      *     :
1089      * }
1090      *
1091      * var val1 = IntValue.of(10);
1092      * var val2 = IntValue.of(10);                    // val1 and val2 have the same value
1093      * var ref1 = new IntNumber(10);                  // ref1 and ref2 are two reference instances
1094      * var ref2 = new IntNumber(10);
1095      * assertTrue(isSubstitutable(val1, val2));       // val1 and val2 are both value instances of IntValue
1096      * assertFalse(isSubstitutable(ref1, ref2));      // ref1 and ref2 are two reference instances that are not substitutable
1097      * assertTrue(isSubstitutable(ref1, ref1));       // a reference instance is substitutable with itself
1098      *
1099      * var rval1 = RefValue.of(List.of("list"));      // rval1.o and rval2.o both contain a list of one-single element "list"
1100      * var rval2 = RefValue.of(List.of("list");
1101      * var rval3 = RefValue.of(rval1.o);
1102      *
1103      * assertFalse(isSubstitutable(rval1, rval2));    // rval1.o and rval2.o are two different List instances and hence not substitutable
1104      * assertTrue(isSubstitutable(rval1, rval3 ));    // rval1.o and rval3.o are the same reference instance
1105      * }</pre>
1106      *
1107      * @param a an object
1108      * @param b an object to be compared with {@code a} for substitutability
1109      * @return {@code true} if the arguments are substitutable to each other;
1110      *         {@code false} otherwise.
1111      * @param <T> type
1112      * @see Float#floatToRawIntBits(float)
1113      * @see Double#doubleToRawLongBits(double)
1114      */
1115     private static <T> boolean isSubstitutable(T a, Object b) {
1116         if (VERBOSE) {
1117             System.out.println("substitutable " + a.getClass() + ": " + a + " vs " + b);
1118         }
1119 
1120         // Called directly from the VM.
1121         //
1122         // DO NOT use "==" or "!=" on args "a" and "b", with this code or any of
1123         // its callees. Could be inside of if_acmp<eq|ne> bytecode implementation.
1124 
1125         if (a == null && b == null) return true;
1126         if (a == null || b == null) return false;
1127         if (a.getClass() != b.getClass()) return false;
1128 
1129         try {
1130             Class<?> type = a.getClass();
1131             return (boolean) substitutableInvoker(type).invoke(a, b);
1132         } catch (Error|RuntimeException e) {
1133             if (VERBOSE) e.printStackTrace();
1134             throw e;
1135         } catch (Throwable e) {
1136             if (VERBOSE) e.printStackTrace();
1137             throw new InternalError(e);
1138         }
1139     }
1140 
1141     /**
1142      * Produces a method handle which tests if two arguments are
1143      * {@linkplain #isSubstitutable(Object, Object) substitutable}.
1144      *
1145      * <ul>
1146      * <li>If {@code T} is a non-floating point primitive type, this method
1147      *     returns a method handle testing the two arguments are the same value,
1148      *     i.e. {@code a == b}.
1149      * <li>If {@code T} is {@code float} or {@code double}, this method
1150      *     returns a method handle representing {@link Float#floatToRawIntBits(float)} or
1151      *     {@link Double#doubleToRawLongBits(double)} respectively.
1152      * <li>If {@code T} is a reference type that is not {@code Object} and not an
1153      *     interface, this method returns a method handle testing
1154      *     the two arguments are the same reference, i.e. {@code a == b}.
1155      * <li>If {@code T} is a value class, this method returns
1156      *     a method handle that returns {@code true} if
1157      *     for all fields {@code f} declared in {@code T}, where {@code U} is
1158      *     the type of {@code f}, if {@code a.f} and {@code b.f} are substitutable
1159      *     with respect to {@code U}.
1160      * <li>If {@code T} is an interface or {@code Object}, and
1161      *     {@code a} and {@code b} are of the same value class {@code V},
1162      *     this method returns a method handle that returns {@code true} if
1163      *     {@code a} and {@code b} are substitutable with respect to {@code V}.
1164      * </ul>
1165      *
1166      * @param type class type
1167      * @param <T> type
1168      * @return a method handle for substitutability test
1169      */
1170     private static <T> MethodHandle substitutableInvoker(Class<T> type) {
1171         if (type.isPrimitive()) {
1172             return MethodHandleBuilder.builtinPrimitiveSubstitutable(type);
1173         }
1174         if (type.isValue()) {
1175             return SUBST_TEST_METHOD_HANDLES.get(type);
1176         }
1177         return MethodHandleBuilder.referenceTypeEquals(type);
1178     }
1179 
1180     private static final ClassValue<MethodHandleBuilder> METHOD_HANDLE_BUILDERS = new ClassValue<>() {
1181         @Override protected MethodHandleBuilder computeValue(Class<?> type) {
1182             var builder = CACHED_METHOD_HANDLE_BUILDERS.get(type);
1183             if (builder == null) {
1184                 builder = MethodHandleBuilder.newBuilder(type).build();
1185             }
1186             return builder;
1187         }
1188     };
1189 
1190     // This cache is only used to propagate the builders of mutual recursive types
1191     // A -> B -> C -> A as method handles for equals/hashCode for A, B, C are
1192     // all precomputed.  This map should only be non-empty only during the short
1193     // window propagating to the method handle builder class value.
1194     private static Map<Class<?>, MethodHandleBuilder> CACHED_METHOD_HANDLE_BUILDERS = new ConcurrentHashMap<>();
1195 
1196     // store the method handle for value classes in ClassValue
1197     private static final ClassValue<MethodHandle> SUBST_TEST_METHOD_HANDLES = new ClassValue<>() {
1198         @Override protected MethodHandle computeValue(Class<?> type) {
1199             return MethodHandleBuilder.valueTypeEquals(type);
1200         }
1201     };
1202 
1203     /**
1204      * Invoke the hashCode method for the given value object.
1205      * @param o the instance to hash.
1206      * @return the hash code of the given value object.
1207      */
1208     private static int valueObjectHashCode(Object o) {
1209         Class<?> type = o.getClass();
1210         try {
1211             // Note: javac disallows user to call super.hashCode if user implemented
1212             // risk for recursion for experts crafting byte-code
1213             if (!type.isValue())
1214                 throw new InternalError("must be value class: " + type.getName());
1215 
1216             return (int) HASHCODE_METHOD_HANDLES.get(type).invoke(o);
1217         } catch (Error|RuntimeException e) {
1218             throw e;
1219         } catch (Throwable e) {
1220             if (VERBOSE) e.printStackTrace();
1221             throw new InternalError(e);
1222         }
1223     }
1224 
1225     private static final ClassValue<MethodHandle> HASHCODE_METHOD_HANDLES = new ClassValue<>() {
1226         @Override protected MethodHandle computeValue(Class<?> type) {
1227             return MethodHandleBuilder.valueTypeHashCode(type);
1228         }
1229     };
1230 
1231     private static final Comparator<MethodHandle> TYPE_SORTER = (mh1, mh2) -> {
1232         // sort the getters with the return type
1233         Class<?> t1 = mh1.type().returnType();
1234         Class<?> t2 = mh2.type().returnType();
1235         if (t1 == t2) return 0;
1236 
1237         if (t1.isPrimitive()) {
1238             if (!t2.isPrimitive()) {
1239                 return 1;
1240             }
1241         } else {
1242             if (t2.isPrimitive()) {
1243                 return -1;
1244             }
1245         }
1246         return -1;
1247     };
1248 
1249 
1250     /**
1251      * Constructs a method handle that is capable of recursively
1252      * calling itself, whose behavior is determined by a non-recursive
1253      * base method handle which gets both the original arguments and a
1254      * reference to the recursive method handle.
1255      * <p>
1256      * Here is pseudocode for the resulting loop handle, plus a sketch
1257      * of the behavior of the base function. The symbols {@code A},
1258      * {@code a}, and {@code R} represent arguments and return value
1259      * for both the recursive function and the base function.
1260      *
1261      * <blockquote><pre>{@code
1262      * R recursive(A... a) {
1263      *   MethodHandle recur = &recursive;
1264      *   return base(recur, a...);
1265      * }
1266      * R base(MethodHandle recur, A... a) {
1267      *   ... if (no recursion)  return f(a);  ...
1268      *   var r2 = recur.invokeExact(a2...);
1269      *   var r3 = recur.invokeExact(a3...);
1270      *   ... do stuff with r2, r3, etc. ...
1271      * }
1272      * }</pre></blockquote>
1273      * <p>
1274      * To make several functions mutually recursive, additional base
1275      * arguments can be passed to this combinator.  For each base
1276      * function, a recursive adapter is formed (like {@code recur}
1277      * above).  The sequence of recursive adapters is passed as
1278      * initial arguments to each base function.  Here is pseudocode
1279      * that corresponds to three base functions:
1280      * <blockquote><pre>{@code
1281      * R recursive(A... a) {
1282      *   return base(&recursive, &recursive2, &recursive3, a...);
1283      * }
1284      * R2 recursive2(A2... a2) {
1285      *   return base2(&recursive, &recursive2, &recursive3, a2...);
1286      * }
1287      * R3 recursive3(A3... a3) {
1288      *   return base3(&recursive, &recursive2, &recursive3, a3...);
1289      * }
1290      * R base(MethodHandle recur, MethodHandle recur2,
1291      *        MethodHandle recur3, A... a) {
1292      *   ... if (no recursion)  return f(a);  ...
1293      *   var r2 = recur2.invokeExact(a2...);
1294      *   var r3 = recur3.invokeExact(a3...);
1295      *   ... do stuff with r2, r3, etc. ...
1296      * }
1297      * R2 base2(MethodHandle recur, MethodHandle recur2,
1298      *        MethodHandle recur3, A2... a2) { ... }
1299      * R3 base3(MethodHandle recur, MethodHandle recur2,
1300      *        MethodHandle recur3, A3... a3) { ... }
1301      * }</pre></blockquote>
1302      *
1303      * @apiNote Example:
1304      * {@snippet lang="java" :
1305      * // classic recursive implementation of the factorial function
1306      * static int base(MethodHandle recur, int k) throws Throwable {
1307      *   if (k <= 1)  return 1;
1308      *   return k * (int) recur.invokeExact(k - 1);
1309      * }
1310      * // assume MH_base is a handle to the above method
1311      * MethodHandle recur = MethodHandles.recursive(MH_base);
1312      * assertEquals(120, recur.invoke(5));
1313      * }
1314      * <p>
1315      * A constructed recursive method handle is made varargs
1316      * if its corresponding base method handle is varargs.
1317      * @implSpec
1318      * For a single base function, this produces a result equivalent to:
1319      * <pre>{@code
1320      * class Holder {
1321      *   final MethodHandle recur;
1322      *   static final MH_recur = ...;  //field getter
1323      *   Holder(MethodHandle base) {
1324      *     recur = filterArguments(base, 0, MH_recur).bindTo(this);
1325      *   }
1326      * }
1327      * return new Holder(base).recur;
1328      * }</pre>
1329      * @param base the logic of the function to make recursive
1330      * @param moreBases additional base functions to be made mutually recursive
1331      * @throws NullPointerException if any argument is null
1332      * @throws IllegalArgumentException if any base function does not accept
1333      *          the required leading arguments of type {@code MethodHandle}
1334      *
1335      * @return a method handle which invokes the (first) base function
1336      *         on the incoming arguments, with recursive versions of the
1337      *         base function (or functions) prepended as extra arguments
1338      *
1339      * @since Valhalla
1340      */
1341     static MethodHandle recursive(MethodHandle base, MethodHandle... moreBases) {
1342         // freeze the varargs and check for nulls:
1343         List<MethodHandle> bases2 = List.of(moreBases);
1344         int baseCount = 1 + bases2.size();
1345         recursiveChecks(base, baseCount);
1346         for (var base2 : bases2) { recursiveChecks(base2, baseCount); }
1347         class Holder {
1348             final MethodHandle recur;
1349             final List<MethodHandle> recurs2;
1350             MethodHandle recurs2(int i) { return recurs2.get(i); }
1351             Holder() {
1352                 // Feed the first baseCount parameters of each base
1353                 // with a fetch of each recur, so we can bind to this:
1354                 var fetchers = new MethodHandle[baseCount];
1355                 fetchers[0] = MH_recur;
1356                 for (int pos = 1; pos < fetchers.length; pos++) {
1357                     int i = pos-1;  // index into recurs2
1358                     fetchers[pos] = MethodHandles.insertArguments(MH_recurs2, 1, i);
1359                 }
1360                 this.recur = makeRecur(base, fetchers);
1361                 if (baseCount == 1) {
1362                     this.recurs2 = List.of();
1363                 } else {
1364                     var recurs2 = new MethodHandle[baseCount-1];
1365                     for (int i = 0; i < recurs2.length; i++) {
1366                         recurs2[i] = makeRecur(bases2.get(i), fetchers);
1367                     }
1368                     this.recurs2 = List.of(recurs2);
1369                 }
1370             }
1371             MethodHandle makeRecur(MethodHandle base, MethodHandle[] fetchers) {
1372                 var adapt = filterArguments(base, 0, fetchers);
1373                 for (int pos = 0; pos < fetchers.length; pos++) {
1374                     adapt = adapt.bindTo(this);
1375                 }
1376                 return adapt.withVarargs(base.isVarargsCollector());
1377             }
1378             static final MethodHandle MH_recur, MH_recurs2;
1379             static {
1380                 try {
1381                     MH_recur = MethodHandles.lookup()
1382                             .findGetter(Holder.class, "recur", MethodHandle.class);
1383                     MH_recurs2 = MethodHandles.lookup()
1384                             .findVirtual(Holder.class, "recurs2",
1385                                     methodType(MethodHandle.class, int.class));
1386                 } catch (ReflectiveOperationException ex) {
1387                     throw new InternalError(ex);
1388                 }
1389             }
1390         }
1391         return new Holder().recur;
1392     }
1393 
1394     private static void recursiveChecks(MethodHandle base, int baseCount) {
1395         MethodType mt = base.type();  // implicit null check
1396         boolean wrong = (mt.parameterCount() < baseCount);
1397         for (int i = 0; i < baseCount && !wrong; i++) {
1398             if (mt.parameterType(i) != MethodHandle.class) {
1399                 wrong = true;
1400             }
1401         }
1402         if (!wrong)  return;
1403         throw new IllegalArgumentException("missing leading MethodHandle parameters: " + mt);
1404     }
1405 
1406 }