< 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 >