1 /*
   2  * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.internal.reflect;
  27 
  28 import jdk.internal.vm.annotation.Stable;
  29 
  30 import java.lang.constant.*;
  31 import java.lang.constant.DirectMethodHandleDesc.Kind;
  32 import java.lang.reflect.Field;
  33 import java.lang.reflect.Member;
  34 import java.util.Arrays;
  35 
  36 /** Provides reflective access to the constant pools of classes.
  37     Currently this is needed to provide reflective access to annotations
  38     and bootstrap methods
  39     but may be used by other internal subsystems in the future.
  40  <p>
  41     When applying this API to internal subsystems, take special account
  42     of interactions with the JVMTI class redefinition features.
  43     If a class reflects on its constant pool, and then is redefined to
  44     have a different constant pool, the data reported by the reflected
  45     constant pool may become out of date.
  46  */
  47 
  48 public class ConstantPool {
  49   // Number of entries in this constant pool (= maximum valid constant pool index)
  50   public int      getSize()                      { return getSize1(); }
  51   // Class holding this CP
  52   public Class<?> getHolder()                    { return getHolder1(); }
  53   public Class<?> getClassAt         (int index) { return (Class<?>) getRefAt(index, Tag.CLASS, true); }
  54 
  55   public Class<?> getClassAtIfLoaded (int index) { return (Class<?>) getRefAt(index, Tag.CLASS, false); }
  56   // Returns a class reference index for a method or a field.
  57   public int getClassRefIndexAt(int index)       { return getWordAt1(index, 0); }
  58   // Returns either a Method or Constructor.
  59   // Static initializers are returned as Method objects.
  60   public Member   getMethodAt        (int index) { return (Member) getRefAt(index, Tag.METHODREF, true); }
  61   public Member   getMethodAtIfLoaded(int index) { return (Member) getRefAt(index, Tag.METHODREF, false); }
  62   public Field    getFieldAt         (int index) { return (Field)  getRefAt(index, Tag.FIELDREF,  true); }
  63   public Field    getFieldAtIfLoaded (int index) { return (Field)  getRefAt(index, Tag.FIELDREF,  false); }
  64   // Fetches the class name, member (field, method or interface
  65   // method) name, and type descriptor as an array of three Strings
  66   public String[] getMemberRefInfoAt (int index) {
  67       return new String[] { getUtf8At(index, 2), getUtf8At(index, 3), getUtf8At(index, 4) };
  68   }
  69 
  70     // Returns a name and type reference index for a method, a field or an invokedynamic.
  71   public int getNameAndTypeRefIndexAt(int index) { return getWordAt1(index, 1); }
  72   // Fetches the name and type from name_and_type index as an array of two Strings
  73   public String[] getNameAndTypeRefInfoAt(int index) {
  74       return (String[]) getRefAt(index, Tag.NAMEANDTYPE, true);
  75   }
  76 
  77   public int      getIntAt           (int index) { return getIntAt1           (index); }
  78   public long     getLongAt          (int index) { return getLongAt1          (index); }
  79   public float    getFloatAt         (int index) { return getFloatAt1         (index); }
  80   public double   getDoubleAt        (int index) { return getDoubleAt1        (index); }
  81   public String   getStringAt        (int index) { return (String) getRefAt(index, Tag.STRING, true); }
  82   public String   getUTF8At          (int index) { return (String) getRefAt1(index, 0, BAR_SYMREF, null); }
  83   public Tag      getTagAt           (int index) { return Tag.valueOf(getCachedTagAt(index)); }
  84 
  85   public static enum Tag {
  86       UTF8(1),
  87       INTEGER(3),
  88       FLOAT(4),
  89       LONG(5),
  90       DOUBLE(6),
  91       CLASS(7),
  92       STRING(8),
  93       FIELDREF(9),
  94       METHODREF(10),
  95       INTERFACEMETHODREF(11),
  96       NAMEANDTYPE(12),
  97       METHODHANDLE(15),
  98       METHODTYPE(16),
  99       DYNAMIC(17),        // condy
 100       INVOKEDYNAMIC(18),  // indy
 101       INVALID(0);
 102 
 103       private final int tagCode;
 104 
 105       private Tag(int tagCode) {
 106           this.tagCode = tagCode;
 107       }
 108 
 109       private static @Stable final Tag TAG_TABLE[] = new Tag[20];
 110       static {
 111           for (Tag tag : values()) {
 112               assert(TAG_TABLE[tag.tagCode] == null); // unique
 113               TAG_TABLE[tag.tagCode] = tag;
 114           }
 115       }
 116       private static Tag valueOf(byte v) {
 117           Tag tag = (v >= 0 && v < TAG_TABLE.length) ? TAG_TABLE[v] : null;
 118           if (tag != null)  return tag;
 119           throw new IllegalArgumentException("Unknown constant pool tag code " + v);
 120       }
 121    }
 122 
 123   public Object getConstantAt(int index) {
 124       return getRefAt1(index, -1, BAR_FORCE, null);
 125   }
 126   public Object getConstantAt(int index, Object ifNotPresent) {
 127       return getRefAt1(index, -1, BAR_IFPRESENT, ifNotPresent);
 128   }
 129 
 130   private static final byte BAR_IFPRESENT = 0, BAR_FORCE = 1, BAR_SYMREF = 2;
 131 
 132   public ConstantDesc<?> getConstantDescAt(int index) {
 133       Tag tag = getTagAt(index);
 134       switch (tag) {
 135       case UTF8:        return getUTF8At(index);
 136       case INTEGER:     return getIntAt(index);
 137       case LONG:        return getLongAt(index);
 138       case FLOAT:       return getFloatAt(index);
 139       case DOUBLE:      return getDoubleAt(index);
 140       case CLASS:       return classDescOf(getUTF8At(index));
 141       case STRING:      return getStringAt(index);
 142       //case FIELDREF:
 143       //case METHODREF:
 144       //case INTERFACEMETHODREF:
 145       //case NAMEANDTYPE:
 146       case METHODHANDLE:
 147       {
 148           int w0 = getWordAt1(index, 0);  // refKind
 149           int w1 = getWordAt1(index, 1);  // member
 150           boolean isInterface = getTagAt(w1) == Tag.INTERFACEMETHODREF;
 151           Kind kind = Kind.valueOf(w0, isInterface);
 152           // Note:  Even if isInterface is true Kind.valueOf may discard it.
 153           ClassDesc clazz = classDescOf(getUtf8At(w1, 2));
 154           return MethodHandleDesc.of(kind, clazz, getUtf8At(w1, 3), getUtf8At(w1, 4));
 155       }
 156       case METHODTYPE:
 157           return MethodTypeDesc.ofDescriptor(getUTF8At(index));
 158       //case INVOKEDYNAMIC:
 159       case DYNAMIC:
 160           return (DynamicConstantDesc)  getBootstrappedEntryAt(index);
 161       }
 162      throw new IllegalArgumentException("no ConstantDesc representation for "+tag+" at CP["+index+"]");
 163   }
 164 
 165   public DynamicCallSiteDesc getDynamicCallSiteDescAt(int index) {
 166       checkTag(index, Tag.INVOKEDYNAMIC);
 167       return (DynamicCallSiteDesc)  getBootstrappedEntryAt(index);
 168   }
 169 
 170     /**
 171      * Get bootstrap arguments for the indy or condy at the given index.
 172      * @param index  CP index of the selected indy or condy constant
 173      * @param start which bootstrap argument to start copying
 174      * @param end  which bootstrap argument (exclusive) to stop copying
 175      * @param buf  where to put the copied arguments (must be int[] for BAR_SYMREF, Object[] for other modes)
 176      * @param pos  where to store arguments into the buf
 177      * @param resolving  resolution mode:  0=BAR_IFPRESENT, 1=BAR_FORCE, 2=BAR_SYMREF
 178      * @param ifNotPresent  in BAR_IFPRESENT mode, sentinel to store for values not yet resolved
 179      * @param ifNullConstant  in BAR_IFPRESENT or BAR_FORCE mode, sentinel to store for an actual {@code null}
 180      * @param skipNonNull  BAR_IFPRESENT or BAR_FORCE mode, do not store over elements of buf which are non-{@code null}
 181      */
 182     public void copyOutBootstrapArgumentsAt(int index,
 183                                             int start, int end,
 184                                             Object buf, int pos,
 185                                             byte resolving,
 186                                             Object ifNotPresent,
 187                                             Object ifNullConstant,
 188                                             boolean skipNonNull) {
 189         if (start < 0 || end < start)  throw new IllegalArgumentException();
 190         copyOutRefsAt1(index, start + BSS_HEADER_WORDS, end + BSS_HEADER_WORDS,
 191                 buf, pos, resolving, ifNotPresent, ifNullConstant, skipNonNull);
 192     }
 193 
 194   //---------------------------------------------------------------------------
 195   // Internals only below this point
 196   //
 197 
 198     private @Stable byte[] tags;
 199       private byte getCachedTagAt(int index) {
 200         if (tags == null)  tags = getTags1();
 201         if (index >= 0 && index < tags.length) {
 202             return tags[index];
 203         }
 204         // constant pool can grow over time
 205         return getTagAt1(index);
 206       }
 207 
 208     private static final int
 209             BSS_HEADER_WORDS = 6,  // { attrIndex, natIndex, bsm, name, type, argc }
 210             BSS_HEADER_BSM = 2, BSS_HEADER_NAME = 3, BSS_HEADER_TYPE = 4, BSS_HEADER_ARGC = 5;
 211     private Object getBootstrappedEntryAt(int index) {
 212       int argc = getWordAt1(index, BSS_HEADER_ARGC);
 213       int[] argIndexes = copyOutWordsAt(index, BSS_HEADER_WORDS, BSS_HEADER_WORDS+argc);
 214       int bsmIndex = getWordAt1(index, BSS_HEADER_BSM);
 215       DirectMethodHandleDesc bsm = (DirectMethodHandleDesc) getConstantDescAt(bsmIndex);
 216       String name = (String) getRefAt1(index, BSS_HEADER_NAME, BAR_FORCE, null);
 217       String type = (String) getRefAt1(index, BSS_HEADER_TYPE, BAR_FORCE, null);
 218       ConstantDesc<?>[] args = new ConstantDesc<?>[argc];
 219       for (int i = 0; i < argc; i++) {
 220           args[i] = getConstantDescAt(argIndexes[i]);
 221       }
 222       if (getTagAt(index) == Tag.DYNAMIC)
 223           return DynamicConstantDesc.ofNamed(bsm, name, ClassDesc.ofDescriptor(type), args);
 224       else
 225           return DynamicCallSiteDesc.of(bsm, name, MethodTypeDesc.ofDescriptor(type), args);
 226     }
 227 
 228 
 229   private ClassDesc classDescOf(String name) {
 230     return ClassDesc.of(name.replace('/', '.'));
 231   }
 232 
 233     private Object getRefAt(int index, Tag tag, boolean forceResolution) {
 234       return getRefAt1(index, -1, forceResolution ? BAR_FORCE : BAR_IFPRESENT, null);
 235   }
 236 
 237   private int getWordAt(int index, Tag tag, int word) {
 238       checkTag(index, tag);
 239       return getWordAt1(index, word);
 240   }
 241 
 242   private void checkTag(int index, Tag needTag) {
 243       Tag haveTag = getTagAt(index);
 244       if (haveTag == needTag)  return;
 245       switch (needTag) {
 246       case METHODREF:
 247           if (haveTag == Tag.INTERFACEMETHODREF)  return;
 248           break;
 249       }
 250       throw new IllegalArgumentException("expected "+needTag+" but found "+haveTag);
 251   }
 252 
 253   private String getUtf8At(int index, int word) {
 254     return (String) getRefAt1(index, word, BAR_SYMREF, null);
 255   }
 256 
 257 
 258   private native Class<?> getHolder1          ();
 259   private native int      getSize1            ();
 260   private native int      getWordCountAt1     (int index);
 261   private native int      getWordAt1          (int index, int word);
 262   private native Object   getRefAt1           (int index, int word, byte resolving, Object ifNotPresent);
 263   private native int      getIntAt1           (int index);
 264   private native long     getLongAt1          (int index);
 265   private native float    getFloatAt1         (int index);
 266   private native double   getDoubleAt1        (int index);
 267   private native byte     getTagAt1           (int index);
 268   private native byte[]   getTags1            ();
 269 
 270   /**
 271    * @param index which CP entry to process
 272    * @param startWord which word to start copying
 273    * @param endWord  which word (exclusive) to stop copying
 274    * @param buf  where to put the copied arguments (must be int[] for BAR_SYMREF, Object[] for other modes)
 275    * @param bufPos  where to store arguments into the buf
 276    * @param resolving  resolution mode:  0=BAR_IFPRESENT, 1=BAR_FORCE, 2=BAR_SYMREF
 277    * @param ifNotPresent    in BAR_IFPRESENT mode, sentinel to store for values not yet resolved
 278    * @param ifNullConstant  in BAR_IFPRESENT or BAR_FORCE mode, sentinel to store for an actual {@code null}
 279    * @param skipNonNull  BAR_IFPRESENT or BAR_FORCE mode, do not store over elements of buf which are non-{@code null}
 280    */
 281   private native void copyOutRefsAt1(int index,
 282                                      int startWord, int endWord,
 283                                      Object buf, int bufPos, // destination
 284                                      byte resolving,
 285                                      Object ifNotPresent,
 286                                      Object ifNullConstant,
 287                                      boolean skipNonNull);
 288 
 289   private int[] copyOutWordsAt(int index, int startWord, int endWord) {
 290       int[] buf = new int[endWord - startWord];
 291       copyOutRefsAt1(index, startWord, endWord, buf, 0, BAR_SYMREF, null, null, false);
 292       return buf;
 293   }
 294   private Object[] copyOutRefsAt(int index, int startWord, int endWord, boolean forceResolution,
 295                                  Object ifNotPresent, Object ifNullConstant) {
 296       Object[] buf = new Object[endWord - startWord];
 297       copyOutRefsAt1(index, startWord, endWord, buf, 0, forceResolution ? BAR_FORCE : BAR_IFPRESENT, ifNotPresent, ifNullConstant, false);
 298       return buf;
 299   }
 300 
 301 }