| /* |
| * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. |
| * Copyright (c) 2018 SAP SE. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| /** |
| * @test |
| * @summary Check that the verbose message of the AME is printed correctly. |
| * @requires !(os.arch=="arm") & vm.flavor == "server" & !vm.emulatedClient & vm.compMode=="Xmixed" & (!vm.graal.enabled | vm.opt.TieredCompilation == true) & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel==4) |
| * @library /test/lib / |
| * @build sun.hotspot.WhiteBox |
| * @run driver ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission |
| * @compile AbstractMethodErrorTest.java |
| * @compile AME1_E.jasm AME2_C.jasm AME3_C.jasm AME4_E.jasm AME5_B.jasm AME6_B.jasm |
| * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI |
| * -XX:CompileThreshold=1000 -XX:-BackgroundCompilation -XX:-Inline |
| * -XX:CompileCommand=exclude,AbstractMethodErrorTest::test_ame1 |
| * AbstractMethodErrorTest |
| */ |
| |
| import sun.hotspot.WhiteBox; |
| import compiler.whitebox.CompilerWhiteBoxTest; |
| import java.lang.reflect.Method; |
| |
| // This test assembles an errorneous installation of classes. |
| // First, compile the test by @compile. This results in a legal set |
| // of classes. |
| // Then, with jasm, generate incompatible classes that overwrite |
| // the class files in the build directory. |
| // Last, call the real test throwing an AbstractMethodError and |
| // check the message generated. |
| public class AbstractMethodErrorTest { |
| |
| private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); |
| |
| private static boolean enableChecks = true; |
| |
| private static boolean compile(Class<?> clazz, String name) { |
| try { |
| Method method = clazz.getMethod(name); |
| boolean enqueued = WHITE_BOX.enqueueMethodForCompilation(method, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION); |
| if (!enqueued) { |
| System.out.println("Warning: Blocking compilation failed for " + clazz.getName() + "." + name + " (timeout?)"); |
| return false; |
| } else if (!WHITE_BOX.isMethodCompiled(method)) { |
| throw new RuntimeException(clazz.getName() + "." + name + " is not compiled"); |
| } |
| } catch (NoSuchMethodException e) { |
| throw new RuntimeException(clazz.getName() + "." + name + " not found", e); |
| } |
| return true; |
| } |
| |
| public static boolean setup_test() { |
| // Assure all exceptions are loaded. |
| new AbstractMethodError(); |
| new IncompatibleClassChangeError(); |
| |
| enableChecks = false; |
| // Warmup |
| System.out.println("warmup:"); |
| test_ame5_compiled_vtable_stub(); |
| test_ame6_compiled_itable_stub(); |
| enableChecks = true; |
| |
| // Compile |
| if (!compile(AbstractMethodErrorTest.class, "test_ame5_compiled_vtable_stub") || |
| !compile(AbstractMethodErrorTest.class, "test_ame6_compiled_itable_stub") || |
| !compile(AME5_C.class, "mc") || |
| !compile(AME5_D.class, "mc") || |
| !compile(AME5_E.class, "mc") || |
| !compile(AME6_C.class, "mc") || |
| !compile(AME6_D.class, "mc") || |
| !compile(AME6_E.class, "mc")) { |
| return false; |
| } |
| |
| System.out.println("warmup done."); |
| return true; |
| } |
| |
| private static String expectedErrorMessageAME1_1 = |
| "Missing implementation of resolved method 'abstract " + |
| "java.lang.String anAbstractMethod()' of abstract class AME1_B."; |
| private static String expectedErrorMessageAME1_2 = |
| "Receiver class AME1_E does not define or inherit an implementation of the " + |
| "resolved method 'abstract java.lang.String aFunctionOfMyInterface()' of " + |
| "interface AME1_C."; |
| |
| public static void test_ame1() { |
| AME1_B objectAbstract = new AME1_D(); |
| AME1_C objectInterface = new AME1_D(); |
| objectInterface.secondFunctionOfMyInterface(); |
| objectAbstract.anAbstractMethod(); |
| objectInterface.aFunctionOfMyInterface(); |
| |
| try { |
| objectAbstract = new AME1_E(); |
| // AbstractMethodError gets thrown in the interpreter at: |
| // InterpreterGenerator::generate_abstract_entry |
| objectAbstract.anAbstractMethod(); |
| throw new RuntimeException("Expected AbstractRuntimeError was not thrown."); |
| } catch (AbstractMethodError e) { |
| String errorMsg = e.getMessage(); |
| if (errorMsg == null) { |
| throw new RuntimeException("Caught AbstractMethodError with empty message."); |
| } else if (!errorMsg.equals(expectedErrorMessageAME1_1)) { |
| System.out.println("Expected: " + expectedErrorMessageAME1_1 + "\n" + |
| "but got: " + errorMsg); |
| throw new RuntimeException("Wrong error message of AbstractMethodError."); |
| } |
| } catch (RuntimeException e) { |
| throw e; |
| } catch (Throwable e) { |
| throw new RuntimeException("Caught unexpected exception: " + e); |
| } |
| |
| try { |
| objectInterface = new AME1_E(); |
| // AbstractMethodError gets thrown in: |
| // TemplateTable::invokeinterface or C-Interpreter loop |
| objectInterface.aFunctionOfMyInterface(); |
| throw new RuntimeException("Expected AbstractRuntimeError was not thrown."); |
| } catch (AbstractMethodError e) { |
| String errorMsg = e.getMessage(); |
| if (errorMsg == null) { |
| throw new RuntimeException("Caught AbstractMethodError with empty message."); |
| } else if (!errorMsg.equals(expectedErrorMessageAME1_2)) { |
| // Thrown via InterpreterRuntime::throw_AbstractMethodErrorVerbose(). |
| System.out.println("Expected: " + expectedErrorMessageAME1_2 + "\n" + |
| "but got: " + errorMsg); |
| throw new RuntimeException("Wrong error message of AbstractMethodError."); |
| } else { |
| System.out.println("Passed with message: " + errorMsg); |
| } |
| } catch (Throwable e) { |
| throw new RuntimeException("Caught unexpected exception: " + e); |
| } |
| } |
| |
| private static String expectedErrorMessageAME2_Interpreted = |
| "Missing implementation of resolved method 'abstract " + |
| "void aFunctionOfMyInterface()' of interface AME2_A."; |
| private static String expectedErrorMessageAME2_Compiled = |
| "Receiver class AME2_C does not define or inherit an implementation of the resolved method " + |
| "'abstract void aFunctionOfMyInterface()' of interface AME2_A."; |
| |
| public AbstractMethodErrorTest() throws InstantiationException, IllegalAccessException { |
| try { |
| AME2_B myAbstract = new ImplementsAllFunctions(); |
| myAbstract.fun2(); |
| myAbstract.aFunctionOfMyInterface(); |
| |
| // AME2_C does not implement the method |
| // aFunctionOfMyInterface(). Expected runtime behavior is |
| // throwing an AbstractMethodError. |
| // The error will be thrown via throw_AbstractMethodErrorWithMethod() |
| // if the template interpreter calls an abstract method by |
| // entering the abstract method entry. |
| myAbstract = new AME2_C(); |
| myAbstract.fun2(); |
| myAbstract.aFunctionOfMyInterface(); |
| } catch (SecurityException e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| // Loop so that method gets eventually compiled/osred. |
| public static void test_ame2() throws Exception { |
| boolean seenInterpreted = false; |
| boolean seenCompiled = false; |
| |
| // Loop to test both, the interpreted and the compiled case. |
| for (int i = 0; i < 10000 && !(seenInterpreted && seenCompiled); ++i) { |
| try { |
| // Supposed to throw AME with verbose message. |
| new AbstractMethodErrorTest(); |
| |
| throw new RuntimeException("Expected AbstractMethodError was not thrown."); |
| } catch (AbstractMethodError e) { |
| String errorMsg = e.getMessage(); |
| |
| // Check the message obtained. |
| if (errorMsg == null) { |
| throw new RuntimeException("Caught AbstractMethodError with empty message."); |
| } else if (errorMsg.equals(expectedErrorMessageAME2_Interpreted)) { |
| seenInterpreted = true; |
| } else if (errorMsg.equals(expectedErrorMessageAME2_Compiled)) { |
| // Sparc and the other platforms behave differently here: |
| // Sparc throws the exception via SharedRuntime::handle_wrong_method_abstract(), |
| // x86, ppc and s390 via LinkResolver::runtime_resolve_virtual_method(). Thus, |
| // sparc misses the test case for LinkResolver::runtime_resolve_virtual_method(). |
| seenCompiled = true; |
| } else { |
| System.out.println("Expected: " + expectedErrorMessageAME2_Interpreted + "\n" + |
| "or: " + expectedErrorMessageAME2_Compiled + "\n" + |
| "but got: " + errorMsg); |
| throw new RuntimeException("Wrong error message of AbstractMethodError."); |
| } |
| } |
| } |
| if (!(seenInterpreted && seenCompiled)) { |
| if (seenInterpreted) { System.out.println("Saw interpreted message."); } |
| if (seenCompiled) { System.out.println("Saw compiled message."); } |
| throw new RuntimeException("Test did not produce wrong error messages for AbstractMethodError, " + |
| "but it did not test both cases (interpreted and compiled)."); |
| } |
| } |
| |
| private static String expectedErrorMessageAME3_1 = |
| "Receiver class AME3_C does not define or inherit an implementation of the resolved method " + |
| "'void ma()' of class AME3_A. Selected method is 'abstract void AME3_B.ma()'."; |
| |
| // Testing abstract class that extends a class that has an implementation. |
| // Loop so that method gets eventually compiled/osred. |
| public static void test_ame3_1() throws Exception { |
| AME3_A c = new AME3_C(); |
| |
| try { |
| // Supposed to throw AME with verbose message. |
| c.ma(); |
| |
| throw new RuntimeException("Expected AbstractMethodError was not thrown."); |
| } catch (AbstractMethodError e) { |
| String errorMsg = e.getMessage(); |
| |
| // Check the message obtained. |
| if (errorMsg == null) { |
| throw new RuntimeException("Caught AbstractMethodError with empty message."); |
| } else if (errorMsg.equals(expectedErrorMessageAME3_1)) { |
| // Expected test case thrown via LinkResolver::runtime_resolve_virtual_method(). |
| System.out.println("Passed with message: " + errorMsg); |
| } else { |
| System.out.println("Expected: " + expectedErrorMessageAME3_1 + "\n" + |
| "but got: " + errorMsg); |
| throw new RuntimeException("Wrong error message of AbstractMethodError."); |
| } |
| } |
| } |
| |
| private static String expectedErrorMessageAME3_2 = |
| "Receiver class AME3_C does not define or inherit an implementation of " + |
| "the resolved method 'abstract void ma()' of abstract class AME3_B."; |
| |
| // Testing abstract class that extends a class that has an implementation. |
| // Loop so that method gets eventually compiled/osred. |
| public static void test_ame3_2() throws Exception { |
| AME3_C c = new AME3_C(); |
| |
| try { |
| // Supposed to throw AME with verbose message. |
| c.ma(); |
| |
| throw new RuntimeException("Expected AbstractMethodError was not thrown."); |
| } catch (AbstractMethodError e) { |
| String errorMsg = e.getMessage(); |
| |
| // Check the message obtained. |
| if (errorMsg == null) { |
| throw new RuntimeException("Caught AbstractMethodError with empty message."); |
| } else if (errorMsg.equals(expectedErrorMessageAME3_2)) { |
| // Expected test case thrown via LinkResolver::runtime_resolve_virtual_method(). |
| System.out.println("Passed with message: " + errorMsg); |
| } else { |
| System.out.println("Expected: " + expectedErrorMessageAME3_2 + "\n" + |
| "but got: " + errorMsg); |
| throw new RuntimeException("Wrong error message of AbstractMethodError."); |
| } |
| } |
| } |
| |
| private static String expectedErrorMessageAME4 = |
| "Missing implementation of resolved method 'abstract void ma()' of " + |
| "abstract class AME4_B."; |
| |
| // Testing abstract class that extends a class that has an implementation. |
| public static void test_ame4() throws Exception { |
| AME4_C c = new AME4_C(); |
| AME4_D d = new AME4_D(); |
| AME4_E e = new AME4_E(); // Errorneous. |
| |
| AME4_A a; |
| try { |
| // Test: calls errorneous e.ma() in the last iteration. |
| final int iterations = 10; |
| for (int i = 0; i < iterations; i++) { |
| a = e; |
| if (i % 2 == 0 && i < iterations - 1) { |
| a = c; |
| } |
| if (i % 2 == 1 && i < iterations - 1) { |
| a = d; |
| } |
| |
| // AbstractMethodError gets thrown in the interpreter at: |
| // InterpreterGenerator::generate_abstract_entry |
| a.ma(); |
| } |
| |
| throw new RuntimeException("Expected AbstractMethodError was not thrown."); |
| } catch (AbstractMethodError exc) { |
| System.out.println(); |
| String errorMsg = exc.getMessage(); |
| |
| // Check the message obtained. |
| if (enableChecks && errorMsg == null) { |
| throw new RuntimeException("Caught AbstractMethodError with empty message."); |
| } else if (errorMsg.equals(expectedErrorMessageAME4)) { |
| // Expected test case. |
| System.out.println("Passed with message: " + errorMsg); |
| } else if (enableChecks) { |
| System.out.println("Expected: " + expectedErrorMessageAME4 + "\n" + |
| "but got: " + errorMsg); |
| throw new RuntimeException("Wrong error message of AbstractMethodError."); |
| } |
| } |
| } |
| |
| private static String expectedErrorMessageAME5_VtableStub = |
| "Receiver class AME5_B does not define or inherit an implementation of the resolved method 'abstract void mc()' " + |
| "of abstract class AME5_A."; |
| |
| // AbstractMethodErrors detected in vtable stubs. |
| // Note: How can we verify that we really stepped through the vtable stub? |
| // - Bimorphic inlining should not happen since we have no profiling data when |
| // we compile the method |
| // - As a result, an inline cache call should be generated |
| // - This inline cache call is patched into a real vtable call at the first |
| // re-resolve, which happens constantly during the first 10 iterations of the loop. |
| // => we should be fine! :-) |
| public static void test_ame5_compiled_vtable_stub() { |
| // Allocated the objects we need and call a valid method. |
| boolean caught_ame = false; |
| AME5_B b = new AME5_B(); |
| AME5_C c = new AME5_C(); |
| AME5_D d = new AME5_D(); |
| AME5_E e = new AME5_E(); |
| b.ma(); |
| c.ma(); |
| d.ma(); |
| e.ma(); |
| |
| try { |
| final int iterations = 10; |
| // Test: calls b.c() in the last iteration. |
| for (int i = 0; i < iterations; i++) { |
| AME5_A a = b; |
| if (i % 3 == 0 && i < iterations - 1) { |
| a = c; |
| } |
| if (i % 3 == 1 && i < iterations - 1) { |
| a = d; |
| } |
| if (i % 3 == 2 && i < iterations - 1) { |
| a = e; |
| } |
| |
| a.mc(); |
| } |
| System.out.println(); |
| } catch (AbstractMethodError exc) { |
| caught_ame = true; |
| System.out.println(); |
| String errorMsg = exc.getMessage(); |
| if (enableChecks && errorMsg == null) { |
| System.out.println(exc); |
| throw new RuntimeException("Empty error message of AbstractMethodError."); |
| } |
| if (enableChecks && |
| !errorMsg.equals(expectedErrorMessageAME5_VtableStub)) { |
| // Thrown via SharedRuntime::handle_wrong_method_abstract(). |
| System.out.println("Expected: " + expectedErrorMessageAME5_VtableStub + "\n" + |
| "but got: " + errorMsg); |
| System.out.println(exc); |
| throw new RuntimeException("Wrong error message of AbstractMethodError."); |
| } |
| if (enableChecks) { |
| System.out.println("Passed with message: " + errorMsg); |
| } |
| } catch (Throwable exc) { |
| |
| throw exc; |
| } |
| |
| // Check that we got the exception at some point. |
| if (enableChecks && !caught_ame) { |
| throw new RuntimeException("Expected AbstractMethodError was not thrown."); |
| } |
| } |
| |
| private static String expectedErrorMessageAME6_ItableStub = |
| "Receiver class AME6_B does not define or inherit an implementation of the resolved" + |
| " method 'abstract void mc()' of interface AME6_A."; |
| |
| // ------------------------------------------------------------------------- |
| // AbstractMethodErrors detected in itable stubs. |
| // Note: How can we verify that we really stepped through the itable stub? |
| // - Bimorphic inlining should not happen since we have no profiling data when |
| // we compile the method |
| // - As a result, an inline cache call should be generated |
| // - This inline cache call is patched into a real vtable call at the first |
| // re-resolve, which happens constantly during the first 10 iterations of the loop. |
| // => we should be fine! :-) |
| public static void test_ame6_compiled_itable_stub() { |
| // Allocated the objects we need and call a valid method. |
| boolean caught_ame = false; |
| AME6_B b = new AME6_B(); |
| AME6_C c = new AME6_C(); |
| AME6_D d = new AME6_D(); |
| AME6_E e = new AME6_E(); |
| b.ma(); |
| c.ma(); |
| d.ma(); |
| e.ma(); |
| |
| try { |
| final int iterations = 10; |
| // Test: calls b.c() in the last iteration. |
| for (int i = 0; i < iterations; i++) { |
| AME6_A a = b; |
| if (i % 3 == 0 && i < iterations - 1) { |
| a = c; |
| } |
| if (i % 3 == 1 && i < iterations - 1) { |
| a = d; |
| } |
| if (i % 3 == 2 && i < iterations - 1) { |
| a = e; |
| } |
| a.mc(); |
| } |
| System.out.println(); |
| } catch (AbstractMethodError exc) { |
| caught_ame = true; |
| System.out.println(); |
| String errorMsg = exc.getMessage(); |
| if (enableChecks && errorMsg == null) { |
| System.out.println(exc); |
| throw new RuntimeException("Empty error message of AbstractMethodError."); |
| } |
| if (enableChecks && |
| !errorMsg.equals(expectedErrorMessageAME6_ItableStub)) { |
| // Thrown via LinkResolver::runtime_resolve_interface_method(). |
| System.out.println("Expected: " + expectedErrorMessageAME6_ItableStub + "\n" + |
| "but got: " + errorMsg); |
| System.out.println(exc); |
| throw new RuntimeException("Wrong error message of AbstractMethodError."); |
| } |
| if (enableChecks) { |
| System.out.println("Passed with message: " + errorMsg); |
| } |
| } catch (Throwable exc) { |
| throw exc; |
| } |
| |
| // Check that we got the exception at some point. |
| if (enableChecks && !caught_ame) { |
| throw new RuntimeException("Expected AbstractMethodError was not thrown."); |
| } |
| } |
| |
| |
| public static void main(String[] args) throws Exception { |
| if (!setup_test()) { |
| return; |
| } |
| test_ame1(); |
| test_ame2(); |
| test_ame3_1(); |
| test_ame3_2(); |
| test_ame4(); |
| test_ame5_compiled_vtable_stub(); |
| test_ame6_compiled_itable_stub(); |
| } |
| } |
| |
| // Helper classes to test abstract method error. |
| // |
| // Errorneous versions of these classes are implemented in java |
| // assembler. |
| |
| |
| // ------------------------------------------------------------------------- |
| // This error should be detected interpreted. |
| // |
| // Class hierachy: |
| // |
| // C // interface, defines aFunctionOfMyInterface() |
| // | |
| // A | // interface |
| // | | |
| // B | // abstract class, defines anAbstractMethod() |
| // \ / |
| // E // errorneous class implementation lacks methods C::aFunctionOfMyInterface() |
| // B::anAbstractMethod() |
| interface AME1_A { |
| |
| public String firstFunctionOfMyInterface0(); |
| |
| public String secondFunctionOfMyInterface0(); |
| } |
| |
| abstract class AME1_B implements AME1_A { |
| |
| abstract public String firstAbstractMethod(); |
| |
| abstract public String secondAbstractMethod(); |
| |
| abstract public String anAbstractMethod(); |
| } |
| |
| interface AME1_C { |
| |
| public String firstFunctionOfMyInterface(); |
| |
| public String secondFunctionOfMyInterface(); |
| |
| public String aFunctionOfMyInterface(); |
| } |
| |
| class AME1_D extends AME1_B implements AME1_C { |
| |
| public AME1_D() { |
| } |
| |
| public String firstAbstractMethod() { |
| return this.getClass().getName(); |
| } |
| |
| public String secondAbstractMethod() { |
| return this.getClass().getName(); |
| } |
| |
| public String anAbstractMethod() { |
| return this.getClass().getName(); |
| } |
| |
| public String firstFunctionOfMyInterface0() { |
| return this.getClass().getName(); |
| } |
| |
| public String secondFunctionOfMyInterface0() { |
| return this.getClass().getName(); |
| } |
| |
| public String firstFunctionOfMyInterface() { |
| return this.getClass().getName(); |
| } |
| |
| public String secondFunctionOfMyInterface() { |
| return this.getClass().getName(); |
| } |
| |
| public String aFunctionOfMyInterface() { |
| return this.getClass().getName(); |
| } |
| } |
| |
| class AME1_E extends AME1_B implements AME1_C { |
| |
| public AME1_E() { |
| } |
| |
| public String firstAbstractMethod() { |
| return this.getClass().getName(); |
| } |
| |
| public String secondAbstractMethod() { |
| return this.getClass().getName(); |
| } |
| |
| // This method is missing in the .jasm implementation. |
| public String anAbstractMethod() { |
| return this.getClass().getName(); |
| } |
| |
| public String firstFunctionOfMyInterface0() { |
| return this.getClass().getName(); |
| } |
| |
| public String secondFunctionOfMyInterface0() { |
| return this.getClass().getName(); |
| } |
| |
| public String firstFunctionOfMyInterface() { |
| return this.getClass().getName(); |
| } |
| |
| public String secondFunctionOfMyInterface() { |
| return this.getClass().getName(); |
| } |
| |
| // This method is missing in the .jasm implementation. |
| public String aFunctionOfMyInterface() { |
| return this.getClass().getName(); |
| } |
| } |
| |
| // ------------------------------------------------------------------------- |
| // This error should be detected interpreted. |
| // |
| // Class hierachy: |
| // |
| // A // an interface declaring aFunctionOfMyInterface() |
| // | |
| // B // an abstract class |
| // | |
| // C // errorneous implementation lacks method A::aFunctionOfMyInterface() |
| // |
| interface AME2_A { |
| public void aFunctionOfMyInterface(); |
| } |
| |
| abstract class AME2_B implements AME2_A { |
| abstract public void fun2(); |
| } |
| |
| class ImplementsAllFunctions extends AME2_B { |
| |
| public ImplementsAllFunctions() {} |
| |
| public void fun2() { |
| //System.out.print("You called public void ImplementsAllFunctions::fun2().\n"); |
| } |
| |
| public void aFunctionOfMyInterface() { |
| //System.out.print("You called public void ImplementsAllFunctions::aFunctionOfMyInterface()\n"); |
| } |
| } |
| |
| class AME2_C extends AME2_B { |
| |
| public AME2_C() {} |
| |
| public void fun2() { |
| //System.out.print("You called public void AME2_C::fun2().\n"); |
| } |
| |
| // This method is missing in the .jasm implementation. |
| public void aFunctionOfMyInterface() { |
| //System.out.print("You called public void AME2_C::aFunctionOfMyInterface()\n"); |
| } |
| } |
| |
| // ----------------------------------------------------------------------- |
| // Test AbstractMethod error shadowing existing implementation. |
| // |
| // Class hierachy: |
| // |
| // A // a class implementing m() |
| // | |
| // B // an abstract class defining m() abstract |
| // | |
| // C // an errorneous class lacking an implementation of m() |
| // |
| class AME3_A { |
| public void ma() { |
| System.out.print("A.ma() "); |
| } |
| } |
| |
| abstract class AME3_B extends AME3_A { |
| public abstract void ma(); |
| } |
| |
| class AME3_C extends AME3_B { |
| // This method is missing in the .jasm implementation. |
| public void ma() { |
| System.out.print("C.ma() "); |
| } |
| } |
| |
| // ----------------------------------------------------------------------- |
| // Test AbstractMethod error shadowing existing implementation. In |
| // this test there are several subclasses of the abstract class. |
| // |
| // Class hierachy: |
| // |
| // A // A: a class implementing ma() |
| // | |
| // B // B: an abstract class defining ma() abstract |
| // / | \ |
| // C D E // E: an errorneous class lacking an implementation of ma() |
| // |
| class AME4_A { |
| public void ma() { |
| System.out.print("A.ma() "); |
| } |
| } |
| |
| abstract class AME4_B extends AME4_A { |
| public abstract void ma(); |
| } |
| |
| class AME4_C extends AME4_B { |
| public void ma() { |
| System.out.print("C.ma() "); |
| } |
| } |
| |
| class AME4_D extends AME4_B { |
| public void ma() { |
| System.out.print("D.ma() "); |
| } |
| } |
| |
| class AME4_E extends AME4_B { |
| // This method is missing in the .jasm implementation. |
| public void ma() { |
| System.out.print("E.ma() "); |
| } |
| } |
| |
| // ------------------------------------------------------------------------- |
| // This error should be detected while processing the vtable stub. |
| // |
| // Class hierachy: |
| // |
| // A__ // abstract |
| // /|\ \ |
| // C D E \ |
| // B // Bad class, missing method implementation. |
| // |
| // Test: |
| // - Call D.mc() / E.mc() / F.mc() several times to force real vtable call constrution |
| // - Call errorneous B.mc() in the end to raise the AbstraceMethodError |
| |
| abstract class AME5_A { |
| public abstract void ma(); |
| public abstract void mb(); |
| public abstract void mc(); |
| } |
| |
| class AME5_B extends AME5_A { |
| public void ma() { |
| System.out.print("B.ma() "); |
| } |
| |
| public void mb() { |
| System.out.print("B.mb() "); |
| } |
| |
| // This method is missing in the .jasm implementation. |
| public void mc() { |
| System.out.print("B.mc() "); |
| } |
| } |
| |
| class AME5_C extends AME5_A { |
| public void ma() { |
| System.out.print("C.ma() "); |
| } |
| |
| public void mb() { |
| System.out.print("C.mb() "); |
| } |
| |
| public void mc() { |
| System.out.print("C.mc() "); |
| } |
| } |
| |
| class AME5_D extends AME5_A { |
| public void ma() { |
| System.out.print("D.ma() "); |
| } |
| |
| public void mb() { |
| System.out.print("D.mb() "); |
| } |
| |
| public void mc() { |
| System.out.print("D.mc() "); |
| } |
| } |
| |
| class AME5_E extends AME5_A { |
| public void ma() { |
| System.out.print("E.ma() "); |
| } |
| |
| public void mb() { |
| System.out.print("E.mb() "); |
| } |
| |
| public void mc() { |
| System.out.print("E.mc() "); |
| } |
| } |
| |
| //------------------------------------------------------------------------- |
| // Test AbstractMethod error detected while processing |
| // the itable stub. |
| // |
| // Class hierachy: |
| // |
| // A__ (interface) |
| // /|\ \ |
| // C D E \ |
| // B (bad class, missing method) |
| // |
| // Test: |
| // - Call D.mc() / E.mc() / F.mc() several times to force real itable call constrution |
| // - Call errorneous B.mc() in the end to raise the AbstraceMethodError |
| |
| interface AME6_A { |
| abstract void ma(); |
| abstract void mb(); |
| abstract void mc(); |
| } |
| |
| class AME6_B implements AME6_A { |
| public void ma() { |
| System.out.print("B.ma() "); |
| } |
| |
| public void mb() { |
| System.out.print("B.mb() "); |
| } |
| |
| // This method is missing in the .jasm implementation. |
| public void mc() { |
| System.out.print("B.mc() "); |
| } |
| } |
| |
| class AME6_C implements AME6_A { |
| public void ma() { |
| System.out.print("C.ma() "); |
| } |
| |
| public void mb() { |
| System.out.print("C.mb() "); |
| } |
| |
| public void mc() { |
| System.out.print("C.mc() "); |
| } |
| } |
| |
| class AME6_D implements AME6_A { |
| public void ma() { |
| System.out.print("D.ma() "); |
| } |
| |
| public void mb() { |
| System.out.print("D.mb() "); |
| } |
| |
| public void mc() { |
| System.out.print("D.mc() "); |
| } |
| } |
| |
| class AME6_E implements AME6_A { |
| public void ma() { |
| System.out.print("E.ma() "); |
| } |
| |
| public void mb() { |
| System.out.print("E.mb() "); |
| } |
| |
| public void mc() { |
| System.out.print("E.mc() "); |
| } |
| } |