8357660: [JVMCI] Add support for retrieving all BootstrapMethodInvocations directly from ConstantPool
Reviewed-by: dnsimon, yzheng
This commit is contained in:
parent
a653ff4893
commit
0352477ff5
@ -813,6 +813,14 @@ C2V_VMENTRY_NULL(jobject, lookupConstantInPool, (JNIEnv* env, jobject, ARGUMENT_
|
||||
return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(obj));
|
||||
C2V_END
|
||||
|
||||
C2V_VMENTRY_0(jint, getNumIndyEntries, (JNIEnv* env, jobject, ARGUMENT_PAIR(cp)))
|
||||
constantPoolHandle cp(THREAD, UNPACK_PAIR(ConstantPool, cp));
|
||||
if (cp->cache()->resolved_indy_entries() == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return cp->resolved_indy_entries_length();
|
||||
C2V_END
|
||||
|
||||
C2V_VMENTRY_NULL(jobjectArray, resolveBootstrapMethod, (JNIEnv* env, jobject, ARGUMENT_PAIR(cp), jint index))
|
||||
constantPoolHandle cp(THREAD, UNPACK_PAIR(ConstantPool, cp));
|
||||
constantTag tag = cp->tag_at(index);
|
||||
@ -3320,6 +3328,7 @@ JNINativeMethod CompilerToVM::methods[] = {
|
||||
{CC "lookupAppendixInPool", CC "(" HS_CONSTANT_POOL2 "II)" 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 "getNumIndyEntries", CC "(" HS_CONSTANT_POOL2 ")I", FN_PTR(getNumIndyEntries)},
|
||||
{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)},
|
||||
|
@ -468,9 +468,19 @@ final class CompilerToVM {
|
||||
*/
|
||||
int decodeMethodIndexToCPIndex(HotSpotConstantPool constantPool, int rawIndex) {
|
||||
return decodeMethodIndexToCPIndex(constantPool, constantPool.getConstantPoolPointer(), rawIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private native int decodeMethodIndexToCPIndex(HotSpotConstantPool constantPool, long constantPoolPointer, int rawIndex);
|
||||
private native int decodeMethodIndexToCPIndex(HotSpotConstantPool constantPool, long constantPoolPointer, int rawIndex);
|
||||
|
||||
/**
|
||||
* Returns the number of {@code ResolvedIndyEntry}s present within this constant
|
||||
* pool.
|
||||
*/
|
||||
int getNumIndyEntries(HotSpotConstantPool constantPool) {
|
||||
return getNumIndyEntries(constantPool, constantPool.getConstantPoolPointer());
|
||||
}
|
||||
|
||||
private native int getNumIndyEntries(HotSpotConstantPool constantPool, long constantPoolPointer);
|
||||
|
||||
/**
|
||||
* Resolves the details for invoking the bootstrap method associated with the
|
||||
|
@ -25,6 +25,7 @@ package jdk.vm.ci.hotspot;
|
||||
import java.util.AbstractList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import jdk.vm.ci.common.JVMCIError;
|
||||
import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM;
|
||||
@ -530,19 +531,21 @@ public final class HotSpotConstantPool implements ConstantPool, MetaspaceHandleO
|
||||
}
|
||||
}
|
||||
|
||||
static class BootstrapMethodInvocationImpl implements BootstrapMethodInvocation {
|
||||
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;
|
||||
private final int cpiOrIndyIndex;
|
||||
|
||||
BootstrapMethodInvocationImpl(boolean indy, ResolvedJavaMethod method, String name, JavaConstant type, List<JavaConstant> staticArguments) {
|
||||
BootstrapMethodInvocationImpl(boolean indy, ResolvedJavaMethod method, String name, JavaConstant type, List<JavaConstant> staticArguments, int cpiOrIndyIndex) {
|
||||
this.indy = indy;
|
||||
this.method = method;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.staticArguments = staticArguments;
|
||||
this.cpiOrIndyIndex = cpiOrIndyIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -570,6 +573,24 @@ public final class HotSpotConstantPool implements ConstantPool, MetaspaceHandleO
|
||||
return staticArguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolve() {
|
||||
if (isInvokeDynamic()) {
|
||||
loadReferencedType(cpiOrIndyIndex, Bytecodes.INVOKEDYNAMIC);
|
||||
} else {
|
||||
lookupConstant(cpiOrIndyIndex, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaConstant lookup() {
|
||||
if (isInvokeDynamic()) {
|
||||
return lookupAppendix(cpiOrIndyIndex, Bytecodes.INVOKEDYNAMIC);
|
||||
} else {
|
||||
return (JavaConstant) lookupConstant(cpiOrIndyIndex, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String static_args = staticArguments.stream().map(BootstrapMethodInvocationImpl::argumentAsString).collect(Collectors.joining(", ", "[", "]"));
|
||||
@ -612,12 +633,36 @@ public final class HotSpotConstantPool implements ConstantPool, MetaspaceHandleO
|
||||
int bss_index = bsciArgs[1];
|
||||
staticArgumentsList = new CachedBSMArgs(this, bss_index, argCount);
|
||||
}
|
||||
return new BootstrapMethodInvocationImpl(tag.name.equals("InvokeDynamic"), method, name, type, staticArgumentsList);
|
||||
boolean isIndy = tag.name.equals("InvokeDynamic");
|
||||
return new BootstrapMethodInvocationImpl(isIndy, method, name, type, staticArgumentsList, isIndy ? index : cpi);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isDynamicEntry(int cpi) {
|
||||
JvmConstant tagAt = getTagAt(cpi);
|
||||
return tagAt != null && tagAt.name.equals("Dynamic");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BootstrapMethodInvocation> lookupBootstrapMethodInvocations(boolean invokeDynamic){
|
||||
if (invokeDynamic) {
|
||||
int numIndys = compilerToVM().getNumIndyEntries(this);
|
||||
if (numIndys == 0) {
|
||||
return List.of();
|
||||
}
|
||||
return IntStream.range(0, numIndys)
|
||||
.mapToObj(i -> lookupBootstrapMethodInvocation(i, Bytecodes.INVOKEDYNAMIC))
|
||||
.toList();
|
||||
} else {
|
||||
return IntStream.range(1, length())
|
||||
.filter(this::isDynamicEntry)
|
||||
.mapToObj(cpi -> lookupBootstrapMethodInvocation(cpi, -1))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link JavaConstant} for the {@code ConstantValue} attribute of a field.
|
||||
*/
|
||||
|
@ -186,11 +186,28 @@ public interface ConstantPool {
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* The other types of entries are already resolved an can be used directly.
|
||||
* The other types of entries are already resolved and can be used directly.
|
||||
*
|
||||
* @jvms 5.4.3.6
|
||||
*/
|
||||
List<JavaConstant> getStaticArguments();
|
||||
|
||||
/**
|
||||
* Resolves the element corresponding to this bootstrap. If
|
||||
* {@code isInvokeDynamic()}, then the corresponding invoke dynamic is resolved.
|
||||
* If {@code !isInvokeDynamic()}, then the dynamic constant pool entry will be
|
||||
* resolved.
|
||||
*
|
||||
* @jvms 5.4.3.6
|
||||
*/
|
||||
void resolve();
|
||||
|
||||
/**
|
||||
* If {@code isInvokeDynamic()}, then this method looks up the corresponding
|
||||
* invoke dynamic's appendix. If {@code !isInvokeDynamic()}, then this will
|
||||
* return the constant pool entry's value.
|
||||
*/
|
||||
JavaConstant lookup();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -204,13 +221,27 @@ public interface ConstantPool {
|
||||
* @param opcode must be {@code Bytecodes.INVOKEDYNAMIC}, or -1 if
|
||||
* {@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}
|
||||
* is not a {@code CONSTANT_Dynamic_info} or {@code CONSTANT_InvokeDynamic_info}
|
||||
* @jvms 4.7.23 The {@code BootstrapMethods} Attribute
|
||||
*/
|
||||
default BootstrapMethodInvocation lookupBootstrapMethodInvocation(int index, int opcode) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns either the BootstrapMethodInvocation instances for all invokedynamic
|
||||
* bytecodes which reference this constant pool, or all
|
||||
* {@code CONSTANT_Dynamic_info} BootstrapMethodInvocations within this constant
|
||||
* pool. The returned List is unmodifiable; calls to any mutator method will
|
||||
* always cause {@code UnsupportedOperationException} to be thrown.
|
||||
*
|
||||
* @param invokeDynamic when true, return all invokedynamic
|
||||
* BootstrapMethodInvocations; otherwise, return all
|
||||
* {@code CONSTANT_Dynamic_info}
|
||||
* BootstrapMethodInvocations.
|
||||
*/
|
||||
List<BootstrapMethodInvocation> lookupBootstrapMethodInvocations(boolean invokeDynamic);
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -49,7 +49,7 @@ import java.lang.invoke.StringConcatFactory;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Files;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Map;
|
||||
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
@ -376,9 +376,10 @@ public class TestDynamicConstant implements Opcodes {
|
||||
ResolvedJavaMethod concat = metaAccess.lookupJavaMethod(m);
|
||||
ConstantPool cp = concat.getConstantPool();
|
||||
|
||||
Set<String> expectedBSMs = Set.of(
|
||||
"jdk.vm.ci.hotspot.test.TestDynamicConstant.shouldNotBeCalledBSM",
|
||||
"java.lang.invoke.StringConcatFactory.makeConcatWithConstants"
|
||||
// Contains a map of (bootstrap method names, resolvable) values.
|
||||
Map<String, Boolean> expectedIndyBSMs = Map.of(
|
||||
"jdk.vm.ci.hotspot.test.TestDynamicConstant.shouldNotBeCalledBSM", false,
|
||||
"java.lang.invoke.StringConcatFactory.makeConcatWithConstants", true
|
||||
);
|
||||
|
||||
for (int cpi = 1; cpi < cp.length(); cpi++) {
|
||||
@ -389,9 +390,10 @@ public class TestDynamicConstant implements Opcodes {
|
||||
String bsm = bsmi.getMethod().format("%H.%n");
|
||||
if (tag.equals("InvokeDynamic")) {
|
||||
Assert.assertTrue(bsmi.isInvokeDynamic());
|
||||
Assert.assertTrue(expectedBSMs.contains(bsm), expectedBSMs.toString());
|
||||
Assert.assertTrue(expectedIndyBSMs.containsKey(bsm), expectedIndyBSMs.toString());
|
||||
} else {
|
||||
Assert.assertFalse(bsmi.isInvokeDynamic());
|
||||
Assert.assertNull(bsmi.lookup());
|
||||
checkBsmName(condyType, bsm);
|
||||
List<JavaConstant> staticArguments = bsmi.getStaticArguments();
|
||||
for (int i = 0; i < staticArguments.size(); ++i) {
|
||||
@ -423,6 +425,41 @@ public class TestDynamicConstant implements Opcodes {
|
||||
}
|
||||
|
||||
testLoadReferencedType(concat, cp);
|
||||
|
||||
testLookupBootstrapMethodInvocations(condyType, cp, expectedIndyBSMs);
|
||||
}
|
||||
|
||||
private static void testLookupBootstrapMethodInvocations(CondyType condyType, ConstantPool cp, Map<String, Boolean> expectedIndyBSMs) {
|
||||
List<BootstrapMethodInvocation> indyBSMs = cp.lookupBootstrapMethodInvocations(true);
|
||||
Assert.assertEquals(indyBSMs.size(), 2);
|
||||
for (var bsmi : indyBSMs) {
|
||||
String bsm = bsmi.getMethod().format("%H.%n");
|
||||
Assert.assertTrue(expectedIndyBSMs.containsKey(bsm), expectedIndyBSMs.toString());
|
||||
Assert.assertTrue(bsmi.isInvokeDynamic());
|
||||
if (expectedIndyBSMs.get(bsm)) {
|
||||
bsmi.resolve();
|
||||
Assert.assertNotNull(bsmi.lookup());
|
||||
} else {
|
||||
try {
|
||||
bsmi.resolve();
|
||||
} catch (BootstrapMethodError bme) {
|
||||
// expected error
|
||||
}
|
||||
Assert.assertNull(bsmi.lookup());
|
||||
}
|
||||
}
|
||||
|
||||
List<BootstrapMethodInvocation> condyBSMs = cp.lookupBootstrapMethodInvocations(false);
|
||||
int expectedNumCondys = switch(condyType) {
|
||||
case CALL_DIRECT_BSM, CALL_INDIRECT_BSM -> 1;
|
||||
case CALL_DIRECT_WITH_ARGS_BSM, CALL_INDIRECT_WITH_ARGS_BSM -> 2;
|
||||
};
|
||||
Assert.assertEquals(condyBSMs.size(), expectedNumCondys);
|
||||
for (var bsmi : condyBSMs) {
|
||||
Assert.assertTrue(!bsmi.isInvokeDynamic());
|
||||
bsmi.resolve();
|
||||
Assert.assertNotNull(bsmi.lookup());
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkBsmName(CondyType condyType, String bsm) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user