diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index 8f51f5424a2..68212170d21 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -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;") \ diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index f54102f09bf..a85126fa2b6 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -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)}, diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java index 6db2d371a2d..0e08c18ad05 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java @@ -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 - * signature - * polymorphic 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: + * + *
+ * 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 + * ] + *+ * + * @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); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java index 40a63fff8ce..d884525ab0b 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java @@ -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
* (ILjava/lang/String;D)V
diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java
index 0764c87a7e9..bf399a05756 100644
--- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java
@@ -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));
}
}
}