1 /*
   2  * Copyright (c) 2018, 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.constant;
  26 
  27 import java.lang.invoke.MethodHandle;
  28 import java.lang.invoke.MethodHandleInfo;
  29 import java.util.OptionalInt;
  30 import java.util.stream.Stream;
  31 
  32 import jdk.internal.vm.annotation.Stable;
  33 
  34 import static java.lang.invoke.MethodHandleInfo.REF_getField;
  35 import static java.lang.invoke.MethodHandleInfo.REF_getStatic;
  36 import static java.lang.invoke.MethodHandleInfo.REF_invokeInterface;
  37 import static java.lang.invoke.MethodHandleInfo.REF_invokeSpecial;
  38 import static java.lang.invoke.MethodHandleInfo.REF_invokeStatic;
  39 import static java.lang.invoke.MethodHandleInfo.REF_invokeVirtual;
  40 import static java.lang.invoke.MethodHandleInfo.REF_newInvokeSpecial;
  41 import static java.lang.invoke.MethodHandleInfo.REF_putField;
  42 import static java.lang.invoke.MethodHandleInfo.REF_putStatic;
  43 
  44 /**
  45  * A <a href="package-summary.html#nominal">nominal descriptor</a> for a direct
  46  * {@link MethodHandle}.  A {@linkplain DirectMethodHandleDesc} corresponds to
  47  * a {@code Constant_MethodHandle_info} entry in the constant pool of a classfile.
  48  *
  49  * @apiNote In the future, if the Java language permits, {@linkplain DirectMethodHandleDesc}
  50  * may become a {@code sealed} interface, which would prohibit subclassing except
  51  * by explicitly permitted types.  Non-platform classes should not implement
  52  * {@linkplain DirectMethodHandleDesc} directly.
  53  *
  54  * @since 12
  55  */
  56 public interface DirectMethodHandleDesc extends MethodHandleDesc {
  57     /**
  58      * Kinds of method handles that can be described with {@linkplain DirectMethodHandleDesc}.
  59      *
  60      * @since 12
  61      */
  62     enum Kind {
  63         /** A method handle for a method invoked as with {@code invokestatic} */
  64         STATIC(REF_invokeStatic),
  65         /** A method handle for a method invoked as with {@code invokestatic} */
  66         INTERFACE_STATIC(REF_invokeStatic, true),
  67         /** A method handle for a method invoked as with {@code invokevirtual} */
  68         VIRTUAL(REF_invokeVirtual),
  69         /** A method handle for a method invoked as with {@code invokeinterface} */
  70         INTERFACE_VIRTUAL(REF_invokeInterface, true),
  71         /** A method handle for a method invoked as with {@code invokespecial} */
  72         SPECIAL(REF_invokeSpecial),
  73         /** A method handle for an interface method invoked as with {@code invokespecial} */
  74         INTERFACE_SPECIAL(REF_invokeSpecial, true),
  75         /** A method handle for a constructor */
  76         CONSTRUCTOR(REF_newInvokeSpecial),
  77         /** A method handle for a read accessor for an instance field  */
  78         GETTER(REF_getField),
  79         /** A method handle for a write accessor for an instance field  */
  80         SETTER(REF_putField),
  81         /** A method handle for a read accessor for a static field  */
  82         STATIC_GETTER(REF_getStatic),
  83         /** A method handle for a write accessor for a static field  */
  84         STATIC_SETTER(REF_putStatic);
  85 
  86         /** The corresponding {@code refKind} value for this kind of method handle,
  87          * as defined by {@link MethodHandleInfo}
  88          */
  89         public final int refKind;
  90 
  91         /** Is this an interface
  92          */
  93         public final boolean isInterface;
  94         Kind(int refKind) {
  95             this(refKind, false);
  96         }
  97 
  98         Kind(int refKind, boolean isInterface) { this.refKind = refKind; this.isInterface = isInterface; }
  99 
 100         /**
 101          * Returns the enumeration member with the given {@code refKind} field.
 102          * Behaves as if {@code valueOf(refKind, false)}.  As a special case,
 103          * if {@code refKind} is {@code REF_invokeInterface} (9) then the
 104          * {@code isInterface} field will be true.
 105          *
 106          * @param refKind refKind of desired member
 107          * @return the matching enumeration member
 108          * @throws IllegalArgumentException if there is no such member
 109          */
 110         public static Kind valueOf(int refKind) {
 111             return valueOf(refKind, false);
 112         }
 113 
 114         /**
 115          * Returns the enumeration member with the given the {@code refKind} and
 116          * {@code isInterface} arguments.
 117          * For most values of {@code refKind} there is an exact match regardless of the value of {@code isInterface}.
 118          * These are:
 119          * <UL>
 120          *     <LI>{@code REF_invokeVirtual} which matches to {@code VIRTUAL}
 121          *     <LI>{@code REF_invokeInterface} which matches to {@code INTERFACE_VIRTUAL}
 122          *     <LI>{@code REF_newInvokeSpecial} which matches to {@code CONSTRUCTOR}
 123          *     <LI>{@code REF_getField} which matches to {@code GETTER}
 124          *     <LI>{@code REF_putField} which matches to {@code SETTER}
 125          *     <LI>{@code REF_getStatic} which matches to {@code STATIC_GETTER}
 126          *     <LI>{@code REF_putStatic} which matches to {@code STATIC_SETTER}
 127          * </UL>
 128          * As for the rest, the returned kind will depend on the value (false or true accordingly) of {@code isInterface}:
 129          * <UL>
 130          *     <LI>{@code REF_invokeStatic} which matches to {@code STATIC} or {@code INTERFACE_STATIC}
 131          *     <LI>{@code REF_invokeSpecial} which matches to {@code SPECIAL} or {@code INTERFACE_SPECIAL}
 132          * </UL>
 133          * @param refKind refKind of desired member
 134          * @param isInterface whether desired member is for interface methods
 135          * @return the matching enumeration member
 136          * @throws IllegalArgumentException if there is no such member
 137          */
 138         public static Kind valueOf(int refKind, boolean isInterface) {
 139             int i = tableIndex(refKind, isInterface);
 140             if (i >= 0 && i < TABLE.length) {
 141                 Kind kind = TABLE[i];
 142                 if (kind == null) {
 143                     throw new IllegalArgumentException(String.format("refKind=%d", refKind));
 144                 }
 145                 if (kind.refKind == refKind && kind.isInterface == isInterface) {
 146                     return kind;
 147                 }
 148             }
 149             throw new IllegalArgumentException(String.format("refKind=%d", refKind));
 150         }
 151 
 152         private static int tableIndex(int refKind, boolean isInterface) {
 153             if (refKind < 0)  return refKind;
 154             return (refKind * 2) + (isInterface ? 1 : 0);
 155         }
 156 
 157         private static final @Stable Kind[] TABLE;
 158 
 159         static {
 160             // Pack the static table.
 161             int max = 0;
 162             for (Kind k : values())
 163                 max = Math.max(max, tableIndex(k.refKind, true));
 164 
 165             TABLE = new Kind[max+1];
 166             for (Kind kind : values()) {
 167                 int i = tableIndex(kind.refKind, kind.isInterface);
 168                 if (i >= TABLE.length || TABLE[i] != null)
 169                     throw new AssertionError("TABLE entry for " + kind);
 170                 TABLE[i] = kind;
 171             }
 172 
 173             // Pack in some aliases also.
 174             int ii = tableIndex(REF_invokeInterface, false);
 175             if (TABLE[ii] != null)
 176                 throw new AssertionError("TABLE entry for (invokeInterface, false) used by " + TABLE[ii]);
 177             TABLE[ii] = INTERFACE_VIRTUAL;
 178 
 179             for (Kind kind : values()) {
 180                 if (!kind.isInterface) {
 181                     // Add extra cache entry to alias the isInterface case.
 182                     // For example, (REF_getStatic, X) will produce STATIC_GETTER
 183                     // for either truth value of X.
 184                     int i = tableIndex(kind.refKind, true);
 185                     if (TABLE[i] == null) {
 186                         // There is not a specific Kind for interfaces
 187                         if (kind == VIRTUAL)  kind = INTERFACE_VIRTUAL;
 188                         if (TABLE[i] == null)  TABLE[i] = kind;
 189                     }
 190                 }
 191             }
 192         }
 193 
 194         /**
 195          * Does this {@code Kind} correspond to a virtual method invocation?
 196          *
 197          * @return if this {@code Kind} corresponds to a virtual method invocation
 198          */
 199         boolean isVirtualMethod() {
 200             switch (this) {
 201                 case VIRTUAL:
 202                 case SPECIAL:
 203                 case INTERFACE_VIRTUAL:
 204                 case INTERFACE_SPECIAL:
 205                     return true;
 206                 default:
 207                     return false;
 208             }
 209         }
 210     }
 211 
 212     /**
 213      * Returns the {@code kind} of the method handle described by this nominal
 214      * descriptor.
 215      *
 216      * @return the {@link Kind}
 217      */
 218     Kind kind();
 219 
 220     /**
 221      * Returns the {@code refKind} of the method handle described by this nominal
 222      * reference, as defined by {@link MethodHandleInfo}.
 223      *
 224      * @return the reference kind
 225      */
 226     int refKind();
 227 
 228     /**
 229      * Indicates if the method is declared by an interface
 230      *
 231      * @return true if the method is declared by an interface
 232      */
 233     boolean isOwnerInterface();
 234 
 235     /**
 236      * Returns a {@link ClassDesc} describing the class declaring the
 237      * method or field described by this nominal descriptor.
 238      *
 239      * @return the class declaring the method or field
 240      */
 241     ClassDesc owner();
 242 
 243     /**
 244      * Returns the name of the method or field described by this nominal descriptor.
 245      * For constructors, returns the reserved name {@code "<init>"}.
 246      *
 247      * @return the name of the method or field
 248      */
 249     String methodName();
 250 
 251     /**
 252      * Returns the lookup descriptor of the method handle described by this descriptor,
 253      * after adjusting for the invocation mode.  This will correspond to either
 254      * a method type descriptor string (for methods and constructors), or a field
 255      * descriptor string (for field access method handles).  The lookup descriptor
 256      * string is in the same format as accepted by {@link MethodHandleDesc#of(Kind, ClassDesc, String, String)}.
 257      *
 258      * @return the lookup descriptor string
 259      */
 260     String lookupDescriptor();
 261 }