001/*
002 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package jdk.internal.jvmci.hotspot;
024
025import static jdk.internal.jvmci.common.UnsafeAccess.*;
026import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*;
027
028import java.lang.invoke.*;
029import java.util.*;
030
031import jdk.internal.jvmci.common.*;
032import jdk.internal.jvmci.meta.*;
033import jdk.internal.jvmci.options.*;
034
035/**
036 * Implementation of {@link ConstantPool} for HotSpot.
037 */
038public class HotSpotConstantPool implements ConstantPool, HotSpotProxified {
039
040    public static class Options {
041        // @formatter:off
042        @Option(help = "Use Java code to access the constant pool cache and resolved references array", type = OptionType.Expert)
043        public static final OptionValue<Boolean> UseConstantPoolCacheJavaCode = new OptionValue<>(false);
044        // @formatter:on
045    }
046
047    /**
048     * Subset of JVM bytecode opcodes used by {@link HotSpotConstantPool}.
049     */
050    public static class Bytecodes {
051        public static final int LDC = 18; // 0x12
052        public static final int LDC_W = 19; // 0x13
053        public static final int LDC2_W = 20; // 0x14
054        public static final int GETSTATIC = 178; // 0xB2
055        public static final int PUTSTATIC = 179; // 0xB3
056        public static final int GETFIELD = 180; // 0xB4
057        public static final int PUTFIELD = 181; // 0xB5
058        public static final int INVOKEVIRTUAL = 182; // 0xB6
059        public static final int INVOKESPECIAL = 183; // 0xB7
060        public static final int INVOKESTATIC = 184; // 0xB8
061        public static final int INVOKEINTERFACE = 185; // 0xB9
062        public static final int INVOKEDYNAMIC = 186; // 0xBA
063        public static final int NEW = 187; // 0xBB
064        public static final int NEWARRAY = 188; // 0xBC
065        public static final int ANEWARRAY = 189; // 0xBD
066        public static final int CHECKCAST = 192; // 0xC0
067        public static final int INSTANCEOF = 193; // 0xC1
068        public static final int MULTIANEWARRAY = 197; // 0xC5
069
070        static boolean isInvoke(int opcode) {
071            switch (opcode) {
072                case INVOKEVIRTUAL:
073                case INVOKESPECIAL:
074                case INVOKESTATIC:
075                case INVOKEINTERFACE:
076                case INVOKEDYNAMIC:
077                    return true;
078                default:
079                    return false;
080            }
081        }
082
083        /**
084         * See: {@code Rewriter::maybe_rewrite_invokehandle}.
085         */
086        static boolean isInvokeHandleAlias(int opcode) {
087            switch (opcode) {
088                case INVOKEVIRTUAL:
089                case INVOKESPECIAL:
090                    return true;
091                default:
092                    return false;
093            }
094        }
095    }
096
097    /**
098     * Enum of all {@code JVM_CONSTANT} constants used in the VM. This includes the public and
099     * 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        private JVM_CONSTANT(int tag) {
130            this.tag = tag;
131        }
132
133        private static HotSpotVMConfig config() {
134            return runtime().getConfig();
135        }
136
137        /**
138         * Maps JVM_CONSTANT tags to {@link JVM_CONSTANT} values. Using a separate class for lazy
139         * initialization.
140         */
141        static class TagValueMap {
142            private static final JVM_CONSTANT[] table = new JVM_CONSTANT[ExternalMax + 1 + (InternalMax - InternalMin) + 1];
143
144            static {
145                assert InternalMin > ExternalMax;
146                for (JVM_CONSTANT e : values()) {
147                    table[indexOf(e.tag)] = e;
148                }
149            }
150
151            private static int indexOf(int tag) {
152                if (tag >= InternalMin) {
153                    return tag - InternalMin + ExternalMax + 1;
154                } else {
155                    assert tag <= ExternalMax;
156                }
157                return tag;
158            }
159
160            static JVM_CONSTANT get(int tag) {
161                JVM_CONSTANT res = table[indexOf(tag)];
162                if (res != null) {
163                    return res;
164                }
165                throw new JVMCIError("Unknown JVM_CONSTANT tag %s", tag);
166            }
167        }
168
169        public static JVM_CONSTANT getEnum(int tag) {
170            return TagValueMap.get(tag);
171        }
172    }
173
174    private static class LookupTypeCacheElement {
175        int lastCpi = Integer.MIN_VALUE;
176        JavaType javaType;
177
178        public LookupTypeCacheElement(int lastCpi, JavaType javaType) {
179            super();
180            this.lastCpi = lastCpi;
181            this.javaType = javaType;
182        }
183    }
184
185    /**
186     * Reference to the C++ ConstantPool object.
187     */
188    private final long metaspaceConstantPool;
189    private volatile LookupTypeCacheElement lastLookupType;
190
191    /**
192     * The constant pool cache of this constant pool.
193     */
194    private final Cache cache;
195
196    /**
197     * Represents a {@code ConstantPoolCache}. The cache needs to be lazy since the constant pool
198     * cache is created when the methods of this class are rewritten and rewriting happens when the
199     * class is linked.
200     */
201    private final class Cache {
202
203        private long address;
204
205        public Cache() {
206            // Maybe the constant pool cache already exists...
207            queryAddress();
208        }
209
210        /**
211         * Queries the current value of {@code ConstantPool::_cache} if the current address is null.
212         */
213        private void queryAddress() {
214            if (address == 0) {
215                address = unsafe.getAddress(metaspaceConstantPool + runtime().getConfig().constantPoolCacheOffset);
216            }
217        }
218
219        /**
220         * Returns whether a constant pool cache for this constant pool exists.
221         *
222         * @return true if it exists, false otherwise
223         */
224        public boolean exists() {
225            queryAddress();
226            return address != 0;
227        }
228
229        /**
230         * Represents a {@code ConstantPoolCacheEntry}.
231         */
232        private final class Entry {
233
234            private final long address;
235
236            public Entry(final long address) {
237                this.address = address;
238            }
239
240            /**
241             * {@code ConstantPoolCacheEntry::_indices} is volatile of type {@code intx}.
242             *
243             * @return value of field {@code _indices}
244             */
245            private long getIndices() {
246                assert runtime().getHostJVMCIBackend().getTarget().wordSize == 8 : "port to non-64-bit platform";
247                return unsafe.getLongVolatile(null, address + runtime().getConfig().constantPoolCacheEntryIndicesOffset);
248            }
249
250            /**
251             * {@code ConstantPoolCacheEntry::_f1} is volatile of type {@code Metadata*}.
252             *
253             * @return value of field {@code _f1}
254             */
255            private long getF1() {
256                assert runtime().getHostJVMCIBackend().getTarget().wordSize == 8 : "port to non-64-bit platform";
257                return unsafe.getLongVolatile(null, address + runtime().getConfig().constantPoolCacheEntryF1Offset);
258            }
259
260            /**
261             * {@code ConstantPoolCacheEntry::_f2} is volatile of type {@code intx}.
262             *
263             * @return value of field {@code _f2}
264             */
265            private long getF2() {
266                assert runtime().getHostJVMCIBackend().getTarget().wordSize == 8 : "port to non-64-bit platform";
267                return unsafe.getLongVolatile(null, address + runtime().getConfig().constantPoolCacheEntryF2Offset);
268            }
269
270            /**
271             * {@code ConstantPoolCacheEntry::_flags} is volatile of type {@code intx}.
272             *
273             * @return flag bits
274             */
275            private long flags() {
276                assert runtime().getHostJVMCIBackend().getTarget().wordSize == 8 : "port to non-64-bit platform";
277                return unsafe.getLongVolatile(null, address + runtime().getConfig().constantPoolCacheEntryFlagsOffset);
278            }
279
280            private boolean isF1Null() {
281                final long f1 = getF1();
282                return f1 == 0;
283            }
284
285            /**
286             * Returns the constant pool index for this entry. See
287             * {@code ConstantPoolCacheEntry::constant_pool_index()}
288             *
289             * @return the constant pool index for this entry
290             */
291            public int getConstantPoolIndex() {
292                return ((int) getIndices()) & runtime().getConfig().constantPoolCacheEntryCpIndexMask;
293            }
294
295            /**
296             * See {@code ConstantPoolCache::has_appendix()}.
297             *
298             * @return true if there is an appendix, false otherwise
299             */
300            private boolean hasAppendix() {
301                return (!isF1Null()) && (flags() & (1 << runtime().getConfig().constantPoolCacheEntryHasAppendixShift)) != 0;
302            }
303
304            /**
305             * See {@code ConstantPoolCache::appendix_if_resolved()}.
306             */
307            public Object getAppendixIfResolved() {
308                if (!hasAppendix()) {
309                    return null;
310                }
311                final int index = ((int) getF2()) + runtime().getConfig().constantPoolCacheEntryIndyResolvedReferencesAppendixOffset;
312                return resolvedReferences.getArray()[index];
313            }
314        }
315
316        /**
317         * Get the constant pool cache entry at index {@code index}.
318         *
319         * @param index index of entry to return
320         * @return constant pool cache entry at given index
321         */
322        public Entry getEntryAt(int index) {
323            queryAddress();
324            assert exists();
325            HotSpotVMConfig config = runtime().getConfig();
326            return new Entry(address + config.constantPoolCacheSize + config.constantPoolCacheEntrySize * index);
327        }
328
329        /**
330         * Maps the constant pool cache index back to a constant pool index. See
331         * {@code ConstantPool::remap_instruction_operand_from_cache}.
332         *
333         * @param index the constant pool cache index
334         * @return constant pool index
335         */
336        public int constantPoolCacheIndexToConstantPoolIndex(int index) {
337            final int cacheIndex = index - runtime().getConfig().constantPoolCpCacheIndexTag;
338            return getEntryAt(cacheIndex).getConstantPoolIndex();
339        }
340
341    }
342
343    /**
344     * Resolved references of this constant pool.
345     */
346    private final ResolvedReferences resolvedReferences = new ResolvedReferences();
347
348    /**
349     * Hide the resolved references array in a private class so it cannot be accessed directly. The
350     * reason is the resolved references array is created when the constant pool cache is created.
351     *
352     * @see Cache
353     */
354    private final class ResolvedReferences {
355
356        /**
357         * Pointer to the {@code ConstantPool::_resolved_references} array.
358         */
359        private Object[] resolvedReferences;
360
361        /**
362         * Map of constant pool indexes to {@code ConstantPool::_resolved_references} indexes.
363         */
364        private final HashMap<Integer, Integer> referenceMap = new HashMap<>();
365
366        /**
367         * Returns the {@code ConstantPool::_resolved_references} array for this constant pool.
368         *
369         * @return resolved references array if exists, null otherwise
370         */
371        public Object[] getArray() {
372            if (resolvedReferences == null) {
373                final long handle = unsafe.getAddress(metaspaceConstantPool + runtime().getConfig().constantPoolResolvedReferencesOffset);
374                if (handle != 0) {
375                    resolvedReferences = (Object[]) runtime().getCompilerToVM().readUncompressedOop(handle + runtime().getConfig().handleHandleOffset);
376                    fillReferenceMap();
377                }
378            }
379            return resolvedReferences;
380        }
381
382        /**
383         * Fills the {@link #referenceMap} with all the values from
384         * {@code ConstantPool::_reference_map} for faster lookup.
385         */
386        private void fillReferenceMap() {
387            // It is possible there is a resolved references array but no reference map.
388            final long address = unsafe.getAddress(metaspaceConstantPool + runtime().getConfig().constantPoolReferenceMapOffset);
389            if (address != 0) {
390                final int length = unsafe.getInt(null, address + runtime().getConfig().arrayU1LengthOffset);
391                for (int i = 0; i < length; i++) {
392                    final int value = unsafe.getShort(address + runtime().getConfig().arrayU2DataOffset + i * Short.BYTES);
393                    referenceMap.put(value, i);
394                }
395            }
396        }
397
398        /**
399         * See {@code ConstantPool::cp_to_object_index}.
400         *
401         * @param cpi constant pool index
402         * @return resolved references array index
403         */
404        public int constantPoolIndexToResolvedReferencesIndex(int cpi) {
405            final Integer index = referenceMap.get(cpi);
406            // We might not find the index for jsr292 call.
407            return (index == null) ? -1 : index;
408        }
409
410    }
411
412    public HotSpotConstantPool(long metaspaceConstantPool) {
413        this.metaspaceConstantPool = metaspaceConstantPool;
414
415        // Cache constructor needs metaspaceConstantPool.
416        cache = new Cache();
417    }
418
419    /**
420     * Gets the holder for this constant pool as {@link HotSpotResolvedObjectTypeImpl}.
421     *
422     * @return holder for this constant pool
423     */
424    private HotSpotResolvedObjectType getHolder() {
425        final long metaspaceKlass = unsafe.getAddress(metaspaceConstantPool + runtime().getConfig().constantPoolHolderOffset);
426        return HotSpotResolvedObjectTypeImpl.fromMetaspaceKlass(metaspaceKlass);
427    }
428
429    /**
430     * Converts a raw index from the bytecodes to a constant pool index by adding a
431     * {@link HotSpotVMConfig#constantPoolCpCacheIndexTag constant}.
432     *
433     * @param rawIndex index from the bytecode
434     * @param opcode bytecode to convert the index for
435     * @return constant pool index
436     */
437    private static int rawIndexToConstantPoolIndex(int rawIndex, int opcode) {
438        int index;
439        if (opcode == Bytecodes.INVOKEDYNAMIC) {
440            index = rawIndex;
441            // See: ConstantPool::is_invokedynamic_index
442            assert index < 0 : "not an invokedynamic constant pool index " + index;
443        } else {
444            assert opcode == Bytecodes.GETFIELD || opcode == Bytecodes.PUTFIELD || opcode == Bytecodes.GETSTATIC || opcode == Bytecodes.PUTSTATIC || opcode == Bytecodes.INVOKEINTERFACE ||
445                            opcode == Bytecodes.INVOKEVIRTUAL || opcode == Bytecodes.INVOKESPECIAL || opcode == Bytecodes.INVOKESTATIC : "unexpected invoke opcode " + opcode;
446            index = rawIndex + runtime().getConfig().constantPoolCpCacheIndexTag;
447        }
448        return index;
449    }
450
451    /**
452     * Decode a constant pool cache index to a constant pool index.
453     *
454     * See {@code ConstantPool::decode_cpcache_index}.
455     *
456     * @param index constant pool cache index
457     * @return decoded index
458     */
459    private static int decodeConstantPoolCacheIndex(int index) {
460        if (isInvokedynamicIndex(index)) {
461            return decodeInvokedynamicIndex(index);
462        } else {
463            return index - runtime().getConfig().constantPoolCpCacheIndexTag;
464        }
465    }
466
467    /**
468     * See {@code ConstantPool::is_invokedynamic_index}.
469     */
470    private static boolean isInvokedynamicIndex(int index) {
471        return index < 0;
472    }
473
474    /**
475     * See {@code ConstantPool::decode_invokedynamic_index}.
476     */
477    private static int decodeInvokedynamicIndex(int i) {
478        assert isInvokedynamicIndex(i) : i;
479        return ~i;
480    }
481
482    /**
483     * Gets the constant pool tag at index {@code index}.
484     *
485     * @param index constant pool index
486     * @return constant pool tag
487     */
488    private JVM_CONSTANT getTagAt(int index) {
489        assertBounds(index);
490        HotSpotVMConfig config = runtime().getConfig();
491        final long metaspaceConstantPoolTags = unsafe.getAddress(metaspaceConstantPool + config.constantPoolTagsOffset);
492        final int tag = unsafe.getByteVolatile(null, metaspaceConstantPoolTags + config.arrayU1DataOffset + index);
493        if (tag == 0) {
494            return null;
495        }
496        return JVM_CONSTANT.getEnum(tag);
497    }
498
499    /**
500     * Gets the constant pool entry at index {@code index}.
501     *
502     * @param index constant pool index
503     * @return constant pool entry
504     */
505    private long getEntryAt(int index) {
506        assertBounds(index);
507        return unsafe.getAddress(metaspaceConstantPool + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize);
508    }
509
510    /**
511     * Gets the integer constant pool entry at index {@code index}.
512     *
513     * @param index constant pool index
514     * @return integer constant pool entry at index
515     */
516    private int getIntAt(int index) {
517        assertTag(index, JVM_CONSTANT.Integer);
518        return unsafe.getInt(metaspaceConstantPool + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize);
519    }
520
521    /**
522     * Gets the long constant pool entry at index {@code index}.
523     *
524     * @param index constant pool index
525     * @return long constant pool entry
526     */
527    private long getLongAt(int index) {
528        assertTag(index, JVM_CONSTANT.Long);
529        return unsafe.getLong(metaspaceConstantPool + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize);
530    }
531
532    /**
533     * Gets the float constant pool entry at index {@code index}.
534     *
535     * @param index constant pool index
536     * @return float constant pool entry
537     */
538    private float getFloatAt(int index) {
539        assertTag(index, JVM_CONSTANT.Float);
540        return unsafe.getFloat(metaspaceConstantPool + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize);
541    }
542
543    /**
544     * Gets the double constant pool entry at index {@code index}.
545     *
546     * @param index constant pool index
547     * @return float constant pool entry
548     */
549    private double getDoubleAt(int index) {
550        assertTag(index, JVM_CONSTANT.Double);
551        return unsafe.getDouble(metaspaceConstantPool + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize);
552    }
553
554    /**
555     * Gets the {@code JVM_CONSTANT_NameAndType} constant pool entry at index {@code index}.
556     *
557     * @param index constant pool index
558     * @return {@code JVM_CONSTANT_NameAndType} constant pool entry
559     */
560    private int getNameAndTypeAt(int index) {
561        assertTag(index, JVM_CONSTANT.NameAndType);
562        return unsafe.getInt(metaspaceConstantPool + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize);
563    }
564
565    /**
566     * Gets the {@code JVM_CONSTANT_NameAndType} reference index constant pool entry at index
567     * {@code index}.
568     *
569     * @param index constant pool index
570     * @return {@code JVM_CONSTANT_NameAndType} reference constant pool entry
571     */
572    private int getNameAndTypeRefIndexAt(int index) {
573        return runtime().getCompilerToVM().lookupNameAndTypeRefIndexInPool(metaspaceConstantPool, index);
574    }
575
576    /**
577     * Gets the name of a {@code JVM_CONSTANT_NameAndType} constant pool entry at index
578     * {@code index}.
579     *
580     * @param index constant pool index
581     * @return name as {@link String}
582     */
583    private String getNameRefAt(int index) {
584        if (Options.UseConstantPoolCacheJavaCode.getValue()) {
585            final int nameRefIndex = getNameRefIndexAt(getNameAndTypeRefIndexAt(index));
586            return new HotSpotSymbol(getEntryAt(nameRefIndex)).asString();
587        } else {
588            return runtime().getCompilerToVM().lookupNameRefInPool(metaspaceConstantPool, index);
589        }
590    }
591
592    /**
593     * Gets the name reference index of a {@code JVM_CONSTANT_NameAndType} constant pool entry at
594     * index {@code index}.
595     *
596     * @param index constant pool index
597     * @return name reference index
598     */
599    private int getNameRefIndexAt(int index) {
600        final int refIndex = getNameAndTypeAt(index);
601        // name ref index is in the low 16-bits.
602        return refIndex & 0xFFFF;
603    }
604
605    /**
606     * Gets the signature of a {@code JVM_CONSTANT_NameAndType} constant pool entry at index
607     * {@code index}.
608     *
609     * @param index constant pool index
610     * @return signature as {@link String}
611     */
612    private String getSignatureRefAt(int index) {
613        if (Options.UseConstantPoolCacheJavaCode.getValue()) {
614            final int signatureRefIndex = getSignatureRefIndexAt(getNameAndTypeRefIndexAt(index));
615            return new HotSpotSymbol(getEntryAt(signatureRefIndex)).asString();
616        } else {
617            return runtime().getCompilerToVM().lookupSignatureRefInPool(metaspaceConstantPool, index);
618        }
619    }
620
621    /**
622     * Gets the signature reference index of a {@code JVM_CONSTANT_NameAndType} constant pool entry
623     * at index {@code index}.
624     *
625     * @param index constant pool index
626     * @return signature reference index
627     */
628    private int getSignatureRefIndexAt(int index) {
629        final int refIndex = getNameAndTypeAt(index);
630        // signature ref index is in the high 16-bits.
631        return refIndex >>> 16;
632    }
633
634    /**
635     * Gets the klass reference index constant pool entry at index {@code index}. See
636     * {@code ConstantPool::klass_ref_index_at}.
637     *
638     * @param index constant pool index
639     * @param cached whether to go through the constant pool cache
640     * @return klass reference index
641     */
642    private int getKlassRefIndexAt(int index, boolean cached) {
643        int cpi = index;
644        if (cached && cache.exists()) {
645            // change byte-ordering and go via cache
646            cpi = cache.constantPoolCacheIndexToConstantPoolIndex(index);
647        }
648        assertTagIsFieldOrMethod(cpi);
649        final int refIndex = unsafe.getInt(metaspaceConstantPool + runtime().getConfig().constantPoolSize + cpi * runtime().getHostJVMCIBackend().getTarget().wordSize);
650        // klass ref index is in the low 16-bits.
651        return refIndex & 0xFFFF;
652    }
653
654    /**
655     * Gets the klass reference index constant pool entry at index {@code index}. See
656     * {@code ConstantPool::klass_ref_index_at}.
657     *
658     * @param index constant pool index
659     * @return klass reference index
660     */
661    private int getKlassRefIndexAt(int index) {
662        if (Options.UseConstantPoolCacheJavaCode.getValue()) {
663            return getKlassRefIndexAt(index, true);
664        } else {
665            return runtime().getCompilerToVM().lookupKlassRefIndexInPool(metaspaceConstantPool, index);
666        }
667    }
668
669    /**
670     * Gets the uncached klass reference index constant pool entry at index {@code index}. See:
671     * {@code ConstantPool::uncached_klass_ref_index_at}.
672     *
673     * @param index constant pool index
674     * @return klass reference index
675     */
676    private int getUncachedKlassRefIndexAt(int index) {
677        if (Options.UseConstantPoolCacheJavaCode.getValue()) {
678            return getKlassRefIndexAt(index, false);
679        } else {
680            assertTagIsFieldOrMethod(index);
681            final int refIndex = unsafe.getInt(metaspaceConstantPool + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize);
682            // klass ref index is in the low 16-bits.
683            return refIndex & 0xFFFF;
684        }
685    }
686
687    /**
688     * Asserts that the constant pool index {@code index} is in the bounds of the constant pool.
689     *
690     * @param index constant pool index
691     */
692    private void assertBounds(int index) {
693        assert 0 <= index && index < length() : "index " + index + " not between 0 and " + length();
694    }
695
696    /**
697     * Asserts that the constant pool tag at index {@code index} is equal to {@code tag}.
698     *
699     * @param index constant pool index
700     * @param tag expected tag
701     */
702    private void assertTag(int index, JVM_CONSTANT tag) {
703        final JVM_CONSTANT tagAt = getTagAt(index);
704        assert tagAt == tag : "constant pool tag at index " + index + " is " + tagAt + " but expected " + tag;
705    }
706
707    /**
708     * Asserts that the constant pool tag at index {@code index} is a {@link JVM_CONSTANT#Fieldref},
709     * or a {@link JVM_CONSTANT#MethodRef}, or a {@link JVM_CONSTANT#InterfaceMethodref}.
710     *
711     * @param index constant pool index
712     */
713    private void assertTagIsFieldOrMethod(int index) {
714        final JVM_CONSTANT tagAt = getTagAt(index);
715        assert tagAt == JVM_CONSTANT.Fieldref || tagAt == JVM_CONSTANT.MethodRef || tagAt == JVM_CONSTANT.InterfaceMethodref : tagAt;
716    }
717
718    @Override
719    public int length() {
720        return unsafe.getInt(metaspaceConstantPool + runtime().getConfig().constantPoolLengthOffset);
721    }
722
723    @Override
724    public Object lookupConstant(int cpi) {
725        assert cpi != 0;
726        final JVM_CONSTANT tag = getTagAt(cpi);
727        switch (tag) {
728            case Integer:
729                return JavaConstant.forInt(getIntAt(cpi));
730            case Long:
731                return JavaConstant.forLong(getLongAt(cpi));
732            case Float:
733                return JavaConstant.forFloat(getFloatAt(cpi));
734            case Double:
735                return JavaConstant.forDouble(getDoubleAt(cpi));
736            case Class:
737            case UnresolvedClass:
738            case UnresolvedClassInError:
739                final int opcode = -1;  // opcode is not used
740                return lookupType(cpi, opcode);
741            case String:
742                /*
743                 * Normally, we would expect a String here, but anonymous classes can have
744                 * "pseudo strings" (arbitrary live objects) patched into a String entry. Such
745                 * entries do not have a symbol in the constant pool slot.
746                 */
747                Object string;
748                if (Options.UseConstantPoolCacheJavaCode.getValue()) {
749                    // See: ConstantPool::resolve_constant_at_impl
750                    /*
751                     * Note: Call getArray() before constantPoolIndexToResolvedReferencesIndex()
752                     * because it fills the map if the array exists.
753                     */
754                    Object[] localResolvedReferences = resolvedReferences.getArray();
755                    final int index = resolvedReferences.constantPoolIndexToResolvedReferencesIndex(cpi);
756                    assert index >= 0;
757                    // See: ConstantPool::string_at_impl
758                    string = localResolvedReferences[index];
759                    if (string != null) {
760                        assert string instanceof String || getEntryAt(index) == 0L;
761                        return HotSpotObjectConstantImpl.forObject(string);
762                    } else {
763                        final long metaspaceSymbol = getEntryAt(cpi);
764                        if (metaspaceSymbol != 0L) {
765                            HotSpotSymbol symbol = new HotSpotSymbol(metaspaceSymbol);
766                            string = symbol.asString().intern();
767                            // See: ConstantPool::string_at_put
768                            localResolvedReferences[index] = string;
769                        }
770                    }
771                } else {
772                    string = runtime().getCompilerToVM().resolvePossiblyCachedConstantInPool(metaspaceConstantPool, cpi);
773                }
774                return HotSpotObjectConstantImpl.forObject(string);
775            case MethodHandle:
776            case MethodHandleInError:
777            case MethodType:
778            case MethodTypeInError:
779                Object obj = runtime().getCompilerToVM().resolveConstantInPool(metaspaceConstantPool, cpi);
780                return HotSpotObjectConstantImpl.forObject(obj);
781            default:
782                throw new JVMCIError("Unknown constant pool tag %s", tag);
783        }
784    }
785
786    @Override
787    public String lookupUtf8(int cpi) {
788        assertTag(cpi, JVM_CONSTANT.Utf8);
789        String s;
790        if (Options.UseConstantPoolCacheJavaCode.getValue()) {
791            HotSpotSymbol symbol = new HotSpotSymbol(getEntryAt(cpi));
792            s = symbol.asString();
793            // It shouldn't but just in case something went wrong...
794            if (s == null) {
795                throw JVMCIError.shouldNotReachHere("malformed UTF-8 string in constant pool");
796            }
797        } else {
798            s = runtime().getCompilerToVM().getSymbol(getEntryAt(cpi));
799        }
800        return s;
801    }
802
803    @Override
804    public Signature lookupSignature(int cpi) {
805        return new HotSpotSignature(runtime(), lookupUtf8(cpi));
806    }
807
808    @Override
809    public JavaConstant lookupAppendix(int cpi, int opcode) {
810        assert Bytecodes.isInvoke(opcode);
811        final int index = rawIndexToConstantPoolIndex(cpi, opcode);
812
813        Object appendix = null;
814
815        if (Options.UseConstantPoolCacheJavaCode.getValue()) {
816            if (!cache.exists()) {
817                // Nothing to load yet.
818                return null;
819            }
820            final int cacheIndex = decodeConstantPoolCacheIndex(index);
821            Cache.Entry entry = cache.getEntryAt(cacheIndex);
822            appendix = entry.getAppendixIfResolved();
823        } else {
824            appendix = runtime().getCompilerToVM().lookupAppendixInPool(metaspaceConstantPool, index);
825        }
826
827        if (appendix == null) {
828            return null;
829        } else {
830            return HotSpotObjectConstantImpl.forObject(appendix);
831        }
832    }
833
834    /**
835     * Gets a {@link JavaType} corresponding a given metaspace Klass or a metaspace Symbol depending
836     * on the {@link HotSpotVMConfig#compilerToVMKlassTag tag}.
837     *
838     * @param metaspacePointer either a metaspace Klass or a metaspace Symbol
839     */
840    private static JavaType getJavaType(final long metaspacePointer) {
841        HotSpotJVMCIRuntime runtime = runtime();
842        HotSpotVMConfig config = runtime.getConfig();
843        if ((metaspacePointer & config.compilerToVMSymbolTag) != 0) {
844            final long metaspaceSymbol = metaspacePointer & ~config.compilerToVMSymbolTag;
845            String name;
846            if (Options.UseConstantPoolCacheJavaCode.getValue()) {
847                HotSpotSymbol symbol = new HotSpotSymbol(metaspaceSymbol);
848                name = symbol.asString();
849                // It shouldn't but just in case something went wrong...
850                if (name == null) {
851                    throw JVMCIError.shouldNotReachHere("malformed UTF-8 string in constant pool");
852                }
853            } else {
854                name = runtime.getCompilerToVM().getSymbol(metaspaceSymbol);
855            }
856            return HotSpotUnresolvedJavaType.create(runtime(), "L" + name + ";");
857        } else {
858            assert (metaspacePointer & config.compilerToVMKlassTag) == 0;
859            return HotSpotResolvedObjectTypeImpl.fromMetaspaceKlass(metaspacePointer);
860        }
861    }
862
863    @Override
864    public JavaMethod lookupMethod(int cpi, int opcode) {
865        final int index = rawIndexToConstantPoolIndex(cpi, opcode);
866        final long metaspaceMethod = runtime().getCompilerToVM().lookupMethodInPool(metaspaceConstantPool, index, (byte) opcode);
867        if (metaspaceMethod != 0L) {
868            HotSpotResolvedJavaMethod result = HotSpotResolvedJavaMethodImpl.fromMetaspace(metaspaceMethod);
869            return result;
870        } else {
871            // Get the method's name and signature.
872            String name = getNameRefAt(index);
873            HotSpotSignature signature = new HotSpotSignature(runtime(), getSignatureRefAt(index));
874            if (opcode == Bytecodes.INVOKEDYNAMIC) {
875                HotSpotResolvedObjectType holder = HotSpotResolvedObjectTypeImpl.fromObjectClass(MethodHandle.class);
876                return new HotSpotMethodUnresolved(name, signature, holder);
877            } else {
878                final int klassIndex = getKlassRefIndexAt(index);
879                final long metaspacePointer = runtime().getCompilerToVM().lookupKlassInPool(metaspaceConstantPool, klassIndex);
880                JavaType holder = getJavaType(metaspacePointer);
881                return new HotSpotMethodUnresolved(name, signature, holder);
882            }
883        }
884    }
885
886    @Override
887    public JavaType lookupType(int cpi, int opcode) {
888        final LookupTypeCacheElement elem = this.lastLookupType;
889        if (elem != null && elem.lastCpi == cpi) {
890            return elem.javaType;
891        } else {
892            final long metaspacePointer = runtime().getCompilerToVM().lookupKlassInPool(metaspaceConstantPool, cpi);
893            JavaType result = getJavaType(metaspacePointer);
894            if (result instanceof ResolvedJavaType) {
895                this.lastLookupType = new LookupTypeCacheElement(cpi, result);
896            }
897            return result;
898        }
899    }
900
901    @Override
902    public JavaField lookupField(int cpi, int opcode) {
903        final int index = rawIndexToConstantPoolIndex(cpi, opcode);
904        final int nameAndTypeIndex = getNameAndTypeRefIndexAt(index);
905        final int nameIndex = getNameRefIndexAt(nameAndTypeIndex);
906        String name = lookupUtf8(nameIndex);
907        final int typeIndex = getSignatureRefIndexAt(nameAndTypeIndex);
908        String typeName = lookupUtf8(typeIndex);
909        JavaType type = runtime().lookupType(typeName, getHolder(), false);
910
911        final int holderIndex = getKlassRefIndexAt(index);
912        JavaType holder = lookupType(holderIndex, opcode);
913
914        if (holder instanceof HotSpotResolvedObjectTypeImpl) {
915            long[] info = new long[2];
916            long metaspaceKlass;
917            try {
918                metaspaceKlass = runtime().getCompilerToVM().resolveField(metaspaceConstantPool, index, (byte) opcode, info);
919            } catch (Throwable t) {
920                /*
921                 * If there was an exception resolving the field we give up and return an unresolved
922                 * field.
923                 */
924                return new HotSpotUnresolvedField(holder, name, type);
925            }
926            HotSpotResolvedObjectTypeImpl resolvedHolder = HotSpotResolvedObjectTypeImpl.fromMetaspaceKlass(metaspaceKlass);
927            final int flags = (int) info[0];
928            final long offset = info[1];
929            HotSpotResolvedJavaField result = resolvedHolder.createField(name, type, offset, flags);
930            return result;
931        } else {
932            return new HotSpotUnresolvedField(holder, name, type);
933        }
934    }
935
936    @Override
937    public void loadReferencedType(int cpi, int opcode) {
938        int index;
939        switch (opcode) {
940            case Bytecodes.CHECKCAST:
941            case Bytecodes.INSTANCEOF:
942            case Bytecodes.NEW:
943            case Bytecodes.ANEWARRAY:
944            case Bytecodes.MULTIANEWARRAY:
945            case Bytecodes.LDC:
946            case Bytecodes.LDC_W:
947            case Bytecodes.LDC2_W:
948                index = cpi;
949                break;
950            case Bytecodes.INVOKEDYNAMIC: {
951                // invokedynamic instructions point to a constant pool cache entry.
952                if (Options.UseConstantPoolCacheJavaCode.getValue()) {
953                    // index = decodeConstantPoolCacheIndex(cpi) +
954                    // runtime().getConfig().constantPoolCpCacheIndexTag;
955                    // index = cache.constantPoolCacheIndexToConstantPoolIndex(index);
956                    final int cacheIndex = cpi;
957                    index = cache.getEntryAt(decodeInvokedynamicIndex(cacheIndex)).getConstantPoolIndex();
958                    // JVMCIError.guarantee(index == x, index + " != " + x);
959                } else {
960                    index = decodeConstantPoolCacheIndex(cpi) + runtime().getConfig().constantPoolCpCacheIndexTag;
961                    index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(metaspaceConstantPool, index);
962                }
963                break;
964            }
965            case Bytecodes.GETSTATIC:
966            case Bytecodes.PUTSTATIC:
967            case Bytecodes.GETFIELD:
968            case Bytecodes.PUTFIELD:
969            case Bytecodes.INVOKEVIRTUAL:
970            case Bytecodes.INVOKESPECIAL:
971            case Bytecodes.INVOKESTATIC:
972            case Bytecodes.INVOKEINTERFACE: {
973                // invoke and field instructions point to a constant pool cache entry.
974                if (Options.UseConstantPoolCacheJavaCode.getValue()) {
975                    // index = rawIndexToConstantPoolIndex(cpi, opcode);
976                    // index = cache.constantPoolCacheIndexToConstantPoolIndex(index);
977                    final int cacheIndex = cpi;
978                    index = cache.getEntryAt(cacheIndex).getConstantPoolIndex();
979                    // JVMCIError.guarantee(index == x, index + " != " + x);
980                } else {
981                    index = rawIndexToConstantPoolIndex(cpi, opcode);
982                    index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(metaspaceConstantPool, index);
983                }
984                break;
985            }
986            default:
987                throw JVMCIError.shouldNotReachHere("Unexpected opcode " + opcode);
988        }
989
990        final JVM_CONSTANT tag = getTagAt(index);
991        if (tag == null) {
992            assert getTagAt(index - 1) == JVM_CONSTANT.Double || getTagAt(index - 1) == JVM_CONSTANT.Long;
993            return;
994        }
995        switch (tag) {
996            case MethodRef:
997            case Fieldref:
998            case InterfaceMethodref:
999                index = getUncachedKlassRefIndexAt(index);
1000                // Read the tag only once because it could change between multiple reads.
1001                final JVM_CONSTANT klassTag = getTagAt(index);
1002                assert klassTag == JVM_CONSTANT.Class || klassTag == JVM_CONSTANT.UnresolvedClass || klassTag == JVM_CONSTANT.UnresolvedClassInError : klassTag;
1003                // fall through
1004            case Class:
1005            case UnresolvedClass:
1006            case UnresolvedClassInError:
1007                final long metaspaceKlass = runtime().getCompilerToVM().constantPoolKlassAt(metaspaceConstantPool, index);
1008                HotSpotResolvedObjectTypeImpl type = HotSpotResolvedObjectTypeImpl.fromMetaspaceKlass(metaspaceKlass);
1009                Class<?> klass = type.mirror();
1010                if (!klass.isPrimitive() && !klass.isArray()) {
1011                    unsafe.ensureClassInitialized(klass);
1012                }
1013                switch (tag) {
1014                    case MethodRef:
1015                        if (Bytecodes.isInvokeHandleAlias(opcode)) {
1016                            final int methodRefCacheIndex = rawIndexToConstantPoolIndex(cpi, opcode);
1017                            if (isInvokeHandle(methodRefCacheIndex, type)) {
1018                                runtime().getCompilerToVM().resolveInvokeHandle(metaspaceConstantPool, methodRefCacheIndex);
1019                            }
1020                        }
1021                }
1022                break;
1023            case InvokeDynamic:
1024                if (isInvokedynamicIndex(cpi)) {
1025                    runtime().getCompilerToVM().resolveInvokeDynamic(metaspaceConstantPool, cpi);
1026                }
1027                break;
1028            default:
1029                // nothing
1030                break;
1031        }
1032    }
1033
1034    private boolean isInvokeHandle(int methodRefCacheIndex, HotSpotResolvedObjectTypeImpl klass) {
1035        int index;
1036        if (Options.UseConstantPoolCacheJavaCode.getValue()) {
1037            index = cache.constantPoolCacheIndexToConstantPoolIndex(methodRefCacheIndex);
1038        } else {
1039            index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(metaspaceConstantPool, methodRefCacheIndex);
1040        }
1041        assertTag(index, JVM_CONSTANT.MethodRef);
1042        return ResolvedJavaMethod.isSignaturePolymorphic(klass, getNameRefAt(methodRefCacheIndex), runtime().getHostJVMCIBackend().getMetaAccess());
1043    }
1044
1045    @Override
1046    public String toString() {
1047        HotSpotResolvedObjectType holder = getHolder();
1048        return "HotSpotConstantPool<" + holder.toJavaName() + ">";
1049    }
1050}