1 /*
   2  * Copyright (c) 2011, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package jdk.vm.ci.hotspot;
  24 
  25 import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM;
  26 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
  27 import static jdk.vm.ci.hotspot.HotSpotVMConfig.config;
  28 import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE;
  29 
  30 import java.lang.invoke.MethodHandle;
  31 
  32 import jdk.vm.ci.common.JVMCIError;
  33 import jdk.vm.ci.meta.ConstantPool;
  34 import jdk.vm.ci.meta.JavaConstant;
  35 import jdk.vm.ci.meta.JavaField;
  36 import jdk.vm.ci.meta.JavaMethod;
  37 import jdk.vm.ci.meta.JavaType;
  38 import jdk.vm.ci.meta.ResolvedJavaMethod;
  39 import jdk.vm.ci.meta.ResolvedJavaType;
  40 import jdk.vm.ci.meta.Signature;
  41 import jdk.vm.ci.meta.UnresolvedJavaField;
  42 import jdk.vm.ci.meta.UnresolvedJavaMethod;
  43 import jdk.vm.ci.meta.UnresolvedJavaType;
  44 
  45 /**
  46  * Implementation of {@link ConstantPool} for HotSpot.
  47  */
  48 public final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject {
  49 
  50     /**
  51      * Subset of JVM bytecode opcodes used by {@link HotSpotConstantPool}.
  52      */
  53     public static class Bytecodes {
  54         public static final int LDC = 18; // 0x12
  55         public static final int LDC_W = 19; // 0x13
  56         public static final int LDC2_W = 20; // 0x14
  57         public static final int GETSTATIC = 178; // 0xB2
  58         public static final int PUTSTATIC = 179; // 0xB3
  59         public static final int GETFIELD = 180; // 0xB4
  60         public static final int PUTFIELD = 181; // 0xB5
  61         public static final int INVOKEVIRTUAL = 182; // 0xB6
  62         public static final int INVOKESPECIAL = 183; // 0xB7
  63         public static final int INVOKESTATIC = 184; // 0xB8
  64         public static final int INVOKEINTERFACE = 185; // 0xB9
  65         public static final int INVOKEDYNAMIC = 186; // 0xBA
  66         public static final int NEW = 187; // 0xBB
  67         public static final int NEWARRAY = 188; // 0xBC
  68         public static final int ANEWARRAY = 189; // 0xBD
  69         public static final int CHECKCAST = 192; // 0xC0
  70         public static final int INSTANCEOF = 193; // 0xC1
  71         public static final int MULTIANEWARRAY = 197; // 0xC5
  72 
  73         static boolean isInvoke(int opcode) {
  74             switch (opcode) {
  75                 case INVOKEVIRTUAL:
  76                 case INVOKESPECIAL:
  77                 case INVOKESTATIC:
  78                 case INVOKEINTERFACE:
  79                 case INVOKEDYNAMIC:
  80                     return true;
  81                 default:
  82                     return false;
  83             }
  84         }
  85 
  86         /**
  87          * See: {@code Rewriter::maybe_rewrite_invokehandle}.
  88          */
  89         static boolean isInvokeHandleAlias(int opcode) {
  90             switch (opcode) {
  91                 case INVOKEVIRTUAL:
  92                 case INVOKESPECIAL:
  93                     return true;
  94                 default:
  95                     return false;
  96             }
  97         }
  98     }
  99 
 100     /**
 101      * Enum of all {@code JVM_CONSTANT} constants used in the VM. This includes the public and
 102      * internal ones.
 103      */
 104     private enum JVM_CONSTANT {
 105         // @formatter:off
 106         Utf8(config().jvmConstantUtf8),
 107         Integer(config().jvmConstantInteger),
 108         Long(config().jvmConstantLong),
 109         Float(config().jvmConstantFloat),
 110         Double(config().jvmConstantDouble),
 111         Class(config().jvmConstantClass),
 112         UnresolvedClass(config().jvmConstantUnresolvedClass),
 113         UnresolvedClassInError(config().jvmConstantUnresolvedClassInError),
 114         String(config().jvmConstantString),
 115         Fieldref(config().jvmConstantFieldref),
 116         MethodRef(config().jvmConstantMethodref),
 117         InterfaceMethodref(config().jvmConstantInterfaceMethodref),
 118         NameAndType(config().jvmConstantNameAndType),
 119         MethodHandle(config().jvmConstantMethodHandle),
 120         MethodHandleInError(config().jvmConstantMethodHandleInError),
 121         MethodType(config().jvmConstantMethodType),
 122         MethodTypeInError(config().jvmConstantMethodTypeInError),
 123         InvokeDynamic(config().jvmConstantInvokeDynamic);
 124         // @formatter:on
 125 
 126         private final int tag;
 127 
 128         private static final int ExternalMax = config().jvmConstantExternalMax;
 129         private static final int InternalMin = config().jvmConstantInternalMin;
 130         private static final int InternalMax = config().jvmConstantInternalMax;
 131 
 132         JVM_CONSTANT(int tag) {
 133             this.tag = tag;
 134         }
 135 
 136         /**
 137          * Maps JVM_CONSTANT tags to {@link JVM_CONSTANT} values. Using a separate class for lazy
 138          * initialization.
 139          */
 140         static class TagValueMap {
 141             private static final JVM_CONSTANT[] table = new JVM_CONSTANT[ExternalMax + 1 + (InternalMax - InternalMin) + 1];
 142 
 143             static {
 144                 assert InternalMin > ExternalMax;
 145                 for (JVM_CONSTANT e : values()) {
 146                     table[indexOf(e.tag)] = e;
 147                 }
 148             }
 149 
 150             private static int indexOf(int tag) {
 151                 if (tag >= InternalMin) {
 152                     return tag - InternalMin + ExternalMax + 1;
 153                 } else {
 154                     assert tag <= ExternalMax;
 155                 }
 156                 return tag;
 157             }
 158 
 159             static JVM_CONSTANT get(int tag) {
 160                 JVM_CONSTANT res = table[indexOf(tag)];
 161                 if (res != null) {
 162                     return res;
 163                 }
 164                 throw new JVMCIError("Unknown JVM_CONSTANT tag %s", tag);
 165             }
 166         }
 167 
 168         public static JVM_CONSTANT getEnum(int tag) {
 169             return TagValueMap.get(tag);
 170         }
 171     }
 172 
 173     private static class LookupTypeCacheElement {
 174         int lastCpi = Integer.MIN_VALUE;
 175         JavaType javaType;
 176 
 177         LookupTypeCacheElement(int lastCpi, JavaType javaType) {
 178             super();
 179             this.lastCpi = lastCpi;
 180             this.javaType = javaType;
 181         }
 182     }
 183 
 184     /**
 185      * Reference to the C++ ConstantPool object.
 186      */
 187     private final long metaspaceConstantPool;
 188     private volatile LookupTypeCacheElement lastLookupType;
 189 
 190     /**
 191      * Gets the JVMCI mirror from a HotSpot constant pool.The VM is responsible for ensuring that
 192      * the ConstantPool is kept alive for the duration of this call and the
 193      * {@link HotSpotJVMCIMetaAccessContext} keeps it alive after that.
 194      *
 195      * Called from the VM.
 196      *
 197      * @param metaspaceConstantPool a metaspace ConstantPool object
 198      * @return the {@link HotSpotConstantPool} corresponding to {@code metaspaceConstantPool}
 199      */
 200     @SuppressWarnings("unused")
 201     private static HotSpotConstantPool fromMetaspace(long metaspaceConstantPool) {
 202         HotSpotConstantPool cp = new HotSpotConstantPool(metaspaceConstantPool);
 203         runtime().metaAccessContext.add(cp);
 204         return cp;
 205     }
 206 
 207     private HotSpotConstantPool(long metaspaceConstantPool) {
 208         this.metaspaceConstantPool = metaspaceConstantPool;
 209     }
 210 
 211     /**
 212      * Gets the holder for this constant pool as {@link HotSpotResolvedObjectTypeImpl}.
 213      *
 214      * @return holder for this constant pool
 215      */
 216     private HotSpotResolvedObjectType getHolder() {
 217         return compilerToVM().getResolvedJavaType(this, config().constantPoolHolderOffset, false);
 218     }
 219 
 220     /**
 221      * Converts a raw index from the bytecodes to a constant pool cache index by adding a
 222      * {@link HotSpotVMConfig#constantPoolCpCacheIndexTag constant}.
 223      *
 224      * @param rawIndex index from the bytecode
 225      * @param opcode bytecode to convert the index for
 226      * @return constant pool cache index
 227      */
 228     private static int rawIndexToConstantPoolCacheIndex(int rawIndex, int opcode) {
 229         int index;
 230         if (opcode == Bytecodes.INVOKEDYNAMIC) {
 231             index = rawIndex;
 232             // See: ConstantPool::is_invokedynamic_index
 233             assert index < 0 : "not an invokedynamic constant pool index " + index;
 234         } else {
 235             assert opcode == Bytecodes.GETFIELD || opcode == Bytecodes.PUTFIELD || opcode == Bytecodes.GETSTATIC || opcode == Bytecodes.PUTSTATIC || opcode == Bytecodes.INVOKEINTERFACE ||
 236                             opcode == Bytecodes.INVOKEVIRTUAL || opcode == Bytecodes.INVOKESPECIAL || opcode == Bytecodes.INVOKESTATIC : "unexpected invoke opcode " + opcode;
 237             index = rawIndex + config().constantPoolCpCacheIndexTag;
 238         }
 239         return index;
 240     }
 241 
 242     /**
 243      * Decode a constant pool cache index to a constant pool index.
 244      *
 245      * See {@code ConstantPool::decode_cpcache_index}.
 246      *
 247      * @param index constant pool cache index
 248      * @return decoded index
 249      */
 250     private static int decodeConstantPoolCacheIndex(int index) {
 251         if (isInvokedynamicIndex(index)) {
 252             return decodeInvokedynamicIndex(index);
 253         } else {
 254             return index - config().constantPoolCpCacheIndexTag;
 255         }
 256     }
 257 
 258     /**
 259      * See {@code ConstantPool::is_invokedynamic_index}.
 260      */
 261     private static boolean isInvokedynamicIndex(int index) {
 262         return index < 0;
 263     }
 264 
 265     /**
 266      * See {@code ConstantPool::decode_invokedynamic_index}.
 267      */
 268     private static int decodeInvokedynamicIndex(int i) {
 269         assert isInvokedynamicIndex(i) : i;
 270         return ~i;
 271     }
 272 
 273     long getMetaspaceConstantPool() {
 274         return metaspaceConstantPool;
 275     }
 276 
 277     @Override
 278     public long getMetaspacePointer() {
 279         return getMetaspaceConstantPool();
 280     }
 281 
 282     /**
 283      * Gets the constant pool tag at index {@code index}.
 284      *
 285      * @param index constant pool index
 286      * @return constant pool tag
 287      */
 288     private JVM_CONSTANT getTagAt(int index) {
 289         assert checkBounds(index);
 290         HotSpotVMConfig config = config();
 291         final long metaspaceConstantPoolTags = UNSAFE.getAddress(getMetaspaceConstantPool() + config.constantPoolTagsOffset);
 292         final int tag = UNSAFE.getByteVolatile(null, metaspaceConstantPoolTags + config.arrayU1DataOffset + index);
 293         if (tag == 0) {
 294             return null;
 295         }
 296         return JVM_CONSTANT.getEnum(tag);
 297     }
 298 
 299     /**
 300      * Gets the constant pool entry at index {@code index}.
 301      *
 302      * @param index constant pool index
 303      * @return constant pool entry
 304      */
 305     long getEntryAt(int index) {
 306         assert checkBounds(index);
 307         int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize;
 308         return UNSAFE.getAddress(getMetaspaceConstantPool() + config().constantPoolSize + offset);
 309     }
 310 
 311     /**
 312      * Gets the integer constant pool entry at index {@code index}.
 313      *
 314      * @param index constant pool index
 315      * @return integer constant pool entry at index
 316      */
 317     private int getIntAt(int index) {
 318         assert checkTag(index, JVM_CONSTANT.Integer);
 319         int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize;
 320         return UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolSize + offset);
 321     }
 322 
 323     /**
 324      * Gets the long constant pool entry at index {@code index}.
 325      *
 326      * @param index constant pool index
 327      * @return long constant pool entry
 328      */
 329     private long getLongAt(int index) {
 330         assert checkTag(index, JVM_CONSTANT.Long);
 331         int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize;
 332         return UNSAFE.getLong(getMetaspaceConstantPool() + config().constantPoolSize + offset);
 333     }
 334 
 335     /**
 336      * Gets the float constant pool entry at index {@code index}.
 337      *
 338      * @param index constant pool index
 339      * @return float constant pool entry
 340      */
 341     private float getFloatAt(int index) {
 342         assert checkTag(index, JVM_CONSTANT.Float);
 343         int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize;
 344         return UNSAFE.getFloat(getMetaspaceConstantPool() + config().constantPoolSize + offset);
 345     }
 346 
 347     /**
 348      * Gets the double constant pool entry at index {@code index}.
 349      *
 350      * @param index constant pool index
 351      * @return float constant pool entry
 352      */
 353     private double getDoubleAt(int index) {
 354         assert checkTag(index, JVM_CONSTANT.Double);
 355         int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize;
 356         return UNSAFE.getDouble(getMetaspaceConstantPool() + config().constantPoolSize + offset);
 357     }
 358 
 359     /**
 360      * Gets the {@code JVM_CONSTANT_NameAndType} constant pool entry at index {@code index}.
 361      *
 362      * @param index constant pool index
 363      * @return {@code JVM_CONSTANT_NameAndType} constant pool entry
 364      */
 365     private int getNameAndTypeAt(int index) {
 366         assert checkTag(index, JVM_CONSTANT.NameAndType);
 367         int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize;
 368         return UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolSize + offset);
 369     }
 370 
 371     /**
 372      * Gets the {@code JVM_CONSTANT_NameAndType} reference index constant pool entry at index
 373      * {@code index}.
 374      *
 375      * @param index constant pool index
 376      * @return {@code JVM_CONSTANT_NameAndType} reference constant pool entry
 377      */
 378     private int getNameAndTypeRefIndexAt(int index) {
 379         return compilerToVM().lookupNameAndTypeRefIndexInPool(this, index);
 380     }
 381 
 382     /**
 383      * Gets the name of a {@code JVM_CONSTANT_NameAndType} constant pool entry referenced by another
 384      * entry denoted by {@code which}.
 385      *
 386      * @param which constant pool index or constant pool cache index
 387      * @return name as {@link String}
 388      */
 389     private String getNameOf(int which) {
 390         return compilerToVM().lookupNameInPool(this, which);
 391     }
 392 
 393     /**
 394      * Gets the name reference index of a {@code JVM_CONSTANT_NameAndType} constant pool entry at
 395      * index {@code index}.
 396      *
 397      * @param index constant pool index
 398      * @return name reference index
 399      */
 400     private int getNameRefIndexAt(int index) {
 401         final int refIndex = getNameAndTypeAt(index);
 402         // name ref index is in the low 16-bits.
 403         return refIndex & 0xFFFF;
 404     }
 405 
 406     /**
 407      * Gets the signature of a {@code JVM_CONSTANT_NameAndType} constant pool entry referenced by
 408      * another entry denoted by {@code which}.
 409      *
 410      * @param which constant pool index or constant pool cache index
 411      * @return signature as {@link String}
 412      */
 413     private String getSignatureOf(int which) {
 414         return compilerToVM().lookupSignatureInPool(this, which);
 415     }
 416 
 417     /**
 418      * Gets the signature reference index of a {@code JVM_CONSTANT_NameAndType} constant pool entry
 419      * at index {@code index}.
 420      *
 421      * @param index constant pool index
 422      * @return signature reference index
 423      */
 424     private int getSignatureRefIndexAt(int index) {
 425         final int refIndex = getNameAndTypeAt(index);
 426         // signature ref index is in the high 16-bits.
 427         return refIndex >>> 16;
 428     }
 429 
 430     /**
 431      * Gets the klass reference index constant pool entry at index {@code index}.
 432      *
 433      * @param index constant pool index
 434      * @return klass reference index
 435      */
 436     private int getKlassRefIndexAt(int index) {
 437         return compilerToVM().lookupKlassRefIndexInPool(this, index);
 438     }
 439 
 440     /**
 441      * Gets the uncached klass reference index constant pool entry at index {@code index}. See:
 442      * {@code ConstantPool::uncached_klass_ref_index_at}.
 443      *
 444      * @param index constant pool index
 445      * @return klass reference index
 446      */
 447     private int getUncachedKlassRefIndexAt(int index) {
 448         assert checkTagIsFieldOrMethod(index);
 449         int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize;
 450         final int refIndex = UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolSize + offset);
 451         // klass ref index is in the low 16-bits.
 452         return refIndex & 0xFFFF;
 453     }
 454 
 455     /**
 456      * Checks that the constant pool index {@code index} is in the bounds of the constant pool.
 457      *
 458      * @param index constant pool index
 459      * @throws AssertionError if the check fails
 460      */
 461     private boolean checkBounds(int index) {
 462         assert 0 <= index && index < length() : "index " + index + " not between 0 and " + length();
 463         return true;
 464     }
 465 
 466     /**
 467      * Checks that the constant pool tag at index {@code index} is equal to {@code tag}.
 468      *
 469      * @param index constant pool index
 470      * @param tag expected tag
 471      * @throws AssertionError if the check fails
 472      */
 473     private boolean checkTag(int index, JVM_CONSTANT tag) {
 474         final JVM_CONSTANT tagAt = getTagAt(index);
 475         assert tagAt == tag : "constant pool tag at index " + index + " is " + tagAt + " but expected " + tag;
 476         return true;
 477     }
 478 
 479     /**
 480      * Asserts that the constant pool tag at index {@code index} is a {@link JVM_CONSTANT#Fieldref},
 481      * or a {@link JVM_CONSTANT#MethodRef}, or a {@link JVM_CONSTANT#InterfaceMethodref}.
 482      *
 483      * @param index constant pool index
 484      * @throws AssertionError if the check fails
 485      */
 486     private boolean checkTagIsFieldOrMethod(int index) {
 487         final JVM_CONSTANT tagAt = getTagAt(index);
 488         assert tagAt == JVM_CONSTANT.Fieldref || tagAt == JVM_CONSTANT.MethodRef || tagAt == JVM_CONSTANT.InterfaceMethodref : tagAt;
 489         return true;
 490     }
 491 
 492     @Override
 493     public int length() {
 494         return UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolLengthOffset);
 495     }
 496 
 497     public boolean hasDynamicConstant() {
 498         return (flags() & config().constantPoolHasDynamicConstant) != 0;
 499     }
 500 
 501     private int flags() {
 502         return UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolFlagsOffset);
 503     }
 504 
 505     @Override
 506     public Object lookupConstant(int cpi) {
 507         assert cpi != 0;
 508         final JVM_CONSTANT tag = getTagAt(cpi);
 509         switch (tag) {
 510             case Integer:
 511                 return JavaConstant.forInt(getIntAt(cpi));
 512             case Long:
 513                 return JavaConstant.forLong(getLongAt(cpi));
 514             case Float:
 515                 return JavaConstant.forFloat(getFloatAt(cpi));
 516             case Double:
 517                 return JavaConstant.forDouble(getDoubleAt(cpi));
 518             case Class:
 519             case UnresolvedClass:
 520             case UnresolvedClassInError:
 521                 final int opcode = -1;  // opcode is not used
 522                 return lookupType(cpi, opcode);
 523             case String:
 524                 /*
 525                  * Normally, we would expect a String here, but unsafe anonymous classes can have
 526                  * "pseudo strings" (arbitrary live objects) patched into a String entry. Such
 527                  * entries do not have a symbol in the constant pool slot.
 528                  */
 529                 Object string = compilerToVM().resolvePossiblyCachedConstantInPool(this, cpi);
 530                 return HotSpotObjectConstantImpl.forObject(string);
 531             case MethodHandle:
 532             case MethodHandleInError:
 533             case MethodType:
 534             case MethodTypeInError:
 535                 Object obj = compilerToVM().resolveConstantInPool(this, cpi);
 536                 return HotSpotObjectConstantImpl.forObject(obj);
 537             default:
 538                 throw new JVMCIError("Unknown constant pool tag %s", tag);
 539         }
 540     }
 541 
 542     @Override
 543     public String lookupUtf8(int cpi) {
 544         assert checkTag(cpi, JVM_CONSTANT.Utf8);
 545         return compilerToVM().getSymbol(getEntryAt(cpi));
 546     }
 547 
 548     @Override
 549     public Signature lookupSignature(int cpi) {
 550         return new HotSpotSignature(runtime(), lookupUtf8(cpi));
 551     }
 552 
 553     @Override
 554     public JavaConstant lookupAppendix(int cpi, int opcode) {
 555         assert Bytecodes.isInvoke(opcode);
 556         final int index = rawIndexToConstantPoolCacheIndex(cpi, opcode);
 557         Object appendix = compilerToVM().lookupAppendixInPool(this, index);
 558         if (appendix == null) {
 559             return null;
 560         } else {
 561             return HotSpotObjectConstantImpl.forObject(appendix);
 562         }
 563     }
 564 
 565     /**
 566      * Gets a {@link JavaType} corresponding a given resolved or unresolved type.
 567      *
 568      * @param type either a ResolvedJavaType or a String naming a unresolved type.
 569      */
 570     private static JavaType getJavaType(final Object type) {
 571         if (type instanceof String) {
 572             String name = (String) type;
 573             return UnresolvedJavaType.create("L" + name + ";");
 574         } else {
 575             return (JavaType) type;
 576         }
 577     }
 578 
 579     @Override
 580     public JavaMethod lookupMethod(int cpi, int opcode) {
 581         final int index = rawIndexToConstantPoolCacheIndex(cpi, opcode);
 582         final HotSpotResolvedJavaMethod method = compilerToVM().lookupMethodInPool(this, index, (byte) opcode);
 583         if (method != null) {
 584             return method;
 585         } else {
 586             // Get the method's name and signature.
 587             String name = getNameOf(index);
 588             HotSpotSignature signature = new HotSpotSignature(runtime(), getSignatureOf(index));
 589             if (opcode == Bytecodes.INVOKEDYNAMIC) {
 590                 HotSpotResolvedObjectType holder = HotSpotResolvedObjectTypeImpl.fromObjectClass(MethodHandle.class);
 591                 return new UnresolvedJavaMethod(name, signature, holder);
 592             } else {
 593                 final int klassIndex = getKlassRefIndexAt(index);
 594                 final Object type = compilerToVM().lookupKlassInPool(this, klassIndex);
 595                 JavaType holder = getJavaType(type);
 596                 return new UnresolvedJavaMethod(name, signature, holder);
 597             }
 598         }
 599     }
 600 
 601     @Override
 602     public JavaType lookupType(int cpi, int opcode) {
 603         final LookupTypeCacheElement elem = this.lastLookupType;
 604         if (elem != null && elem.lastCpi == cpi) {
 605             return elem.javaType;
 606         } else {
 607             final Object type = compilerToVM().lookupKlassInPool(this, cpi);
 608             JavaType result = getJavaType(type);
 609             if (result instanceof ResolvedJavaType) {
 610                 this.lastLookupType = new LookupTypeCacheElement(cpi, result);
 611             }
 612             return result;
 613         }
 614     }
 615 
 616     @Override
 617     public JavaField lookupField(int cpi, ResolvedJavaMethod method, int opcode) {
 618         final int index = rawIndexToConstantPoolCacheIndex(cpi, opcode);
 619         final int nameAndTypeIndex = getNameAndTypeRefIndexAt(index);
 620         final int typeIndex = getSignatureRefIndexAt(nameAndTypeIndex);
 621         String typeName = lookupUtf8(typeIndex);
 622         JavaType type = runtime().lookupType(typeName, getHolder(), false);
 623 
 624         final int holderIndex = getKlassRefIndexAt(index);
 625         JavaType holder = lookupType(holderIndex, opcode);
 626 
 627         if (holder instanceof HotSpotResolvedObjectTypeImpl) {
 628             int[] info = new int[3];
 629             HotSpotResolvedObjectTypeImpl resolvedHolder;
 630             try {
 631                 resolvedHolder = compilerToVM().resolveFieldInPool(this, index, (HotSpotResolvedJavaMethodImpl) method, (byte) opcode, info);
 632             } catch (Throwable t) {
 633                 /*
 634                  * If there was an exception resolving the field we give up and return an unresolved
 635                  * field.
 636                  */
 637                 return new UnresolvedJavaField(holder, lookupUtf8(getNameRefIndexAt(nameAndTypeIndex)), type);
 638             }
 639             final int flags = info[0];
 640             final int offset = info[1];
 641             final int fieldIndex = info[2];
 642             HotSpotResolvedJavaField result = resolvedHolder.createField(type, offset, flags, fieldIndex);
 643             return result;
 644         } else {
 645             return new UnresolvedJavaField(holder, lookupUtf8(getNameRefIndexAt(nameAndTypeIndex)), type);
 646         }
 647     }
 648 
 649     /*
 650      * Converts a raw index from the bytecodes to a constant pool index (not a cache index).
 651      *
 652      * @param rawIndex index from the bytecode
 653      *
 654      * @param opcode bytecode to convert the index for
 655      *
 656      * @return constant pool index
 657      */
 658     public int rawIndexToConstantPoolIndex(int rawIndex, int opcode) {
 659         int index;
 660         if (isInvokedynamicIndex(rawIndex)) {
 661             assert opcode == Bytecodes.INVOKEDYNAMIC;
 662             index = decodeInvokedynamicIndex(rawIndex) + config().constantPoolCpCacheIndexTag;
 663         } else {
 664             assert opcode != Bytecodes.INVOKEDYNAMIC;
 665             index = rawIndexToConstantPoolCacheIndex(rawIndex, opcode);
 666         }
 667         return compilerToVM().constantPoolRemapInstructionOperandFromCache(this, index);
 668     }
 669 
 670     @Override
 671     public void loadReferencedType(int cpi, int opcode) {
 672         loadReferencedType(cpi, opcode, true /* initialize */);
 673     }
 674 
 675     @SuppressWarnings("fallthrough")
 676     public void loadReferencedType(int cpi, int opcode, boolean initialize) {
 677         int index;
 678         switch (opcode) {
 679             case Bytecodes.CHECKCAST:
 680             case Bytecodes.INSTANCEOF:
 681             case Bytecodes.NEW:
 682             case Bytecodes.ANEWARRAY:
 683             case Bytecodes.MULTIANEWARRAY:
 684             case Bytecodes.LDC:
 685             case Bytecodes.LDC_W:
 686             case Bytecodes.LDC2_W:
 687                 index = cpi;
 688                 break;
 689             case Bytecodes.INVOKEDYNAMIC: {
 690                 // invokedynamic instructions point to a constant pool cache entry.
 691                 index = decodeConstantPoolCacheIndex(cpi) + config().constantPoolCpCacheIndexTag;
 692                 index = compilerToVM().constantPoolRemapInstructionOperandFromCache(this, index);
 693                 break;
 694             }
 695             case Bytecodes.GETSTATIC:
 696             case Bytecodes.PUTSTATIC:
 697             case Bytecodes.GETFIELD:
 698             case Bytecodes.PUTFIELD:
 699             case Bytecodes.INVOKEVIRTUAL:
 700             case Bytecodes.INVOKESPECIAL:
 701             case Bytecodes.INVOKESTATIC:
 702             case Bytecodes.INVOKEINTERFACE: {
 703                 // invoke and field instructions point to a constant pool cache entry.
 704                 index = rawIndexToConstantPoolCacheIndex(cpi, opcode);
 705                 index = compilerToVM().constantPoolRemapInstructionOperandFromCache(this, index);
 706                 break;
 707             }
 708             default:
 709                 throw JVMCIError.shouldNotReachHere("Unexpected opcode " + opcode);
 710         }
 711 
 712         final JVM_CONSTANT tag = getTagAt(index);
 713         if (tag == null) {
 714             assert getTagAt(index - 1) == JVM_CONSTANT.Double || getTagAt(index - 1) == JVM_CONSTANT.Long;
 715             return;
 716         }
 717         switch (tag) {
 718             case MethodRef:
 719             case Fieldref:
 720             case InterfaceMethodref:
 721                 index = getUncachedKlassRefIndexAt(index);
 722                 // Read the tag only once because it could change between multiple reads.
 723                 final JVM_CONSTANT klassTag = getTagAt(index);
 724                 assert klassTag == JVM_CONSTANT.Class || klassTag == JVM_CONSTANT.UnresolvedClass || klassTag == JVM_CONSTANT.UnresolvedClassInError : klassTag;
 725                 // fall through
 726             case Class:
 727             case UnresolvedClass:
 728             case UnresolvedClassInError:
 729                 final HotSpotResolvedObjectTypeImpl type = compilerToVM().resolveTypeInPool(this, index);
 730                 if (initialize) {
 731                     Class<?> klass = type.mirror();
 732                     if (!klass.isPrimitive() && !klass.isArray()) {
 733                         UNSAFE.ensureClassInitialized(klass);
 734                     }
 735                 }
 736                 if (tag == JVM_CONSTANT.MethodRef) {
 737                     if (Bytecodes.isInvokeHandleAlias(opcode) && isSignaturePolymorphicHolder(type)) {
 738                         final int methodRefCacheIndex = rawIndexToConstantPoolCacheIndex(cpi, opcode);
 739                         assert checkTag(compilerToVM().constantPoolRemapInstructionOperandFromCache(this, methodRefCacheIndex), JVM_CONSTANT.MethodRef);
 740                         compilerToVM().resolveInvokeHandleInPool(this, methodRefCacheIndex);
 741                     }
 742                 }
 743 
 744                 break;
 745             case InvokeDynamic:
 746                 if (isInvokedynamicIndex(cpi)) {
 747                     compilerToVM().resolveInvokeDynamicInPool(this, cpi);
 748                 }
 749                 break;
 750             default:
 751                 // nothing
 752                 break;
 753         }
 754 
 755     }
 756 
 757     // Lazily initialized.
 758     private static String[] signaturePolymorphicHolders;
 759 
 760     /**
 761      * Determines if {@code type} contains signature polymorphic methods.
 762      */
 763     static boolean isSignaturePolymorphicHolder(final ResolvedJavaType type) {
 764         String name = type.getName();
 765         if (signaturePolymorphicHolders == null) {
 766             signaturePolymorphicHolders = compilerToVM().getSignaturePolymorphicHolders();
 767         }
 768         for (String holder : signaturePolymorphicHolders) {
 769             if (name.equals(holder)) {
 770                 return true;
 771             }
 772         }
 773         return false;
 774     }
 775 
 776     /**
 777      * Check for a resolved dynamic adapter method at the specified index, resulting from either a
 778      * resolved invokedynamic or invokevirtual on a signature polymorphic MethodHandle method
 779      * (HotSpot invokehandle).
 780      *
 781      * @param cpi the constant pool index
 782      * @param opcode the opcode of the instruction for which the lookup is being performed
 783      * @return {@code true} if a signature polymorphic method reference was found, otherwise
 784      *         {@code false}
 785      */
 786     public boolean isResolvedDynamicInvoke(int cpi, int opcode) {
 787         if (Bytecodes.isInvokeHandleAlias(opcode)) {
 788             final int methodRefCacheIndex = rawIndexToConstantPoolCacheIndex(cpi, opcode);
 789             assert checkTag(compilerToVM().constantPoolRemapInstructionOperandFromCache(this, methodRefCacheIndex), JVM_CONSTANT.MethodRef);
 790             int op = compilerToVM().isResolvedInvokeHandleInPool(this, methodRefCacheIndex);
 791             return op == opcode;
 792         }
 793         return false;
 794     }
 795 
 796     @Override
 797     public String toString() {
 798         HotSpotResolvedObjectType holder = getHolder();
 799         return "HotSpotConstantPool<" + holder.toJavaName() + ">";
 800     }
 801 }