--- old/src/java.base/share/classes/jdk/internal/reflect/ConstantPool.java 2018-09-28 11:54:31.000000000 -0700 +++ new/src/java.base/share/classes/jdk/internal/reflect/ConstantPool.java 2018-09-28 11:54:30.000000000 -0700 @@ -25,49 +25,63 @@ package jdk.internal.reflect; -import java.lang.reflect.*; -import java.util.Set; +import jdk.internal.vm.annotation.Stable; + +import java.lang.constant.*; +import java.lang.constant.DirectMethodHandleDesc.Kind; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.util.Arrays; /** Provides reflective access to the constant pools of classes. Currently this is needed to provide reflective access to annotations - but may be used by other internal subsystems in the future. */ + and bootstrap methods + but may be used by other internal subsystems in the future. +

+ When applying this API to internal subsystems, take special account + of interactions with the JVMTI class redefinition features. + If a class reflects on its constant pool, and then is redefined to + have a different constant pool, the data reported by the reflected + constant pool may become out of date. + */ public class ConstantPool { // Number of entries in this constant pool (= maximum valid constant pool index) - public int getSize() { return getSize0 (constantPoolOop); } - public Class getClassAt (int index) { return getClassAt0 (constantPoolOop, index); } - public Class getClassAtIfLoaded (int index) { return getClassAtIfLoaded0 (constantPoolOop, index); } + public int getSize() { return getSize1(); } + // Class holding this CP + public Class getHolder() { return getHolder1(); } + public Class getClassAt (int index) { return (Class) getRefAt(index, Tag.CLASS, true); } + + public Class getClassAtIfLoaded (int index) { return (Class) getRefAt(index, Tag.CLASS, false); } // Returns a class reference index for a method or a field. - public int getClassRefIndexAt(int index) { - return getClassRefIndexAt0(constantPoolOop, index); - } + public int getClassRefIndexAt(int index) { return getWordAt1(index, 0); } // Returns either a Method or Constructor. // Static initializers are returned as Method objects. - public Member getMethodAt (int index) { return getMethodAt0 (constantPoolOop, index); } - public Member getMethodAtIfLoaded(int index) { return getMethodAtIfLoaded0(constantPoolOop, index); } - public Field getFieldAt (int index) { return getFieldAt0 (constantPoolOop, index); } - public Field getFieldAtIfLoaded (int index) { return getFieldAtIfLoaded0 (constantPoolOop, index); } + public Member getMethodAt (int index) { return (Member) getRefAt(index, Tag.METHODREF, true); } + public Member getMethodAtIfLoaded(int index) { return (Member) getRefAt(index, Tag.METHODREF, false); } + public Field getFieldAt (int index) { return (Field) getRefAt(index, Tag.FIELDREF, true); } + public Field getFieldAtIfLoaded (int index) { return (Field) getRefAt(index, Tag.FIELDREF, false); } // Fetches the class name, member (field, method or interface // method) name, and type descriptor as an array of three Strings - public String[] getMemberRefInfoAt (int index) { return getMemberRefInfoAt0 (constantPoolOop, index); } - // Returns a name and type reference index for a method, a field or an invokedynamic. - public int getNameAndTypeRefIndexAt(int index) { - return getNameAndTypeRefIndexAt0(constantPoolOop, index); + public String[] getMemberRefInfoAt (int index) { + return new String[] { getUtf8At(index, 2), getUtf8At(index, 3), getUtf8At(index, 4) }; } + + // Returns a name and type reference index for a method, a field or an invokedynamic. + public int getNameAndTypeRefIndexAt(int index) { return getWordAt1(index, 1); } // Fetches the name and type from name_and_type index as an array of two Strings public String[] getNameAndTypeRefInfoAt(int index) { - return getNameAndTypeRefInfoAt0(constantPoolOop, index); - } - public int getIntAt (int index) { return getIntAt0 (constantPoolOop, index); } - public long getLongAt (int index) { return getLongAt0 (constantPoolOop, index); } - public float getFloatAt (int index) { return getFloatAt0 (constantPoolOop, index); } - public double getDoubleAt (int index) { return getDoubleAt0 (constantPoolOop, index); } - public String getStringAt (int index) { return getStringAt0 (constantPoolOop, index); } - public String getUTF8At (int index) { return getUTF8At0 (constantPoolOop, index); } - public Tag getTagAt(int index) { - return Tag.valueOf(getTagAt0(constantPoolOop, index)); + return (String[]) getRefAt(index, Tag.NAMEANDTYPE, true); } + public int getIntAt (int index) { return getIntAt1 (index); } + public long getLongAt (int index) { return getLongAt1 (index); } + public float getFloatAt (int index) { return getFloatAt1 (index); } + public double getDoubleAt (int index) { return getDoubleAt1 (index); } + public String getStringAt (int index) { return (String) getRefAt(index, Tag.STRING, true); } + public String getUTF8At (int index) { return (String) getRefAt1(index, 0, BAR_SYMREF, null); } + public Tag getTagAt (int index) { return Tag.valueOf(getCachedTagAt(index)); } + public static enum Tag { UTF8(1), INTEGER(3), @@ -82,7 +96,8 @@ NAMEANDTYPE(12), METHODHANDLE(15), METHODTYPE(16), - INVOKEDYNAMIC(18), + DYNAMIC(17), // condy + INVOKEDYNAMIC(18), // indy INVALID(0); private final int tagCode; @@ -91,42 +106,196 @@ this.tagCode = tagCode; } - private static Tag valueOf(byte v) { - for (Tag tag : Tag.values()) { - if (tag.tagCode == v) { - return tag; - } + private static @Stable final Tag TAG_TABLE[] = new Tag[20]; + static { + for (Tag tag : values()) { + assert(TAG_TABLE[tag.tagCode] == null); // unique + TAG_TABLE[tag.tagCode] = tag; } + } + private static Tag valueOf(byte v) { + Tag tag = (v >= 0 && v < TAG_TABLE.length) ? TAG_TABLE[v] : null; + if (tag != null) return tag; throw new IllegalArgumentException("Unknown constant pool tag code " + v); } } + + public Object getConstantAt(int index) { + return getRefAt1(index, -1, BAR_FORCE, null); + } + public Object getConstantAt(int index, Object ifNotPresent) { + return getRefAt1(index, -1, BAR_IFPRESENT, ifNotPresent); + } + + private static final byte BAR_IFPRESENT = 0, BAR_FORCE = 1, BAR_SYMREF = 2; + + public ConstantDesc getConstantDescAt(int index) { + Tag tag = getTagAt(index); + switch (tag) { + case UTF8: return getUTF8At(index); + case INTEGER: return getIntAt(index); + case LONG: return getLongAt(index); + case FLOAT: return getFloatAt(index); + case DOUBLE: return getDoubleAt(index); + case CLASS: return classDescOf(getUTF8At(index)); + case STRING: return getStringAt(index); + //case FIELDREF: + //case METHODREF: + //case INTERFACEMETHODREF: + //case NAMEANDTYPE: + case METHODHANDLE: + { + int w0 = getWordAt1(index, 0); // refKind + int w1 = getWordAt1(index, 1); // member + boolean isInterface = getTagAt(w1) == Tag.INTERFACEMETHODREF; + Kind kind = Kind.valueOf(w0, isInterface); + // Note: Even if isInterface is true Kind.valueOf may discard it. + ClassDesc clazz = classDescOf(getUtf8At(w1, 2)); + return MethodHandleDesc.of(kind, clazz, getUtf8At(w1, 3), getUtf8At(w1, 4)); + } + case METHODTYPE: + return MethodTypeDesc.ofDescriptor(getUTF8At(index)); + //case INVOKEDYNAMIC: + case DYNAMIC: + return (DynamicConstantDesc) getBootstrappedEntryAt(index); + } + throw new IllegalArgumentException("no ConstantDesc representation for "+tag+" at CP["+index+"]"); + } + + public DynamicCallSiteDesc getDynamicCallSiteDescAt(int index) { + checkTag(index, Tag.INVOKEDYNAMIC); + return (DynamicCallSiteDesc) getBootstrappedEntryAt(index); + } + + /** + * Get bootstrap arguments for the indy or condy at the given index. + * @param index CP index of the selected indy or condy constant + * @param start which bootstrap argument to start copying + * @param end which bootstrap argument (exclusive) to stop copying + * @param buf where to put the copied arguments (must be int[] for BAR_SYMREF, Object[] for other modes) + * @param pos where to store arguments into the buf + * @param resolving resolution mode: 0=BAR_IFPRESENT, 1=BAR_FORCE, 2=BAR_SYMREF + * @param ifNotPresent in BAR_IFPRESENT mode, sentinel to store for values not yet resolved + * @param ifNullConstant in BAR_IFPRESENT or BAR_FORCE mode, sentinel to store for an actual {@code null} + * @param skipNonNull BAR_IFPRESENT or BAR_FORCE mode, do not store over elements of buf which are non-{@code null} + */ + public void copyOutBootstrapArgumentsAt(int index, + int start, int end, + Object buf, int pos, + byte resolving, + Object ifNotPresent, + Object ifNullConstant, + boolean skipNonNull) { + if (start < 0 || end < start) throw new IllegalArgumentException(); + copyOutRefsAt1(index, start + BSS_HEADER_WORDS, end + BSS_HEADER_WORDS, + buf, pos, resolving, ifNotPresent, ifNullConstant, skipNonNull); + } + //--------------------------------------------------------------------------- // Internals only below this point // - static { - Reflection.registerFieldsToFilter(ConstantPool.class, Set.of("constantPoolOop")); + private @Stable byte[] tags; + private byte getCachedTagAt(int index) { + if (tags == null) tags = getTags1(); + if (index >= 0 && index < tags.length) { + return tags[index]; + } + // constant pool can grow over time + return getTagAt1(index); + } + + private static final int + BSS_HEADER_WORDS = 6, // { attrIndex, natIndex, bsm, name, type, argc } + BSS_HEADER_BSM = 2, BSS_HEADER_NAME = 3, BSS_HEADER_TYPE = 4, BSS_HEADER_ARGC = 5; + private Object getBootstrappedEntryAt(int index) { + int argc = getWordAt1(index, BSS_HEADER_ARGC); + int[] argIndexes = copyOutWordsAt(index, BSS_HEADER_WORDS, BSS_HEADER_WORDS+argc); + int bsmIndex = getWordAt1(index, BSS_HEADER_BSM); + DirectMethodHandleDesc bsm = (DirectMethodHandleDesc) getConstantDescAt(bsmIndex); + String name = (String) getRefAt1(index, BSS_HEADER_NAME, BAR_FORCE, null); + String type = (String) getRefAt1(index, BSS_HEADER_TYPE, BAR_FORCE, null); + ConstantDesc[] args = new ConstantDesc[argc]; + for (int i = 0; i < argc; i++) { + args[i] = getConstantDescAt(argIndexes[i]); + } + if (getTagAt(index) == Tag.DYNAMIC) + return DynamicConstantDesc.ofNamed(bsm, name, ClassDesc.ofDescriptor(type), args); + else + return DynamicCallSiteDesc.of(bsm, name, MethodTypeDesc.ofDescriptor(type), args); + } + + + private ClassDesc classDescOf(String name) { + return ClassDesc.of(name.replace('/', '.')); } - // HotSpot-internal constant pool object (set by the VM, name known to the VM) - private Object constantPoolOop; + private Object getRefAt(int index, Tag tag, boolean forceResolution) { + return getRefAt1(index, -1, forceResolution ? BAR_FORCE : BAR_IFPRESENT, null); + } + + private int getWordAt(int index, Tag tag, int word) { + checkTag(index, tag); + return getWordAt1(index, word); + } + + private void checkTag(int index, Tag needTag) { + Tag haveTag = getTagAt(index); + if (haveTag == needTag) return; + switch (needTag) { + case METHODREF: + if (haveTag == Tag.INTERFACEMETHODREF) return; + break; + } + throw new IllegalArgumentException("expected "+needTag+" but found "+haveTag); + } + + private String getUtf8At(int index, int word) { + return (String) getRefAt1(index, word, BAR_SYMREF, null); + } + + + private native Class getHolder1 (); + private native int getSize1 (); + private native int getWordCountAt1 (int index); + private native int getWordAt1 (int index, int word); + private native Object getRefAt1 (int index, int word, byte resolving, Object ifNotPresent); + private native int getIntAt1 (int index); + private native long getLongAt1 (int index); + private native float getFloatAt1 (int index); + private native double getDoubleAt1 (int index); + private native byte getTagAt1 (int index); + private native byte[] getTags1 (); + + /** + * @param index which CP entry to process + * @param startWord which word to start copying + * @param endWord which word (exclusive) to stop copying + * @param buf where to put the copied arguments (must be int[] for BAR_SYMREF, Object[] for other modes) + * @param bufPos where to store arguments into the buf + * @param resolving resolution mode: 0=BAR_IFPRESENT, 1=BAR_FORCE, 2=BAR_SYMREF + * @param ifNotPresent in BAR_IFPRESENT mode, sentinel to store for values not yet resolved + * @param ifNullConstant in BAR_IFPRESENT or BAR_FORCE mode, sentinel to store for an actual {@code null} + * @param skipNonNull BAR_IFPRESENT or BAR_FORCE mode, do not store over elements of buf which are non-{@code null} + */ + private native void copyOutRefsAt1(int index, + int startWord, int endWord, + Object buf, int bufPos, // destination + byte resolving, + Object ifNotPresent, + Object ifNullConstant, + boolean skipNonNull); + + private int[] copyOutWordsAt(int index, int startWord, int endWord) { + int[] buf = new int[endWord - startWord]; + copyOutRefsAt1(index, startWord, endWord, buf, 0, BAR_SYMREF, null, null, false); + return buf; + } + private Object[] copyOutRefsAt(int index, int startWord, int endWord, boolean forceResolution, + Object ifNotPresent, Object ifNullConstant) { + Object[] buf = new Object[endWord - startWord]; + copyOutRefsAt1(index, startWord, endWord, buf, 0, forceResolution ? BAR_FORCE : BAR_IFPRESENT, ifNotPresent, ifNullConstant, false); + return buf; + } - private native int getSize0 (Object constantPoolOop); - private native Class getClassAt0 (Object constantPoolOop, int index); - private native Class getClassAtIfLoaded0 (Object constantPoolOop, int index); - private native int getClassRefIndexAt0 (Object constantPoolOop, int index); - private native Member getMethodAt0 (Object constantPoolOop, int index); - private native Member getMethodAtIfLoaded0(Object constantPoolOop, int index); - private native Field getFieldAt0 (Object constantPoolOop, int index); - private native Field getFieldAtIfLoaded0 (Object constantPoolOop, int index); - private native String[] getMemberRefInfoAt0 (Object constantPoolOop, int index); - private native int getNameAndTypeRefIndexAt0(Object constantPoolOop, int index); - private native String[] getNameAndTypeRefInfoAt0(Object constantPoolOop, int index); - private native int getIntAt0 (Object constantPoolOop, int index); - private native long getLongAt0 (Object constantPoolOop, int index); - private native float getFloatAt0 (Object constantPoolOop, int index); - private native double getDoubleAt0 (Object constantPoolOop, int index); - private native String getStringAt0 (Object constantPoolOop, int index); - private native String getUTF8At0 (Object constantPoolOop, int index); - private native byte getTagAt0 (Object constantPoolOop, int index); }