test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/README
author mseledtsov
Wed, 23 May 2018 17:09:49 -0700
changeset 50243 4fac3c99487d
child 52310 a8e43293b4c4
permissions -rw-r--r--
8199255: [TESTBUG] Open source VM testbase default methods tests Summary: Open sourced default method tests Reviewed-by: ccheung, iignatyev, erikj

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 <int>
              additional access flags on default methods (default: 0)

        -ver <int>
              class file major version (default: 52)

        -redefine <boolean>
              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 <boolean>
            list available tests

        -filter <regex>
            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 <long>
            Stress execution time in seconds (default: 60)

        -stressThreadsFactor <int>
              Stress threads factor (default: 1)

        -seed <int>
              force deterministic behavior (default: 0)

        -redefine <boolean>
              use scenarios w/ class redefinition (default: false)

        -ver <int>
              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 <test_name> 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