提交 b9fd5a85 编写于 作者: K kshefov

8057719: Develop new tests for LambdaForm Reduction and Caching feature

Reviewed-by: iignatyev, vlivanov, psandoz
上级 5cf2c79c
/*
* Copyright (c) 2014, 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.
*/
import java.lang.invoke.MethodHandle;
import java.lang.reflect.InvocationTargetException;
/**
* Abstract class for lambda forms caching testing.
*
* @author kshefov
*/
public abstract class LFCachingTestCase extends LambdaFormTestCase {
/**
* Constructor for lambda forms caching test case.
*
* @param testMethod A method from {@code j.l.i.MethodHandles} class that
* returns a {@code j.l.i.MethodHandle} instance.
*/
protected LFCachingTestCase(TestMethods testMethod) {
super(testMethod);
}
/**
* Checks that the lambda forms of the two adapter method handles adapter1
* and adapter2 are the same.
*
* @param adapter1 First method handle.
* @param adapter2 Second method handle.
*/
public void checkLFCaching(MethodHandle adapter1, MethodHandle adapter2) {
try {
if (!adapter1.type().equals(adapter2.type())) {
throw new Error("TESTBUG: Types of the two method handles are not the same");
}
Object lambdaForm0 = LambdaFormTestCase.INTERNAL_FORM.invoke(adapter1);
Object lambdaForm1 = LambdaFormTestCase.INTERNAL_FORM.invoke(adapter2);
if (lambdaForm0 == null || lambdaForm1 == null) {
throw new Error("Unexpected error: One or both lambda forms of the method handles are null");
}
if (lambdaForm0 != lambdaForm1) {
System.err.println("Lambda form 0 toString is:");
System.err.println(lambdaForm0);
System.err.println("Lambda form 1 toString is:");
System.err.println(lambdaForm1);
throw new AssertionError("Error: Lambda forms of the two method handles"
+ " are not the same. LF cahing does not work");
}
} catch (IllegalAccessException | IllegalArgumentException |
SecurityException | InvocationTargetException ex) {
throw new Error("Unexpected exception: ", ex);
}
}
}
/*
* Copyright (c) 2014, 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.
*/
/*
* @test LFGarbageCollectedTest
* @bug 8046703
* @summary Test verifies that lambda forms are garbage collected
* @author kshefov
* @library /lib/testlibrary/jsr292 /lib/testlibrary
* @build TestMethods
* @build LambdaFormTestCase
* @build LFGarbageCollectedTest
* @run main/othervm/timeout=600 -Djava.lang.invoke.MethodHandle.USE_LF_EDITOR=true -DtestLimit=150 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI LFGarbageCollectedTest
*/
import java.lang.invoke.MethodHandle;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Map;
/**
* Lambda forms garbage collection test class.
*/
public final class LFGarbageCollectedTest extends LambdaFormTestCase {
/**
* Constructor for a lambda forms garbage collection test case.
*
* @param testMethod A method from {@code j.l.i.MethodHandles} class that
* returns a {@code j.l.i.MethodHandle} instance.
*/
public LFGarbageCollectedTest(TestMethods testMethod) {
super(testMethod);
}
@Override
public void doTest() {
try {
Map<String, Object> data = getTestMethod().getTestCaseData();
MethodHandle adapter;
try {
adapter = getTestMethod().getTestCaseMH(data, TestMethods.Kind.ONE);
} catch (NoSuchMethodException ex) {
throw new Error("Unexpected exception: ", ex);
}
Object lambdaForm = LambdaFormTestCase.INTERNAL_FORM.invoke(adapter);
if (lambdaForm == null) {
throw new Error("Unexpected error: Lambda form of the method handle is null");
}
ReferenceQueue rq = new ReferenceQueue();
PhantomReference ph = new PhantomReference(lambdaForm, rq);
lambdaForm = null;
data = null;
adapter = null;
for (int i = 0; i < 1000 && !ph.isEnqueued(); i++) {
System.gc();
}
if (!ph.isEnqueued()) {
throw new AssertionError("Error: Lambda form is not garbage collected");
}
} catch (IllegalAccessException | IllegalArgumentException |
InvocationTargetException ex) {
throw new Error("Unexpected exception: ", ex);
}
}
/**
* Main routine for lambda forms garbage collection test.
*
* @param args Accepts no arguments.
*/
public static void main(String[] args) {
// The "identity" and "constant" methods should be removed from this test,
// because their lambda forms are stored in a static filed and are not GC'ed.
// There can be only 5 such LFs for each method, so no memory leak happens.
EnumSet<TestMethods> testMethods = EnumSet.complementOf(EnumSet.of(TestMethods.IDENTITY, TestMethods.CONSTANT));
LambdaFormTestCase.runTests(LFGarbageCollectedTest::new, testMethods);
}
}
/*
* Copyright (c) 2014, 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.
*/
/*
* @test LFMultiThreadCachingTest
* @bug 8046703
* @summary Test verifies that lambda forms are cached when run with multiple threads
* @author kshefov
* @library /lib/testlibrary/jsr292 /lib/testlibrary
* @build TestMethods
* @build LambdaFormTestCase
* @build LFCachingTestCase
* @build LFMultiThreadCachingTest
* @run main/othervm/timeout=300 -Djava.lang.invoke.MethodHandle.USE_LF_EDITOR=true LFMultiThreadCachingTest
*/
import java.lang.invoke.MethodHandle;
import java.util.EnumSet;
import java.util.Map;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
/**
* Multiple threaded lambda forms caching test class.
*/
public final class LFMultiThreadCachingTest extends LFCachingTestCase {
private static final TestMethods.Kind[] KINDS;
static {
EnumSet<TestMethods.Kind> set = EnumSet.complementOf(EnumSet.of(TestMethods.Kind.EXCEPT));
KINDS = set.toArray(new TestMethods.Kind[set.size()]);
if (KINDS.length < 2) {
throw new Error("TESTBUG: KINDS.length[" + KINDS.length + "] should be at least 2");
}
}
private static final int CORES = Math.max(KINDS.length, Runtime.getRuntime().availableProcessors());
/**
* Constructor a for multiple threaded lambda forms caching test case.
*
* @param testMethod A method from {@code j.l.i.MethodHandles} class that
* returns a {@code j.l.i.MethodHandle} instance.
*/
public LFMultiThreadCachingTest(TestMethods testMethod) {
super(testMethod);
}
@Override
public void doTest() {
Map<String, Object> data = getTestMethod().getTestCaseData();
ConcurrentLinkedQueue<MethodHandle> adapters = new ConcurrentLinkedQueue<>();
CyclicBarrier begin = new CyclicBarrier(CORES);
CountDownLatch end = new CountDownLatch(CORES);
for (int i = 0; i < CORES; ++i) {
TestMethods.Kind kind = KINDS[i % KINDS.length];
new Thread(() -> {
try {
begin.await();
adapters.add(getTestMethod().getTestCaseMH(data, kind));
} catch (InterruptedException | BrokenBarrierException | IllegalAccessException | NoSuchMethodException ex) {
throw new Error("Unexpected exception: ", ex);
} finally {
end.countDown();
}
}).start();
}
try {
end.await();
} catch (InterruptedException ex) {
throw new Error("Unexpected exception: ", ex);
}
if (adapters.size() < CORES) {
throw new Error("adapters size[" + adapters.size() + "] is less than " + CORES);
}
MethodHandle prev = adapters.poll();
for (MethodHandle current : adapters) {
checkLFCaching(prev, current);
prev = current;
}
}
/**
* Main routine for multiple threaded lambda forms caching test.
*
* @param args Accepts no arguments.
*/
public static void main(String[] args) {
LambdaFormTestCase.runTests(LFMultiThreadCachingTest::new, EnumSet.allOf(TestMethods.class));
}
}
/*
* Copyright (c) 2014, 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.
*/
/*
* @test LFSingleThreadCachingTest
* @bug 8046703
* @summary Test verifies that lambda forms are cached when run with single thread
* @author kshefov
* @library /lib/testlibrary/jsr292 /lib/testlibrary
* @build TestMethods
* @build LambdaFormTestCase
* @build LFCachingTestCase
* @build LFSingleThreadCachingTest
* @run main/othervm/timeout=300 -Djava.lang.invoke.MethodHandle.USE_LF_EDITOR=true LFSingleThreadCachingTest
*/
import java.lang.invoke.MethodHandle;
import java.util.EnumSet;
import java.util.Map;
/**
* Single threaded lambda forms caching test class.
*/
public final class LFSingleThreadCachingTest extends LFCachingTestCase {
/**
* Constructor for a single threaded lambda forms caching test case.
*
* @param testMethod A method from {@code j.l.i.MethodHandles} class that
* returns a {@code j.l.i.MethodHandle} instance.
*/
public LFSingleThreadCachingTest(TestMethods testMethod) {
super(testMethod);
}
@Override
public void doTest() {
MethodHandle adapter1;
MethodHandle adapter2;
Map<String, Object> data = getTestMethod().getTestCaseData();
try {
adapter1 = getTestMethod().getTestCaseMH(data, TestMethods.Kind.ONE);
adapter2 = getTestMethod().getTestCaseMH(data, TestMethods.Kind.TWO);
} catch (NoSuchMethodException | IllegalAccessException ex) {
throw new Error("Unexpected exception: ", ex);
}
checkLFCaching(adapter1, adapter2);
}
/**
* Main routine for single threaded lambda forms caching test.
*
* @param args Accepts no arguments.
*/
public static void main(String[] args) {
LambdaFormTestCase.runTests(LFSingleThreadCachingTest::new, EnumSet.allOf(TestMethods.class));
}
}
/*
* Copyright (c) 2014, 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.
*/
import com.oracle.testlibrary.jsr292.Helper;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.function.Function;
/**
* Lambda forms caching test case class. Contains all necessary test routines to
* test lambda forms caching in method handles returned by methods of
* MethodHandles class.
*
* @author kshefov
*/
public abstract class LambdaFormTestCase {
private final static String METHOD_HANDLE_CLASS_NAME = "java.lang.invoke.MethodHandle";
private final static String INTERNAL_FORM_METHOD_NAME = "internalForm";
/**
* Reflection link to {@code j.l.i.MethodHandle.internalForm} method. It is
* used to get a lambda form from a method handle.
*/
protected final static Method INTERNAL_FORM;
static {
try {
Class mhClass = Class.forName(METHOD_HANDLE_CLASS_NAME);
INTERNAL_FORM = mhClass.getDeclaredMethod(INTERNAL_FORM_METHOD_NAME);
INTERNAL_FORM.setAccessible(true);
} catch (Exception ex) {
throw new Error("Unexpected exception: ", ex);
}
}
private final TestMethods testMethod;
/**
* Test case constructor. Generates test cases with random method types for
* given methods form {@code j.l.i.MethodHandles} class.
*
* @param testMethod A method from {@code j.l.i.MethodHandles} class which
* returns a {@code j.l.i.MethodHandle}.
*/
protected LambdaFormTestCase(TestMethods testMethod) {
this.testMethod = testMethod;
}
public TestMethods getTestMethod() {
return testMethod;
}
/**
* Routine that executes a test case.
*/
public abstract void doTest();
/**
* Runs a number of test cases defined by the size of testCases list.
*
* @param ctor constructor of LambdaFormCachingTest or its child classes
* object.
* @param testMethods list of test methods
*/
public static void runTests(Function<TestMethods, LambdaFormTestCase> ctor, Collection<TestMethods> testMethods) {
boolean passed = true;
int testCounter = 0;
int failCounter = 0;
long iterations = Math.max(1, Helper.TEST_LIMIT / testMethods.size());
for (long i = 0; i < iterations; i++) {
System.err.println(String.format("Iteration %d:", i));
for (TestMethods testMethod : testMethods) {
LambdaFormTestCase testCase = ctor.apply(testMethod);
try {
System.err.printf("Tested LF caching feature with MethodHandles.%s method.%n",
testCase.getTestMethod().name);
testCase.doTest();
System.err.println("PASSED");
} catch (Throwable t) {
t.printStackTrace();
System.err.println("FAILED");
passed = false;
failCounter++;
}
testCounter++;
}
}
if (!passed) {
throw new Error(String.format("%d of %d test cases FAILED! %n"
+ "Rerun the test with the same \"-Dseed=\" option as in the log file!",
failCounter, testCounter));
} else {
System.err.println(String.format("All %d test cases PASSED!", testCounter));
}
}
}
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册