1 /*
   2  * Copyright (c) 2019, 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 package java.lang.runtime;
  26 
  27 import java.lang.invoke.MethodHandle;
  28 import java.lang.invoke.MethodHandles;
  29 import java.lang.invoke.MethodType;
  30 import java.util.List;
  31 import java.util.Objects;
  32 import java.util.stream.IntStream;
  33 import java.util.stream.Stream;
  34 
  35 import sun.invoke.util.BytecodeName;
  36 import sun.invoke.util.Wrapper;
  37 
  38 import static java.lang.invoke.MethodHandleInfo.REF_invokeInterface;
  39 import static java.lang.invoke.MethodHandleInfo.REF_invokeStatic;
  40 import static java.lang.invoke.MethodHandleInfo.REF_invokeVirtual;
  41 import static java.lang.invoke.MethodHandleInfo.REF_newInvokeSpecial;
  42 import static java.util.Objects.requireNonNull;
  43 
  44 /**
  45  * Factories and combinators for {@link PatternHandle}s.
  46  */
  47 public final class PatternHandles {
  48     private static final MethodHandle[] EMPTY_MH_ARRAY = new MethodHandle[0];
  49     private static final Object NULL_SENTINEL = new Object();
  50 
  51     private PatternHandles() {
  52     }
  53 
  54     // Factories
  55 
  56     /**
  57      * Returns a {@linkplain PatternHandle} for a <em>type pattern</em>, which
  58      * matches all non-null instances of the match type, with a single binding
  59      * variable which is the target cast to the match type.  The target type of
  60      * the resulting pattern is the match type; if a broader target type is
  61      * desired, use {@link #ofType(Class, Class)} or adapt the resulting pattern
  62      * handle with {@link #adaptTarget(PatternHandle, Class)}.
  63      *
  64      * @param matchType the type to match against
  65      * @return a pattern handle for a type pattern
  66      */
  67     public static PatternHandle ofType(Class<?> matchType) {
  68         requireNonNull(matchType);
  69         MethodType descriptor = MethodType.methodType(matchType, matchType);
  70         MethodHandle component = MethodHandles.identity(matchType);
  71         MethodHandle tryMatch
  72                 = matchType.isPrimitive()
  73                   ? MethodHandles.identity(matchType)
  74                   : MH_OF_TYPE_TRY_MATCH.bindTo(matchType).asType(descriptor);
  75 
  76         return new PatternHandleImpl(descriptor, tryMatch, List.of(component));
  77     }
  78 
  79     /**
  80      * Returns a {@linkplain PatternHandle} for a <em>type pattern</em>, which
  81      * matches all non-null instances of the match type, with a single binding
  82      * variable which is the target cast to the match type.  The target type of
  83      * the resulting pattern is the {@code targetType}.
  84      *
  85      * @param matchType  the type to match against
  86      * @param targetType the desired target type for the resulting pattern
  87      *                   handle
  88      * @return a pattern handle for a type pattern
  89      * @throws IllegalArgumentException if the provided match type and target
  90      *                                  type are not compatible
  91      */
  92     public static PatternHandle ofType(Class<?> matchType, Class<?> targetType) {
  93         return adaptTarget(ofType(matchType), targetType);
  94     }
  95 
  96     /**
  97      * Returns a {@linkplain PatternHandle} for a <em>nullable type
  98      * pattern</em>, which matches all instances of the match type, plus {@code
  99      * null}, with a single binding variable which is the target cast to the
 100      * match type.  The target type of the resulting pattern is the match type;
 101      * if a broader target type is desired, use {@link #ofType(Class, Class)} or
 102      * adapt the resulting pattern handle with {@link #adaptTarget(PatternHandle,
 103      * Class)}.
 104      *
 105      * @param matchType the type to match against
 106      * @return a pattern handle for a nullable type pattern
 107      */
 108     public static PatternHandle ofTypeNullable(Class<?> matchType) {
 109         requireNonNull(matchType);
 110         MethodType descriptor = MethodType.methodType(matchType, matchType);
 111         MethodHandle component = MH_OF_TYPE_NULLABLE_COMPONENT
 112                 .asType(MethodType.methodType(matchType, Object.class));
 113         MethodHandle tryMatch
 114                 = matchType.isPrimitive()
 115                   ? MethodHandles.identity(matchType)
 116                   : MH_OF_TYPE_NULLABLE_TRY_MATCH.bindTo(matchType)
 117                                                  .asType(MethodType.methodType(Object.class, matchType));
 118 
 119         return new PatternHandleImpl(descriptor, tryMatch, List.of(component));
 120     }
 121 
 122     /**
 123      * Returns a {@linkplain PatternHandle} for a <em>nullable type
 124      * pattern</em>, which matches all instances of the match type, plus {@code
 125      * null}, with a single binding variable which is the target cast to the
 126      * match type.  The target type of the resulting pattern is the {@code
 127      * targetType}.
 128      *
 129      * @param matchType  the type to match against
 130      * @param targetType the desired target type for the resulting pattern
 131      *                   handle
 132      * @return a pattern handle for a nullable type pattern
 133      * @throws IllegalArgumentException if the provided match type and target
 134      *                                  type are not compatible
 135      */
 136     public static PatternHandle ofTypeNullable(Class<?> matchType, Class<?> targetType) {
 137         return adaptTarget(ofTypeNullable(matchType), targetType);
 138     }
 139 
 140     /**
 141      * Returns a {@linkplain PatternHandle} for a <em>constant pattern</em>,
 142      * which matches all instances that are {@link Object#equals(Object)} to
 143      * the specified constant.  The resulting pattern has no binding variables.
 144      * If the constant is {@code null}, the target type of the pattern is
 145      * {@link Object}, otherwise it is the result of {@code Object::getClass}
 146      * on the constant.
 147      *
 148      * <p>TODO: restrict type of constant to String, boxes, and enums?
 149      *
 150      * @param o the constant
 151      * @return a pattern handle for a constant pattern
 152      */
 153     public static PatternHandle ofConstant(Object o) {
 154         Class<?> type = o == null ? Object.class : o.getClass();
 155         MethodHandle match = partialize(MethodHandles.dropArguments(MethodHandles.constant(Object.class, Boolean.TRUE), 0, type),
 156                                         MethodHandles.insertArguments(MH_OBJECTS_EQUAL, 0, o)
 157                                                      .asType(MethodType.methodType(boolean.class, type)));
 158         return new PatternHandleImpl(MethodType.methodType(type), match, List.of());
 159     }
 160 
 161     /**
 162      * Returns a {@linkplain PatternHandle} for a <em>constant pattern</em>,
 163      * which matches all instances that are {@link Object#equals(Object)} to
 164      * the specified constant.  The resulting pattern has no binding variables.
 165      * The target type of the pattern is {@code targetType}.
 166      *
 167      * @param o the constant
 168      * @param targetType the target type for the pattern
 169      * @return a pattern handle for a constant pattern
 170      * @throws IllegalArgumentException if the type of the constant and the
 171      * target type are not compatible
 172      */
 173     public static PatternHandle ofConstant(Object o, Class<?> targetType) {
 174         return adaptTarget(ofConstant(0), targetType);
 175     }
 176 
 177     // @@@ Primitive constant patterns
 178 
 179     /**
 180      * Returns a {@linkplain PatternHandle} for decomposing a target into its
 181      * components.  It matches all non-null instances of the specified target
 182      * type, and extracts one binding variable for each component specified in
 183      * the {@code components} argument.  The method handles in {@code components}
 184      * must be of type {@code (T)Bi} where T is the target type of the pattern
 185      * and Bi is the i'th binding variable.  The components are extracted
 186      * <em>lazily</em> -- when the component method handle is invoked by the
 187      * client -- rather than when the {@code tryMatch} method handle is invoked.
 188      *
 189      * @param targetType The type of the match target
 190      * @param components The component method handles
 191      * @return a pattern handle for a decomposition pattern
 192      */
 193     public static PatternHandle ofLazyProjection(Class<?> targetType,
 194                                                  MethodHandle... components) {
 195         requireNonNull(targetType);
 196         requireNonNull(components);
 197         return new PatternHandleImpl(descriptor(targetType, components),
 198                                      MethodHandles.identity(targetType),
 199                                      List.of(components));
 200     }
 201 
 202     /**
 203      * Returns a {@linkplain PatternHandle} for decomposing a target into its
 204      * components.  It matches all non-null instances of the specified target
 205      * type, and extracts one binding variable for each component specified in
 206      * the {@code components} argument.  The method handles in {@code components}
 207      * must be of type {@code (T)Bi} where T is the target type of the pattern
 208      * and Bi is the i'th binding variable.  The components are extracted
 209      * <em>eagerly</em> -- at the time the {@code tryMatch} method handle is
 210      * invoked.
 211      *
 212      * @param targetType The type of the match target
 213      * @param components The component method handles
 214      * @return a pattern handle for a decomposition pattern
 215      */
 216     public static PatternHandle ofEagerProjection(Class<?> targetType,
 217                                                   MethodHandle... components) {
 218         requireNonNull(targetType);
 219         requireNonNull(components);
 220         MethodType descriptor = descriptor(targetType, components);
 221         return new PatternHandleImpl(descriptor,
 222                                      carrierTryExtract(descriptor, components),
 223                                      PatternCarriers.carrierComponents(descriptor));
 224     }
 225 
 226     /**
 227      * Returns a {@linkplain PatternHandle} that delegates matching and
 228      * extraction to another method handle.  The target type of the pattern is
 229      * the return type of the {@code descriptor}, and the binding variable types
 230      * are the parameter types of the {@code descriptor}.  The {@code tryMatch}
 231      * method handle will invoke the specified {@code digester} method handle
 232      * with the target, as well as a method handle whose parameter types are
 233      * the binding variable types and whose return type is some type {@code C}.
 234      * For a successful match, the digester method should invoke this method
 235      * handle with the extracted bindings, and return the result; for an
 236      * unsuccessful match, it should return {@code null}.
 237      *
 238      * @param descriptor the type descriptor of the pattern
 239      * @param digester   the digester method handle
 240      * @return a pattern handle implementing the pattern
 241      */
 242     public static PatternHandle ofImperative(MethodType descriptor,
 243                                              MethodHandle digester) {
 244         Class<?> targetType = descriptor.returnType();
 245         return new PatternHandleImpl(descriptor,
 246                                      partialize(MethodHandles.insertArguments(digester,
 247                                                                               1, PatternCarriers.carrierFactory(descriptor)),
 248                                                 MH_OBJECTS_NONNULL.asType(MH_OBJECTS_NONNULL.type().changeParameterType(0, targetType))),
 249                                      PatternCarriers.carrierComponents(descriptor));
 250     }
 251 
 252     /**
 253      * Compose a pattern handle with a method handle that receives the bindings. The
 254      * argument types of the target method must match those of the binding
 255      * types.  The resulting method handle accepts an argument which is the
 256      * target type of the pattern, and which returns either {@code null}
 257      * if the match fails or the result of the target method handle
 258      * if the match succeeds.
 259      *
 260      * @param patternHandle the pattern handle
 261      * @param target        a method handle that receives the bindings and
 262      *                      produces a result
 263      * @return the composed method handle
 264      */
 265     public static MethodHandle compose(PatternHandle patternHandle, MethodHandle target) {
 266         int count = patternHandle.descriptor().parameterCount();
 267         MethodHandle[] components = patternHandle.components().toArray(EMPTY_MH_ARRAY);
 268         Class<?> carrierType = patternHandle.tryMatch().type().returnType();
 269         Class<?> resultType = target.type().returnType();
 270 
 271         MethodHandle mh = MethodHandles.filterArguments(target, 0, components);
 272         mh = MethodHandles.permuteArguments(mh, MethodType.methodType(resultType, carrierType), new int[count]);
 273         mh = MethodHandles.guardWithTest(MH_OBJECTS_NONNULL.asType(MethodType.methodType(boolean.class, carrierType)),
 274                                          mh,
 275                                          MethodHandles.dropArguments(MethodHandles.constant(resultType, null), 0, carrierType));
 276         mh = MethodHandles.filterArguments(mh, 0, patternHandle.tryMatch());
 277         return mh;
 278     }
 279 
 280     // Combinators
 281 
 282     /**
 283      * Adapts a {@linkplain PatternHandle} to a new target type.  If the
 284      * pattern is of primitive type, it may be adapted to a supertype of its
 285      * corresponding box type; if it is of reference type, it may be widened
 286      * or narrowed to another reference type.
 287      *
 288      * @param pattern the pattern
 289      * @param newTarget the new target type
 290      * @return the adapted pattern
 291      * @throws IllegalArgumentException if the new target type is not compatible
 292      * with the target type of the pattern
 293      */
 294     public static PatternHandle adaptTarget(PatternHandle pattern, Class<?> newTarget) {
 295         Class<?> oldTarget = pattern.descriptor().returnType();
 296         if (oldTarget == newTarget)
 297             return pattern;
 298 
 299         Class<?> oldWrapperType = oldTarget.isPrimitive() ? Wrapper.forPrimitiveType(oldTarget).wrapperType() : null;
 300         MethodType guardType = MethodType.methodType(boolean.class, newTarget);
 301         MethodHandle guard;
 302         if (oldWrapperType != null && newTarget.isAssignableFrom(oldWrapperType)) {
 303             // Primitive boxing (with optional widening)
 304             guard = MH_PRIMITIVE_ADAPT_HELPER.bindTo(oldWrapperType).asType(guardType);
 305         }
 306         else if (newTarget.isAssignableFrom(oldTarget) || oldTarget.isAssignableFrom(newTarget)) {
 307             // reference narrowing or widening
 308             guard = MH_REFERENCE_ADAPT_HELPER.bindTo(oldTarget).asType(guardType);
 309         }
 310         else {
 311             throw new IllegalArgumentException(String.format("New target type %s not compatible with old target type %s",
 312                                                              newTarget, oldTarget));
 313         }
 314 
 315         MethodType tryMatchType = pattern.tryMatch().type().changeParameterType(0, newTarget);
 316         return new PatternHandleImpl(pattern.descriptor().changeReturnType(newTarget),
 317                                      partialize(pattern.tryMatch().asType(tryMatchType),
 318                                                 guard),
 319                                      pattern.components());
 320     }
 321 
 322     /**
 323      * Returns a {@linkplain PatternHandle} that implements the same pattern
 324      * as another {@linkplain PatternHandle}, but potentially with fewer binding
 325      * variables.
 326      *
 327      * @param pattern the original pattern
 328      * @param positions the indexes of the binding variables to drop
 329      * @return the new pattern
 330      * @throws IndexOutOfBoundsException if any of the indexes are out of range
 331      * for the bindings of the original pattern
 332      */
 333     public static PatternHandle dropBindings(PatternHandle pattern, int... positions) {
 334         MethodHandle[] mhs = pattern.components().toArray(EMPTY_MH_ARRAY);
 335         for (int position : positions)
 336             mhs[position] = null;
 337         mhs = Stream.of(mhs).filter(Objects::nonNull).toArray(MethodHandle[]::new);
 338         return new PatternHandleImpl(descriptor(pattern.descriptor().returnType(), mhs), pattern.tryMatch(), List.of(mhs));
 339     }
 340 
 341     /**
 342      * Returns a {@linkplain PatternHandle} for a <em>nested</em> pattern.  A
 343      * nested pattern first matches the target to the outer pattern, and if
 344      * it matches successfully, then matches the resulting bindings to the inner
 345      * patterns.  The resulting pattern matches if the outer pattern matches
 346      * the target, and the bindings match the appropriate inner patterns.  The
 347      * target type of the nested pattern is the same as the target type of
 348      * the outer pattern.  The bindings are the bindings for the outer pattern,
 349      * followed by the concatenation of the bindings for the inner patterns.
 350      *
 351      * @param outer  The outer pattern
 352      * @param inners The inner patterns, which can be null if no nested pattern
 353      *               for the corresponding binding is desired
 354      * @return the nested pattern
 355      */
 356     public static PatternHandle nested(PatternHandle outer, PatternHandle... inners) {
 357         PatternHandle[] patternHandles = inners.clone();
 358         int outerCount = outer.descriptor().parameterCount();
 359         Class<?> outerCarrierType = outer.tryMatch().type().returnType();
 360 
 361         // Adapt inners to types of outer bindings
 362         for (int i = 0; i < patternHandles.length; i++) {
 363             PatternHandle patternHandle = patternHandles[i];
 364             if (patternHandle.descriptor().returnType() != outer.descriptor().parameterType(i))
 365                 patternHandles[i] = adaptTarget(patternHandle, outer.descriptor().parameterType(i));
 366         }
 367 
 368         int[] innerPositions = IntStream.range(0, patternHandles.length)
 369                                         .filter(i -> patternHandles[i] != null)
 370                                         .toArray();
 371         MethodHandle[] innerComponents = Stream.of(patternHandles)
 372                                                .filter(Objects::nonNull)
 373                                                .map(PatternHandle::components)
 374                                                .flatMap(List::stream)
 375                                                .toArray(MethodHandle[]::new);
 376         MethodHandle[] innerTryMatches = Stream.of(patternHandles)
 377                                                .filter(Objects::nonNull)
 378                                                .map(PatternHandle::tryMatch)
 379                                                .toArray(MethodHandle[]::new);
 380         Class<?>[] innerCarriers = Stream.of(patternHandles)
 381                                          .filter(Objects::nonNull)
 382                                          .map(e -> e.tryMatch().type().returnType())
 383                                          .toArray(Class[]::new);
 384         Class<?>[] innerTypes = Stream.of(innerComponents)
 385                                       .map(mh -> mh.type().returnType())
 386                                       .toArray(Class[]::new);
 387 
 388         MethodType descriptor = outer.descriptor().appendParameterTypes(innerTypes);
 389 
 390         MethodHandle mh = PatternCarriers.carrierFactory(descriptor);
 391         mh = MethodHandles.filterArguments(mh, outerCount, innerComponents);
 392         int[] spreadInnerCarriers = new int[outerCount + innerComponents.length];
 393         for (int i = 0; i < outerCount; i++)
 394             spreadInnerCarriers[i] = i;
 395         int k = outerCount;
 396         int j = 0;
 397         for (PatternHandle e : patternHandles) {
 398             if (e == null)
 399                 continue;
 400             for (int i = 0; i < e.descriptor().parameterCount(); i++)
 401                 spreadInnerCarriers[k++] = outerCount + j;
 402             j++;
 403         }
 404         MethodType spreadInnerCarriersMT = outer.descriptor()
 405                                                 .appendParameterTypes(innerCarriers)
 406                                                 .changeReturnType(mh.type().returnType());
 407         mh = MethodHandles.permuteArguments(mh, spreadInnerCarriersMT, spreadInnerCarriers);
 408         for (int position : innerPositions)
 409             mh = bailIfNthNull(mh, outerCount + position);
 410         mh = MethodHandles.filterArguments(mh, outerCount, innerTryMatches);
 411         int[] spreadNestedCarrier = new int[outerCount + innerPositions.length];
 412         for (int i = 0; i < outerCount; i++)
 413             spreadNestedCarrier[i] = i;
 414         for (int i = 0; i < innerPositions.length; i++)
 415             spreadNestedCarrier[outerCount + i] = innerPositions[i];
 416         mh = MethodHandles.permuteArguments(mh, outer.descriptor().changeReturnType(mh.type().returnType()),
 417                                             spreadNestedCarrier);
 418         mh = MethodHandles.filterArguments(mh, 0, outer.components().toArray(EMPTY_MH_ARRAY));
 419         mh = MethodHandles.permuteArguments(mh, MethodType.methodType(mh.type().returnType(), outerCarrierType),
 420                                             new int[outerCount]);
 421         mh = bailIfNthNull(mh, 0);
 422         mh = MethodHandles.filterArguments(mh, 0, outer.tryMatch());
 423 
 424         MethodHandle tryExtract = mh;
 425 
 426         return new PatternHandleImpl(descriptor, tryExtract, PatternCarriers.carrierComponents(descriptor));
 427     }
 428 
 429     // @@@ AND combinator
 430     // @@@ GUARDED combinator
 431 
 432     // Bootstraps
 433 
 434     /**
 435      * Bootstrap method for creating a lazy projection pattern, as per
 436      * {@link #ofLazyProjection(Class, MethodHandle...)},
 437      * suitable for use as a {@code constantdynamic} bootstrap.  Suitable for use
 438      * by compilers which are generating implementations of patterns whose bindings
 439      * are independently derived from the target.
 440      *
 441      * @apiNote When the "bootstrap consolidation" project completes, this method
 442      * can go away and {@link #ofLazyProjection(Class, MethodHandle...)}
 443      * can be used directly as a condy bootstrap.
 444      *
 445      * @param lookup       ignored
 446      * @param constantName ignored
 447      * @param constantType Must be {@code PatternHandle.class}
 448      * @param targetType   the target type of the pattern
 449      * @param components   the pattern components
 450      * @return a pattern handle
 451      * @throws Throwable doc
 452      */
 453     public static PatternHandle ofLazyProjection(MethodHandles.Lookup lookup,
 454                                                  String constantName,
 455                                                  Class<?> constantType,
 456                                                  Class<?> targetType,
 457                                                  MethodHandle... components)
 458             throws Throwable {
 459         return ofLazyProjection(targetType, components);
 460     }
 461 
 462     /**
 463      * Bootstrap method for finding named {@link PatternHandle}s that have been
 464      * compiled according to the scheme outlined in JLS ?.?.
 465      *
 466      * @param lookup       the lookup context
 467      * @param constantName ignored
 468      * @param constantType must be {@code PatternHandle.class}
 469      * @param owner        the class containing the pattern
 470      * @param descriptor   the extractor descriptor
 471      * @param name         the extractor name
 472      * @param refKind      the kind of method
 473      * @return the extractor
 474      * @throws Throwable if something went wrong
 475      */
 476     public static PatternHandle ofNamed(MethodHandles.Lookup lookup,
 477                                         String constantName,
 478                                         Class<PatternHandle> constantType,
 479                                         Class<?> owner,
 480                                         MethodType descriptor,
 481                                         String name,
 482                                         int refKind) throws Throwable {
 483         String dd = descriptor.toMethodDescriptorString();
 484         String memberName = String.format("$pattern$%s$%s",
 485                                       (refKind == REF_newInvokeSpecial ? owner.getSimpleName() : name),
 486                                       dd.substring(0, dd.indexOf(')') + 1));
 487         String patternMethodName = BytecodeName.toBytecodeName(memberName);
 488         MethodType factoryDesc = MethodType.methodType(PatternHandle.class);
 489         MethodHandle mh;
 490         switch (refKind) {
 491             case REF_invokeStatic:
 492             case REF_newInvokeSpecial:
 493                 mh = lookup.findStatic(owner, patternMethodName, factoryDesc);
 494                 break;
 495             case REF_invokeVirtual:
 496             case REF_invokeInterface:
 497                 mh = lookup.findVirtual(owner, patternMethodName, factoryDesc);
 498                 break;
 499             default:
 500                 throw new IllegalAccessException(Integer.toString(refKind));
 501         }
 502 
 503         return (PatternHandle) mh.invoke();
 504     }
 505 
 506     /**
 507      * Bootstrap method for extracting the {@code tryMatch} method handle from a
 508      * {@linkplain PatternHandle}.
 509      *
 510      * @apiNote When the "bootstrap consolidation" project completes, this method
 511      * can go away and {@link PatternHandle#tryMatch()} can be used directly as
 512      * a condy bootstrap.
 513      *
 514      * @param lookup        ignored
 515      * @param constantName  ignored
 516      * @param constantType  Must be {@code MethodHandle.class}
 517      * @param patternHandle the pattern handle
 518      * @return the {@code tryMatch} method handle
 519      */
 520     public static MethodHandle tryMatch(MethodHandles.Lookup lookup, String constantName, Class<MethodHandle> constantType,
 521                                         PatternHandle patternHandle) {
 522         return patternHandle.tryMatch();
 523     }
 524 
 525     /**
 526      * Bootstrap method for extracting a {@code component} method handle from a
 527      * {@linkplain PatternHandle}.
 528      *
 529      * @apiNote When the "bootstrap consolidation" project completes, this method
 530      * can go away and {@link PatternHandle#component(int)} ()} can be used directly as
 531      * a condy bootstrap.
 532      *
 533      * @param lookup        ignored
 534      * @param constantName  ignored
 535      * @param constantType  Must be {@code MethodHandle.class}
 536      * @param patternHandle the pattern
 537      * @param i the index of the desired component
 538      * @return the component method handle
 539      */
 540     public static MethodHandle component(MethodHandles.Lookup lookup,
 541                                          String constantName,
 542                                          Class<MethodHandle> constantType,
 543                                          PatternHandle patternHandle, int i) {
 544         return patternHandle.component(i);
 545     }
 546 
 547     // Helpers
 548 
 549     /**
 550      * Construct a partial method handle that uses the predicate as
 551      * guardWithTest, which applies the target if the test succeeds, and returns
 552      * null if the test fails.  The resulting method handle is of the same type
 553      * as the {@code target} method handle.
 554      *
 555      * @param target
 556      * @param predicate
 557      * @return
 558      */
 559     private static MethodHandle partialize(MethodHandle target,
 560                                            MethodHandle predicate) {
 561         Class<?> targetType = target.type().parameterType(0);
 562         Class<?> carrierType = target.type().returnType();
 563         return MethodHandles.guardWithTest(predicate,
 564                                            target,
 565                                            MethodHandles.dropArguments(MethodHandles.constant(carrierType, null),
 566                                                                        0, targetType));
 567     }
 568 
 569     /**
 570      * Construct a method handle that delegates to target, unless the nth
 571      * argument is null, in which case it returns null
 572      */
 573     private static MethodHandle bailIfNthNull(MethodHandle target, int n) {
 574         MethodHandle test = MH_OBJECTS_ISNULL
 575                 .asType(MH_OBJECTS_ISNULL.type()
 576                                          .changeParameterType(0, target.type().parameterType(n)));
 577         test = MethodHandles.permuteArguments(test, target.type().changeReturnType(boolean.class), n);
 578         MethodHandle nullh = MethodHandles.dropArguments(MethodHandles.constant(target.type().returnType(), null),
 579                                                          0, target.type().parameterArray());
 580         return MethodHandles.guardWithTest(test, nullh, target);
 581     }
 582 
 583     private static MethodType descriptor(Class<?> targetType, MethodHandle[] components) {
 584         Class<?>[] paramTypes = Stream.of(components)
 585                                       .map(mh -> mh.type().returnType())
 586                                       .toArray(Class[]::new);
 587         return MethodType.methodType(targetType, paramTypes);
 588     }
 589 
 590     private static MethodHandle carrierTryExtract(MethodType descriptor, MethodHandle[] components) {
 591         MethodHandle carrierFactory = PatternCarriers.carrierFactory(descriptor);
 592         int[] reorder = new int[descriptor.parameterCount()]; // default value is what we want already
 593 
 594         Class<?> targetType = descriptor.returnType();
 595         return partialize(MethodHandles.permuteArguments(MethodHandles.filterArguments(carrierFactory, 0, components),
 596                                                          MethodType.methodType(carrierFactory.type().returnType(), targetType),
 597                                                          reorder),
 598                           MH_OBJECTS_NONNULL.asType(MH_OBJECTS_NONNULL.type().changeParameterType(0, targetType)));
 599     }
 600 
 601     private static MethodHandle lookupStatic(Class<?> clazz,
 602                                              String name,
 603                                              Class<?> returnType,
 604                                              Class<?>... paramTypes)
 605             throws ExceptionInInitializerError {
 606         try {
 607             return MethodHandles.lookup().findStatic(clazz, name, MethodType.methodType(returnType, paramTypes));
 608         }
 609         catch (ReflectiveOperationException e) {
 610             throw new ExceptionInInitializerError(e);
 611         }
 612     }
 613 
 614     private static final MethodHandle MH_OF_TYPE_TRY_MATCH
 615             = lookupStatic(PatternHandles.class, "ofTypeTryMatch",
 616                            Object.class, Class.class, Object.class);
 617     private static final MethodHandle MH_OF_TYPE_NULLABLE_TRY_MATCH
 618             = lookupStatic(PatternHandles.class, "ofTypeNullableTryMatch",
 619                            Object.class, Class.class, Object.class);
 620     private static final MethodHandle MH_OF_TYPE_NULLABLE_COMPONENT
 621             = lookupStatic(PatternHandles.class, "ofTypeNullableComponent",
 622                            Object.class, Object.class);
 623     private static final MethodHandle MH_PRIMITIVE_ADAPT_HELPER
 624             = lookupStatic(PatternHandles.class, "primitiveAdaptHelper",
 625                            boolean.class, Class.class, Object.class);
 626     private static final MethodHandle MH_REFERENCE_ADAPT_HELPER
 627             = lookupStatic(PatternHandles.class, "referenceAdaptHelper",
 628                            boolean.class, Class.class, Object.class);
 629     private static final MethodHandle MH_OBJECTS_ISNULL
 630             = lookupStatic(Objects.class, "isNull",
 631                            boolean.class, Object.class);
 632     private static final MethodHandle MH_OBJECTS_NONNULL
 633             = lookupStatic(Objects.class, "nonNull",
 634                            boolean.class, Object.class);
 635     private static final MethodHandle MH_OBJECTS_EQUAL
 636             = lookupStatic(Objects.class, "equals",
 637                            boolean.class, Object.class, Object.class);
 638 
 639     private static Object ofTypeTryMatch(Class<?> type, Object o) {
 640         return o != null && type.isAssignableFrom(o.getClass())
 641                ? o
 642                : null;
 643     }
 644 
 645     private static Object ofTypeNullableTryMatch(Class<?> type, Object o) {
 646         if (o == null)
 647             return NULL_SENTINEL;
 648         else if (type.isAssignableFrom(o.getClass()))
 649             return o;
 650         else
 651             return null;
 652     }
 653 
 654     private static Object ofTypeNullableComponent(Object o) {
 655         return o == NULL_SENTINEL ? null : o;
 656     }
 657 
 658     private static boolean primitiveAdaptHelper(Class<?> type, Object o) {
 659         return o != null && type.isAssignableFrom(o.getClass());
 660     }
 661 
 662     private static boolean referenceAdaptHelper(Class<?> type, Object o) {
 663         return o == null || type.isAssignableFrom(o.getClass());
 664     }
 665 
 666     /**
 667      * Non-public implementation of {@link PatternHandle}
 668      */
 669     private static class PatternHandleImpl implements PatternHandle {
 670 
 671         private final MethodType descriptor;
 672         private final MethodHandle tryMatch;
 673         private final List<MethodHandle> components;
 674 
 675 
 676         /**
 677          * Construct an {@link PatternHandle} from components Constraints: -
 678          * output of tryMatch must match input of components - input of tryMatch
 679          * must match descriptor - output of components must match descriptor
 680          *
 681          * @param descriptor The {@code descriptor} method type
 682          * @param tryMatch   The {@code tryMatch} method handle
 683          * @param components The {@code component} method handles
 684          */
 685         PatternHandleImpl(MethodType descriptor, MethodHandle tryMatch,
 686                           List<MethodHandle> components) {
 687             MethodHandle[] componentsArray = components.toArray(new MethodHandle[0]);
 688             Class<?> carrierType = tryMatch.type().returnType();
 689             if (descriptor.parameterCount() != componentsArray.length)
 690                 throw new IllegalArgumentException(String.format("MethodType %s arity should match component count %d",
 691                                                                  descriptor, componentsArray.length));
 692             if (!descriptor.returnType().equals(tryMatch.type().parameterType(0)))
 693                 throw new IllegalArgumentException(String.format("Descriptor %s should match tryMatch input %s",
 694                                                                  descriptor, tryMatch.type()));
 695             for (int i = 0; i < componentsArray.length; i++) {
 696                 MethodType componentType = componentsArray[i].type();
 697                 if (componentType.parameterCount() != 1
 698                     || componentType.returnType().equals(void.class)
 699                     || !componentType.parameterType(0).equals(carrierType))
 700                     throw new IllegalArgumentException("Invalid component descriptor " + componentType);
 701                 if (!componentType.returnType().equals(descriptor.parameterType(i)))
 702                     throw new IllegalArgumentException(String.format("Descriptor %s should match %d'th component %s",
 703                                                                      descriptor, i, componentsArray[i]));
 704             }
 705 
 706             if (!carrierType.equals(Object.class)) {
 707                 tryMatch = tryMatch.asType(tryMatch.type().changeReturnType(Object.class));
 708                 for (int i = 0; i < componentsArray.length; i++) {
 709                     MethodHandle component = componentsArray[i];
 710                     componentsArray[i] = component.asType(component.type().changeParameterType(0, Object.class));
 711                 }
 712             }
 713 
 714             this.descriptor = descriptor;
 715             this.tryMatch = tryMatch;
 716             this.components = List.of(componentsArray);
 717         }
 718 
 719         @Override
 720         public MethodHandle tryMatch() {
 721             return tryMatch;
 722         }
 723 
 724         @Override
 725         public MethodHandle component(int i) {
 726             return components.get(i);
 727         }
 728 
 729         @Override
 730         public List<MethodHandle> components() {
 731             return components;
 732         }
 733 
 734         @Override
 735         public MethodType descriptor() {
 736             return descriptor;
 737         }
 738 
 739     }
 740 }