Skip to content
This repository has been archived by the owner on May 29, 2024. It is now read-only.

Commit

Permalink
[GR-45806] Execute boostrap methods at run time
Browse files Browse the repository at this point in the history
PullRequest: labsjdk-ce-21/31
  • Loading branch information
Zeavee committed Oct 26, 2023
2 parents b04c6ce + 30396b0 commit c23572f
Show file tree
Hide file tree
Showing 7 changed files with 355 additions and 76 deletions.
49 changes: 34 additions & 15 deletions src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -697,15 +697,24 @@ C2V_VMENTRY_NULL(jobject, getUncachedStringInPool, (JNIEnv* env, jobject, ARGUME
return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(obj));
C2V_END

C2V_VMENTRY_NULL(jobject, resolvePossiblyCachedConstantInPool, (JNIEnv* env, jobject, ARGUMENT_PAIR(cp), jint index))
C2V_VMENTRY_NULL(jobject, lookupConstantInPool, (JNIEnv* env, jobject, ARGUMENT_PAIR(cp), jint cp_index, bool resolve))
constantPoolHandle cp(THREAD, UNPACK_PAIR(ConstantPool, cp));
oop obj = cp->resolve_possibly_cached_constant_at(index, CHECK_NULL);
constantTag tag = cp->tag_at(index);
oop obj;
if (!resolve) {
bool found_it;
obj = cp->find_cached_constant_at(cp_index, found_it, CHECK_NULL);
if (!found_it) {
return nullptr;
}
} else {
obj = cp->resolve_possibly_cached_constant_at(cp_index, CHECK_NULL);
}
constantTag tag = cp->tag_at(cp_index);
if (tag.is_dynamic_constant()) {
if (obj == nullptr) {
return JVMCIENV->get_jobject(JVMCIENV->get_JavaConstant_NULL_POINTER());
}
BasicType bt = Signature::basic_type(cp->uncached_signature_ref_at(index));
BasicType bt = Signature::basic_type(cp->uncached_signature_ref_at(cp_index));
if (!is_reference_type(bt)) {
if (!is_java_primitive(bt)) {
return JVMCIENV->get_jobject(JVMCIENV->get_JavaConstant_ILLEGAL());
Expand Down Expand Up @@ -746,9 +755,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 @@ -814,6 +825,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 @@ -1577,16 +1593,18 @@ C2V_VMENTRY_NULL(jobject, iterateFrames, (JNIEnv* env, jobject compilerToVM, job
return nullptr;
C2V_END

C2V_VMENTRY_0(int, resolveInvokeDynamicInPool, (JNIEnv* env, jobject, ARGUMENT_PAIR(cp), jint index))
if (!ConstantPool::is_invokedynamic_index(index)) {
JVMCI_THROW_MSG_0(IllegalStateException, err_msg("not an invokedynamic index %d", index));
C2V_VMENTRY_0(int, decodeIndyIndexToCPIndex, (JNIEnv* env, jobject, ARGUMENT_PAIR(cp), jint encoded_indy_index, jboolean resolve))
if (!ConstantPool::is_invokedynamic_index(encoded_indy_index)) {
JVMCI_THROW_MSG_0(IllegalStateException, err_msg("not an encoded indy index %d", encoded_indy_index));
}

constantPoolHandle cp(THREAD, UNPACK_PAIR(ConstantPool, cp));
CallInfo callInfo;
LinkResolver::resolve_invoke(callInfo, Handle(), cp, index, Bytecodes::_invokedynamic, CHECK_0);
int indy_index = cp->decode_invokedynamic_index(index);
cp->cache()->set_dynamic_call(callInfo, indy_index);
int indy_index = cp->decode_invokedynamic_index(encoded_indy_index);
if (resolve) {
LinkResolver::resolve_invoke(callInfo, Handle(), cp, encoded_indy_index, Bytecodes::_invokedynamic, CHECK_0);
cp->cache()->set_dynamic_call(callInfo, indy_index);
}
return cp->resolved_indy_entry_at(indy_index)->constant_pool_index();
C2V_END

Expand Down Expand Up @@ -3105,13 +3123,14 @@ JNINativeMethod CompilerToVM::methods[] = {
{CC "lookupKlassInPool", CC "(" HS_CONSTANT_POOL2 "I)Ljava/lang/Object;", FN_PTR(lookupKlassInPool)},
{CC "lookupAppendixInPool", CC "(" HS_CONSTANT_POOL2 "I)" OBJECTCONSTANT, FN_PTR(lookupAppendixInPool)},
{CC "lookupMethodInPool", CC "(" HS_CONSTANT_POOL2 "IB" HS_METHOD2 ")" HS_METHOD, FN_PTR(lookupMethodInPool)},
{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 "resolvePossiblyCachedConstantInPool", CC "(" HS_CONSTANT_POOL2 "I)" JAVACONSTANT, FN_PTR(resolvePossiblyCachedConstantInPool)},
{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)},
{CC "resolveInvokeDynamicInPool", CC "(" HS_CONSTANT_POOL2 "I)I", FN_PTR(resolveInvokeDynamicInPool)},
{CC "decodeIndyIndexToCPIndex", CC "(" HS_CONSTANT_POOL2 "IZ)I", FN_PTR(decodeIndyIndexToCPIndex)},
{CC "resolveInvokeHandleInPool", CC "(" HS_CONSTANT_POOL2 "I)V", FN_PTR(resolveInvokeHandleInPool)},
{CC "isResolvedInvokeHandleInPool", CC "(" HS_CONSTANT_POOL2 "I)I", FN_PTR(isResolvedInvokeHandleInPool)},
{CC "resolveMethod", CC "(" HS_KLASS2 HS_METHOD2 HS_KLASS2 ")" HS_METHOD, FN_PTR(resolveMethod)},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,19 +271,22 @@ JavaConstant getUncachedStringInPool(HotSpotConstantPool constantPool, int cpi)
private native JavaConstant getUncachedStringInPool(HotSpotConstantPool constantPool, long constantPoolPointer, int cpi);

/**
* Resolves the entry at index {@code cpi} in {@code constantPool} to an object, looking in the
* Gets the entry at index {@code cpi} in {@code constantPool}, looking in the
* constant pool cache first.
*
* The behavior of this method is undefined if {@code cpi} does not denote one of the following
* entry types: {@code JVM_CONSTANT_Dynamic}, {@code JVM_CONSTANT_String},
* {@code JVM_CONSTANT_MethodHandle}, {@code JVM_CONSTANT_MethodHandleInError},
* {@code JVM_CONSTANT_MethodType} and {@code JVM_CONSTANT_MethodTypeInError}.
*
* @param resolve specifies if a resolved entry is expected. If {@code false},
* {@code null} is returned for an unresolved entry.
*/
JavaConstant resolvePossiblyCachedConstantInPool(HotSpotConstantPool constantPool, int cpi) {
return resolvePossiblyCachedConstantInPool(constantPool, constantPool.getConstantPoolPointer(), cpi);
JavaConstant lookupConstantInPool(HotSpotConstantPool constantPool, int cpi, boolean resolve) {
return lookupConstantInPool(constantPool, constantPool.getConstantPoolPointer(), cpi, resolve);
}

private native JavaConstant resolvePossiblyCachedConstantInPool(HotSpotConstantPool constantPool, long constantPoolPointer, int cpi);
private native JavaConstant lookupConstantInPool(HotSpotConstantPool constantPool, long constantPoolPointer, int cpi, boolean resolve);

/**
* Gets the {@code JVM_CONSTANT_NameAndType} index referenced by the {@code rawIndex}.
Expand Down Expand Up @@ -387,17 +390,18 @@ private native HotSpotResolvedJavaMethodImpl lookupMethodInPool(HotSpotConstantP
long callerMethodPointer);

/**
* Ensures that the type referenced by the specified {@code JVM_CONSTANT_InvokeDynamic} entry at
* index {@code cpi} in {@code constantPool} is loaded and initialized.
* Converts the encoded indy index operand of an invokedynamic instruction
* to an index directly into {@code constantPool}.
*
* @throws IllegalArgumentException if {@code cpi} is not an invokedynamic index
* @return the invokedynamic index
* @param resolve if {@true}, then resolve the entry (which may call a bootstrap method)
* @throws IllegalArgumentException if {@code encoded_indy_index} is not an encoded indy index
* @return {@code JVM_CONSTANT_InvokeDynamic} constant pool entry index for the invokedynamic
*/
int resolveInvokeDynamicInPool(HotSpotConstantPool constantPool, int cpi) {
return resolveInvokeDynamicInPool(constantPool, constantPool.getConstantPoolPointer(), cpi);
int decodeIndyIndexToCPIndex(HotSpotConstantPool constantPool, int encoded_indy_index, boolean resolve) {
return decodeIndyIndexToCPIndex(constantPool, constantPool.getConstantPoolPointer(), encoded_indy_index, resolve);
}

private native int resolveInvokeDynamicInPool(HotSpotConstantPool constantPool, long constantPoolPointer, int cpi);
private native int decodeIndyIndexToCPIndex(HotSpotConstantPool constantPool, long constantPoolPointer, int encoded_indy_index, boolean resolve);

/**
* Resolves the details for invoking the bootstrap method associated with the
Expand Down Expand Up @@ -427,6 +431,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 All @@ -440,7 +466,7 @@ void resolveInvokeHandleInPool(HotSpotConstantPool constantPool, int cpi) {

/**
* If {@code cpi} denotes an entry representing a resolved dynamic adapter (see
* {@link #resolveInvokeDynamicInPool} and {@link #resolveInvokeHandleInPool}), return the
* {@link #decodeIndyIndexToCPIndex} and {@link #resolveInvokeHandleInPool}), return the
* opcode of the instruction for which the resolution was performed ({@code invokedynamic} or
* {@code invokevirtual}), or {@code -1} otherwise.
*/
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 @@ -527,6 +530,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 @@ -605,8 +662,9 @@ public BootstrapMethodInvocation lookupBootstrapMethodInvocation(int rawCpi, 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 Expand Up @@ -637,6 +695,11 @@ JavaConstant getStaticFieldConstantValue(int cpi) {

@Override
public Object lookupConstant(int cpi) {
return lookupConstant(cpi, true);
}

@Override
public Object lookupConstant(int cpi, boolean resolve) {
final JvmConstant tag = getTagAt(cpi);
switch (tag.name) {
case "Integer":
Expand All @@ -658,17 +721,18 @@ public Object lookupConstant(int cpi) {
* "pseudo strings" (arbitrary live objects) patched into a String entry. Such
* entries do not have a symbol in the constant pool slot.
*/
return compilerToVM().resolvePossiblyCachedConstantInPool(this, cpi);
return compilerToVM().lookupConstantInPool(this, cpi, true);
case "MethodHandle":
case "MethodHandleInError":
case "MethodType":
case "MethodTypeInError":
case "Dynamic":
case "DynamicInError":
return compilerToVM().resolvePossiblyCachedConstantInPool(this, cpi);
return compilerToVM().lookupConstantInPool(this, cpi, resolve);
default:
throw new JVMCIError("Unknown constant pool tag %s", tag);
}

}

@Override
Expand Down Expand Up @@ -822,7 +886,7 @@ public int rawIndexToConstantPoolIndex(int rawIndex, int opcode) {
if (opcode != Bytecodes.INVOKEDYNAMIC) {
throw new IllegalArgumentException("expected INVOKEDYNAMIC at " + rawIndex + ", got " + opcode);
}
return compilerToVM().resolveInvokeDynamicInPool(this, rawIndex);
return compilerToVM().decodeIndyIndexToCPIndex(this, rawIndex, false);
}
if (opcode == Bytecodes.INVOKEDYNAMIC) {
throw new IllegalArgumentException("unexpected INVOKEDYNAMIC at " + rawIndex);
Expand Down Expand Up @@ -856,7 +920,7 @@ public void loadReferencedType(int cpi, int opcode, boolean initialize) {
if (!isInvokedynamicIndex(cpi)) {
throw new IllegalArgumentException("must use invokedynamic index but got " + cpi);
}
index = compilerToVM().resolveInvokeDynamicInPool(this, cpi);
index = compilerToVM().decodeIndyIndexToCPIndex(this, cpi, true);
break;
}
case Bytecodes.GETSTATIC:
Expand Down
Loading

0 comments on commit c23572f

Please sign in to comment.