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));
|
return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(obj));
|
||||||
C2V_END
|
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))
|
C2V_VMENTRY_NULL(jobjectArray, resolveBootstrapMethod, (JNIEnv* env, jobject, ARGUMENT_PAIR(cp), jint index))
|
||||||
constantPoolHandle cp(THREAD, UNPACK_PAIR(ConstantPool, cp));
|
constantPoolHandle cp(THREAD, UNPACK_PAIR(ConstantPool, cp));
|
||||||
constantTag tag = cp->tag_at(index);
|
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 "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 "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 "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 "resolveBootstrapMethod", CC "(" HS_CONSTANT_POOL2 "I)[" OBJECT, FN_PTR(resolveBootstrapMethod)},
|
||||||
{CC "bootstrapArgumentIndexAt", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(bootstrapArgumentIndexAt)},
|
{CC "bootstrapArgumentIndexAt", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(bootstrapArgumentIndexAt)},
|
||||||
{CC "getUncachedStringInPool", CC "(" HS_CONSTANT_POOL2 "I)" JAVACONSTANT, FN_PTR(getUncachedStringInPool)},
|
{CC "getUncachedStringInPool", CC "(" HS_CONSTANT_POOL2 "I)" JAVACONSTANT, FN_PTR(getUncachedStringInPool)},
|
||||||
|
@ -468,9 +468,19 @@ final class CompilerToVM {
|
|||||||
*/
|
*/
|
||||||
int decodeMethodIndexToCPIndex(HotSpotConstantPool constantPool, int rawIndex) {
|
int decodeMethodIndexToCPIndex(HotSpotConstantPool constantPool, int rawIndex) {
|
||||||
return decodeMethodIndexToCPIndex(constantPool, constantPool.getConstantPoolPointer(), 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
|
* 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.AbstractList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
import jdk.vm.ci.common.JVMCIError;
|
import jdk.vm.ci.common.JVMCIError;
|
||||||
import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM;
|
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 boolean indy;
|
||||||
private final ResolvedJavaMethod method;
|
private final ResolvedJavaMethod method;
|
||||||
private final String name;
|
private final String name;
|
||||||
private final JavaConstant type;
|
private final JavaConstant type;
|
||||||
private final List<JavaConstant> staticArguments;
|
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.indy = indy;
|
||||||
this.method = method;
|
this.method = method;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.staticArguments = staticArguments;
|
this.staticArguments = staticArguments;
|
||||||
|
this.cpiOrIndyIndex = cpiOrIndyIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -570,6 +573,24 @@ public final class HotSpotConstantPool implements ConstantPool, MetaspaceHandleO
|
|||||||
return staticArguments;
|
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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
String static_args = staticArguments.stream().map(BootstrapMethodInvocationImpl::argumentAsString).collect(Collectors.joining(", ", "[", "]"));
|
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];
|
int bss_index = bsciArgs[1];
|
||||||
staticArgumentsList = new CachedBSMArgs(this, bss_index, argCount);
|
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:
|
default:
|
||||||
return null;
|
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.
|
* Gets the {@link JavaConstant} for the {@code ConstantValue} attribute of a field.
|
||||||
*/
|
*/
|
||||||
|
@ -186,11 +186,28 @@ public interface ConstantPool {
|
|||||||
* }
|
* }
|
||||||
* </pre>
|
* </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
|
* @jvms 5.4.3.6
|
||||||
*/
|
*/
|
||||||
List<JavaConstant> getStaticArguments();
|
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
|
* @param opcode must be {@code Bytecodes.INVOKEDYNAMIC}, or -1 if
|
||||||
* {@code index} was not decoded from a bytecode stream
|
* {@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}
|
* @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
|
* @jvms 4.7.23 The {@code BootstrapMethods} Attribute
|
||||||
*/
|
*/
|
||||||
default BootstrapMethodInvocation lookupBootstrapMethodInvocation(int index, int opcode) {
|
default BootstrapMethodInvocation lookupBootstrapMethodInvocation(int index, int opcode) {
|
||||||
throw new UnsupportedOperationException();
|
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
|
* 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
|
* 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.lang.reflect.Method;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.testng.Assert;
|
import org.testng.Assert;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
@ -376,9 +376,10 @@ public class TestDynamicConstant implements Opcodes {
|
|||||||
ResolvedJavaMethod concat = metaAccess.lookupJavaMethod(m);
|
ResolvedJavaMethod concat = metaAccess.lookupJavaMethod(m);
|
||||||
ConstantPool cp = concat.getConstantPool();
|
ConstantPool cp = concat.getConstantPool();
|
||||||
|
|
||||||
Set<String> expectedBSMs = Set.of(
|
// Contains a map of (bootstrap method names, resolvable) values.
|
||||||
"jdk.vm.ci.hotspot.test.TestDynamicConstant.shouldNotBeCalledBSM",
|
Map<String, Boolean> expectedIndyBSMs = Map.of(
|
||||||
"java.lang.invoke.StringConcatFactory.makeConcatWithConstants"
|
"jdk.vm.ci.hotspot.test.TestDynamicConstant.shouldNotBeCalledBSM", false,
|
||||||
|
"java.lang.invoke.StringConcatFactory.makeConcatWithConstants", true
|
||||||
);
|
);
|
||||||
|
|
||||||
for (int cpi = 1; cpi < cp.length(); cpi++) {
|
for (int cpi = 1; cpi < cp.length(); cpi++) {
|
||||||
@ -389,9 +390,10 @@ public class TestDynamicConstant implements Opcodes {
|
|||||||
String bsm = bsmi.getMethod().format("%H.%n");
|
String bsm = bsmi.getMethod().format("%H.%n");
|
||||||
if (tag.equals("InvokeDynamic")) {
|
if (tag.equals("InvokeDynamic")) {
|
||||||
Assert.assertTrue(bsmi.isInvokeDynamic());
|
Assert.assertTrue(bsmi.isInvokeDynamic());
|
||||||
Assert.assertTrue(expectedBSMs.contains(bsm), expectedBSMs.toString());
|
Assert.assertTrue(expectedIndyBSMs.containsKey(bsm), expectedIndyBSMs.toString());
|
||||||
} else {
|
} else {
|
||||||
Assert.assertFalse(bsmi.isInvokeDynamic());
|
Assert.assertFalse(bsmi.isInvokeDynamic());
|
||||||
|
Assert.assertNull(bsmi.lookup());
|
||||||
checkBsmName(condyType, bsm);
|
checkBsmName(condyType, bsm);
|
||||||
List<JavaConstant> staticArguments = bsmi.getStaticArguments();
|
List<JavaConstant> staticArguments = bsmi.getStaticArguments();
|
||||||
for (int i = 0; i < staticArguments.size(); ++i) {
|
for (int i = 0; i < staticArguments.size(); ++i) {
|
||||||
@ -423,6 +425,41 @@ public class TestDynamicConstant implements Opcodes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
testLoadReferencedType(concat, cp);
|
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) {
|
private static void checkBsmName(CondyType condyType, String bsm) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user