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