Copyright (c) 2014, 2018, Oracle and/or its affiliates. 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. ABOUT Once published, it is impossible to add methods to an interface without breaking existing implementations (specifically, adding a method to an interface is not a source-compatible change). The longer the time since a library has been published, the more likely it is that this restriction will cause grief for its maintainers. The addition of closures to the Java language in JDK 8 place additional stress on the aging Collection interfaces; one of the most significant benefits of closures is that it enables the development of more powerful libraries. It would be disappointing to add a language feature that enables better libraries while at the same time not extending the core libraries to take advantage of that feature. A mechanism for adding new methods to existing interfaces is proposed, which is called virtual extension (or default) methods. Existing interfaces can be augmented without compromising backward compatibility by adding extension methods to the interface, whose declaration would contain instructions for finding the default implementation in the event that implementers do not provide a method body. A key characteristic of extension methods is that they are virtual methods just like other interface methods, but provide a default implementation in the event that the implementing class does not provide a method body. VM support is necessary to implement virtual extension methods. OVERVIEW The test suite is organized in the following manner. The tests rely on a framework to generate class hierarchies and tests directly in bytecode from a pseudo-code in Java. Pseudo-code is written using builder pattern and fluent coding style. The framework is located in src/vm/runtime/defmeth/shared and divided into /data and /builder sections. As an example, the following code: TestBuilder b = factory.getBuilder(); Interface I = b.intf("I") .defaultMethod("m", "()I").returns(1).build() .build(); ConcreteClass C = b.clazz("C").implement(I) .concreteMethod("m", "()I").returns(2).build() .build(); b.test().callSite(I, C, "m", "()I").returns(2).done() .test().callSite(C, C, "m", "()I").returns(2).done() .run(); translates into bytecode equivalent of: 2-class hierarchy: interface I { int m() default { return 1; } } class C implements I { public int m() { return 2; } } and 2 tests: Test1_I_C_m { static void test() { I i = new C(); if (i.m() != 2) throw new TestFailure(); } } Test2_C_C_m { static void test() { C c = new C(); if (c.m() != 2) throw new TestFailure(); } } TestBuilder.run() calls Test1_I_C_m.test() and Test2_C_C_m.test() and performs failure reporting, if necessary. All tests are located in src/vm/runtime/defmeth and are grouped according to the area they excercise. The test groups are: - AccessibilityFlagsTest - BasicTest - ConflictingDefaultsTest - DefaultVsAbstractTest - MethodResolutionTest - ObjectMethodOverridesTest - PrivateMethodsTest - RedefineTest - StaticMethodsTest - StressTest - SuperCallTest Each test group can be executed in different modes. For each mode there's a corresponding scenario in src/vm/runtime/defmeth/scenarios. Scenarios are organized in the following manner: .../scenarios/[test_group]_[majorVer]_[methodFlags]_[invocationType]_[shouldRedefine] where majorVer - major version of class files for generated concrete classes values: ver49, ver50, ver51, ver52 methodFlags - additional access flags for methods in generated classes values: none == no additional flags sync == ACC_SYNCHRONIZED strict == ACC_STRICT syncstrict == ACC_SYNCHRONIZED | ACC_STRICT invocationType - how methods in test hiearchies are invoked during testing values: direct - using invoke* bytecodes reflect - using Reflection API invoke - using invokedynamic & java.lang.invoke API (MethodHandles/JSR292) redefine - whether to preload and redefine classes before running individual tests values: redefine, noredefine testGroup - name of test group being used values: BasicTests/BridgeMethod/etc STRESS TESTING Stress test differs from other scenarios - it has only 2 modes: redefine and noredefine. Stress scenario is the following: - in multiple threads (5 by default)... - ... continuously run random vm.runtime.defmeth.* tests ... - ... in random configurations ... - ... until predefined period of time is over... - ... or any failures occured. HOW TO RUN Directly from command-line: $ java -cp ${VMTESTBASE}/bin/classes vm.runtime.defmeth.shared.DefMethTest Specify testing mode: -flags additional access flags on default methods (default: 0) -ver class file major version (default: 52) -redefine redefine classes during execution (default: false) -mode [direct|reflect|invoke] specify method invocation mechanism (default: direct): - direct - invoke* instructions in bytecode - reflect - Reflection API - invoke - invokedynamic & MethodHandle.invoke* -execMode [DIRECT|REFLECTION|INVOKE_EXACT|INVOKE_GENERIC|INVOKE_WITH_ARGS|INDY] specify concrete execution mode Execution-specific flags: -list list available tests -filter filter tests by name (default: .* ) If you run tests directly from command line, in order to make "-redefine true", StressTest or RedefineTest work, additional steps are necessary: add -agentlib:redefineClasses to JVM options set correct LD_LIBRARY_PATH: LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${VM_TESTBASE}/bin/lib/${PLATFORM}/vm/runtime/defmeth/shared/ Also, it is possible to run any test group directly: $ java -cp ${VMTESTBASE}/bin/classes vm.runtime.defmeth.BasicTest StressTest has some specific options: -stressTime Stress execution time in seconds (default: 60) -stressThreadsFactor Stress threads factor (default: 1) -seed force deterministic behavior (default: 0) -redefine use scenarios w/ class redefinition (default: false) -ver minimum class file version to be used in the tests (default: 49) -ignoreTestFailures ignore failures of individual tests To simplify failure analysis, the framework has some additional flags to produce diagnostics output: -Dvm.runtime.defmeth.printTests print pseudo-code for each test; -Dvm.runtime.defmeth.printAssembly print bytecode assembly for all generated class files; -Dvm.runtime.defmeth.printASMify print "asmified" version of generated class files; very useful when preparing reduced test cases. -Dvm.runtime.defmeth.dumpClasses dump class files under DUMP_CLASS_FILES in folder -Dvm.runtime.defmeth.printStackTrace print full stack traces for all errors and test failures -Dvm.runtime.defmeth.traceClassRedefinition trace class redefinition during testing LINKS [1] "Design and Implementation of Default Methods in Hotspot JVM", by Keith McGuigan, 09/18/2012 http://cr.openjdk.java.net/~kamg/default_methods_in_hotspot.txt [2] "Featherweight Defenders: A formal model for virtual extension methods in Java", by Brian Goetz, Robert Field, 03/27/2012 http://cr.openjdk.java.net/~briangoetz/lambda/featherweight-defenders.pdf [3] "Interface evolution via virtual extension methods", by Brian Goetz, 4th draft, 06/2011 http://cr.openjdk.java.net/~briangoetz/lambda/Defender%20Methods%20v4.pdf