--- old/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java 2016-05-04 09:43:29.000000000 -1000 +++ /dev/null 2016-05-04 09:43:29.000000000 -1000 @@ -1,714 +0,0 @@ -/* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.vm.ci.hotspot; - -import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; -import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; -import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; -import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; - -import java.lang.invoke.MethodHandle; - -import jdk.vm.ci.common.JVMCIError; -import jdk.vm.ci.meta.ConstantPool; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaField; -import jdk.vm.ci.meta.JavaMethod; -import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.Signature; - -/** - * Implementation of {@link ConstantPool} for HotSpot. - */ -final class HotSpotConstantPool implements ConstantPool, HotSpotProxified, MetaspaceWrapperObject { - - /** - * Subset of JVM bytecode opcodes used by {@link HotSpotConstantPool}. - */ - public static class Bytecodes { - public static final int LDC = 18; // 0x12 - public static final int LDC_W = 19; // 0x13 - public static final int LDC2_W = 20; // 0x14 - public static final int GETSTATIC = 178; // 0xB2 - public static final int PUTSTATIC = 179; // 0xB3 - public static final int GETFIELD = 180; // 0xB4 - public static final int PUTFIELD = 181; // 0xB5 - public static final int INVOKEVIRTUAL = 182; // 0xB6 - public static final int INVOKESPECIAL = 183; // 0xB7 - public static final int INVOKESTATIC = 184; // 0xB8 - public static final int INVOKEINTERFACE = 185; // 0xB9 - public static final int INVOKEDYNAMIC = 186; // 0xBA - public static final int NEW = 187; // 0xBB - public static final int NEWARRAY = 188; // 0xBC - public static final int ANEWARRAY = 189; // 0xBD - public static final int CHECKCAST = 192; // 0xC0 - public static final int INSTANCEOF = 193; // 0xC1 - public static final int MULTIANEWARRAY = 197; // 0xC5 - - static boolean isInvoke(int opcode) { - switch (opcode) { - case INVOKEVIRTUAL: - case INVOKESPECIAL: - case INVOKESTATIC: - case INVOKEINTERFACE: - case INVOKEDYNAMIC: - return true; - default: - return false; - } - } - - /** - * See: {@code Rewriter::maybe_rewrite_invokehandle}. - */ - static boolean isInvokeHandleAlias(int opcode) { - switch (opcode) { - case INVOKEVIRTUAL: - case INVOKESPECIAL: - return true; - default: - return false; - } - } - } - - /** - * Enum of all {@code JVM_CONSTANT} constants used in the VM. This includes the public and - * internal ones. - */ - private enum JVM_CONSTANT { - // @formatter:off - Utf8(config().jvmConstantUtf8), - Integer(config().jvmConstantInteger), - Long(config().jvmConstantLong), - Float(config().jvmConstantFloat), - Double(config().jvmConstantDouble), - Class(config().jvmConstantClass), - UnresolvedClass(config().jvmConstantUnresolvedClass), - UnresolvedClassInError(config().jvmConstantUnresolvedClassInError), - String(config().jvmConstantString), - Fieldref(config().jvmConstantFieldref), - MethodRef(config().jvmConstantMethodref), - InterfaceMethodref(config().jvmConstantInterfaceMethodref), - NameAndType(config().jvmConstantNameAndType), - MethodHandle(config().jvmConstantMethodHandle), - MethodHandleInError(config().jvmConstantMethodHandleInError), - MethodType(config().jvmConstantMethodType), - MethodTypeInError(config().jvmConstantMethodTypeInError), - InvokeDynamic(config().jvmConstantInvokeDynamic); - // @formatter:on - - private final int tag; - - private static final int ExternalMax = config().jvmConstantExternalMax; - private static final int InternalMin = config().jvmConstantInternalMin; - private static final int InternalMax = config().jvmConstantInternalMax; - - JVM_CONSTANT(int tag) { - this.tag = tag; - } - - /** - * Maps JVM_CONSTANT tags to {@link JVM_CONSTANT} values. Using a separate class for lazy - * initialization. - */ - static class TagValueMap { - private static final JVM_CONSTANT[] table = new JVM_CONSTANT[ExternalMax + 1 + (InternalMax - InternalMin) + 1]; - - static { - assert InternalMin > ExternalMax; - for (JVM_CONSTANT e : values()) { - table[indexOf(e.tag)] = e; - } - } - - private static int indexOf(int tag) { - if (tag >= InternalMin) { - return tag - InternalMin + ExternalMax + 1; - } else { - assert tag <= ExternalMax; - } - return tag; - } - - static JVM_CONSTANT get(int tag) { - JVM_CONSTANT res = table[indexOf(tag)]; - if (res != null) { - return res; - } - throw new JVMCIError("Unknown JVM_CONSTANT tag %s", tag); - } - } - - public static JVM_CONSTANT getEnum(int tag) { - return TagValueMap.get(tag); - } - } - - private static class LookupTypeCacheElement { - int lastCpi = Integer.MIN_VALUE; - JavaType javaType; - - LookupTypeCacheElement(int lastCpi, JavaType javaType) { - super(); - this.lastCpi = lastCpi; - this.javaType = javaType; - } - } - - /** - * Reference to the C++ ConstantPool object. - */ - private final long metaspaceConstantPool; - private volatile LookupTypeCacheElement lastLookupType; - - /** - * Gets the JVMCI mirror from a HotSpot constant pool.The VM is responsible for ensuring that - * the ConstantPool is kept alive for the duration of this call and the - * {@link HotSpotJVMCIMetaAccessContext} keeps it alive after that. - * - * Called from the VM. - * - * @param metaspaceConstantPool a metaspace ConstantPool object - * @return the {@link HotSpotConstantPool} corresponding to {@code metaspaceConstantPool} - */ - @SuppressWarnings("unused") - private static HotSpotConstantPool fromMetaspace(long metaspaceConstantPool) { - return new HotSpotConstantPool(metaspaceConstantPool); - } - - private HotSpotConstantPool(long metaspaceConstantPool) { - this.metaspaceConstantPool = metaspaceConstantPool; - } - - /** - * Gets the holder for this constant pool as {@link HotSpotResolvedObjectTypeImpl}. - * - * @return holder for this constant pool - */ - private HotSpotResolvedObjectType getHolder() { - return compilerToVM().getResolvedJavaType(this, config().constantPoolHolderOffset, false); - } - - /** - * Converts a raw index from the bytecodes to a constant pool index by adding a - * {@link HotSpotVMConfig#constantPoolCpCacheIndexTag constant}. - * - * @param rawIndex index from the bytecode - * @param opcode bytecode to convert the index for - * @return constant pool index - */ - private static int rawIndexToConstantPoolIndex(int rawIndex, int opcode) { - int index; - if (opcode == Bytecodes.INVOKEDYNAMIC) { - index = rawIndex; - // See: ConstantPool::is_invokedynamic_index - assert index < 0 : "not an invokedynamic constant pool index " + index; - } else { - assert opcode == Bytecodes.GETFIELD || opcode == Bytecodes.PUTFIELD || opcode == Bytecodes.GETSTATIC || opcode == Bytecodes.PUTSTATIC || opcode == Bytecodes.INVOKEINTERFACE || - opcode == Bytecodes.INVOKEVIRTUAL || opcode == Bytecodes.INVOKESPECIAL || opcode == Bytecodes.INVOKESTATIC : "unexpected invoke opcode " + opcode; - index = rawIndex + config().constantPoolCpCacheIndexTag; - } - return index; - } - - /** - * Decode a constant pool cache index to a constant pool index. - * - * See {@code ConstantPool::decode_cpcache_index}. - * - * @param index constant pool cache index - * @return decoded index - */ - private static int decodeConstantPoolCacheIndex(int index) { - if (isInvokedynamicIndex(index)) { - return decodeInvokedynamicIndex(index); - } else { - return index - config().constantPoolCpCacheIndexTag; - } - } - - /** - * See {@code ConstantPool::is_invokedynamic_index}. - */ - private static boolean isInvokedynamicIndex(int index) { - return index < 0; - } - - /** - * See {@code ConstantPool::decode_invokedynamic_index}. - */ - private static int decodeInvokedynamicIndex(int i) { - assert isInvokedynamicIndex(i) : i; - return ~i; - } - - long getMetaspaceConstantPool() { - return metaspaceConstantPool; - } - - public long getMetaspacePointer() { - return getMetaspaceConstantPool(); - } - - /** - * Gets the constant pool tag at index {@code index}. - * - * @param index constant pool index - * @return constant pool tag - */ - private JVM_CONSTANT getTagAt(int index) { - assertBounds(index); - HotSpotVMConfig config = config(); - final long metaspaceConstantPoolTags = UNSAFE.getAddress(getMetaspaceConstantPool() + config.constantPoolTagsOffset); - final int tag = UNSAFE.getByteVolatile(null, metaspaceConstantPoolTags + config.arrayU1DataOffset + index); - if (tag == 0) { - return null; - } - return JVM_CONSTANT.getEnum(tag); - } - - /** - * Gets the constant pool entry at index {@code index}. - * - * @param index constant pool index - * @return constant pool entry - */ - private long getEntryAt(int index) { - assertBounds(index); - return UNSAFE.getAddress(getMetaspaceConstantPool() + config().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); - } - - /** - * Gets the integer constant pool entry at index {@code index}. - * - * @param index constant pool index - * @return integer constant pool entry at index - */ - private int getIntAt(int index) { - assertTag(index, JVM_CONSTANT.Integer); - return UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); - } - - /** - * Gets the long constant pool entry at index {@code index}. - * - * @param index constant pool index - * @return long constant pool entry - */ - private long getLongAt(int index) { - assertTag(index, JVM_CONSTANT.Long); - return UNSAFE.getLong(getMetaspaceConstantPool() + config().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); - } - - /** - * Gets the float constant pool entry at index {@code index}. - * - * @param index constant pool index - * @return float constant pool entry - */ - private float getFloatAt(int index) { - assertTag(index, JVM_CONSTANT.Float); - return UNSAFE.getFloat(getMetaspaceConstantPool() + config().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); - } - - /** - * Gets the double constant pool entry at index {@code index}. - * - * @param index constant pool index - * @return float constant pool entry - */ - private double getDoubleAt(int index) { - assertTag(index, JVM_CONSTANT.Double); - return UNSAFE.getDouble(getMetaspaceConstantPool() + config().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); - } - - /** - * Gets the {@code JVM_CONSTANT_NameAndType} constant pool entry at index {@code index}. - * - * @param index constant pool index - * @return {@code JVM_CONSTANT_NameAndType} constant pool entry - */ - private int getNameAndTypeAt(int index) { - assertTag(index, JVM_CONSTANT.NameAndType); - return UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); - } - - /** - * Gets the {@code JVM_CONSTANT_NameAndType} reference index constant pool entry at index - * {@code index}. - * - * @param index constant pool index - * @return {@code JVM_CONSTANT_NameAndType} reference constant pool entry - */ - private int getNameAndTypeRefIndexAt(int index) { - return compilerToVM().lookupNameAndTypeRefIndexInPool(this, index); - } - - /** - * Gets the name of a {@code JVM_CONSTANT_NameAndType} constant pool entry referenced by another - * entry denoted by {@code which}. - * - * @param which constant pool index or constant pool cache index - * @return name as {@link String} - */ - private String getNameOf(int which) { - return compilerToVM().lookupNameInPool(this, which); - } - - /** - * Gets the name reference index of a {@code JVM_CONSTANT_NameAndType} constant pool entry at - * index {@code index}. - * - * @param index constant pool index - * @return name reference index - */ - private int getNameRefIndexAt(int index) { - final int refIndex = getNameAndTypeAt(index); - // name ref index is in the low 16-bits. - return refIndex & 0xFFFF; - } - - /** - * Gets the signature of a {@code JVM_CONSTANT_NameAndType} constant pool entry referenced by - * another entry denoted by {@code which}. - * - * @param which constant pool index or constant pool cache index - * @return signature as {@link String} - */ - private String getSignatureOf(int which) { - return compilerToVM().lookupSignatureInPool(this, which); - } - - /** - * Gets the signature reference index of a {@code JVM_CONSTANT_NameAndType} constant pool entry - * at index {@code index}. - * - * @param index constant pool index - * @return signature reference index - */ - private int getSignatureRefIndexAt(int index) { - final int refIndex = getNameAndTypeAt(index); - // signature ref index is in the high 16-bits. - return refIndex >>> 16; - } - - /** - * Gets the klass reference index constant pool entry at index {@code index}. - * - * @param index constant pool index - * @return klass reference index - */ - private int getKlassRefIndexAt(int index) { - return compilerToVM().lookupKlassRefIndexInPool(this, index); - } - - /** - * Gets the uncached klass reference index constant pool entry at index {@code index}. See: - * {@code ConstantPool::uncached_klass_ref_index_at}. - * - * @param index constant pool index - * @return klass reference index - */ - private int getUncachedKlassRefIndexAt(int index) { - assertTagIsFieldOrMethod(index); - final int refIndex = UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); - // klass ref index is in the low 16-bits. - return refIndex & 0xFFFF; - } - - /** - * Asserts that the constant pool index {@code index} is in the bounds of the constant pool. - * - * @param index constant pool index - */ - private void assertBounds(int index) { - assert 0 <= index && index < length() : "index " + index + " not between 0 and " + length(); - } - - /** - * Asserts that the constant pool tag at index {@code index} is equal to {@code tag}. - * - * @param index constant pool index - * @param tag expected tag - */ - private void assertTag(int index, JVM_CONSTANT tag) { - final JVM_CONSTANT tagAt = getTagAt(index); - assert tagAt == tag : "constant pool tag at index " + index + " is " + tagAt + " but expected " + tag; - } - - /** - * Asserts that the constant pool tag at index {@code index} is a {@link JVM_CONSTANT#Fieldref}, - * or a {@link JVM_CONSTANT#MethodRef}, or a {@link JVM_CONSTANT#InterfaceMethodref}. - * - * @param index constant pool index - */ - private void assertTagIsFieldOrMethod(int index) { - final JVM_CONSTANT tagAt = getTagAt(index); - assert tagAt == JVM_CONSTANT.Fieldref || tagAt == JVM_CONSTANT.MethodRef || tagAt == JVM_CONSTANT.InterfaceMethodref : tagAt; - } - - @Override - public int length() { - return UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolLengthOffset); - } - - @Override - public Object lookupConstant(int cpi) { - assert cpi != 0; - final JVM_CONSTANT tag = getTagAt(cpi); - switch (tag) { - case Integer: - return JavaConstant.forInt(getIntAt(cpi)); - case Long: - return JavaConstant.forLong(getLongAt(cpi)); - case Float: - return JavaConstant.forFloat(getFloatAt(cpi)); - case Double: - return JavaConstant.forDouble(getDoubleAt(cpi)); - case Class: - case UnresolvedClass: - case UnresolvedClassInError: - final int opcode = -1; // opcode is not used - return lookupType(cpi, opcode); - case String: - /* - * Normally, we would expect a String here, but anonymous classes can have - * "pseudo strings" (arbitrary live objects) patched into a String entry. Such - * entries do not have a symbol in the constant pool slot. - */ - Object string = compilerToVM().resolvePossiblyCachedConstantInPool(this, cpi); - return HotSpotObjectConstantImpl.forObject(string); - case MethodHandle: - case MethodHandleInError: - case MethodType: - case MethodTypeInError: - Object obj = compilerToVM().resolveConstantInPool(this, cpi); - return HotSpotObjectConstantImpl.forObject(obj); - default: - throw new JVMCIError("Unknown constant pool tag %s", tag); - } - } - - @Override - public String lookupUtf8(int cpi) { - assertTag(cpi, JVM_CONSTANT.Utf8); - return compilerToVM().getSymbol(getEntryAt(cpi)); - } - - @Override - public Signature lookupSignature(int cpi) { - return new HotSpotSignature(runtime(), lookupUtf8(cpi)); - } - - @Override - public JavaConstant lookupAppendix(int cpi, int opcode) { - assert Bytecodes.isInvoke(opcode); - final int index = rawIndexToConstantPoolIndex(cpi, opcode); - Object appendix = compilerToVM().lookupAppendixInPool(this, index); - if (appendix == null) { - return null; - } else { - return HotSpotObjectConstantImpl.forObject(appendix); - } - } - - /** - * Gets a {@link JavaType} corresponding a given resolved or unresolved type. - * - * @param type either a ResolvedJavaType or a String naming a unresolved type. - */ - private static JavaType getJavaType(final Object type) { - if (type instanceof String) { - String name = (String) type; - return HotSpotUnresolvedJavaType.create(runtime(), "L" + name + ";"); - } else { - return (JavaType) type; - } - } - - @Override - public JavaMethod lookupMethod(int cpi, int opcode) { - final int index = rawIndexToConstantPoolIndex(cpi, opcode); - final HotSpotResolvedJavaMethod method = compilerToVM().lookupMethodInPool(this, index, (byte) opcode); - if (method != null) { - return method; - } else { - // Get the method's name and signature. - String name = getNameOf(index); - HotSpotSignature signature = new HotSpotSignature(runtime(), getSignatureOf(index)); - if (opcode == Bytecodes.INVOKEDYNAMIC) { - HotSpotResolvedObjectType holder = HotSpotResolvedObjectTypeImpl.fromObjectClass(MethodHandle.class); - return new HotSpotMethodUnresolved(name, signature, holder); - } else { - final int klassIndex = getKlassRefIndexAt(index); - final Object type = compilerToVM().lookupKlassInPool(this, klassIndex); - JavaType holder = getJavaType(type); - return new HotSpotMethodUnresolved(name, signature, holder); - } - } - } - - @Override - public JavaType lookupType(int cpi, int opcode) { - final LookupTypeCacheElement elem = this.lastLookupType; - if (elem != null && elem.lastCpi == cpi) { - return elem.javaType; - } else { - final Object type = compilerToVM().lookupKlassInPool(this, cpi); - JavaType result = getJavaType(type); - if (result instanceof ResolvedJavaType) { - this.lastLookupType = new LookupTypeCacheElement(cpi, result); - } - return result; - } - } - - @Override - public JavaField lookupField(int cpi, int opcode) { - final int index = rawIndexToConstantPoolIndex(cpi, opcode); - final int nameAndTypeIndex = getNameAndTypeRefIndexAt(index); - final int nameIndex = getNameRefIndexAt(nameAndTypeIndex); - String name = lookupUtf8(nameIndex); - final int typeIndex = getSignatureRefIndexAt(nameAndTypeIndex); - String typeName = lookupUtf8(typeIndex); - JavaType type = runtime().lookupType(typeName, getHolder(), false); - - final int holderIndex = getKlassRefIndexAt(index); - JavaType holder = lookupType(holderIndex, opcode); - - if (holder instanceof HotSpotResolvedObjectTypeImpl) { - long[] info = new long[2]; - HotSpotResolvedObjectTypeImpl resolvedHolder; - try { - resolvedHolder = compilerToVM().resolveFieldInPool(this, index, (byte) opcode, info); - } catch (Throwable t) { - /* - * If there was an exception resolving the field we give up and return an unresolved - * field. - */ - return new HotSpotUnresolvedField(holder, name, type); - } - final int flags = (int) info[0]; - final long offset = info[1]; - HotSpotResolvedJavaField result = resolvedHolder.createField(name, type, offset, flags); - return result; - } else { - return new HotSpotUnresolvedField(holder, name, type); - } - } - - @Override - @SuppressWarnings("fallthrough") - public void loadReferencedType(int cpi, int opcode) { - int index; - switch (opcode) { - case Bytecodes.CHECKCAST: - case Bytecodes.INSTANCEOF: - case Bytecodes.NEW: - case Bytecodes.ANEWARRAY: - case Bytecodes.MULTIANEWARRAY: - case Bytecodes.LDC: - case Bytecodes.LDC_W: - case Bytecodes.LDC2_W: - index = cpi; - break; - case Bytecodes.INVOKEDYNAMIC: { - // invokedynamic instructions point to a constant pool cache entry. - index = decodeConstantPoolCacheIndex(cpi) + config().constantPoolCpCacheIndexTag; - index = compilerToVM().constantPoolRemapInstructionOperandFromCache(this, index); - break; - } - case Bytecodes.GETSTATIC: - case Bytecodes.PUTSTATIC: - case Bytecodes.GETFIELD: - case Bytecodes.PUTFIELD: - case Bytecodes.INVOKEVIRTUAL: - case Bytecodes.INVOKESPECIAL: - case Bytecodes.INVOKESTATIC: - case Bytecodes.INVOKEINTERFACE: { - // invoke and field instructions point to a constant pool cache entry. - index = rawIndexToConstantPoolIndex(cpi, opcode); - index = compilerToVM().constantPoolRemapInstructionOperandFromCache(this, index); - break; - } - default: - throw JVMCIError.shouldNotReachHere("Unexpected opcode " + opcode); - } - - final JVM_CONSTANT tag = getTagAt(index); - if (tag == null) { - assert getTagAt(index - 1) == JVM_CONSTANT.Double || getTagAt(index - 1) == JVM_CONSTANT.Long; - return; - } - switch (tag) { - case MethodRef: - case Fieldref: - case InterfaceMethodref: - index = getUncachedKlassRefIndexAt(index); - // Read the tag only once because it could change between multiple reads. - final JVM_CONSTANT klassTag = getTagAt(index); - assert klassTag == JVM_CONSTANT.Class || klassTag == JVM_CONSTANT.UnresolvedClass || klassTag == JVM_CONSTANT.UnresolvedClassInError : klassTag; - // fall through - case Class: - case UnresolvedClass: - case UnresolvedClassInError: - final HotSpotResolvedObjectTypeImpl type = compilerToVM().resolveTypeInPool(this, index); - Class klass = type.mirror(); - if (!klass.isPrimitive() && !klass.isArray()) { - UNSAFE.ensureClassInitialized(klass); - } - switch (tag) { - case MethodRef: - if (Bytecodes.isInvokeHandleAlias(opcode)) { - final int methodRefCacheIndex = rawIndexToConstantPoolIndex(cpi, opcode); - if (isInvokeHandle(methodRefCacheIndex, type)) { - compilerToVM().resolveInvokeHandleInPool(this, methodRefCacheIndex); - } - } - } - break; - case InvokeDynamic: - if (isInvokedynamicIndex(cpi)) { - compilerToVM().resolveInvokeDynamicInPool(this, cpi); - } - break; - default: - // nothing - break; - } - } - - private boolean isInvokeHandle(int methodRefCacheIndex, HotSpotResolvedObjectTypeImpl klass) { - assertTag(compilerToVM().constantPoolRemapInstructionOperandFromCache(this, methodRefCacheIndex), JVM_CONSTANT.MethodRef); - return ResolvedJavaMethod.isSignaturePolymorphic(klass, getNameOf(methodRefCacheIndex), runtime().getHostJVMCIBackend().getMetaAccess()); - } - - @Override - public String toString() { - HotSpotResolvedObjectType holder = getHolder(); - return "HotSpotConstantPool<" + holder.toJavaName() + ">"; - } -} --- /dev/null 2016-05-04 09:43:29.000000000 -1000 +++ new/src/jdk.vm.ci.hotspot/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java 2016-05-04 09:43:29.000000000 -1000 @@ -0,0 +1,714 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; +import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; + +import java.lang.invoke.MethodHandle; + +import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.meta.ConstantPool; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaField; +import jdk.vm.ci.meta.JavaMethod; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.Signature; + +/** + * Implementation of {@link ConstantPool} for HotSpot. + */ +final class HotSpotConstantPool implements ConstantPool, HotSpotProxified, MetaspaceWrapperObject { + + /** + * Subset of JVM bytecode opcodes used by {@link HotSpotConstantPool}. + */ + public static class Bytecodes { + public static final int LDC = 18; // 0x12 + public static final int LDC_W = 19; // 0x13 + public static final int LDC2_W = 20; // 0x14 + public static final int GETSTATIC = 178; // 0xB2 + public static final int PUTSTATIC = 179; // 0xB3 + public static final int GETFIELD = 180; // 0xB4 + public static final int PUTFIELD = 181; // 0xB5 + public static final int INVOKEVIRTUAL = 182; // 0xB6 + public static final int INVOKESPECIAL = 183; // 0xB7 + public static final int INVOKESTATIC = 184; // 0xB8 + public static final int INVOKEINTERFACE = 185; // 0xB9 + public static final int INVOKEDYNAMIC = 186; // 0xBA + public static final int NEW = 187; // 0xBB + public static final int NEWARRAY = 188; // 0xBC + public static final int ANEWARRAY = 189; // 0xBD + public static final int CHECKCAST = 192; // 0xC0 + public static final int INSTANCEOF = 193; // 0xC1 + public static final int MULTIANEWARRAY = 197; // 0xC5 + + static boolean isInvoke(int opcode) { + switch (opcode) { + case INVOKEVIRTUAL: + case INVOKESPECIAL: + case INVOKESTATIC: + case INVOKEINTERFACE: + case INVOKEDYNAMIC: + return true; + default: + return false; + } + } + + /** + * See: {@code Rewriter::maybe_rewrite_invokehandle}. + */ + static boolean isInvokeHandleAlias(int opcode) { + switch (opcode) { + case INVOKEVIRTUAL: + case INVOKESPECIAL: + return true; + default: + return false; + } + } + } + + /** + * Enum of all {@code JVM_CONSTANT} constants used in the VM. This includes the public and + * internal ones. + */ + private enum JVM_CONSTANT { + // @formatter:off + Utf8(config().jvmConstantUtf8), + Integer(config().jvmConstantInteger), + Long(config().jvmConstantLong), + Float(config().jvmConstantFloat), + Double(config().jvmConstantDouble), + Class(config().jvmConstantClass), + UnresolvedClass(config().jvmConstantUnresolvedClass), + UnresolvedClassInError(config().jvmConstantUnresolvedClassInError), + String(config().jvmConstantString), + Fieldref(config().jvmConstantFieldref), + MethodRef(config().jvmConstantMethodref), + InterfaceMethodref(config().jvmConstantInterfaceMethodref), + NameAndType(config().jvmConstantNameAndType), + MethodHandle(config().jvmConstantMethodHandle), + MethodHandleInError(config().jvmConstantMethodHandleInError), + MethodType(config().jvmConstantMethodType), + MethodTypeInError(config().jvmConstantMethodTypeInError), + InvokeDynamic(config().jvmConstantInvokeDynamic); + // @formatter:on + + private final int tag; + + private static final int ExternalMax = config().jvmConstantExternalMax; + private static final int InternalMin = config().jvmConstantInternalMin; + private static final int InternalMax = config().jvmConstantInternalMax; + + JVM_CONSTANT(int tag) { + this.tag = tag; + } + + /** + * Maps JVM_CONSTANT tags to {@link JVM_CONSTANT} values. Using a separate class for lazy + * initialization. + */ + static class TagValueMap { + private static final JVM_CONSTANT[] table = new JVM_CONSTANT[ExternalMax + 1 + (InternalMax - InternalMin) + 1]; + + static { + assert InternalMin > ExternalMax; + for (JVM_CONSTANT e : values()) { + table[indexOf(e.tag)] = e; + } + } + + private static int indexOf(int tag) { + if (tag >= InternalMin) { + return tag - InternalMin + ExternalMax + 1; + } else { + assert tag <= ExternalMax; + } + return tag; + } + + static JVM_CONSTANT get(int tag) { + JVM_CONSTANT res = table[indexOf(tag)]; + if (res != null) { + return res; + } + throw new JVMCIError("Unknown JVM_CONSTANT tag %s", tag); + } + } + + public static JVM_CONSTANT getEnum(int tag) { + return TagValueMap.get(tag); + } + } + + private static class LookupTypeCacheElement { + int lastCpi = Integer.MIN_VALUE; + JavaType javaType; + + LookupTypeCacheElement(int lastCpi, JavaType javaType) { + super(); + this.lastCpi = lastCpi; + this.javaType = javaType; + } + } + + /** + * Reference to the C++ ConstantPool object. + */ + private final long metaspaceConstantPool; + private volatile LookupTypeCacheElement lastLookupType; + + /** + * Gets the JVMCI mirror from a HotSpot constant pool.The VM is responsible for ensuring that + * the ConstantPool is kept alive for the duration of this call and the + * {@link HotSpotJVMCIMetaAccessContext} keeps it alive after that. + * + * Called from the VM. + * + * @param metaspaceConstantPool a metaspace ConstantPool object + * @return the {@link HotSpotConstantPool} corresponding to {@code metaspaceConstantPool} + */ + @SuppressWarnings("unused") + private static HotSpotConstantPool fromMetaspace(long metaspaceConstantPool) { + return new HotSpotConstantPool(metaspaceConstantPool); + } + + private HotSpotConstantPool(long metaspaceConstantPool) { + this.metaspaceConstantPool = metaspaceConstantPool; + } + + /** + * Gets the holder for this constant pool as {@link HotSpotResolvedObjectTypeImpl}. + * + * @return holder for this constant pool + */ + private HotSpotResolvedObjectType getHolder() { + return compilerToVM().getResolvedJavaType(this, config().constantPoolHolderOffset, false); + } + + /** + * Converts a raw index from the bytecodes to a constant pool index by adding a + * {@link HotSpotVMConfig#constantPoolCpCacheIndexTag constant}. + * + * @param rawIndex index from the bytecode + * @param opcode bytecode to convert the index for + * @return constant pool index + */ + private static int rawIndexToConstantPoolIndex(int rawIndex, int opcode) { + int index; + if (opcode == Bytecodes.INVOKEDYNAMIC) { + index = rawIndex; + // See: ConstantPool::is_invokedynamic_index + assert index < 0 : "not an invokedynamic constant pool index " + index; + } else { + assert opcode == Bytecodes.GETFIELD || opcode == Bytecodes.PUTFIELD || opcode == Bytecodes.GETSTATIC || opcode == Bytecodes.PUTSTATIC || opcode == Bytecodes.INVOKEINTERFACE || + opcode == Bytecodes.INVOKEVIRTUAL || opcode == Bytecodes.INVOKESPECIAL || opcode == Bytecodes.INVOKESTATIC : "unexpected invoke opcode " + opcode; + index = rawIndex + config().constantPoolCpCacheIndexTag; + } + return index; + } + + /** + * Decode a constant pool cache index to a constant pool index. + * + * See {@code ConstantPool::decode_cpcache_index}. + * + * @param index constant pool cache index + * @return decoded index + */ + private static int decodeConstantPoolCacheIndex(int index) { + if (isInvokedynamicIndex(index)) { + return decodeInvokedynamicIndex(index); + } else { + return index - config().constantPoolCpCacheIndexTag; + } + } + + /** + * See {@code ConstantPool::is_invokedynamic_index}. + */ + private static boolean isInvokedynamicIndex(int index) { + return index < 0; + } + + /** + * See {@code ConstantPool::decode_invokedynamic_index}. + */ + private static int decodeInvokedynamicIndex(int i) { + assert isInvokedynamicIndex(i) : i; + return ~i; + } + + long getMetaspaceConstantPool() { + return metaspaceConstantPool; + } + + public long getMetaspacePointer() { + return getMetaspaceConstantPool(); + } + + /** + * Gets the constant pool tag at index {@code index}. + * + * @param index constant pool index + * @return constant pool tag + */ + private JVM_CONSTANT getTagAt(int index) { + assertBounds(index); + HotSpotVMConfig config = config(); + final long metaspaceConstantPoolTags = UNSAFE.getAddress(getMetaspaceConstantPool() + config.constantPoolTagsOffset); + final int tag = UNSAFE.getByteVolatile(null, metaspaceConstantPoolTags + config.arrayU1DataOffset + index); + if (tag == 0) { + return null; + } + return JVM_CONSTANT.getEnum(tag); + } + + /** + * Gets the constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return constant pool entry + */ + private long getEntryAt(int index) { + assertBounds(index); + return UNSAFE.getAddress(getMetaspaceConstantPool() + config().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the integer constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return integer constant pool entry at index + */ + private int getIntAt(int index) { + assertTag(index, JVM_CONSTANT.Integer); + return UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the long constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return long constant pool entry + */ + private long getLongAt(int index) { + assertTag(index, JVM_CONSTANT.Long); + return UNSAFE.getLong(getMetaspaceConstantPool() + config().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the float constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return float constant pool entry + */ + private float getFloatAt(int index) { + assertTag(index, JVM_CONSTANT.Float); + return UNSAFE.getFloat(getMetaspaceConstantPool() + config().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the double constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return float constant pool entry + */ + private double getDoubleAt(int index) { + assertTag(index, JVM_CONSTANT.Double); + return UNSAFE.getDouble(getMetaspaceConstantPool() + config().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the {@code JVM_CONSTANT_NameAndType} constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return {@code JVM_CONSTANT_NameAndType} constant pool entry + */ + private int getNameAndTypeAt(int index) { + assertTag(index, JVM_CONSTANT.NameAndType); + return UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the {@code JVM_CONSTANT_NameAndType} reference index constant pool entry at index + * {@code index}. + * + * @param index constant pool index + * @return {@code JVM_CONSTANT_NameAndType} reference constant pool entry + */ + private int getNameAndTypeRefIndexAt(int index) { + return compilerToVM().lookupNameAndTypeRefIndexInPool(this, index); + } + + /** + * Gets the name of a {@code JVM_CONSTANT_NameAndType} constant pool entry referenced by another + * entry denoted by {@code which}. + * + * @param which constant pool index or constant pool cache index + * @return name as {@link String} + */ + private String getNameOf(int which) { + return compilerToVM().lookupNameInPool(this, which); + } + + /** + * Gets the name reference index of a {@code JVM_CONSTANT_NameAndType} constant pool entry at + * index {@code index}. + * + * @param index constant pool index + * @return name reference index + */ + private int getNameRefIndexAt(int index) { + final int refIndex = getNameAndTypeAt(index); + // name ref index is in the low 16-bits. + return refIndex & 0xFFFF; + } + + /** + * Gets the signature of a {@code JVM_CONSTANT_NameAndType} constant pool entry referenced by + * another entry denoted by {@code which}. + * + * @param which constant pool index or constant pool cache index + * @return signature as {@link String} + */ + private String getSignatureOf(int which) { + return compilerToVM().lookupSignatureInPool(this, which); + } + + /** + * Gets the signature reference index of a {@code JVM_CONSTANT_NameAndType} constant pool entry + * at index {@code index}. + * + * @param index constant pool index + * @return signature reference index + */ + private int getSignatureRefIndexAt(int index) { + final int refIndex = getNameAndTypeAt(index); + // signature ref index is in the high 16-bits. + return refIndex >>> 16; + } + + /** + * Gets the klass reference index constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return klass reference index + */ + private int getKlassRefIndexAt(int index) { + return compilerToVM().lookupKlassRefIndexInPool(this, index); + } + + /** + * Gets the uncached klass reference index constant pool entry at index {@code index}. See: + * {@code ConstantPool::uncached_klass_ref_index_at}. + * + * @param index constant pool index + * @return klass reference index + */ + private int getUncachedKlassRefIndexAt(int index) { + assertTagIsFieldOrMethod(index); + final int refIndex = UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + // klass ref index is in the low 16-bits. + return refIndex & 0xFFFF; + } + + /** + * Asserts that the constant pool index {@code index} is in the bounds of the constant pool. + * + * @param index constant pool index + */ + private void assertBounds(int index) { + assert 0 <= index && index < length() : "index " + index + " not between 0 and " + length(); + } + + /** + * Asserts that the constant pool tag at index {@code index} is equal to {@code tag}. + * + * @param index constant pool index + * @param tag expected tag + */ + private void assertTag(int index, JVM_CONSTANT tag) { + final JVM_CONSTANT tagAt = getTagAt(index); + assert tagAt == tag : "constant pool tag at index " + index + " is " + tagAt + " but expected " + tag; + } + + /** + * Asserts that the constant pool tag at index {@code index} is a {@link JVM_CONSTANT#Fieldref}, + * or a {@link JVM_CONSTANT#MethodRef}, or a {@link JVM_CONSTANT#InterfaceMethodref}. + * + * @param index constant pool index + */ + private void assertTagIsFieldOrMethod(int index) { + final JVM_CONSTANT tagAt = getTagAt(index); + assert tagAt == JVM_CONSTANT.Fieldref || tagAt == JVM_CONSTANT.MethodRef || tagAt == JVM_CONSTANT.InterfaceMethodref : tagAt; + } + + @Override + public int length() { + return UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolLengthOffset); + } + + @Override + public Object lookupConstant(int cpi) { + assert cpi != 0; + final JVM_CONSTANT tag = getTagAt(cpi); + switch (tag) { + case Integer: + return JavaConstant.forInt(getIntAt(cpi)); + case Long: + return JavaConstant.forLong(getLongAt(cpi)); + case Float: + return JavaConstant.forFloat(getFloatAt(cpi)); + case Double: + return JavaConstant.forDouble(getDoubleAt(cpi)); + case Class: + case UnresolvedClass: + case UnresolvedClassInError: + final int opcode = -1; // opcode is not used + return lookupType(cpi, opcode); + case String: + /* + * Normally, we would expect a String here, but anonymous classes can have + * "pseudo strings" (arbitrary live objects) patched into a String entry. Such + * entries do not have a symbol in the constant pool slot. + */ + Object string = compilerToVM().resolvePossiblyCachedConstantInPool(this, cpi); + return HotSpotObjectConstantImpl.forObject(string); + case MethodHandle: + case MethodHandleInError: + case MethodType: + case MethodTypeInError: + Object obj = compilerToVM().resolveConstantInPool(this, cpi); + return HotSpotObjectConstantImpl.forObject(obj); + default: + throw new JVMCIError("Unknown constant pool tag %s", tag); + } + } + + @Override + public String lookupUtf8(int cpi) { + assertTag(cpi, JVM_CONSTANT.Utf8); + return compilerToVM().getSymbol(getEntryAt(cpi)); + } + + @Override + public Signature lookupSignature(int cpi) { + return new HotSpotSignature(runtime(), lookupUtf8(cpi)); + } + + @Override + public JavaConstant lookupAppendix(int cpi, int opcode) { + assert Bytecodes.isInvoke(opcode); + final int index = rawIndexToConstantPoolIndex(cpi, opcode); + Object appendix = compilerToVM().lookupAppendixInPool(this, index); + if (appendix == null) { + return null; + } else { + return HotSpotObjectConstantImpl.forObject(appendix); + } + } + + /** + * Gets a {@link JavaType} corresponding a given resolved or unresolved type. + * + * @param type either a ResolvedJavaType or a String naming a unresolved type. + */ + private static JavaType getJavaType(final Object type) { + if (type instanceof String) { + String name = (String) type; + return HotSpotUnresolvedJavaType.create(runtime(), "L" + name + ";"); + } else { + return (JavaType) type; + } + } + + @Override + public JavaMethod lookupMethod(int cpi, int opcode) { + final int index = rawIndexToConstantPoolIndex(cpi, opcode); + final HotSpotResolvedJavaMethod method = compilerToVM().lookupMethodInPool(this, index, (byte) opcode); + if (method != null) { + return method; + } else { + // Get the method's name and signature. + String name = getNameOf(index); + HotSpotSignature signature = new HotSpotSignature(runtime(), getSignatureOf(index)); + if (opcode == Bytecodes.INVOKEDYNAMIC) { + HotSpotResolvedObjectType holder = HotSpotResolvedObjectTypeImpl.fromObjectClass(MethodHandle.class); + return new HotSpotMethodUnresolved(name, signature, holder); + } else { + final int klassIndex = getKlassRefIndexAt(index); + final Object type = compilerToVM().lookupKlassInPool(this, klassIndex); + JavaType holder = getJavaType(type); + return new HotSpotMethodUnresolved(name, signature, holder); + } + } + } + + @Override + public JavaType lookupType(int cpi, int opcode) { + final LookupTypeCacheElement elem = this.lastLookupType; + if (elem != null && elem.lastCpi == cpi) { + return elem.javaType; + } else { + final Object type = compilerToVM().lookupKlassInPool(this, cpi); + JavaType result = getJavaType(type); + if (result instanceof ResolvedJavaType) { + this.lastLookupType = new LookupTypeCacheElement(cpi, result); + } + return result; + } + } + + @Override + public JavaField lookupField(int cpi, int opcode) { + final int index = rawIndexToConstantPoolIndex(cpi, opcode); + final int nameAndTypeIndex = getNameAndTypeRefIndexAt(index); + final int nameIndex = getNameRefIndexAt(nameAndTypeIndex); + String name = lookupUtf8(nameIndex); + final int typeIndex = getSignatureRefIndexAt(nameAndTypeIndex); + String typeName = lookupUtf8(typeIndex); + JavaType type = runtime().lookupType(typeName, getHolder(), false); + + final int holderIndex = getKlassRefIndexAt(index); + JavaType holder = lookupType(holderIndex, opcode); + + if (holder instanceof HotSpotResolvedObjectTypeImpl) { + long[] info = new long[2]; + HotSpotResolvedObjectTypeImpl resolvedHolder; + try { + resolvedHolder = compilerToVM().resolveFieldInPool(this, index, (byte) opcode, info); + } catch (Throwable t) { + /* + * If there was an exception resolving the field we give up and return an unresolved + * field. + */ + return new HotSpotUnresolvedField(holder, name, type); + } + final int flags = (int) info[0]; + final long offset = info[1]; + HotSpotResolvedJavaField result = resolvedHolder.createField(name, type, offset, flags); + return result; + } else { + return new HotSpotUnresolvedField(holder, name, type); + } + } + + @Override + @SuppressWarnings("fallthrough") + public void loadReferencedType(int cpi, int opcode) { + int index; + switch (opcode) { + case Bytecodes.CHECKCAST: + case Bytecodes.INSTANCEOF: + case Bytecodes.NEW: + case Bytecodes.ANEWARRAY: + case Bytecodes.MULTIANEWARRAY: + case Bytecodes.LDC: + case Bytecodes.LDC_W: + case Bytecodes.LDC2_W: + index = cpi; + break; + case Bytecodes.INVOKEDYNAMIC: { + // invokedynamic instructions point to a constant pool cache entry. + index = decodeConstantPoolCacheIndex(cpi) + config().constantPoolCpCacheIndexTag; + index = compilerToVM().constantPoolRemapInstructionOperandFromCache(this, index); + break; + } + case Bytecodes.GETSTATIC: + case Bytecodes.PUTSTATIC: + case Bytecodes.GETFIELD: + case Bytecodes.PUTFIELD: + case Bytecodes.INVOKEVIRTUAL: + case Bytecodes.INVOKESPECIAL: + case Bytecodes.INVOKESTATIC: + case Bytecodes.INVOKEINTERFACE: { + // invoke and field instructions point to a constant pool cache entry. + index = rawIndexToConstantPoolIndex(cpi, opcode); + index = compilerToVM().constantPoolRemapInstructionOperandFromCache(this, index); + break; + } + default: + throw JVMCIError.shouldNotReachHere("Unexpected opcode " + opcode); + } + + final JVM_CONSTANT tag = getTagAt(index); + if (tag == null) { + assert getTagAt(index - 1) == JVM_CONSTANT.Double || getTagAt(index - 1) == JVM_CONSTANT.Long; + return; + } + switch (tag) { + case MethodRef: + case Fieldref: + case InterfaceMethodref: + index = getUncachedKlassRefIndexAt(index); + // Read the tag only once because it could change between multiple reads. + final JVM_CONSTANT klassTag = getTagAt(index); + assert klassTag == JVM_CONSTANT.Class || klassTag == JVM_CONSTANT.UnresolvedClass || klassTag == JVM_CONSTANT.UnresolvedClassInError : klassTag; + // fall through + case Class: + case UnresolvedClass: + case UnresolvedClassInError: + final HotSpotResolvedObjectTypeImpl type = compilerToVM().resolveTypeInPool(this, index); + Class klass = type.mirror(); + if (!klass.isPrimitive() && !klass.isArray()) { + UNSAFE.ensureClassInitialized(klass); + } + switch (tag) { + case MethodRef: + if (Bytecodes.isInvokeHandleAlias(opcode)) { + final int methodRefCacheIndex = rawIndexToConstantPoolIndex(cpi, opcode); + if (isInvokeHandle(methodRefCacheIndex, type)) { + compilerToVM().resolveInvokeHandleInPool(this, methodRefCacheIndex); + } + } + } + break; + case InvokeDynamic: + if (isInvokedynamicIndex(cpi)) { + compilerToVM().resolveInvokeDynamicInPool(this, cpi); + } + break; + default: + // nothing + break; + } + } + + private boolean isInvokeHandle(int methodRefCacheIndex, HotSpotResolvedObjectTypeImpl klass) { + assertTag(compilerToVM().constantPoolRemapInstructionOperandFromCache(this, methodRefCacheIndex), JVM_CONSTANT.MethodRef); + return ResolvedJavaMethod.isSignaturePolymorphic(klass, getNameOf(methodRefCacheIndex), runtime().getHostJVMCIBackend().getMetaAccess()); + } + + @Override + public String toString() { + HotSpotResolvedObjectType holder = getHolder(); + return "HotSpotConstantPool<" + holder.toJavaName() + ">"; + } +}