diff options
author | 2024-10-30 15:35:14 +0000 | |
---|---|---|
committer | 2024-11-06 16:24:17 +0000 | |
commit | cc22b57fd30005bdb03495412408a56c7ba08fb6 (patch) | |
tree | d46d259e79dba7d6a481a579fd9420b6c2d8d451 | |
parent | 52f22d080cc077eaf11a1c32bb07f87339343cd4 (diff) |
Don't virtual dispatch non-copied method defined in an interface.
Following what Class::FindVirtualMethodForVirtualOrInterface does.
Currently findVirtual sets MH's kind to INVOKE_INTERFACE only if
class on which lookup is done is interface.
Bug: 297147201
Test: ./art/test/testrunner/testrunner.py -b --host --64
Change-Id: Ib2576f317f7932111a05e464334de69a00e24ca1
-rw-r--r-- | compiler/optimizing/intrinsics_x86_64.cc | 26 | ||||
-rw-r--r-- | test/2277-methodhandle-invokeexact/src/Main.java | 144 |
2 files changed, 157 insertions, 13 deletions
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc index 38954c8fa1..5e7c3a9611 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -163,7 +163,7 @@ class InvokePolymorphicSlowPathX86_64 : public SlowPathCode { SaveLiveRegisters(codegen, instruction_->GetLocations()); // Passing `MethodHandle` object as hidden argument. - __ movq(CpuRegister(RDI), method_handle_); + __ movl(CpuRegister(RDI), method_handle_); x86_64_codegen->InvokeRuntime(QuickEntrypointEnum::kQuickInvokePolymorphicWithHiddenReceiver, instruction_, instruction_->GetDexPc()); @@ -4279,10 +4279,28 @@ void IntrinsicCodeGeneratorX86_64::VisitMethodHandleInvokeExact(HInvoke* invoke) __ testl(Address(method, ArtMethod::AccessFlagsOffset()), Immediate(kAccPrivate)); __ j(kNotZero, &execute_target_method); - CpuRegister vtable_index = locations->GetTemp(0).AsRegister<CpuRegister>(); + Label do_virtual_dispatch; + CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>(); + + __ movl(temp, Address(method, ArtMethod::DeclaringClassOffset())); + __ cmpl(temp, Address(receiver, mirror::Object::ClassOffset())); + // If method is defined in the receiver's class, execute it as it is. + __ j(kEqual, &execute_target_method); + + __ testl(Address(temp, mirror::Class::AccessFlagsOffset()), Immediate(kAccInterface)); + // If `method`'s declaring class is not an interface, do virtual dispatch. + __ j(kZero, &do_virtual_dispatch); + + __ movl(temp, Address(method, ArtMethod::AccessFlagsOffset())); + // These flags are uint32_t and their signed value doesn't fit into int32_t (see b/377275405). + __ andl(temp, Immediate(bit_cast<int32_t, uint32_t>(kAccIntrinsic | kAccCopied))); + __ cmpl(temp, Immediate(kAccCopied)); + // If method is defined in an interface and is not copied it should be interface dispatched. + __ j(kNotEqual, slow_path->GetEntryLabel()); + __ Bind(&do_virtual_dispatch); // MethodIndex is uint16_t. - __ movzxw(vtable_index, Address(method, ArtMethod::MethodIndexOffset())); + __ movzxw(temp, Address(method, ArtMethod::MethodIndexOffset())); constexpr uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); // Re-using method register for receiver class. @@ -4290,7 +4308,7 @@ void IntrinsicCodeGeneratorX86_64::VisitMethodHandleInvokeExact(HInvoke* invoke) constexpr uint32_t vtable_offset = mirror::Class::EmbeddedVTableOffset(art::PointerSize::k64).Int32Value(); - __ movq(method, Address(method, vtable_index, TIMES_8, vtable_offset)); + __ movq(method, Address(method, temp, TIMES_8, vtable_offset)); __ Jump(&execute_target_method); } __ Bind(&static_dispatch); diff --git a/test/2277-methodhandle-invokeexact/src/Main.java b/test/2277-methodhandle-invokeexact/src/Main.java index bb8c5fec01..a34e5eef60 100644 --- a/test/2277-methodhandle-invokeexact/src/Main.java +++ b/test/2277-methodhandle-invokeexact/src/Main.java @@ -33,6 +33,8 @@ public class Main { Multi.$noinline$testMHFromMain(OPTIONAL_GET); $noinline$testWithArgs(); $noinline$nullchecks(); + $noinline$interfaceChecks(); + $noinline$abstractClass(); } private static void $noinline$nullchecks() throws Throwable { @@ -47,6 +49,16 @@ public class Main { } catch (WrongMethodTypeException expected) {} try { + INTERFACE_DEFAULT_METHOD.invokeExact((I) null); + unreachable("Receiver is null, should throw NPE"); + } catch (NullPointerException expected) {} + + try { + INTERFACE_DEFAULT_METHOD.invokeExact((A) null); + unreachable("Should throw WMTE: input is of wrong type"); + } catch (WrongMethodTypeException expected) {} + + try { MethodHandle mh = null; mh.invokeExact(); unreachable("MethodHandle object is null, should throw NPE"); @@ -160,6 +172,56 @@ public class Main { assertEquals(55L, lsum); } + private static void $noinline$interfaceChecks() throws Throwable { + FooBarImpl instance = new FooBarImpl(); + + String result = null; + result = (String) FOO_NONDEFAULT.invokeExact((Foo) instance); + assertEquals("FooBarImpl.nonDefault", result); + + result = (String) FOOBARIMPL_NONDEFAULT.invokeExact(instance); + assertEquals("FooBarImpl.nonDefault", result); + + result = (String) BAR_DEFAULT.invokeExact((Bar) instance); + assertEquals("Bar.defaultToOverride", result); + + result = (String) FOO_DEFAULT.invokeExact((Foo) instance); + assertEquals("Bar.defaultToOverride", result); + + result = (String) FOOBARIMPL_DEFAULT.invokeExact(instance); + assertEquals("Bar.defaultToOverride", result); + + result = (String) FOO_NONOVERRIDDEN_DEFAULT.invokeExact((Foo) instance); + assertEquals("Foo.nonOverriddenDefault", result); + + result = (String) BAR_NONOVERRIDDEN_DEFAULT.invokeExact((Bar) instance); + assertEquals("Foo.nonOverriddenDefault", result); + } + + private static void $noinline$abstractClass() throws Throwable { + FooBarImpl instance = new FooBarImpl(); + + String result = null; + result = (String) FOOBAR_DEFINEDINABSTRACT.invokeExact((FooBar) instance); + assertEquals("FooBar.definedInAbstract", result); + + result = (String) FOOBARIMPL_DEFINEDINABSTRACT.invokeExact(instance); + assertEquals("FooBar.definedInAbstract", result); + + FooBar fooBar = new FooBar() { + @Override + public String nonDefault() { + return "anonymous.nonDefault"; + } + }; + + result = (String) FOOBAR_DEFINEDINABSTRACT.invokeExact(fooBar); + assertEquals("FooBar.definedInAbstract", result); + + result = (String) FOOBAR_NONDEFAULT.invokeExact(fooBar); + assertEquals("anonymous.nonDefault", result); + } + private static void assertEquals(Object expected, Object actual) { if (!Objects.equals(expected, actual)) { throw new AssertionError("Expected: " + expected + ", got: " + actual); @@ -217,6 +279,17 @@ public class Main { private static final MethodHandle SUM_4IJ; private static final MethodHandle SUM_5IJ; + private static final MethodHandle FOO_NONDEFAULT; + private static final MethodHandle FOOBARIMPL_NONDEFAULT; + private static final MethodHandle FOO_DEFAULT; + private static final MethodHandle BAR_DEFAULT; + private static final MethodHandle FOOBAR_DEFINEDINABSTRACT; + private static final MethodHandle FOOBAR_NONDEFAULT; + private static final MethodHandle FOOBARIMPL_DEFINEDINABSTRACT; + private static final MethodHandle FOOBARIMPL_DEFAULT; + private static final MethodHandle FOO_NONOVERRIDDEN_DEFAULT; + private static final MethodHandle BAR_NONOVERRIDDEN_DEFAULT; + static { try { VOID_METHOD = MethodHandles.lookup() @@ -263,27 +336,48 @@ public class Main { SUM_10I = MethodHandles.lookup() .findVirtual(Sums.class, "sum", methodType(int.class, repeat(10, int.class))); - SUM_IJ = MethodHandles.lookup() + SUM_IJ = MethodHandles.lookup() .findVirtual(Sums.class, "sum", methodType(long.class, int.class, long.class)); SUM_2IJ = MethodHandles.lookup() .findVirtual(Sums.class, "sum", methodType(long.class, repeat(2, int.class, long.class))); - SUM_3IJ = MethodHandles.lookup() + SUM_3IJ = MethodHandles.lookup() .findVirtual(Sums.class, "sum", methodType(long.class, repeat(3, int.class, long.class))); - SUM_4IJ = MethodHandles.lookup() + SUM_4IJ = MethodHandles.lookup() .findVirtual(Sums.class, "sum", methodType(long.class, repeat(4, int.class, long.class))); - SUM_5IJ = MethodHandles.lookup() + SUM_5IJ = MethodHandles.lookup() .findVirtual(Sums.class, "sum", methodType(long.class, repeat(5, int.class, long.class))); - } catch (Exception e) { - throw new RuntimeException(e); - } + + FOO_NONDEFAULT = MethodHandles.lookup() + .findVirtual(Foo.class, "nonDefault", methodType(String.class)); + FOOBARIMPL_NONDEFAULT = MethodHandles.lookup() + .findVirtual(FooBarImpl.class, "nonDefault", methodType(String.class)); + FOO_DEFAULT = MethodHandles.lookup() + .findVirtual(Foo.class, "defaultToOverride", methodType(String.class)); + BAR_DEFAULT = MethodHandles.lookup() + .findVirtual(Bar.class, "defaultToOverride", methodType(String.class)); + FOOBAR_DEFINEDINABSTRACT = MethodHandles.lookup() + .findVirtual(FooBar.class, "definedInAbstract", methodType(String.class)); + FOOBAR_NONDEFAULT = MethodHandles.lookup() + .findVirtual(FooBar.class, "nonDefault", methodType(String.class)); + FOOBARIMPL_DEFINEDINABSTRACT = MethodHandles.lookup() + .findVirtual(FooBarImpl.class, "definedInAbstract", methodType(String.class)); + FOOBARIMPL_DEFAULT = MethodHandles.lookup() + .findVirtual(FooBarImpl.class, "defaultToOverride", methodType(String.class)); + FOO_NONOVERRIDDEN_DEFAULT = MethodHandles.lookup() + .findVirtual(Foo.class, "nonOverriddenDefault", methodType(String.class)); + BAR_NONOVERRIDDEN_DEFAULT = MethodHandles.lookup() + .findVirtual(Bar.class, "nonOverriddenDefault", methodType(String.class)); + } catch (Exception e) { + throw new RuntimeException(e); + } } private static Class<?>[] repeat(int times, Class<?> clazz) { @@ -301,6 +395,40 @@ public class Main { return classes; } + static interface Foo { + default String defaultToOverride() { + return "Foo.defaultToOverride"; + } + + default String nonOverriddenDefault() { + return "Foo.nonOverriddenDefault"; + } + + String nonDefault(); + } + + static interface Bar extends Foo { + @Override + default String defaultToOverride() { + return "Bar.defaultToOverride"; + } + } + + static abstract class FooBar implements Foo, Bar { + public String definedInAbstract() { + return "FooBar.definedInAbstract"; + } + } + + static class FooBarImpl extends FooBar { + @Override + public String nonDefault() { + return "FooBarImpl.nonDefault"; + } + } + + static class MyRuntimeException extends RuntimeException {} + static interface I { public default void defaultMethod() { STATUS = "I.defaultMethod"; @@ -315,8 +443,6 @@ public class Main { } } - static class MyRuntimeException extends RuntimeException {} - static class A extends B implements I { public int field; public void voidMethod() { |