Skip to content

Commit 0352477

Browse files
teshullDoug Simon
authored andcommitted
8357660: [JVMCI] Add support for retrieving all BootstrapMethodInvocations directly from ConstantPool
Reviewed-by: dnsimon, yzheng
1 parent a653ff4 commit 0352477

File tree

5 files changed

+144
-12
lines changed

5 files changed

+144
-12
lines changed

src/hotspot/share/jvmci/jvmciCompilerToVM.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,14 @@ C2V_VMENTRY_NULL(jobject, lookupConstantInPool, (JNIEnv* env, jobject, ARGUMENT_
813813
return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(obj));
814814
C2V_END
815815

816+
C2V_VMENTRY_0(jint, getNumIndyEntries, (JNIEnv* env, jobject, ARGUMENT_PAIR(cp)))
817+
constantPoolHandle cp(THREAD, UNPACK_PAIR(ConstantPool, cp));
818+
if (cp->cache()->resolved_indy_entries() == nullptr) {
819+
return 0;
820+
}
821+
return cp->resolved_indy_entries_length();
822+
C2V_END
823+
816824
C2V_VMENTRY_NULL(jobjectArray, resolveBootstrapMethod, (JNIEnv* env, jobject, ARGUMENT_PAIR(cp), jint index))
817825
constantPoolHandle cp(THREAD, UNPACK_PAIR(ConstantPool, cp));
818826
constantTag tag = cp->tag_at(index);
@@ -3320,6 +3328,7 @@ JNINativeMethod CompilerToVM::methods[] = {
33203328
{CC "lookupAppendixInPool", CC "(" HS_CONSTANT_POOL2 "II)" OBJECTCONSTANT, FN_PTR(lookupAppendixInPool)},
33213329
{CC "lookupMethodInPool", CC "(" HS_CONSTANT_POOL2 "IB" HS_METHOD2 ")" HS_METHOD, FN_PTR(lookupMethodInPool)},
33223330
{CC "lookupConstantInPool", CC "(" HS_CONSTANT_POOL2 "IZ)" JAVACONSTANT, FN_PTR(lookupConstantInPool)},
3331+
{CC "getNumIndyEntries", CC "(" HS_CONSTANT_POOL2 ")I", FN_PTR(getNumIndyEntries)},
33233332
{CC "resolveBootstrapMethod", CC "(" HS_CONSTANT_POOL2 "I)[" OBJECT, FN_PTR(resolveBootstrapMethod)},
33243333
{CC "bootstrapArgumentIndexAt", CC "(" HS_CONSTANT_POOL2 "II)I", FN_PTR(bootstrapArgumentIndexAt)},
33253334
{CC "getUncachedStringInPool", CC "(" HS_CONSTANT_POOL2 "I)" JAVACONSTANT, FN_PTR(getUncachedStringInPool)},

src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -468,9 +468,19 @@ int decodeFieldIndexToCPIndex(HotSpotConstantPool constantPool, int rawIndex) {
468468
*/
469469
int decodeMethodIndexToCPIndex(HotSpotConstantPool constantPool, int rawIndex) {
470470
return decodeMethodIndexToCPIndex(constantPool, constantPool.getConstantPoolPointer(), rawIndex);
471-
}
471+
}
472+
473+
private native int decodeMethodIndexToCPIndex(HotSpotConstantPool constantPool, long constantPoolPointer, int rawIndex);
474+
475+
/**
476+
* Returns the number of {@code ResolvedIndyEntry}s present within this constant
477+
* pool.
478+
*/
479+
int getNumIndyEntries(HotSpotConstantPool constantPool) {
480+
return getNumIndyEntries(constantPool, constantPool.getConstantPoolPointer());
481+
}
472482

473-
private native int decodeMethodIndexToCPIndex(HotSpotConstantPool constantPool, long constantPoolPointer, int rawIndex);
483+
private native int getNumIndyEntries(HotSpotConstantPool constantPool, long constantPoolPointer);
474484

475485
/**
476486
* Resolves the details for invoking the bootstrap method associated with the

src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantPool.java

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.AbstractList;
2626
import java.util.List;
2727
import java.util.stream.Collectors;
28+
import java.util.stream.IntStream;
2829

2930
import jdk.vm.ci.common.JVMCIError;
3031
import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM;
@@ -530,19 +531,21 @@ public int size() {
530531
}
531532
}
532533

533-
static class BootstrapMethodInvocationImpl implements BootstrapMethodInvocation {
534+
class BootstrapMethodInvocationImpl implements BootstrapMethodInvocation {
534535
private final boolean indy;
535536
private final ResolvedJavaMethod method;
536537
private final String name;
537538
private final JavaConstant type;
538539
private final List<JavaConstant> staticArguments;
540+
private final int cpiOrIndyIndex;
539541

540-
BootstrapMethodInvocationImpl(boolean indy, ResolvedJavaMethod method, String name, JavaConstant type, List<JavaConstant> staticArguments) {
542+
BootstrapMethodInvocationImpl(boolean indy, ResolvedJavaMethod method, String name, JavaConstant type, List<JavaConstant> staticArguments, int cpiOrIndyIndex) {
541543
this.indy = indy;
542544
this.method = method;
543545
this.name = name;
544546
this.type = type;
545547
this.staticArguments = staticArguments;
548+
this.cpiOrIndyIndex = cpiOrIndyIndex;
546549
}
547550

548551
@Override
@@ -570,6 +573,24 @@ public List<JavaConstant> getStaticArguments() {
570573
return staticArguments;
571574
}
572575

576+
@Override
577+
public void resolve() {
578+
if (isInvokeDynamic()) {
579+
loadReferencedType(cpiOrIndyIndex, Bytecodes.INVOKEDYNAMIC);
580+
} else {
581+
lookupConstant(cpiOrIndyIndex, true);
582+
}
583+
}
584+
585+
@Override
586+
public JavaConstant lookup() {
587+
if (isInvokeDynamic()) {
588+
return lookupAppendix(cpiOrIndyIndex, Bytecodes.INVOKEDYNAMIC);
589+
} else {
590+
return (JavaConstant) lookupConstant(cpiOrIndyIndex, false);
591+
}
592+
}
593+
573594
@Override
574595
public String toString() {
575596
String static_args = staticArguments.stream().map(BootstrapMethodInvocationImpl::argumentAsString).collect(Collectors.joining(", ", "[", "]"));
@@ -612,12 +633,36 @@ public BootstrapMethodInvocation lookupBootstrapMethodInvocation(int index, int
612633
int bss_index = bsciArgs[1];
613634
staticArgumentsList = new CachedBSMArgs(this, bss_index, argCount);
614635
}
615-
return new BootstrapMethodInvocationImpl(tag.name.equals("InvokeDynamic"), method, name, type, staticArgumentsList);
636+
boolean isIndy = tag.name.equals("InvokeDynamic");
637+
return new BootstrapMethodInvocationImpl(isIndy, method, name, type, staticArgumentsList, isIndy ? index : cpi);
616638
default:
617639
return null;
618640
}
619641
}
620642

643+
private boolean isDynamicEntry(int cpi) {
644+
JvmConstant tagAt = getTagAt(cpi);
645+
return tagAt != null && tagAt.name.equals("Dynamic");
646+
}
647+
648+
@Override
649+
public List<BootstrapMethodInvocation> lookupBootstrapMethodInvocations(boolean invokeDynamic){
650+
if (invokeDynamic) {
651+
int numIndys = compilerToVM().getNumIndyEntries(this);
652+
if (numIndys == 0) {
653+
return List.of();
654+
}
655+
return IntStream.range(0, numIndys)
656+
.mapToObj(i -> lookupBootstrapMethodInvocation(i, Bytecodes.INVOKEDYNAMIC))
657+
.toList();
658+
} else {
659+
return IntStream.range(1, length())
660+
.filter(this::isDynamicEntry)
661+
.mapToObj(cpi -> lookupBootstrapMethodInvocation(cpi, -1))
662+
.toList();
663+
}
664+
}
665+
621666
/**
622667
* Gets the {@link JavaConstant} for the {@code ConstantValue} attribute of a field.
623668
*/

src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ConstantPool.java

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,11 +186,28 @@ interface BootstrapMethodInvocation {
186186
* }
187187
* </pre>
188188
*
189-
* The other types of entries are already resolved an can be used directly.
189+
* The other types of entries are already resolved and can be used directly.
190190
*
191191
* @jvms 5.4.3.6
192192
*/
193193
List<JavaConstant> getStaticArguments();
194+
195+
/**
196+
* Resolves the element corresponding to this bootstrap. If
197+
* {@code isInvokeDynamic()}, then the corresponding invoke dynamic is resolved.
198+
* If {@code !isInvokeDynamic()}, then the dynamic constant pool entry will be
199+
* resolved.
200+
*
201+
* @jvms 5.4.3.6
202+
*/
203+
void resolve();
204+
205+
/**
206+
* If {@code isInvokeDynamic()}, then this method looks up the corresponding
207+
* invoke dynamic's appendix. If {@code !isInvokeDynamic()}, then this will
208+
* return the constant pool entry's value.
209+
*/
210+
JavaConstant lookup();
194211
}
195212

196213
/**
@@ -204,13 +221,27 @@ interface BootstrapMethodInvocation {
204221
* @param opcode must be {@code Bytecodes.INVOKEDYNAMIC}, or -1 if
205222
* {@code index} was not decoded from a bytecode stream
206223
* @return the bootstrap method invocation details or {@code null} if the entry specified by {@code index}
207-
* is not a {@code CONSTANT_Dynamic_info} or @{code CONSTANT_InvokeDynamic_info}
224+
* is not a {@code CONSTANT_Dynamic_info} or {@code CONSTANT_InvokeDynamic_info}
208225
* @jvms 4.7.23 The {@code BootstrapMethods} Attribute
209226
*/
210227
default BootstrapMethodInvocation lookupBootstrapMethodInvocation(int index, int opcode) {
211228
throw new UnsupportedOperationException();
212229
}
213230

231+
/**
232+
* Returns either the BootstrapMethodInvocation instances for all invokedynamic
233+
* bytecodes which reference this constant pool, or all
234+
* {@code CONSTANT_Dynamic_info} BootstrapMethodInvocations within this constant
235+
* pool. The returned List is unmodifiable; calls to any mutator method will
236+
* always cause {@code UnsupportedOperationException} to be thrown.
237+
*
238+
* @param invokeDynamic when true, return all invokedynamic
239+
* BootstrapMethodInvocations; otherwise, return all
240+
* {@code CONSTANT_Dynamic_info}
241+
* BootstrapMethodInvocations.
242+
*/
243+
List<BootstrapMethodInvocation> lookupBootstrapMethodInvocations(boolean invokeDynamic);
244+
214245
/**
215246
* Looks up a reference to a type. If {@code opcode} is non-negative, then resolution checks
216247
* specific to the bytecode it denotes are performed if the type is already resolved. Should any

test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
import java.lang.reflect.Method;
5050
import java.nio.file.Files;
5151
import java.util.List;
52-
import java.util.Set;
52+
import java.util.Map;
5353

5454
import org.testng.Assert;
5555
import org.testng.annotations.Test;
@@ -376,9 +376,10 @@ private void testLookupBootstrapMethodInvocation(CondyType condyType, MetaAccess
376376
ResolvedJavaMethod concat = metaAccess.lookupJavaMethod(m);
377377
ConstantPool cp = concat.getConstantPool();
378378

379-
Set<String> expectedBSMs = Set.of(
380-
"jdk.vm.ci.hotspot.test.TestDynamicConstant.shouldNotBeCalledBSM",
381-
"java.lang.invoke.StringConcatFactory.makeConcatWithConstants"
379+
// Contains a map of (bootstrap method names, resolvable) values.
380+
Map<String, Boolean> expectedIndyBSMs = Map.of(
381+
"jdk.vm.ci.hotspot.test.TestDynamicConstant.shouldNotBeCalledBSM", false,
382+
"java.lang.invoke.StringConcatFactory.makeConcatWithConstants", true
382383
);
383384

384385
for (int cpi = 1; cpi < cp.length(); cpi++) {
@@ -389,9 +390,10 @@ private void testLookupBootstrapMethodInvocation(CondyType condyType, MetaAccess
389390
String bsm = bsmi.getMethod().format("%H.%n");
390391
if (tag.equals("InvokeDynamic")) {
391392
Assert.assertTrue(bsmi.isInvokeDynamic());
392-
Assert.assertTrue(expectedBSMs.contains(bsm), expectedBSMs.toString());
393+
Assert.assertTrue(expectedIndyBSMs.containsKey(bsm), expectedIndyBSMs.toString());
393394
} else {
394395
Assert.assertFalse(bsmi.isInvokeDynamic());
396+
Assert.assertNull(bsmi.lookup());
395397
checkBsmName(condyType, bsm);
396398
List<JavaConstant> staticArguments = bsmi.getStaticArguments();
397399
for (int i = 0; i < staticArguments.size(); ++i) {
@@ -423,6 +425,41 @@ private void testLookupBootstrapMethodInvocation(CondyType condyType, MetaAccess
423425
}
424426

425427
testLoadReferencedType(concat, cp);
428+
429+
testLookupBootstrapMethodInvocations(condyType, cp, expectedIndyBSMs);
430+
}
431+
432+
private static void testLookupBootstrapMethodInvocations(CondyType condyType, ConstantPool cp, Map<String, Boolean> expectedIndyBSMs) {
433+
List<BootstrapMethodInvocation> indyBSMs = cp.lookupBootstrapMethodInvocations(true);
434+
Assert.assertEquals(indyBSMs.size(), 2);
435+
for (var bsmi : indyBSMs) {
436+
String bsm = bsmi.getMethod().format("%H.%n");
437+
Assert.assertTrue(expectedIndyBSMs.containsKey(bsm), expectedIndyBSMs.toString());
438+
Assert.assertTrue(bsmi.isInvokeDynamic());
439+
if (expectedIndyBSMs.get(bsm)) {
440+
bsmi.resolve();
441+
Assert.assertNotNull(bsmi.lookup());
442+
} else {
443+
try {
444+
bsmi.resolve();
445+
} catch (BootstrapMethodError bme) {
446+
// expected error
447+
}
448+
Assert.assertNull(bsmi.lookup());
449+
}
450+
}
451+
452+
List<BootstrapMethodInvocation> condyBSMs = cp.lookupBootstrapMethodInvocations(false);
453+
int expectedNumCondys = switch(condyType) {
454+
case CALL_DIRECT_BSM, CALL_INDIRECT_BSM -> 1;
455+
case CALL_DIRECT_WITH_ARGS_BSM, CALL_INDIRECT_WITH_ARGS_BSM -> 2;
456+
};
457+
Assert.assertEquals(condyBSMs.size(), expectedNumCondys);
458+
for (var bsmi : condyBSMs) {
459+
Assert.assertTrue(!bsmi.isInvokeDynamic());
460+
bsmi.resolve();
461+
Assert.assertNotNull(bsmi.lookup());
462+
}
426463
}
427464

428465
private static void checkBsmName(CondyType condyType, String bsm) {

0 commit comments

Comments
 (0)