8283839: [JVMCI] add support for querying indy bootstrap method target and arguments

Reviewed-by: psandoz, kvn
This commit is contained in:
Doug Simon 2022-04-20 20:25:00 +00:00
parent 81a8e2f8b3
commit 8543aaa7eb
13 changed files with 328 additions and 36 deletions

View File

@ -336,6 +336,8 @@
template(findMethodHandleType_signature, "(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/invoke/MethodType;") \
template(invokeExact_name, "invokeExact") \
template(linkMethodHandleConstant_name, "linkMethodHandleConstant") \
template(asFixedArity_name, "asFixedArity") \
template(asFixedArity_signature, "()Ljava/lang/invoke/MethodHandle;") \
template(linkMethodHandleConstant_signature, "(Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/invoke/MethodHandle;") \
template(linkMethod_name, "linkMethod") \
template(linkMethod_signature, "(Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/String;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/invoke/MemberName;") \

View File

@ -584,7 +584,7 @@ C2V_VMENTRY_NULL(jobject, lookupClass, (JNIEnv* env, jobject, jclass mirror))
}
JVMCIObject result = JVMCIENV->get_jvmci_type(klass, JVMCI_CHECK_NULL);
return JVMCIENV->get_jobject(result);
}
C2V_END
C2V_VMENTRY_NULL(jobject, resolvePossiblyCachedConstantInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
constantPoolHandle cp(THREAD, JVMCIENV->asConstantPool(jvmci_constant_pool));
@ -625,6 +625,77 @@ C2V_VMENTRY_NULL(jobject, resolvePossiblyCachedConstantInPool, (JNIEnv* env, job
return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(obj));
C2V_END
C2V_VMENTRY_NULL(jobjectArray, resolveBootstrapMethod, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
constantPoolHandle cp(THREAD, JVMCIENV->asConstantPool(jvmci_constant_pool));
constantTag tag = cp->tag_at(index);
bool is_indy = tag.is_invoke_dynamic();
bool is_condy = tag.is_dynamic_constant();
if (!(is_condy || is_indy)) {
JVMCI_THROW_MSG_0(IllegalArgumentException, err_msg("Unexpected constant pool tag at index %d: %d", index, tag.value()));
}
// Resolve the bootstrap specifier, its name, type, and static arguments
BootstrapInfo bootstrap_specifier(cp, index);
Handle bsm = bootstrap_specifier.resolve_bsm(CHECK_NULL);
// call java.lang.invoke.MethodHandle::asFixedArity() -> MethodHandle
// to get a DirectMethodHandle from which we can then extract a Method*
JavaValue result(T_OBJECT);
JavaCalls::call_virtual(&result,
bsm,
vmClasses::MethodHandle_klass(),
vmSymbols::asFixedArity_name(),
vmSymbols::asFixedArity_signature(),
CHECK_NULL);
bsm = Handle(THREAD, result.get_oop());
// Check assumption about getting a DirectMethodHandle
if (!java_lang_invoke_DirectMethodHandle::is_instance(bsm())) {
JVMCI_THROW_MSG_NULL(InternalError, err_msg("Unexpected MethodHandle subclass: %s", bsm->klass()->external_name()));
}
// Create return array describing the bootstrap method invocation (BSMI)
JVMCIObjectArray bsmi = JVMCIENV->new_Object_array(4, JVMCI_CHECK_NULL);
// Extract Method* and wrap it in a ResolvedJavaMethod
Handle member = Handle(THREAD, java_lang_invoke_DirectMethodHandle::member(bsm()));
JVMCIObject bsmi_method = JVMCIENV->get_jvmci_method(methodHandle(THREAD, java_lang_invoke_MemberName::vmtarget(member())), JVMCI_CHECK_NULL);
JVMCIENV->put_object_at(bsmi, 0, bsmi_method);
JVMCIObject bsmi_name = JVMCIENV->create_string(bootstrap_specifier.name(), JVMCI_CHECK_NULL);
JVMCIENV->put_object_at(bsmi, 1, bsmi_name);
Handle type_arg = bootstrap_specifier.type_arg();
JVMCIObject bsmi_type = JVMCIENV->get_object_constant(type_arg());
JVMCIENV->put_object_at(bsmi, 2, bsmi_type);
Handle arg_values = bootstrap_specifier.arg_values();
if (arg_values.not_null()) {
if (!arg_values->is_array()) {
JVMCIENV->put_object_at(bsmi, 3, JVMCIENV->get_object_constant(arg_values()));
} else if (arg_values->is_objArray()) {
objArrayHandle args_array = objArrayHandle(THREAD, (objArrayOop) arg_values());
int len = args_array->length();
JVMCIObjectArray arguments = JVMCIENV->new_JavaConstant_array(len, JVMCI_CHECK_NULL);
JVMCIENV->put_object_at(bsmi, 3, arguments);
for (int i = 0; i < len; i++) {
oop x = args_array->obj_at(i);
if (x != nullptr) {
JVMCIENV->put_object_at(arguments, i, JVMCIENV->get_object_constant(x));
} else {
JVMCIENV->put_object_at(arguments, i, JVMCIENV->get_JavaConstant_NULL_POINTER());
}
}
} else if (arg_values->is_typeArray()) {
typeArrayHandle bsci = typeArrayHandle(THREAD, (typeArrayOop) arg_values());
JVMCIPrimitiveArray arguments = JVMCIENV->new_intArray(bsci->length(), JVMCI_CHECK_NULL);
JVMCIENV->put_object_at(bsmi, 3, arguments);
for (int i = 0; i < bsci->length(); i++) {
JVMCIENV->put_int_at(arguments, i, bsci->int_at(i));
}
}
}
return JVMCIENV->get_jobjectArray(bsmi);
C2V_END
C2V_VMENTRY_0(jint, lookupNameAndTypeRefIndexInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
constantPoolHandle cp(THREAD, JVMCIENV->asConstantPool(jvmci_constant_pool));
return cp->name_and_type_ref_index_at(index);
@ -2717,6 +2788,7 @@ JNINativeMethod CompilerToVM::methods[] = {
{CC "lookupAppendixInPool", CC "(" HS_CONSTANT_POOL "I)" OBJECTCONSTANT, FN_PTR(lookupAppendixInPool)},
{CC "lookupMethodInPool", CC "(" HS_CONSTANT_POOL "IB)" HS_RESOLVED_METHOD, FN_PTR(lookupMethodInPool)},
{CC "constantPoolRemapInstructionOperandFromCache", CC "(" HS_CONSTANT_POOL "I)I", FN_PTR(constantPoolRemapInstructionOperandFromCache)},
{CC "resolveBootstrapMethod", CC "(" HS_CONSTANT_POOL "I)[" OBJECT, FN_PTR(resolveBootstrapMethod)},
{CC "resolvePossiblyCachedConstantInPool", CC "(" HS_CONSTANT_POOL "I)" JAVACONSTANT, FN_PTR(resolvePossiblyCachedConstantInPool)},
{CC "resolveTypeInPool", CC "(" HS_CONSTANT_POOL "I)" HS_RESOLVED_KLASS, FN_PTR(resolveTypeInPool)},
{CC "resolveFieldInPool", CC "(" HS_CONSTANT_POOL "I" HS_RESOLVED_METHOD "B[I)" HS_RESOLVED_KLASS, FN_PTR(resolveFieldInPool)},

View File

@ -283,8 +283,6 @@ final class CompilerToVM {
*/
native HotSpotResolvedJavaMethodImpl lookupMethodInPool(HotSpotConstantPool constantPool, int cpi, byte opcode);
// TODO resolving JVM_CONSTANT_Dynamic
/**
* Ensures that the type referenced by the specified {@code JVM_CONSTANT_InvokeDynamic} entry at
* index {@code cpi} in {@code constantPool} is loaded and initialized.
@ -295,11 +293,33 @@ final class CompilerToVM {
native void resolveInvokeDynamicInPool(HotSpotConstantPool constantPool, int cpi);
/**
* If {@code cpi} denotes an entry representing a
* <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.9">signature
* polymorphic</a> method, this method ensures that the type referenced by the entry is loaded
* and initialized. It {@code cpi} does not denote a signature polymorphic method, this method
* does nothing.
* Resolves the details for invoking the bootstrap method associated with the
* {@code CONSTANT_Dynamic_info} or @{code CONSTANT_InvokeDynamic_info} entry at {@code cpi} in
* {@code constant pool}.
*
* The return value encodes the details in an object array that is described by the pseudo Java
* object {@code info} below:
*
* <pre>
* bsm_invocation = [
* ResolvedJavaMethod[] method,
* String name,
* Object type, // JavaConstant: reference to Class (condy) or MethodType (indy)
* Object staticArguments, // null: no static arguments
* // JavaConstant: single static argument
* // JavaConstant[]: multiple static arguments
* // int[]: static arguments to be resolved via BootstrapCallInfo
* ]
* </pre>
*
* @return bootstrap method invocation details as encoded above
*/
native Object[] resolveBootstrapMethod(HotSpotConstantPool constantPool, int cpi);
/**
* If {@code cpi} denotes an entry representing a signature polymorphic method ({@jvms 2.9}),
* this method ensures that the type referenced by the entry is loaded and initialized. It
* {@code cpi} does not denote a signature polymorphic method, this method does nothing.
*/
native void resolveInvokeHandleInPool(HotSpotConstantPool constantPool, int cpi);

View File

@ -27,6 +27,11 @@ 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.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import jdk.vm.ci.common.JVMCIError;
import jdk.vm.ci.common.NativeImageReinitialize;
import jdk.vm.ci.meta.ConstantPool;
@ -518,6 +523,93 @@ public final class HotSpotConstantPool implements ConstantPool, MetaspaceHandleO
return UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolFlagsOffset);
}
static class BootstrapMethodInvocationImpl implements BootstrapMethodInvocation {
private final boolean indy;
private final ResolvedJavaMethod method;
private final String name;
private final JavaConstant type;
private final List<JavaConstant> staticArguments;
BootstrapMethodInvocationImpl(boolean indy, ResolvedJavaMethod method, String name, JavaConstant type, List<JavaConstant> staticArguments) {
this.indy = indy;
this.method = method;
this.name = name;
this.type = type;
this.staticArguments = staticArguments;
}
@Override
public ResolvedJavaMethod getMethod() {
return method;
}
@Override
public String getName() {
return name;
}
@Override
public boolean isInvokeDynamic() {
return indy;
}
@Override
public JavaConstant getType() {
return type;
}
@Override
public List<JavaConstant> getStaticArguments() {
return staticArguments;
}
@Override
public String toString() {
String static_args = staticArguments.stream().map(BootstrapMethodInvocationImpl::argumentAsString).collect(Collectors.joining(", ", "[", "]"));
return "BootstrapMethod[" + (indy ? "indy" : "condy") +
", method:" + method.format("%H.%n(%p)") +
", name: " + name +
", type: " + type.toValueString() +
", static arguments:" + static_args;
}
private static String argumentAsString(JavaConstant arg) {
String type = arg.getJavaKind().getJavaName();
String value = arg.toValueString();
return type + ":" + value;
}
}
@Override
public BootstrapMethodInvocation lookupBootstrapMethodInvocation(int rawCpi, int opcode) {
int cpi = opcode == -1 ? rawCpi : rawIndexToConstantPoolIndex(rawCpi, opcode);
final JvmConstant tag = getTagAt(cpi);
switch (tag.name) {
case "InvokeDynamic":
case "Dynamic":
Object[] bsmi = compilerToVM().resolveBootstrapMethod(this, cpi);
ResolvedJavaMethod method = (ResolvedJavaMethod) bsmi[0];
String name = (String) bsmi[1];
JavaConstant type = (JavaConstant) bsmi[2];
Object staticArguments = bsmi[3];
List<JavaConstant> staticArgumentsList;
if (staticArguments == null) {
staticArgumentsList = List.of();
} else if (staticArguments instanceof JavaConstant) {
staticArgumentsList = List.of((JavaConstant) staticArguments);
} else if (staticArguments instanceof JavaConstant[]) {
staticArgumentsList = List.of((JavaConstant[]) staticArguments);
} else {
int[] bsciArgs = (int[]) staticArguments;
String message = String.format("Resolving bootstrap static arguments for %s using BootstrapCallInfo %s not supported", method.format("%H.%n(%p)"), Arrays.toString(bsciArgs));
throw new IllegalArgumentException(message);
}
return new BootstrapMethodInvocationImpl(tag.name.equals("InvokeDynamic"), method, name, type, staticArgumentsList);
default:
return null;
}
}
@Override
public Object lookupConstant(int cpi) {
assert cpi != 0;

View File

@ -30,9 +30,9 @@ import jdk.vm.ci.meta.Signature;
public final class VMIntrinsicMethod {
/**
* The name of the class declaring the intrinsified method. The name is in
* <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.2.1">class
* file format</a> (e.g., {@code "java/lang/Thread"} instead of {@code "java.lang.Thread"}).
* The name of the class declaring the intrinsified method. The name is in class file format
* (see JVMS {@jvms 4.2.1}). For example, {@code "java/lang/Thread"} instead of
* {@code "java.lang.Thread"}.
*/
public final String declaringClass;

View File

@ -22,6 +22,9 @@
*/
package jdk.vm.ci.meta;
import java.lang.invoke.MethodType;
import java.util.List;
/**
* Represents the runtime representation of the constant pool that is used by the compiler when
* parsing bytecode. Provides methods to look up a constant pool entry without performing
@ -84,6 +87,65 @@ public interface ConstantPool {
*/
JavaMethod lookupMethod(int cpi, int opcode);
/**
* The details for invoking a bootstrap method associated with a {@code CONSTANT_Dynamic_info}
* or {@code CONSTANT_InvokeDynamic_info} pool entry .
*
* @jvms 4.4.10 The {@code CONSTANT_Dynamic_info} and {@code CONSTANT_InvokeDynamic_info}
* Structures
* @jvms 4.7.23 The {@code BootstrapMethods} Attribute
*/
interface BootstrapMethodInvocation {
/**
* Gets the bootstrap method that will be invoked.
*/
ResolvedJavaMethod getMethod();
/**
* Returns {@code true} if this bootstrap method invocation is for a
* {@code CONSTANT_InvokeDynamic_info} pool entry, {@code false} if it is for a
* {@code CONSTANT_Dynamic_info} entry.
*/
boolean isInvokeDynamic();
/**
* Gets the name of the pool entry.
*/
String getName();
/**
* Returns a reference to the {@link MethodType} ({@code this.isInvokeDynamic() == true}) or
* {@link Class} ({@code this.isInvokeDynamic() == false}) resolved for the descriptor of
* the pool entry.
*/
JavaConstant getType();
/**
* Gets the static arguments with which the bootstrap method will be invoked.
*
* @jvms 5.4.3.6
*/
List<JavaConstant> getStaticArguments();
}
/**
* Gets the details for invoking a bootstrap method associated with the
* {@code CONSTANT_Dynamic_info} or {@code CONSTANT_InvokeDynamic_info} pool entry {@code cpi}
* in the constant pool.
*
* @param cpi a constant pool index
* @param opcode the opcode of the instruction that has {@code cpi} as an operand or -1 if
* {@code cpi} was not decoded from an instruction stream
* @return the bootstrap method invocation details or {@code null} if the entry at {@code cpi}
* is not a {@code CONSTANT_Dynamic_info} or @{code CONSTANT_InvokeDynamic_info}
* @throws IllegalArgumentException if the bootstrap method invocation makes use of
* {@code java.lang.invoke.BootstrapCallInfo}
* @jvms 4.7.23 The {@code BootstrapMethods} Attribute
*/
default BootstrapMethodInvocation lookupBootstrapMethodInvocation(int cpi, int opcode) {
throw new UnsupportedOperationException();
}
/**
* Looks up a reference to a type. If {@code opcode} is non-negative, then resolution checks
* specific to the bytecode it denotes are performed if the type is already resolved. Should any

View File

@ -101,10 +101,9 @@ public enum JavaKind {
/**
* Returns the name of the kind as a single upper case character. For the void and primitive
* kinds, this is the <i>FieldType</i> term in
* <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.2-200">
* table 4.3-A</a> of the JVM Specification. For {@link #Object}, the character {@code 'A'} is
* returned and for {@link #Illegal}, {@code '-'} is returned.
* kinds, this is the <i>FieldType</i> term in table 4.3-A of JVMS {@jvms 4.3.2}. For
* {@link #Object}, the character {@code 'A'} is returned and for {@link #Illegal}, {@code '-'}
* is returned.
*/
public char getTypeChar() {
return typeChar;

View File

@ -25,7 +25,7 @@ package jdk.vm.ci.meta;
/**
* Maps bytecode indexes to source line numbers.
*
* @see "https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.12"
* @jvms 4.7.12
*/
public class LineNumberTable {

View File

@ -28,7 +28,7 @@ import java.util.List;
/**
* Describes the {@link Local}s for a Java method.
*
* @see "https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.13"
* @jvms 4.7.13
*/
public class LocalVariableTable {

View File

@ -83,9 +83,7 @@ public interface MetaAccessProvider {
long getMemorySize(JavaConstant constant);
/**
* Parses a
* <a href="http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.3">method
* descriptor</a> into a {@link Signature}.
* Parses a method descriptor ({@jvms 4.3.3}) into a {@link Signature}.
*
* @throws IllegalArgumentException if the method descriptor is not well formed
*/

View File

@ -85,20 +85,18 @@ public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersP
boolean isSynthetic();
/**
* Checks that the method is a
* <a href="http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.6">varargs</a>
* method.
* Checks if the method is a varargs method.
*
* @return whether the method is a varargs method
* @jvms 4.6
*/
boolean isVarArgs();
/**
* Checks that the method is a
* <a href="http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.6">bridge</a>
* method.
* Checks if the method is a bridge method.
*
* @return whether the method is a bridge method
* @jvms 4.6
*/
boolean isBridge();

View File

@ -25,8 +25,7 @@ package jdk.vm.ci.meta;
/**
* Represents a method signature provided by the runtime.
*
* @see <a href="http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.3">Method
* Descriptors</a>
* @jvms 4.3.3
*/
public interface Signature {
@ -84,9 +83,7 @@ public interface Signature {
}
/**
* Gets the
* <a href="http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.3">method
* descriptor</a> corresponding to this signature. For example:
* Gets the method descriptor ({@jvms 4.3.3}) corresponding to this signature. For example:
*
* <pre>
* (ILjava/lang/String;D)V

View File

@ -40,6 +40,7 @@ import java.io.File;
import java.io.IOException;
import java.lang.invoke.ConstantBootstraps;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.StringConcatFactory;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.util.List;
@ -54,14 +55,16 @@ import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type;
import jdk.vm.ci.hotspot.HotSpotObjectConstant;
import jdk.vm.ci.hotspot.HotSpotConstantPool;
import jdk.vm.ci.meta.ConstantPool;
import jdk.vm.ci.meta.ConstantPool.BootstrapMethodInvocation;
import jdk.vm.ci.meta.MetaAccessProvider;
import jdk.vm.ci.meta.PrimitiveConstant;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.runtime.JVMCI;
/**
* Tests support for Dynamic constants.
* Tests support for Dynamic constants and {@link jdk.vm.ci.meta.ConstantPool#lookupBootstrapMethodInvocation}.
*
* @see "https://openjdk.java.net/jeps/309"
* @see "https://bugs.openjdk.java.net/browse/JDK-8177279"
@ -145,13 +148,14 @@ public class TestDynamicConstant implements Opcodes {
Handle invokeHandle = new Handle(H_INVOKESTATIC, constantBootstrapsClassInternalName, "invoke", invokeSig, false);
String desc = type.getDescriptor();
ConstantDynamic condy;
if (condyType == CondyType.CALL_DIRECT_BSM) {
// Example: int TestDynamicConstant.getIntBSM(MethodHandles.Lookup l, String name,
// Class<?> type)
String sig = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)" + desc;
Handle handle = new Handle(H_INVOKESTATIC, testClassInternalName, getter + "BSM", sig, false);
ConstantDynamic condy = new ConstantDynamic("const", desc, handle);
condy = new ConstantDynamic("const", desc, handle);
MethodVisitor run = cw.visitMethod(PUBLIC_STATIC, "run", "()" + desc, null, null);
run.visitLdcInsn(condy);
run.visitInsn(type.getOpcode(IRETURN));
@ -161,7 +165,7 @@ public class TestDynamicConstant implements Opcodes {
// Example: int TestDynamicConstant.getInt()
Handle handle = new Handle(H_INVOKESTATIC, testClassInternalName, getter, "()" + desc, false);
ConstantDynamic condy = new ConstantDynamic("const", desc, invokeHandle, handle);
condy = new ConstantDynamic("const", desc, invokeHandle, handle);
MethodVisitor run = cw.visitMethod(PUBLIC_STATIC, "run", "()" + desc, null, null);
run.visitLdcInsn(condy);
run.visitInsn(type.getOpcode(IRETURN));
@ -177,6 +181,7 @@ public class TestDynamicConstant implements Opcodes {
ConstantDynamic condy1 = new ConstantDynamic("const1", desc, invokeHandle, handle1);
ConstantDynamic condy2 = new ConstantDynamic("const2", desc, invokeHandle, handle2, condy1, condy1);
condy = condy2;
MethodVisitor run = cw.visitMethod(PUBLIC_STATIC, "run", "()" + desc, null, null);
run.visitLdcInsn(condy2);
@ -184,6 +189,18 @@ public class TestDynamicConstant implements Opcodes {
run.visitMaxs(0, 0);
run.visitEnd();
}
MethodVisitor concat = cw.visitMethod(PUBLIC_STATIC, "concat", "()Ljava/lang/String;", null, null);
String sig = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;";
Handle handle = new Handle(H_INVOKESTATIC, Type.getInternalName(StringConcatFactory.class), "makeConcatWithConstants", sig, false);
String recipe = "var arg=\u0001, const arg=\u0002";
Object[] bsmArgs = {recipe};
concat.visitLdcInsn(condy);
concat.visitInvokeDynamicInsn("do_concat", "(" + desc + ")Ljava/lang/String;", handle, bsmArgs);
concat.visitInsn(ARETURN);
concat.visitMaxs(0, 0);
concat.visitEnd();
cw.visitEnd();
return cw.toByteArray();
}
@ -234,6 +251,10 @@ public class TestDynamicConstant implements Opcodes {
String.class,
List.class
};
Method getTagAt = HotSpotConstantPool.class.getDeclaredMethod("getTagAt", int.class);
getTagAt.setAccessible(true);
for (Class<?> type : types) {
for (CondyType condyType : CondyType.values()) {
TestGenerator e = new TestGenerator(type, condyType);
@ -241,8 +262,6 @@ public class TestDynamicConstant implements Opcodes {
Method m = testClass.getDeclaredMethod("run");
ResolvedJavaMethod run = metaAccess.lookupJavaMethod(m);
ConstantPool cp = run.getConstantPool();
Method getTagAt = cp.getClass().getDeclaredMethod("getTagAt", int.class);
getTagAt.setAccessible(true);
Object lastConstant = null;
for (int cpi = 1; cpi < cp.length(); cpi++) {
String tag = String.valueOf(getTagAt.invoke(cp, cpi));
@ -262,6 +281,39 @@ public class TestDynamicConstant implements Opcodes {
actual = ((HotSpotObjectConstant) lastConstant).asObject(type);
}
Assert.assertEquals(actual, expect, m + ":");
testLookupBootstrapMethodInvocation(condyType, metaAccess, testClass, getTagAt);
}
}
}
/**
* Tests {@link jdk.vm.ci.meta.ConstantPool#lookupBootstrapMethodInvocation}.
*/
private void testLookupBootstrapMethodInvocation(CondyType condyType, MetaAccessProvider metaAccess, Class<?> testClass, Method getTagAt) throws Throwable {
Method m = testClass.getDeclaredMethod("concat");
ResolvedJavaMethod concat = metaAccess.lookupJavaMethod(m);
ConstantPool cp = concat.getConstantPool();
Object lastConstant = null;
for (int cpi = 1; cpi < cp.length(); cpi++) {
String tag = String.valueOf(getTagAt.invoke(cp, cpi));
BootstrapMethodInvocation bsmi = cp.lookupBootstrapMethodInvocation(cpi, -1);
if (tag.equals("InvokeDynamic") || tag.equals("Dynamic")) {
Assert.assertNotNull(bsmi);
String bsm = bsmi.getMethod().format("%H.%n");
if (tag.equals("InvokeDynamic")) {
Assert.assertTrue(bsmi.isInvokeDynamic());
Assert.assertEquals(bsm, "java.lang.invoke.StringConcatFactory.makeConcatWithConstants");
} else {
Assert.assertFalse(bsmi.isInvokeDynamic());
if (condyType == CondyType.CALL_DIRECT_BSM) {
Assert.assertTrue(bsm.startsWith("jdk.vm.ci.hotspot.test.TestDynamicConstant.get") && bsm.endsWith("BSM"), bsm);
} else {
Assert.assertEquals(bsm, "java.lang.invoke.ConstantBootstraps.invoke");
}
}
} else {
Assert.assertNull(bsmi, String.valueOf(bsmi));
}
}
}