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