mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-08 17:38:38 +00:00
8283839: [JVMCI] add support for querying indy bootstrap method target and arguments
Reviewed-by: psandoz, kvn
This commit is contained in:
parent
81a8e2f8b3
commit
8543aaa7eb
@ -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;") \
|
||||
|
||||
@ -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)},
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 {
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user