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