8203480: IncompatibleClassChangeError thrown at sites linked to default interface methods
Reviewed-by: kvn
This commit is contained in:
parent
ff7db9b11a
commit
ddc42415c0
src/hotspot/share
test/hotspot/jtreg/compiler/jsr292/NonInlinedCall
@ -53,6 +53,9 @@
|
||||
diagnostic(bool, StressGCM, false, \
|
||||
"Randomize instruction scheduling in GCM") \
|
||||
\
|
||||
develop(bool, StressMethodHandleLinkerInlining, false, \
|
||||
"Stress inlining through method handle linkers") \
|
||||
\
|
||||
develop(intx, OptoPrologueNops, 0, \
|
||||
"Insert this many extra nop instructions " \
|
||||
"in the prologue of every nmethod") \
|
||||
|
@ -932,7 +932,7 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod*
|
||||
speculative_receiver_type = (receiver_type != NULL) ? receiver_type->speculative_type() : NULL;
|
||||
}
|
||||
CallGenerator* cg = C->call_generator(target, vtable_index, call_does_dispatch, jvms,
|
||||
true /* allow_inline */,
|
||||
!StressMethodHandleLinkerInlining /* allow_inline */,
|
||||
PROB_ALWAYS,
|
||||
speculative_receiver_type);
|
||||
return cg;
|
||||
|
@ -1082,6 +1082,7 @@ Handle SharedRuntime::find_callee_info_helper(JavaThread* thread,
|
||||
|
||||
Bytecode_invoke bytecode(caller, bci);
|
||||
int bytecode_index = bytecode.index();
|
||||
bc = bytecode.invoke_code();
|
||||
|
||||
methodHandle attached_method = extract_attached_method(vfst);
|
||||
if (attached_method.not_null()) {
|
||||
@ -1095,6 +1096,11 @@ Handle SharedRuntime::find_callee_info_helper(JavaThread* thread,
|
||||
|
||||
// Adjust invocation mode according to the attached method.
|
||||
switch (bc) {
|
||||
case Bytecodes::_invokevirtual:
|
||||
if (attached_method->method_holder()->is_interface()) {
|
||||
bc = Bytecodes::_invokeinterface;
|
||||
}
|
||||
break;
|
||||
case Bytecodes::_invokeinterface:
|
||||
if (!attached_method->method_holder()->is_interface()) {
|
||||
bc = Bytecodes::_invokevirtual;
|
||||
@ -1110,10 +1116,10 @@ Handle SharedRuntime::find_callee_info_helper(JavaThread* thread,
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bc = bytecode.invoke_code();
|
||||
}
|
||||
|
||||
assert(bc != Bytecodes::_illegal, "not initialized");
|
||||
|
||||
bool has_receiver = bc != Bytecodes::_invokestatic &&
|
||||
bc != Bytecodes::_invokedynamic &&
|
||||
bc != Bytecodes::_invokehandle;
|
||||
|
@ -52,10 +52,12 @@ import static jdk.test.lib.Asserts.assertEquals;
|
||||
public class InvokeTest {
|
||||
static MethodHandles.Lookup LOOKUP = MethodHandleHelper.IMPL_LOOKUP;
|
||||
|
||||
static final MethodHandle virtualMH; // invokevirtual T.f1
|
||||
static final MethodHandle staticMH; // invokestatic T.f2
|
||||
static final MethodHandle intfMH; // invokeinterface I.f1
|
||||
static final MethodHandle specialMH; // invokespecial T.f4 T
|
||||
static final MethodHandle virtualMH; // invokevirtual T.f1
|
||||
static final MethodHandle staticMH; // invokestatic T.f2
|
||||
static final MethodHandle intfMH; // invokeinterface I.f3
|
||||
static final MethodHandle defaultMH; // invokevirtual T.f3
|
||||
static final MethodHandle specialMH; // invokespecial T.f4 T
|
||||
static final MethodHandle privateMH; // invokespecial I.f4 T
|
||||
static final MethodHandle basicMH;
|
||||
|
||||
static final WhiteBox WB = WhiteBox.getWhiteBox();
|
||||
@ -69,7 +71,9 @@ public class InvokeTest {
|
||||
virtualMH = LOOKUP.findVirtual(T.class, "f1", mtype);
|
||||
staticMH = LOOKUP.findStatic (T.class, "f2", mtype);
|
||||
intfMH = LOOKUP.findVirtual(I.class, "f3", mtype);
|
||||
defaultMH = LOOKUP.findVirtual(T.class, "f3", mtype);
|
||||
specialMH = LOOKUP.findSpecial(T.class, "f4", mtype, T.class);
|
||||
privateMH = LOOKUP.findSpecial(I.class, "f4", mtype, I.class);
|
||||
basicMH = NonInlinedReinvoker.make(staticMH);
|
||||
} catch (Exception e) {
|
||||
throw new Error(e);
|
||||
@ -92,24 +96,51 @@ public class InvokeTest {
|
||||
@DontInline public Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return P2.class; }
|
||||
}
|
||||
|
||||
static interface I {
|
||||
interface I {
|
||||
@DontInline default Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return I.class; }
|
||||
@DontInline private Class<?> f4() { if (doDeopt) WB.deoptimizeAll(); return I.class; }
|
||||
}
|
||||
|
||||
interface J1 extends I {
|
||||
@DontInline default Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return J1.class; }
|
||||
}
|
||||
|
||||
interface J2 extends I {
|
||||
@DontInline default Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return J2.class; }
|
||||
}
|
||||
|
||||
interface J3 extends I {
|
||||
@DontInline default Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return J3.class; }
|
||||
}
|
||||
|
||||
static class Q1 extends T implements J1 {}
|
||||
static class Q2 extends T implements J2 {}
|
||||
static class Q3 extends T implements J3 {}
|
||||
|
||||
@DontInline
|
||||
static void linkToVirtual(Object obj, Class<?> extecpted) {
|
||||
static void linkToVirtual(T recv, Class<?> expected) {
|
||||
try {
|
||||
Class<?> cls = (Class<?>)virtualMH.invokeExact((T)obj);
|
||||
assertEquals(cls, obj.getClass());
|
||||
Class<?> cls = (Class<?>)virtualMH.invokeExact(recv);
|
||||
assertEquals(cls, expected);
|
||||
} catch (Throwable e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@DontInline
|
||||
static void linkToInterface(Object obj, Class<?> expected) {
|
||||
static void linkToVirtualDefault(T recv, Class<?> expected) {
|
||||
try {
|
||||
Class<?> cls = (Class<?>)intfMH.invokeExact((I)obj);
|
||||
Class<?> cls = (Class<?>)defaultMH.invokeExact(recv);
|
||||
assertEquals(cls, expected);
|
||||
} catch (Throwable e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@DontInline
|
||||
static void linkToInterface(I recv, Class<?> expected) {
|
||||
try {
|
||||
Class<?> cls = (Class<?>)intfMH.invokeExact(recv);
|
||||
assertEquals(cls, expected);
|
||||
} catch (Throwable e) {
|
||||
throw new Error(e);
|
||||
@ -127,15 +158,26 @@ public class InvokeTest {
|
||||
}
|
||||
|
||||
@DontInline
|
||||
static void linkToSpecial(Object obj, Class<?> expected) {
|
||||
static void linkToSpecial(T recv, Class<?> expected) {
|
||||
try {
|
||||
Class<?> cls = (Class<?>)specialMH.invokeExact((T)obj);
|
||||
Class<?> cls = (Class<?>)specialMH.invokeExact(recv);
|
||||
assertEquals(cls, expected);
|
||||
} catch (Throwable e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@DontInline
|
||||
static void linkToSpecialIntf(I recv, Class<?> expected) {
|
||||
try {
|
||||
Class<?> cls = (Class<?>)privateMH.invokeExact(recv);
|
||||
assertEquals(cls, expected);
|
||||
} catch (Throwable e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@DontInline
|
||||
static void invokeBasic() {
|
||||
try {
|
||||
@ -171,13 +213,33 @@ public class InvokeTest {
|
||||
|
||||
// Monomorphic case (optimized virtual call)
|
||||
run(() -> linkToVirtual(new T(), T.class));
|
||||
run(() -> linkToVirtualDefault(new T(), I.class));
|
||||
|
||||
// Megamorphic case (virtual call)
|
||||
Object[] recv = new Object[] { new T(), new P1(), new P2() };
|
||||
// Megamorphic case (optimized virtual call)
|
||||
run(() -> {
|
||||
for (Object r : recv) {
|
||||
linkToVirtual(r, r.getClass());
|
||||
}});
|
||||
linkToVirtual(new T() {}, T.class);
|
||||
linkToVirtual(new T() {}, T.class);
|
||||
linkToVirtual(new T() {}, T.class);
|
||||
});
|
||||
|
||||
run(() -> {
|
||||
linkToVirtualDefault(new T(){}, I.class);
|
||||
linkToVirtualDefault(new T(){}, I.class);
|
||||
linkToVirtualDefault(new T(){}, I.class);
|
||||
});
|
||||
|
||||
// Megamorphic case (virtual call), multiple implementations
|
||||
run(() -> {
|
||||
linkToVirtual(new T(), T.class);
|
||||
linkToVirtual(new P1(), P1.class);
|
||||
linkToVirtual(new P2(), P2.class);
|
||||
});
|
||||
|
||||
run(() -> {
|
||||
linkToVirtualDefault(new Q1(), J1.class);
|
||||
linkToVirtualDefault(new Q2(), J2.class);
|
||||
linkToVirtualDefault(new Q3(), J3.class);
|
||||
});
|
||||
}
|
||||
|
||||
static void testInterface() {
|
||||
@ -190,17 +252,18 @@ public class InvokeTest {
|
||||
run(() -> linkToInterface(new T(), I.class));
|
||||
|
||||
// Megamorphic case (virtual call)
|
||||
Object[][] recv = new Object[][] {{new T(), I.class}, {new P1(), P1.class}, {new P2(), P2.class}};
|
||||
run(() -> {
|
||||
for (Object[] r : recv) {
|
||||
linkToInterface(r[0], (Class<?>)r[1]);
|
||||
}});
|
||||
linkToInterface(new T(), I.class);
|
||||
linkToInterface(new P1(), P1.class);
|
||||
linkToInterface(new P2(), P2.class);
|
||||
});
|
||||
}
|
||||
|
||||
static void testSpecial() {
|
||||
System.out.println("linkToSpecial");
|
||||
// Monomorphic case (optimized virtual call)
|
||||
run(() -> linkToSpecial(new T(), T.class));
|
||||
run(() -> linkToSpecialIntf(new T(), I.class));
|
||||
}
|
||||
|
||||
static void testStatic() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user