< prev index next >

src/java.base/share/classes/jdk/internal/reflect/ConstantPool.java

Print this page
rev 52749 : Bootstrap method consolidation
* clean up and simplify JDK support code for BSM invocation
* simplify JVM bootstrap handshake: use BootstrapCallInfo only
* remove unused JVM paths and data fields
* move bootstrap argument processing from MethodHandleNatives to ConstantPool
* remove ConstantGroup; merge argument access into BootstrapCallInfo
* adjust BSM argument access: remove copyArguments, add argumentRef API
* add metadata-free BSM modes, including symbolic arguments from CP

*** 23,75 **** * questions. */ package jdk.internal.reflect; ! import java.lang.reflect.*; ! import java.util.Set; /** 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. */ 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); } // Returns a class reference index for a method or a field. ! public int getClassRefIndexAt(int index) { ! return getClassRefIndexAt0(constantPoolOop, index); ! } // 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); } // 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); } // 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)); } public static enum Tag { UTF8(1), INTEGER(3), FLOAT(4), LONG(5), --- 23,89 ---- * questions. */ package jdk.internal.reflect; ! 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 ! and bootstrap methods ! but may be used by other internal subsystems in the future. ! <p> ! 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 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 getWordAt1(index, 0); } // Returns either a Method or Constructor. // Static initializers are returned as Method objects. ! 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 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 (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), FLOAT(4), LONG(5),
*** 80,132 **** METHODREF(10), INTERFACEMETHODREF(11), NAMEANDTYPE(12), METHODHANDLE(15), METHODTYPE(16), ! INVOKEDYNAMIC(18), INVALID(0); private final int tagCode; private Tag(int tagCode) { this.tagCode = tagCode; } ! private static Tag valueOf(byte v) { ! for (Tag tag : Tag.values()) { ! if (tag.tagCode == v) { ! return tag; } } throw new IllegalArgumentException("Unknown constant pool tag code " + v); } } //--------------------------------------------------------------------------- // Internals only below this point // ! static { ! Reflection.registerFieldsToFilter(ConstantPool.class, Set.of("constantPoolOop")); } ! // HotSpot-internal constant pool object (set by the VM, name known to the VM) ! private Object constantPoolOop; - 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); } --- 94,301 ---- METHODREF(10), INTERFACEMETHODREF(11), NAMEANDTYPE(12), METHODHANDLE(15), METHODTYPE(16), ! DYNAMIC(17), // condy ! INVOKEDYNAMIC(18), // indy INVALID(0); private final int tagCode; private Tag(int tagCode) { this.tagCode = tagCode; } ! 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 // ! 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('/', '.')); ! } ! ! 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; ! } }
< prev index next >