< 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,53 +23,67 @@
* questions.
*/
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.
+ <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 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),
FLOAT(4),
LONG(5),
@@ -80,53 +94,208 @@
METHODREF(10),
INTERFACEMETHODREF(11),
NAMEANDTYPE(12),
METHODHANDLE(15),
METHODTYPE(16),
- INVOKEDYNAMIC(18),
+ DYNAMIC(17), // condy
+ INVOKEDYNAMIC(18), // indy
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;
+ 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('/', '.'));
+ }
+
+ private Object getRefAt(int index, Tag tag, boolean forceResolution) {
+ return getRefAt1(index, -1, forceResolution ? BAR_FORCE : BAR_IFPRESENT, null);
}
- // HotSpot-internal constant pool object (set by the VM, name known to the VM)
- private Object constantPoolOop;
+ 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);
}
< prev index next >