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