1 /* 2 * Copyright (c) 2003, 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 26 package jdk.internal.reflect; 27 28 import jdk.internal.vm.annotation.Stable; 29 30 import java.lang.constant.*; 31 import java.lang.constant.DirectMethodHandleDesc.Kind; 32 import java.lang.reflect.Field; 33 import java.lang.reflect.Member; 34 import java.util.Arrays; 35 36 /** Provides reflective access to the constant pools of classes. 37 Currently this is needed to provide reflective access to annotations 38 and bootstrap methods 39 but may be used by other internal subsystems in the future. 40 <p> 41 When applying this API to internal subsystems, take special account 42 of interactions with the JVMTI class redefinition features. 43 If a class reflects on its constant pool, and then is redefined to 44 have a different constant pool, the data reported by the reflected 45 constant pool may become out of date. 46 */ 47 48 public class ConstantPool { 49 // Number of entries in this constant pool (= maximum valid constant pool index) 50 public int getSize() { return getSize1(); } 51 // Class holding this CP 52 public Class<?> getHolder() { return getHolder1(); } 53 public Class<?> getClassAt (int index) { return (Class<?>) getRefAt(index, Tag.CLASS, true); } 54 55 public Class<?> getClassAtIfLoaded (int index) { return (Class<?>) getRefAt(index, Tag.CLASS, false); } 56 // Returns a class reference index for a method or a field. 57 public int getClassRefIndexAt(int index) { return getWordAt1(index, 0); } 58 // Returns either a Method or Constructor. 59 // Static initializers are returned as Method objects. 60 public Member getMethodAt (int index) { return (Member) getRefAt(index, Tag.METHODREF, true); } 61 public Member getMethodAtIfLoaded(int index) { return (Member) getRefAt(index, Tag.METHODREF, false); } 62 public Field getFieldAt (int index) { return (Field) getRefAt(index, Tag.FIELDREF, true); } 63 public Field getFieldAtIfLoaded (int index) { return (Field) getRefAt(index, Tag.FIELDREF, false); } 64 // Fetches the class name, member (field, method or interface 65 // method) name, and type descriptor as an array of three Strings 66 public String[] getMemberRefInfoAt (int index) { 67 return new String[] { getUtf8At(index, 2), getUtf8At(index, 3), getUtf8At(index, 4) }; 68 } 69 70 // Returns a name and type reference index for a method, a field or an invokedynamic. 71 public int getNameAndTypeRefIndexAt(int index) { return getWordAt1(index, 1); } 72 // Fetches the name and type from name_and_type index as an array of two Strings 73 public String[] getNameAndTypeRefInfoAt(int index) { 74 return (String[]) getRefAt(index, Tag.NAMEANDTYPE, true); 75 } 76 77 public int getIntAt (int index) { return getIntAt1 (index); } 78 public long getLongAt (int index) { return getLongAt1 (index); } 79 public float getFloatAt (int index) { return getFloatAt1 (index); } 80 public double getDoubleAt (int index) { return getDoubleAt1 (index); } 81 public String getStringAt (int index) { return (String) getRefAt(index, Tag.STRING, true); } 82 public String getUTF8At (int index) { return (String) getRefAt1(index, 0, BAR_SYMREF, null); } 83 public Tag getTagAt (int index) { return Tag.valueOf(getCachedTagAt(index)); } 84 85 public static enum Tag { 86 UTF8(1), 87 INTEGER(3), 88 FLOAT(4), 89 LONG(5), 90 DOUBLE(6), 91 CLASS(7), 92 STRING(8), 93 FIELDREF(9), 94 METHODREF(10), 95 INTERFACEMETHODREF(11), 96 NAMEANDTYPE(12), 97 METHODHANDLE(15), 98 METHODTYPE(16), 99 DYNAMIC(17), // condy 100 INVOKEDYNAMIC(18), // indy 101 INVALID(0); 102 103 private final int tagCode; 104 105 private Tag(int tagCode) { 106 this.tagCode = tagCode; 107 } 108 109 private static @Stable final Tag TAG_TABLE[] = new Tag[20]; 110 static { 111 for (Tag tag : values()) { 112 assert(TAG_TABLE[tag.tagCode] == null); // unique 113 TAG_TABLE[tag.tagCode] = tag; 114 } 115 } 116 private static Tag valueOf(byte v) { 117 Tag tag = (v >= 0 && v < TAG_TABLE.length) ? TAG_TABLE[v] : null; 118 if (tag != null) return tag; 119 throw new IllegalArgumentException("Unknown constant pool tag code " + v); 120 } 121 } 122 123 public Object getConstantAt(int index) { 124 return getRefAt1(index, -1, BAR_FORCE, null); 125 } 126 public Object getConstantAt(int index, Object ifNotPresent) { 127 return getRefAt1(index, -1, BAR_IFPRESENT, ifNotPresent); 128 } 129 130 private static final byte BAR_IFPRESENT = 0, BAR_FORCE = 1, BAR_SYMREF = 2; 131 132 public ConstantDesc<?> getConstantDescAt(int index) { 133 Tag tag = getTagAt(index); 134 switch (tag) { 135 case UTF8: return getUTF8At(index); 136 case INTEGER: return getIntAt(index); 137 case LONG: return getLongAt(index); 138 case FLOAT: return getFloatAt(index); 139 case DOUBLE: return getDoubleAt(index); 140 case CLASS: return classDescOf(getUTF8At(index)); 141 case STRING: return getStringAt(index); 142 //case FIELDREF: 143 //case METHODREF: 144 //case INTERFACEMETHODREF: 145 //case NAMEANDTYPE: 146 case METHODHANDLE: 147 { 148 int w0 = getWordAt1(index, 0); // refKind 149 int w1 = getWordAt1(index, 1); // member 150 boolean isInterface = getTagAt(w1) == Tag.INTERFACEMETHODREF; 151 Kind kind = Kind.valueOf(w0, isInterface); 152 // Note: Even if isInterface is true Kind.valueOf may discard it. 153 ClassDesc clazz = classDescOf(getUtf8At(w1, 2)); 154 return MethodHandleDesc.of(kind, clazz, getUtf8At(w1, 3), getUtf8At(w1, 4)); 155 } 156 case METHODTYPE: 157 return MethodTypeDesc.ofDescriptor(getUTF8At(index)); 158 //case INVOKEDYNAMIC: 159 case DYNAMIC: 160 return (DynamicConstantDesc) getBootstrappedEntryAt(index); 161 } 162 throw new IllegalArgumentException("no ConstantDesc representation for "+tag+" at CP["+index+"]"); 163 } 164 165 public DynamicCallSiteDesc getDynamicCallSiteDescAt(int index) { 166 checkTag(index, Tag.INVOKEDYNAMIC); 167 return (DynamicCallSiteDesc) getBootstrappedEntryAt(index); 168 } 169 170 /** 171 * Get bootstrap arguments for the indy or condy at the given index. 172 * @param index CP index of the selected indy or condy constant 173 * @param start which bootstrap argument to start copying 174 * @param end which bootstrap argument (exclusive) to stop copying 175 * @param buf where to put the copied arguments (must be int[] for BAR_SYMREF, Object[] for other modes) 176 * @param pos where to store arguments into the buf 177 * @param resolving resolution mode: 0=BAR_IFPRESENT, 1=BAR_FORCE, 2=BAR_SYMREF 178 * @param ifNotPresent in BAR_IFPRESENT mode, sentinel to store for values not yet resolved 179 * @param ifNullConstant in BAR_IFPRESENT or BAR_FORCE mode, sentinel to store for an actual {@code null} 180 * @param skipNonNull BAR_IFPRESENT or BAR_FORCE mode, do not store over elements of buf which are non-{@code null} 181 */ 182 public void copyOutBootstrapArgumentsAt(int index, 183 int start, int end, 184 Object buf, int pos, 185 byte resolving, 186 Object ifNotPresent, 187 Object ifNullConstant, 188 boolean skipNonNull) { 189 if (start < 0 || end < start) throw new IllegalArgumentException(); 190 copyOutRefsAt1(index, start + BSS_HEADER_WORDS, end + BSS_HEADER_WORDS, 191 buf, pos, resolving, ifNotPresent, ifNullConstant, skipNonNull); 192 } 193 194 //--------------------------------------------------------------------------- 195 // Internals only below this point 196 // 197 198 private @Stable byte[] tags; 199 private byte getCachedTagAt(int index) { 200 if (tags == null) tags = getTags1(); 201 if (index >= 0 && index < tags.length) { 202 return tags[index]; 203 } 204 // constant pool can grow over time 205 return getTagAt1(index); 206 } 207 208 private static final int 209 BSS_HEADER_WORDS = 6, // { attrIndex, natIndex, bsm, name, type, argc } 210 BSS_HEADER_BSM = 2, BSS_HEADER_NAME = 3, BSS_HEADER_TYPE = 4, BSS_HEADER_ARGC = 5; 211 private Object getBootstrappedEntryAt(int index) { 212 int argc = getWordAt1(index, BSS_HEADER_ARGC); 213 int[] argIndexes = copyOutWordsAt(index, BSS_HEADER_WORDS, BSS_HEADER_WORDS+argc); 214 int bsmIndex = getWordAt1(index, BSS_HEADER_BSM); 215 DirectMethodHandleDesc bsm = (DirectMethodHandleDesc) getConstantDescAt(bsmIndex); 216 String name = (String) getRefAt1(index, BSS_HEADER_NAME, BAR_FORCE, null); 217 String type = (String) getRefAt1(index, BSS_HEADER_TYPE, BAR_FORCE, null); 218 ConstantDesc<?>[] args = new ConstantDesc<?>[argc]; 219 for (int i = 0; i < argc; i++) { 220 args[i] = getConstantDescAt(argIndexes[i]); 221 } 222 if (getTagAt(index) == Tag.DYNAMIC) 223 return DynamicConstantDesc.ofNamed(bsm, name, ClassDesc.ofDescriptor(type), args); 224 else 225 return DynamicCallSiteDesc.of(bsm, name, MethodTypeDesc.ofDescriptor(type), args); 226 } 227 228 229 private ClassDesc classDescOf(String name) { 230 return ClassDesc.of(name.replace('/', '.')); 231 } 232 233 private Object getRefAt(int index, Tag tag, boolean forceResolution) { 234 return getRefAt1(index, -1, forceResolution ? BAR_FORCE : BAR_IFPRESENT, null); 235 } 236 237 private int getWordAt(int index, Tag tag, int word) { 238 checkTag(index, tag); 239 return getWordAt1(index, word); 240 } 241 242 private void checkTag(int index, Tag needTag) { 243 Tag haveTag = getTagAt(index); 244 if (haveTag == needTag) return; 245 switch (needTag) { 246 case METHODREF: 247 if (haveTag == Tag.INTERFACEMETHODREF) return; 248 break; 249 } 250 throw new IllegalArgumentException("expected "+needTag+" but found "+haveTag); 251 } 252 253 private String getUtf8At(int index, int word) { 254 return (String) getRefAt1(index, word, BAR_SYMREF, null); 255 } 256 257 258 private native Class<?> getHolder1 (); 259 private native int getSize1 (); 260 private native int getWordCountAt1 (int index); 261 private native int getWordAt1 (int index, int word); 262 private native Object getRefAt1 (int index, int word, byte resolving, Object ifNotPresent); 263 private native int getIntAt1 (int index); 264 private native long getLongAt1 (int index); 265 private native float getFloatAt1 (int index); 266 private native double getDoubleAt1 (int index); 267 private native byte getTagAt1 (int index); 268 private native byte[] getTags1 (); 269 270 /** 271 * @param index which CP entry to process 272 * @param startWord which word to start copying 273 * @param endWord which word (exclusive) to stop copying 274 * @param buf where to put the copied arguments (must be int[] for BAR_SYMREF, Object[] for other modes) 275 * @param bufPos where to store arguments into the buf 276 * @param resolving resolution mode: 0=BAR_IFPRESENT, 1=BAR_FORCE, 2=BAR_SYMREF 277 * @param ifNotPresent in BAR_IFPRESENT mode, sentinel to store for values not yet resolved 278 * @param ifNullConstant in BAR_IFPRESENT or BAR_FORCE mode, sentinel to store for an actual {@code null} 279 * @param skipNonNull BAR_IFPRESENT or BAR_FORCE mode, do not store over elements of buf which are non-{@code null} 280 */ 281 private native void copyOutRefsAt1(int index, 282 int startWord, int endWord, 283 Object buf, int bufPos, // destination 284 byte resolving, 285 Object ifNotPresent, 286 Object ifNullConstant, 287 boolean skipNonNull); 288 289 private int[] copyOutWordsAt(int index, int startWord, int endWord) { 290 int[] buf = new int[endWord - startWord]; 291 copyOutRefsAt1(index, startWord, endWord, buf, 0, BAR_SYMREF, null, null, false); 292 return buf; 293 } 294 private Object[] copyOutRefsAt(int index, int startWord, int endWord, boolean forceResolution, 295 Object ifNotPresent, Object ifNullConstant) { 296 Object[] buf = new Object[endWord - startWord]; 297 copyOutRefsAt1(index, startWord, endWord, buf, 0, forceResolution ? BAR_FORCE : BAR_IFPRESENT, ifNotPresent, ifNullConstant, false); 298 return buf; 299 } 300 301 }