diff options
author | 2024-11-07 10:01:49 +0000 | |
---|---|---|
committer | 2024-11-12 14:27:31 +0000 | |
commit | 3051a5e03f32ca7aaae6041025ec60f90d41e34c (patch) | |
tree | 6d253e5c533e032ef1a43a914410d32f7e31081a /test/2277-methodhandle-invokeexact/src/AbstractInvokeExactTest.java | |
parent | 20cdc427d5f5875c2d58f9fde775957ad2e28cfd (diff) |
Remove now unnecessary checks from invokeExact intrinsic.
Also rewrote tests to make sure that MethodHandle-s created via
const-method-handle and Java API behave identically. They can
be slightly different even if lookup is done in the same class
for the same method as const-method-handle can target copied
methods.
Bug: 297147201
Test: ./art/test/testrunner/testrunner.py -b --host --64
Test: ./art/test/testrunner/testrunner.py -b --jvm
Change-Id: I69cdf2c44f2838ee0e57eaa2e93a6ed5276c39fb
Diffstat (limited to 'test/2277-methodhandle-invokeexact/src/AbstractInvokeExactTest.java')
-rw-r--r-- | test/2277-methodhandle-invokeexact/src/AbstractInvokeExactTest.java | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/test/2277-methodhandle-invokeexact/src/AbstractInvokeExactTest.java b/test/2277-methodhandle-invokeexact/src/AbstractInvokeExactTest.java new file mode 100644 index 0000000000..569bff61b2 --- /dev/null +++ b/test/2277-methodhandle-invokeexact/src/AbstractInvokeExactTest.java @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.WrongMethodTypeException; +import java.util.Objects; + +public abstract class AbstractInvokeExactTest { + + public static String STATUS = ""; + + public final void runAll() throws Throwable { + STATUS = ""; + Multi.$noinline$testMHFromMain(optionalGet()); + $noinline$privateMethods(); + $noinline$testNoArgsCalls(); + $noinline$nullchecks(); + $noinline$testWithArgs(); + $noinline$interfaceChecks(); + $noinline$abstractClass(); + } + + // There is no privateLookupIn for const-method-handle. + abstract void $noinline$privateMethods() throws Throwable; + + private void $noinline$testNoArgsCalls() throws Throwable { + voidMethod().invokeExact(new A()); + assertEquals("A.voidMethod", STATUS); + + int returnedInt = (int) returnInt().invokeExact(new A()); + assertEquals(42, returnedInt); + + double returnedDouble = (double) returnDouble().invokeExact(new A()); + assertEquals(42.0d, returnedDouble); + try { + interfaceDefaultMethod().invokeExact(new A()); + unreachable("MethodHandle's type is (Main$I)V, but callsite is (Main$A)V"); + } catch (WrongMethodTypeException expected) {} + + interfaceDefaultMethod().invokeExact((I) new A()); + assertEquals("I.defaultMethod", STATUS); + + overwrittenInterfaceDefaultMethod().invokeExact((I) new A()); + assertEquals("A.overrideMe", STATUS); + + + try { + exceptionThrowingMethod().invokeExact(new A()); + unreachable("Target method always throws"); + } catch (MyRuntimeException expected) { + assertEquals("A.throwException", STATUS); + } + + try { + returnInt().invokeExact(new A()); + unreachable("MethodHandle's type is (Main$A)I, but callsite type is (Main$A)V"); + } catch (WrongMethodTypeException expected) {} + + String returnedString = (String) staticMethod().invokeExact(new A()); + assertEquals("staticMethod", returnedString); + } + + private void $noinline$nullchecks() throws Throwable { + try { + voidMethod().invokeExact((A) null); + unreachable("Receiver is null, should throw NPE"); + } catch (NullPointerException expected) {} + + try { + voidMethod().invokeExact((Main) null); + unreachable("Should throw WMTE: input is of wrong type"); + } catch (WrongMethodTypeException expected) {} + + try { + interfaceDefaultMethod().invokeExact((I) null); + unreachable("Receiver is null, should throw NPE"); + } catch (NullPointerException expected) {} + + try { + interfaceDefaultMethod().invokeExact((A) null); + unreachable("Should throw WMTE: input is of wrong type"); + } catch (WrongMethodTypeException expected) {} + + try { + MethodHandle mh = $noinline$nullMethodHandle(); + mh.invokeExact(); + unreachable("MethodHandle object is null, should throw NPE"); + } catch (NullPointerException expected) {} + } + + private static MethodHandle $noinline$nullMethodHandle() { + return null; + } + + private void $noinline$testWithArgs() throws Throwable { + int sum = (int) sumI().invokeExact(new Sums(), 1); + assertEquals(1, sum); + + sum = (int) sum2I().invokeExact(new Sums(), 1, 2); + assertEquals(3, sum); + + sum = (int) sum3I().invokeExact(new Sums(), 1, 2, 3); + assertEquals(6, sum); + + sum = (int) sum4I().invokeExact(new Sums(), 1, 2, 3, 4); + assertEquals(10, sum); + + sum = (int) sum5I().invokeExact(new Sums(), 1, 2, 3, 4, 5); + assertEquals(15, sum); + + sum = (int) sum6I().invokeExact(new Sums(), 1, 2, 3, 4, 5, 6); + assertEquals(21, sum); + + sum = (int) sum7I().invokeExact(new Sums(), 1, 2, 3, 4, 5, 6, 7); + assertEquals(28, sum); + + sum = (int) sum8I().invokeExact(new Sums(), 1, 2, 3, 4, 5, 6, 7, 8); + assertEquals(36, sum); + + sum = (int) sum9I().invokeExact(new Sums(), 1, 2, 3, 4, 5, 6, 7, 8, 9); + assertEquals(45, sum); + + sum = (int) sum10I().invokeExact(new Sums(), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + assertEquals(55, sum); + + long lsum = (long) sumIJ().invokeExact(new Sums(), 1, 2L); + assertEquals(3L, lsum); + + lsum = (long) sum2IJ().invokeExact(new Sums(), 1, 2L, 3, 4L); + assertEquals(10L, lsum); + + lsum = (long) sum3IJ().invokeExact(new Sums(), 1, 2L, 3, 4L, 5, 6L); + assertEquals(21L, lsum); + + lsum = (long) sum4IJ().invokeExact(new Sums(), 1, 2L, 3, 4L, 5, 6L, 7, 8L); + assertEquals(36L, lsum); + + lsum = (long) sum5IJ().invokeExact(new Sums(), 1, 2L, 3, 4L, 5, 6L, 7, 8L, 9, 10L); + assertEquals(55L, lsum); + } + + private void $noinline$interfaceChecks() throws Throwable { + FooBarImpl instance = new FooBarImpl(); + + String result = null; + result = (String) fooNonDefault().invokeExact((Foo) instance); + assertEquals("FooBarImpl.nonDefault", result); + + result = (String) fooBarImplNonDefault().invokeExact(instance); + assertEquals("FooBarImpl.nonDefault", result); + + result = (String) barDefault().invokeExact((Bar) instance); + assertEquals("Bar.defaultToOverride", result); + + result = (String) fooDefault().invokeExact((Foo) instance); + assertEquals("Bar.defaultToOverride", result); + + result = (String) fooBarImplDefault().invokeExact(instance); + assertEquals("Bar.defaultToOverride", result); + + result = (String) fooNonOverriddenDefault().invokeExact((Foo) instance); + assertEquals("Foo.nonOverriddenDefault", result); + + result = (String) barNonOverriddenDefault().invokeExact((Bar) instance); + assertEquals("Foo.nonOverriddenDefault", result); + } + + private void $noinline$abstractClass() throws Throwable { + FooBarImpl instance = new FooBarImpl(); + + String result = null; + result = (String) fooBarDefinedInAbstract().invokeExact((FooBar) instance); + assertEquals("FooBar.definedInAbstract", result); + + result = (String) fooBarImplDefinedInAbstract().invokeExact(instance); + assertEquals("FooBar.definedInAbstract", result); + + FooBar fooBar = new FooBar() { + @Override + public String nonDefault() { + return "anonymous.nonDefault"; + } + }; + + result = (String) fooBarDefinedInAbstract().invokeExact(fooBar); + assertEquals("FooBar.definedInAbstract", result); + + result = (String) fooBarNonDefault().invokeExact(fooBar); + assertEquals("anonymous.nonDefault", result); + } + + static void assertEquals(Object expected, Object actual) { + if (!Objects.equals(expected, actual)) { + throw new AssertionError("Expected: " + expected + ", got: " + actual); + } + } + + private static void assertEquals(int expected, int actual) { + if (expected != actual) { + throw new AssertionError("Expected: " + expected + ", got: " + actual); + } + } + + private static void assertEquals(long expected, long actual) { + if (expected != actual) { + throw new AssertionError("Expected: " + expected + ", got: " + actual); + } + } + + private static void assertEquals(double expected, double actual) { + if (expected != actual) { + throw new AssertionError("Expected: " + expected + ", got: " + actual); + } + } + + static void unreachable(String msg) { + throw new AssertionError("Unexpectedly reached this point, but shouldn't: " + msg); + } + + public abstract MethodHandle optionalGet(); + + public abstract MethodHandle voidMethod(); + public abstract MethodHandle returnInt(); + public abstract MethodHandle returnDouble(); + public abstract MethodHandle interfaceDefaultMethod(); + public abstract MethodHandle overwrittenInterfaceDefaultMethod(); + public abstract MethodHandle exceptionThrowingMethod(); + public abstract MethodHandle staticMethod(); + + public abstract MethodHandle sumI(); + public abstract MethodHandle sum2I(); + public abstract MethodHandle sum3I(); + public abstract MethodHandle sum4I(); + public abstract MethodHandle sum5I(); + public abstract MethodHandle sum6I(); + public abstract MethodHandle sum7I(); + public abstract MethodHandle sum8I(); + public abstract MethodHandle sum9I(); + public abstract MethodHandle sum10I(); + public abstract MethodHandle sumIJ(); + public abstract MethodHandle sum2IJ(); + public abstract MethodHandle sum3IJ(); + public abstract MethodHandle sum4IJ(); + public abstract MethodHandle sum5IJ(); + + public abstract MethodHandle fooNonDefault(); + public abstract MethodHandle fooBarImplNonDefault(); + public abstract MethodHandle barDefault(); + public abstract MethodHandle fooDefault(); + public abstract MethodHandle fooBarImplDefault(); + public abstract MethodHandle fooNonOverriddenDefault(); + public abstract MethodHandle barNonOverriddenDefault(); + + public abstract MethodHandle fooBarDefinedInAbstract(); + public abstract MethodHandle fooBarImplDefinedInAbstract(); + public abstract MethodHandle fooBarNonDefault(); +} |