1 /*
   2  * Copyright (c) 2012, 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.compiler;
  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 
  33 /**
  34  * Non-public implementation of {@link Extractor}
  35  */
  36 class ExtractorImpl implements Extractor {
  37     private final MethodType descriptor;
  38     private final MethodHandle tryMatch;
  39     private final List<MethodHandle> components;
  40 
  41     // These are helpers for Extractors
  42     static final MethodHandle MH_OF_TYPE_HELPER;
  43     static final MethodHandle MH_OF_TYPE_NULLABLE_HELPER;
  44     static final MethodHandle MH_ADAPT_HELPER;
  45     static final MethodHandle MH_OBJECTS_ISNULL;
  46     static final MethodHandle MH_OBJECTS_NONNULL;
  47     static final MethodHandle MH_OBJECTS_EQUAL;
  48     static {
  49         try {
  50             MH_OF_TYPE_HELPER = MethodHandles.lookup().findStatic(ExtractorImpl.class, "ofTypeHelper", MethodType.methodType(Object.class, Class.class, Object.class));
  51             MH_OF_TYPE_NULLABLE_HELPER = MethodHandles.lookup().findStatic(ExtractorImpl.class, "ofTypeNullableHelper", MethodType.methodType(Object.class, Class.class, Object.class));
  52             MH_ADAPT_HELPER = MethodHandles.lookup().findStatic(ExtractorImpl.class, "adaptHelper", MethodType.methodType(boolean.class, Class.class, Object.class));
  53             MH_OBJECTS_ISNULL = MethodHandles.lookup().findStatic(Objects.class, "isNull", MethodType.methodType(boolean.class, Object.class));
  54             MH_OBJECTS_NONNULL = MethodHandles.lookup().findStatic(Objects.class, "nonNull", MethodType.methodType(boolean.class, Object.class));
  55             MH_OBJECTS_EQUAL = MethodHandles.lookup().findStatic(Objects.class, "equals", MethodType.methodType(boolean.class, Object.class, Object.class));
  56         }
  57         catch (ReflectiveOperationException e) {
  58             throw new ExceptionInInitializerError(e);
  59         }
  60     }
  61 
  62     /**
  63      * Construct an {@link Extractor} from components
  64      * Constraints:
  65      *  - output of tryMatch must match input of components
  66      *  - input of tryMatch must match descriptor
  67      *  - output of components must match descriptor
  68      *
  69      * @param descriptor The {@code descriptor} method type
  70      * @param tryMatch The {@code tryMatch} method handle
  71      * @param components The {@code component} method handles
  72      */
  73     ExtractorImpl(MethodType descriptor, MethodHandle tryMatch, MethodHandle... components) {
  74         Class<?> carrierType = tryMatch.type().returnType();
  75         if (descriptor.parameterCount() != components.length)
  76             throw new IllegalArgumentException(String.format("MethodType %s arity should match component count %d", descriptor, components.length));
  77         if (!descriptor.returnType().equals(tryMatch.type().parameterType(0)))
  78             throw new IllegalArgumentException(String.format("Descriptor %s should match tryMatch input %s", descriptor, tryMatch.type()));
  79         for (int i = 0; i < components.length; i++) {
  80             MethodHandle component = components[i];
  81             if (component.type().parameterCount() != 1
  82                 || component.type().returnType().equals(void.class)
  83                 || !component.type().parameterType(0).equals(carrierType))
  84                 throw new IllegalArgumentException("Invalid component descriptor " + component.type());
  85             if (!component.type().returnType().equals(descriptor.parameterType(i)))
  86                 throw new IllegalArgumentException(String.format("Descriptor %s should match %d'th component %s", descriptor, i, component));
  87         }
  88 
  89         this.descriptor = descriptor;
  90         this.tryMatch = tryMatch;
  91         this.components = List.of(components);
  92     }
  93 
  94     @Override
  95     public MethodHandle tryMatch() {
  96         return tryMatch;
  97     }
  98 
  99     @Override
 100     public MethodHandle component(int i) {
 101         return components.get(i);
 102     }
 103 
 104     @Override
 105     public MethodHandle[] components() {
 106         return components.toArray(new MethodHandle[0]);
 107     }
 108 
 109     @Override
 110     public MethodType descriptor() {
 111         return descriptor;
 112     }
 113 
 114     private static Object ofTypeHelper(Class<?> type, Object o) {
 115         return o != null && type.isAssignableFrom(o.getClass()) ? o : null;
 116     }
 117 
 118     private static Object ofTypeNullableHelper(Class<?> type, Object o) {
 119         return o == null || type.isAssignableFrom(o.getClass()) ? o : null;
 120     }
 121 
 122     private static boolean adaptHelper(Class<?> type, Object o) {
 123         return o != null && type.isAssignableFrom(o.getClass());
 124     }
 125 }