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