Skip to content

Commit

Permalink
8315771: [JVMCI] Resolution of bootstrap methods with int[] static ar…
Browse files Browse the repository at this point in the history
…guments

Reviewed-by: dnsimon, psandoz
  • Loading branch information
Zeavee authored and Doug Simon committed Sep 21, 2023
1 parent 83b01cf commit 015f6f5
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 18 deletions.
14 changes: 11 additions & 3 deletions src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -771,9 +771,11 @@ C2V_VMENTRY_NULL(jobjectArray, resolveBootstrapMethod, (JNIEnv* env, jobject, AR
}
// Get the indy entry based on CP index
int indy_index = -1;
for (int i = 0; i < cp->resolved_indy_entries_length(); i++) {
if (cp->resolved_indy_entry_at(i)->constant_pool_index() == index) {
indy_index = i;
if (is_indy) {
for (int i = 0; i < cp->resolved_indy_entries_length(); i++) {
if (cp->resolved_indy_entry_at(i)->constant_pool_index() == index) {
indy_index = i;
}
}
}
// Resolve the bootstrap specifier, its name, type, and static arguments
Expand Down Expand Up @@ -839,6 +841,11 @@ C2V_VMENTRY_NULL(jobjectArray, resolveBootstrapMethod, (JNIEnv* env, jobject, AR
return JVMCIENV->get_jobjectArray(bsmi);
C2V_END

C2V_VMENTRY_0(jint, bootstrapArgumentIndexAt, (JNIEnv* env, jobject, ARGUMENT_PAIR(cp), jint cpi, jint index))
constantPoolHandle cp(THREAD, UNPACK_PAIR(ConstantPool, cp));
return cp->bootstrap_argument_index_at(cpi, index);
C2V_END

C2V_VMENTRY_0(jint, lookupNameAndTypeRefIndexInPool, (JNIEnv* env, jobject, ARGUMENT_PAIR(cp), jint index, jint opcode))
constantPoolHandle cp(THREAD, UNPACK_PAIR(ConstantPool, cp));
return cp->name_and_type_ref_index_at(index, (Bytecodes::Code)opcode);
Expand Down Expand Up @@ -3177,6 +3184,7 @@ JNINativeMethod CompilerToVM::methods[] = {
{CC "lookupConstantInPool", CC "(" HS_CONSTANT_POOL2 "IZ)" JAVACONSTANT, FN_PTR(lookupConstantInPool)},
{CC "constantPoolRemapInstructionOperandFromCache", CC "(" HS_CONSTANT_POOL2 "I)I", FN_PTR(constantPoolRemapInstructionOperandFromCache)},
{CC "resolveBootstrapMethod", CC "(" HS_CONSTANT_POOL2 "I)[" OBJECT, FN_PTR(resolveBootstrapMethod)},
{CC "bootstrapArgumentIndexAt", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(bootstrapArgumentIndexAt)},
{CC "getUncachedStringInPool", CC "(" HS_CONSTANT_POOL2 "I)" JAVACONSTANT, FN_PTR(getUncachedStringInPool)},
{CC "resolveTypeInPool", CC "(" HS_CONSTANT_POOL2 "I)" HS_KLASS, FN_PTR(resolveTypeInPool)},
{CC "resolveFieldInPool", CC "(" HS_CONSTANT_POOL2 "I" HS_METHOD2 "B[I)" HS_KLASS, FN_PTR(resolveFieldInPool)},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,28 @@ Object[] resolveBootstrapMethod(HotSpotConstantPool constantPool, int cpi) {

private native Object[] resolveBootstrapMethod(HotSpotConstantPool constantPool, long constantPoolPointer, int cpi);

/**
* Gets the constant pool index of a static argument of a {@code CONSTANT_Dynamic_info} or
* @{code CONSTANT_InvokeDynamic_info} entry. Used when the list of static arguments in the
* {@link BootstrapMethodInvocation} is a {@code List<PrimitiveConstant>} of the form
* {{@code arg_count}, {@code pool_index}}, meaning the arguments are not already resolved and that
* the JDK has to lookup the arguments when they are needed. The {@code cpi} corresponds to
* {@code pool_index} and the {@code index} has to be smaller than {@code arg_count}.
*
* The behavior of this method is undefined if {@code cpi} does not denote an entry representing
* a {@code CONSTANT_Dynamic_info} or a @{code CONSTANT_InvokeDynamic_info}, or if the index
* is out of bounds.
*
* @param cpi the index of a {@code CONSTANT_Dynamic_info} or @{code CONSTANT_InvokeDynamic_info} entry
* @param index the index of the static argument in the list of static arguments
* @return the constant pool index associated with the static argument
*/
int bootstrapArgumentIndexAt(HotSpotConstantPool constantPool, int cpi, int index) {
return bootstrapArgumentIndexAt(constantPool, constantPool.getConstantPoolPointer(), cpi, index);
}

private native int bootstrapArgumentIndexAt(HotSpotConstantPool constantPool, long constantPoolPointer, int cpi, int index);

/**
* 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import static jdk.vm.ci.hotspot.HotSpotVMConfig.config;
import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE;

import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
Expand All @@ -38,6 +40,7 @@
import jdk.vm.ci.meta.JavaField;
import jdk.vm.ci.meta.JavaMethod;
import jdk.vm.ci.meta.JavaType;
import jdk.vm.ci.meta.PrimitiveConstant;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.vm.ci.meta.Signature;
Expand Down Expand Up @@ -504,6 +507,60 @@ private int flags() {
return UNSAFE.getInt(getConstantPoolPointer() + config().constantPoolFlagsOffset);
}

/**
* Represents a list of static arguments from a {@link BootstrapMethodInvocation} of the form
* {{@code arg_count}, {@code pool_index}}, meaning the arguments are not already resolved
* and that the JDK has to lookup the arguments when they are needed. The {@code bssIndex}
* corresponds to {@code pool_index} and the {@code size} corresponds to {@code arg_count}.
*/
static class CachedBSMArgs extends AbstractList<JavaConstant> {
private final JavaConstant[] cache;
private final HotSpotConstantPool cp;
private final int bssIndex;

CachedBSMArgs(HotSpotConstantPool cp, int bssIndex, int size) {
this.cp = cp;
this.bssIndex = bssIndex;
this.cache = new JavaConstant[size];
}

/**
* Lazily resolves and caches the argument at the given index and returns it. The method
* {@link CompilerToVM#bootstrapArgumentIndexAt} is used to obtain the constant pool
* index of the entry and the method {@link ConstantPool#lookupConstant} is used to
* resolve it. If the resolution failed, the index is returned as a
* {@link PrimitiveConstant}.
*
* @param index index of the element to return
* @return A {@link JavaConstant} corresponding to the static argument requested. A return
* value of type {@link PrimitiveConstant} represents an unresolved constant pool entry
*/
@Override
public JavaConstant get(int index) {
JavaConstant res = cache[index];
if (res == null) {
int argCpi = compilerToVM().bootstrapArgumentIndexAt(cp, bssIndex, index);
Object object = cp.lookupConstant(argCpi, false);
if (object instanceof PrimitiveConstant primitiveConstant) {
res = runtime().getReflection().boxPrimitive(primitiveConstant);
} else if (object instanceof JavaConstant javaConstant) {
res = javaConstant;
} else if (object instanceof JavaType type) {
res = runtime().getReflection().forObject(type);
} else {
res = JavaConstant.forInt(argCpi);
}
cache[index] = res;
}
return res;
}

@Override
public int size() {
return cache.length;
}
}

static class BootstrapMethodInvocationImpl implements BootstrapMethodInvocation {
private final boolean indy;
private final ResolvedJavaMethod method;
Expand Down Expand Up @@ -582,8 +639,9 @@ public BootstrapMethodInvocation lookupBootstrapMethodInvocation(int index, int
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);
int argCount = bsciArgs[0];
int bss_index = bsciArgs[1];
staticArgumentsList = new CachedBSMArgs(this, bss_index, argCount);
}
return new BootstrapMethodInvocationImpl(tag.name.equals("InvokeDynamic"), method, name, type, staticArgumentsList);
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ default 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 .
* or {@code CONSTANT_InvokeDynamic_info} pool entry.
*
* @jvms 4.4.10 The {@code CONSTANT_Dynamic_info} and {@code CONSTANT_InvokeDynamic_info}
* Structures
Expand Down Expand Up @@ -165,6 +165,29 @@ interface BootstrapMethodInvocation {
/**
* Gets the static arguments with which the bootstrap method will be invoked.
*
* The {@linkplain JavaConstant#getJavaKind kind} of each argument will be
* {@link JavaKind#Object} or {@link JavaKind#Int}. The latter represents an
* unresolved {@code CONSTANT_Dynamic_info} entry. To resolve this entry, the
* corresponding bootstrap method has to be called first:
*
* <pre>
* List<JavaConstant> args = bmi.getStaticArguments();
* List<JavaConstant> resolvedArgs = new ArrayList<>(args.size());
* for (JavaConstant c : args) {
* JavaConstant r = c;
* if (c.getJavaKind() == JavaKind.Int) {
* // If needed, access corresponding BootstrapMethodInvocation using
* // cp.lookupBootstrapMethodInvocation(pc.asInt(), -1)
* r = cp.lookupConstant(c.asInt(), true);
* } else {
* assert c.getJavaKind() == JavaKind.Object;
* }
* resolvedArgs.append(r);
* }
* </pre>
*
* The other types of entries are already resolved an can be used directly.
*
* @jvms 5.4.3.6
*/
List<JavaConstant> getStaticArguments();
Expand All @@ -182,8 +205,6 @@ interface BootstrapMethodInvocation {
* {@code index} was not decoded from a bytecode stream
* @return the bootstrap method invocation details or {@code null} if the entry specified by {@code index}
* 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 index, int opcode) {
Expand Down
Loading

1 comment on commit 015f6f5

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.