Skip to content

Commit 0299364

Browse files
committed
8314249: Refactor handling of invokedynamic in JVMCI ConstantPool
Reviewed-by: dnsimon, coleenp
1 parent 96778dd commit 0299364

File tree

6 files changed

+166
-68
lines changed

6 files changed

+166
-68
lines changed

src/hotspot/share/jvmci/jvmciCompilerToVM.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -906,9 +906,9 @@ C2V_VMENTRY_NULL(jobject, lookupKlassInPool, (JNIEnv* env, jobject, ARGUMENT_PAI
906906
return JVMCIENV->get_jobject(result);
907907
C2V_END
908908

909-
C2V_VMENTRY_NULL(jobject, lookupAppendixInPool, (JNIEnv* env, jobject, ARGUMENT_PAIR(cp), jint index))
909+
C2V_VMENTRY_NULL(jobject, lookupAppendixInPool, (JNIEnv* env, jobject, ARGUMENT_PAIR(cp), jint which))
910910
constantPoolHandle cp(THREAD, UNPACK_PAIR(ConstantPool, cp));
911-
oop appendix_oop = ConstantPool::appendix_at_if_loaded(cp, index);
911+
oop appendix_oop = ConstantPool::appendix_at_if_loaded(cp, which);
912912
return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(appendix_oop));
913913
C2V_END
914914

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -560,14 +560,17 @@ int constantPoolRemapInstructionOperandFromCache(HotSpotConstantPool constantPoo
560560
private native int constantPoolRemapInstructionOperandFromCache(HotSpotConstantPool constantPool, long constantPoolPointer, int cpci);
561561

562562
/**
563-
* Gets the appendix object (if any) associated with the entry at index {@code cpi} in
564-
* {@code constantPool}.
563+
* Gets the appendix object (if any) associated with the entry identified by {@code which}.
564+
*
565+
* @param which if negative, is treated as an encoded indy index for INVOKEDYNAMIC;
566+
* Otherwise, it's treated as a constant pool cache index (returned by HotSpotConstantPool::rawIndexToConstantPoolCacheIndex)
567+
* for INVOKE{VIRTUAL,SPECIAL,STATIC,INTERFACE}.
565568
*/
566-
HotSpotObjectConstantImpl lookupAppendixInPool(HotSpotConstantPool constantPool, int cpi) {
567-
return lookupAppendixInPool(constantPool, constantPool.getConstantPoolPointer(), cpi);
569+
HotSpotObjectConstantImpl lookupAppendixInPool(HotSpotConstantPool constantPool, int which) {
570+
return lookupAppendixInPool(constantPool, constantPool.getConstantPoolPointer(), which);
568571
}
569572

570-
private native HotSpotObjectConstantImpl lookupAppendixInPool(HotSpotConstantPool constantPool, long constantPoolPointer, int cpi);
573+
private native HotSpotObjectConstantImpl lookupAppendixInPool(HotSpotConstantPool constantPool, long constantPoolPointer, int which);
571574

572575
/**
573576
* Installs the result of a compilation into the code cache.

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

Lines changed: 43 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,19 @@
4747

4848
/**
4949
* Implementation of {@link ConstantPool} for HotSpot.
50+
*
51+
* The following convention is used in the jdk.vm.ci.hotspot package when accessing the ConstantPool with an index:
52+
* <ul>
53+
* <li>rawIndex - Index in the bytecode stream after the opcode (could be rewritten for some opcodes)</li>
54+
* <li>cpi - The constant pool index (as specified in JVM Spec)</li>
55+
* <li>cpci - The constant pool cache index, used only by the four bytecodes INVOKE{VIRTUAL,SPECIAL,STATIC,INTERFACE}.
56+
* It's the same as {@code rawIndex + HotSpotVMConfig::constantPoolCpCacheIndexTag}. </li>
57+
* <li>which - May be either a {@code rawIndex} or a {@code cpci}.</li>
58+
* </ul>
59+
*
60+
* Note that {@code cpci} and {@code which} are used only in the HotSpot-specific implementation. They
61+
* are not used by the public interface in jdk.vm.ci.meta.*.
62+
* After JDK-8301993, all uses of {@code cpci} and {@code which} will be replaced with {@code rawIndex}.
5063
*/
5164
public final class HotSpotConstantPool implements ConstantPool, MetaspaceHandleObject {
5265

@@ -252,25 +265,15 @@ private HotSpotResolvedObjectType getHolder() {
252265
* @return constant pool cache index
253266
*/
254267
private static int rawIndexToConstantPoolCacheIndex(int rawIndex, int opcode) {
255-
int index;
256-
if (opcode == Bytecodes.INVOKEDYNAMIC) {
257-
index = rawIndex;
258-
// See: ConstantPool::is_invokedynamic_index
259-
if (index >= 0) {
260-
throw new IllegalArgumentException("not an invokedynamic constant pool index " + index);
261-
}
268+
if (opcode == Bytecodes.INVOKEINTERFACE ||
269+
opcode == Bytecodes.INVOKEVIRTUAL ||
270+
opcode == Bytecodes.INVOKESPECIAL ||
271+
opcode == Bytecodes.INVOKESTATIC) {
272+
return rawIndex + config().constantPoolCpCacheIndexTag;
262273
} else {
263-
if (opcode == Bytecodes.INVOKEINTERFACE ||
264-
opcode == Bytecodes.INVOKEVIRTUAL ||
265-
opcode == Bytecodes.INVOKESPECIAL ||
266-
opcode == Bytecodes.INVOKESTATIC) {
267-
index = rawIndex + config().constantPoolCpCacheIndexTag;
268-
} else {
269-
throw new IllegalArgumentException("unexpected opcode " + opcode);
270-
271-
}
274+
// Only the above 4 bytecodes use ConstantPoolCacheIndex
275+
throw new IllegalArgumentException("unexpected opcode " + opcode);
272276
}
273-
return index;
274277
}
275278

276279
/**
@@ -581,8 +584,8 @@ private static String argumentAsString(JavaConstant arg) {
581584
}
582585

583586
@Override
584-
public BootstrapMethodInvocation lookupBootstrapMethodInvocation(int rawCpi, int opcode) {
585-
int cpi = opcode == -1 ? rawCpi : rawIndexToConstantPoolIndex(rawCpi, opcode);
587+
public BootstrapMethodInvocation lookupBootstrapMethodInvocation(int index, int opcode) {
588+
int cpi = opcode == -1 ? index : indyIndexConstantPoolIndex(index, opcode);
586589
final JvmConstant tag = getTagAt(cpi);
587590
switch (tag.name) {
588591
case "InvokeDynamic":
@@ -685,13 +688,19 @@ public Signature lookupSignature(int cpi) {
685688
}
686689

687690
@Override
688-
public JavaConstant lookupAppendix(int cpi, int opcode) {
691+
public JavaConstant lookupAppendix(int rawIndex, int opcode) {
689692
if (!Bytecodes.isInvoke(opcode)) {
690-
throw new IllegalArgumentException("expected an invoke bytecode at " + cpi + ", got " + opcode);
693+
throw new IllegalArgumentException("expected an invoke bytecode for " + rawIndex + ", got " + opcode);
691694
}
692695

693-
final int index = rawIndexToConstantPoolCacheIndex(cpi, opcode);
694-
return compilerToVM().lookupAppendixInPool(this, index);
696+
if (opcode == Bytecodes.INVOKEDYNAMIC) {
697+
if (!isInvokedynamicIndex(rawIndex)) {
698+
throw new IllegalArgumentException("expected a raw index for INVOKEDYNAMIC but got " + rawIndex);
699+
}
700+
return compilerToVM().lookupAppendixInPool(this, rawIndex);
701+
} else {
702+
return compilerToVM().lookupAppendixInPool(this, rawIndexToConstantPoolCacheIndex(rawIndex, opcode));
703+
}
695704
}
696705

697706
/**
@@ -709,19 +718,19 @@ private static JavaType getJavaType(final Object type) {
709718
}
710719

711720
@Override
712-
public JavaMethod lookupMethod(int cpi, int opcode, ResolvedJavaMethod caller) {
713-
final int index = rawIndexToConstantPoolCacheIndex(cpi, opcode);
714-
final HotSpotResolvedJavaMethod method = compilerToVM().lookupMethodInPool(this, index, (byte) opcode, (HotSpotResolvedJavaMethodImpl) caller);
721+
public JavaMethod lookupMethod(int rawIndex, int opcode, ResolvedJavaMethod caller) {
722+
final int cpci = rawIndexToConstantPoolCacheIndex(rawIndex, opcode);
723+
final HotSpotResolvedJavaMethod method = compilerToVM().lookupMethodInPool(this, cpci, (byte) opcode, (HotSpotResolvedJavaMethodImpl) caller);
715724
if (method != null) {
716725
return method;
717726
} else {
718727
// Get the method's name and signature.
719-
String name = getNameOf(index, opcode);
720-
HotSpotSignature signature = new HotSpotSignature(runtime(), getSignatureOf(index, opcode));
728+
String name = getNameOf(cpci, opcode);
729+
HotSpotSignature signature = new HotSpotSignature(runtime(), getSignatureOf(cpci, opcode));
721730
if (opcode == Bytecodes.INVOKEDYNAMIC) {
722731
return new UnresolvedJavaMethod(name, signature, runtime().getMethodHandleClass());
723732
} else {
724-
final int klassIndex = getKlassRefIndexAt(index, opcode);
733+
final int klassIndex = getKlassRefIndexAt(cpci, opcode);
725734
final Object type = compilerToVM().lookupKlassInPool(this, klassIndex);
726735
return new UnresolvedJavaMethod(name, signature, getJavaType(type));
727736
}
@@ -780,7 +789,6 @@ public JavaType lookupReferencedType(int rawIndex, int opcode) {
780789

781790
@Override
782791
public JavaField lookupField(int rawIndex, ResolvedJavaMethod method, int opcode) {
783-
final int cpi = compilerToVM().decodeFieldIndexToCPIndex(this, rawIndex);
784792
final int nameAndTypeIndex = getNameAndTypeRefIndexAt(rawIndex, opcode);
785793
final int typeIndex = getSignatureRefIndexAt(nameAndTypeIndex);
786794
String typeName = lookupUtf8(typeIndex);
@@ -813,32 +821,23 @@ public JavaField lookupField(int rawIndex, ResolvedJavaMethod method, int opcode
813821
}
814822

815823
/**
816-
* Converts a raw index from the bytecodes to a constant pool index (not a cache index).
824+
* Converts a raw index for the INVOKEDYNAMIC bytecode to a constant pool index.
817825
*
818826
* @param rawIndex index from the bytecode
819827
*
820-
* @param opcode bytecode to convert the index for
828+
* @param opcode bytecode to convert the index for. Must be INVOKEDYNAMIC.
821829
*
822830
* @return constant pool index
823831
*/
824-
public int rawIndexToConstantPoolIndex(int rawIndex, int opcode) {
832+
private int indyIndexConstantPoolIndex(int rawIndex, int opcode) {
825833
if (isInvokedynamicIndex(rawIndex)) {
826834
if (opcode != Bytecodes.INVOKEDYNAMIC) {
827835
throw new IllegalArgumentException("expected INVOKEDYNAMIC at " + rawIndex + ", got " + opcode);
828836
}
829837
return compilerToVM().decodeIndyIndexToCPIndex(this, rawIndex, false);
838+
} else {
839+
throw new IllegalArgumentException("expected a raw index for INVOKEDYNAMIC but got " + rawIndex);
830840
}
831-
if (opcode == Bytecodes.INVOKEDYNAMIC) {
832-
throw new IllegalArgumentException("unexpected INVOKEDYNAMIC at " + rawIndex);
833-
}
834-
if (opcode == Bytecodes.GETSTATIC ||
835-
opcode == Bytecodes.PUTSTATIC ||
836-
opcode == Bytecodes.GETFIELD ||
837-
opcode == Bytecodes.PUTFIELD) {
838-
return compilerToVM().decodeFieldIndexToCPIndex(this, rawIndex);
839-
}
840-
int index = rawIndexToConstantPoolCacheIndex(rawIndex, opcode);
841-
return compilerToVM().constantPoolRemapInstructionOperandFromCache(this, index);
842841
}
843842

844843
@Override

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

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -172,19 +172,21 @@ interface BootstrapMethodInvocation {
172172

173173
/**
174174
* Gets the details for invoking a bootstrap method associated with the
175-
* {@code CONSTANT_Dynamic_info} or {@code CONSTANT_InvokeDynamic_info} pool entry {@code cpi}
175+
* {@code CONSTANT_Dynamic_info} or {@code CONSTANT_InvokeDynamic_info} pool entry
176176
* in the constant pool.
177177
*
178-
* @param cpi a constant pool index
179-
* @param opcode the opcode of the instruction that has {@code cpi} as an operand or -1 if
180-
* {@code cpi} was not decoded from an instruction stream
181-
* @return the bootstrap method invocation details or {@code null} if the entry at {@code cpi}
178+
* @param index if {@code opcode} is -1, {@code index} is a constant pool index. Otherwise {@code opcode}
179+
* must be {@code Bytecodes.INVOKEDYNAMIC}, and {@code index} must be the operand of that
180+
* opcode in the bytecode stream (i.e., a {@code rawIndex}).
181+
* @param opcode must be {@code Bytecodes.INVOKEDYNAMIC}, or -1 if
182+
* {@code index} was not decoded from a bytecode stream
183+
* @return the bootstrap method invocation details or {@code null} if the entry specified by {@code index}
182184
* is not a {@code CONSTANT_Dynamic_info} or @{code CONSTANT_InvokeDynamic_info}
183185
* @throws IllegalArgumentException if the bootstrap method invocation makes use of
184186
* {@code java.lang.invoke.BootstrapCallInfo}
185187
* @jvms 4.7.23 The {@code BootstrapMethods} Attribute
186188
*/
187-
default BootstrapMethodInvocation lookupBootstrapMethodInvocation(int cpi, int opcode) {
189+
default BootstrapMethodInvocation lookupBootstrapMethodInvocation(int index, int opcode) {
188190
throw new UnsupportedOperationException();
189191
}
190192

@@ -242,10 +244,9 @@ default BootstrapMethodInvocation lookupBootstrapMethodInvocation(int cpi, int o
242244
/**
243245
* Looks up the appendix at the specified index.
244246
*
245-
* @param cpi the constant pool index
246-
* @param opcode the opcode of the instruction for which the lookup is being performed or
247-
* {@code -1}
247+
* @param rawIndex index in the bytecode stream after the {@code opcode} (could be rewritten for some opcodes)
248+
* @param opcode the opcode of the instruction for which the lookup is being performed
248249
* @return the appendix if it exists and is resolved or {@code null}
249250
*/
250-
JavaConstant lookupAppendix(int cpi, int opcode);
251+
JavaConstant lookupAppendix(int rawIndex, int opcode);
251252
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,8 @@ private static void assertNoEagerConstantResolution(Class<?> testClass, Constant
271271
private static void assertLookupBMIDoesNotInvokeBM(MetaAccessProvider metaAccess, Class<?> testClass) throws Exception {
272272
ResolvedJavaMethod shouldNotBeCalled = metaAccess.lookupJavaMethod(testClass.getDeclaredMethod("shouldNotBeCalled"));
273273
ConstantPool cp = shouldNotBeCalled.getConstantPool();
274-
int cpi = getFirstInvokedynamicOperand(shouldNotBeCalled);
275-
BootstrapMethodInvocation bmi = cp.lookupBootstrapMethodInvocation(cpi, INVOKEDYNAMIC);
274+
int rawIndex = getFirstInvokedynamicOperand(shouldNotBeCalled);
275+
BootstrapMethodInvocation bmi = cp.lookupBootstrapMethodInvocation(rawIndex, INVOKEDYNAMIC);
276276
Assert.assertEquals(bmi.getName(), "do_shouldNotBeCalled");
277277
Assert.assertEquals(bmi.getMethod().getName(), "shouldNotBeCalledBSM");
278278
}
@@ -408,8 +408,8 @@ private static int getFirstInvokedynamicOperand(ResolvedJavaMethod method) {
408408
* Ensures that loadReferencedType for an invokedynamic call site does not throw an exception.
409409
*/
410410
private static void testLoadReferencedType(ResolvedJavaMethod method, ConstantPool cp) {
411-
int cpi = getFirstInvokedynamicOperand(method);
412-
cp.loadReferencedType(cpi, INVOKEDYNAMIC, false);
411+
int rawIndex = getFirstInvokedynamicOperand(method);
412+
cp.loadReferencedType(rawIndex, INVOKEDYNAMIC, false);
413413
}
414414

415415
// @formatter:off

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

Lines changed: 98 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,15 @@
3737
*/
3838
package jdk.vm.ci.runtime.test;
3939

40+
import java.lang.invoke.MethodHandle;
41+
import java.lang.invoke.MethodHandles;
42+
import java.lang.invoke.MethodHandles.Lookup;
43+
import java.lang.invoke.MethodType;
44+
4045
import org.testng.Assert;
4146
import org.testng.annotations.Test;
4247

48+
import jdk.vm.ci.meta.JavaConstant;
4349
import jdk.vm.ci.meta.JavaField;
4450
import jdk.vm.ci.meta.JavaMethod;
4551
import jdk.vm.ci.meta.MetaAccessProvider;
@@ -82,9 +88,12 @@ static Object cloneObjectArray(Object[] arr) {
8288
return arr.clone();
8389
}
8490

85-
public static final int ALOAD_0 = 42; // 0x2A
86-
public static final int GETSTATIC = 178; // 0xB2
87-
public static final int INVOKEVIRTUAL = 182; // 0xB6
91+
public static final int ICONST_0 = 3;
92+
public static final int ALOAD_0 = 42;
93+
public static final int ALOAD_1 = 43;
94+
public static final int GETSTATIC = 178;
95+
public static final int INVOKEVIRTUAL = 182;
96+
public static final int INVOKEDYNAMIC = 186;
8897

8998
public static int beU2(byte[] data, int bci) {
9099
return ((data[bci] & 0xff) << 8) | (data[bci + 1] & 0xff);
@@ -94,6 +103,10 @@ public static int beU1(byte[] data, int bci) {
94103
return data[bci] & 0xff;
95104
}
96105

106+
public static int beS4(byte[] data, int bci) {
107+
return (data[bci] << 24) | ((data[bci + 1] & 0xff) << 16) | ((data[bci + 2] & 0xff) << 8) | (data[bci + 3] & 0xff);
108+
}
109+
97110
@Test
98111
public void lookupArrayCloneMethodTest() throws Exception {
99112
MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess();
@@ -138,4 +151,86 @@ public void lookupFieldTest() throws Exception {
138151
JavaField field = m.getConstantPool().lookupField(rawIndex, m, GETSTATIC);
139152
Assert.assertEquals("someStaticField", field.getName(), "Wrong field name; rawIndex = " + rawIndex + ";");
140153
}
154+
155+
static String concatString1(String a, String b) {
156+
return a + b;
157+
}
158+
159+
static String concatString2(String a, String b) {
160+
return a + b;
161+
}
162+
163+
static void invokeHandle(MethodHandle mh) throws Throwable {
164+
mh.invokeExact(0);
165+
}
166+
167+
static void intFunc(int t) {}
168+
169+
@Test
170+
public void lookupAppendixTest() throws Throwable {
171+
// We want at least two indy bytecodes -- with a single indy, the rawIndex is -1,
172+
// or 0xffffffff. Even if we load it with the wrong endianness, it will still come
173+
// "correctly" out as -1.
174+
concatString1("aaa", "bbb"); // force the indy to be resolved
175+
concatString2("aaa", "bbb"); // force the indy to be resolved
176+
177+
MethodHandles.Lookup lookup = MethodHandles.lookup();
178+
MethodType mt = MethodType.methodType(void.class, int.class);
179+
MethodHandle mh = lookup.findStatic(ConstantPoolTest.class, "intFunc", mt);
180+
invokeHandle(mh);
181+
182+
lookupAppendixTest_dynamic("concatString1");
183+
lookupAppendixTest_dynamic("concatString2");
184+
lookupAppendixTest_virtual();
185+
}
186+
187+
public void lookupAppendixTest_dynamic(String methodName) throws Exception {
188+
MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess();
189+
ResolvedJavaType type = metaAccess.lookupJavaType(ConstantPoolTest.class);
190+
Signature methodSig = metaAccess.parseMethodDescriptor("(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
191+
ResolvedJavaMethod m = type.findMethod(methodName, methodSig);
192+
Assert.assertNotNull(m);
193+
194+
// Expected:
195+
// aload_0;
196+
// aload_1;
197+
// invokedynamic ...StringConcatFactory.makeConcatWithConstants...
198+
byte[] bytecode = m.getCode();
199+
Assert.assertNotNull(bytecode);
200+
Assert.assertEquals(8, bytecode.length);
201+
Assert.assertEquals(ALOAD_0, beU1(bytecode, 0));
202+
Assert.assertEquals(ALOAD_1, beU1(bytecode, 1));
203+
Assert.assertEquals(INVOKEDYNAMIC, beU1(bytecode, 2));
204+
205+
// Note: internally HotSpot stores the indy index as a native int32, but m.getCode() byte-swaps all such
206+
// indices so they appear to be big-endian.
207+
int rawIndex = beS4(bytecode, 3);
208+
JavaConstant constant = m.getConstantPool().lookupAppendix(rawIndex, INVOKEDYNAMIC);
209+
Assert.assertTrue(constant.toString().startsWith("Object["), "wrong appendix: " + constant);
210+
}
211+
212+
public void lookupAppendixTest_virtual() throws Exception {
213+
MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess();
214+
ResolvedJavaType type = metaAccess.lookupJavaType(ConstantPoolTest.class);
215+
Signature methodSig = metaAccess.parseMethodDescriptor("(Ljava/lang/invoke/MethodHandle;)V");
216+
ResolvedJavaMethod m = type.findMethod("invokeHandle", methodSig);
217+
Assert.assertNotNull(m);
218+
219+
// Expected
220+
// aload_0
221+
// iconst_0
222+
// invokevirtual #rawIndex // Method java/lang/invoke/MethodHandle.invokeExact:(I)V
223+
byte[] bytecode = m.getCode();
224+
Assert.assertNotNull(bytecode);
225+
Assert.assertEquals(6, bytecode.length);
226+
Assert.assertEquals(ALOAD_0, beU1(bytecode, 0));
227+
Assert.assertEquals(ICONST_0, beU1(bytecode, 1));
228+
Assert.assertEquals(INVOKEVIRTUAL, beU1(bytecode, 2));
229+
230+
int rawIndex = beU2(bytecode, 3);
231+
//System.out.println("rawIndex = " + rawIndex);
232+
JavaConstant constant = m.getConstantPool().lookupAppendix(rawIndex, INVOKEVIRTUAL);
233+
//System.out.println("constant = " + constant);
234+
Assert.assertTrue(constant.toString().startsWith("Object["), "wrong appendix: " + constant);
235+
}
141236
}

0 commit comments

Comments
 (0)