blob: 27f437844fdc1733036dd7ca746fdfe72c59abed [file] [log] [blame]
/*
* Copyright (c) 2011, 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.
*/
/*
* @test
*
* @summary converted from VM Testbase vm/mlvm/meth/stress/compiler/i2c_c2i.
* VM Testbase keywords: [feature_mlvm, nonconcurrent, quarantine]
* VM Testbase comments: 8208255
* VM Testbase readme:
* DESCRIPTION
* The test attempts to check MethodHandle i2c and c2i adapters by using sequences.
* Then it forces compilation of some of intermediate method handles. The test enables
* diagnostic printing of compilation and analyse it's own standard output
* to see if method is really has been compiled. When some subsequence is compiled,
* the test calls the whole sequence and forces decompilation (by using uncommon trap logic)
* of some smaller subsequence. This way both i2c and c2i adapters are created.
* The test compares result of calling the sequence of MHs with the results computed
* by the test and fails if the result is different.
* The test is a random one, it makes random sequences of MH and calls random subsequences.
* To facilitate reproducing test failures, it prints it's random seed, which can be fed
* to test when reproducing a problem.
* See vm.mlvm.meth.stress.java.sequences.Test for details on MH sequences.
*
* @library /vmTestbase
* /test/lib
* @run driver jdk.test.lib.FileInstaller . .
*
* @comment build test class and indify classes
* @build vm.mlvm.meth.stress.compiler.i2c_c2i.Test
* @run driver vm.mlvm.share.IndifiedClassesBuilder
*
* @run main/othervm vm.mlvm.meth.stress.compiler.i2c_c2i.Test
*/
package vm.mlvm.meth.stress.compiler.i2c_c2i;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.concurrent.CyclicBarrier;
import vm.mlvm.meth.share.Argument;
import vm.mlvm.meth.share.MHTransformationGen;
import vm.mlvm.meth.share.RandomArgumentsGen;
import vm.mlvm.meth.share.transform.v2.MHMacroTF;
import vm.mlvm.share.Env;
import vm.mlvm.share.MlvmTest;
// TODO: check that i2c/c2i adapters are really created
// TODO: check deopt using vm.mlvm.share.comp framework
// TODO: use multi-threaded test framework
public class Test extends MlvmTest {
private static final int THREADS
= Runtime.getRuntime().availableProcessors();
Object finalTarget() {
return new Integer(0);
}
static class A {
MHMacroTF trList;
A(MHMacroTF trList) {
this.trList = trList;
}
Object m() throws Throwable {
Env.traceNormal("Original m() in thread "
+ Thread.currentThread().getName());
return MHTransformationGen.callSequence(this.trList, false);
}
}
static class B extends A {
B() {
super(null);
}
@Override
Object m() throws Throwable {
Env.traceNormal("Deoptimized m() in thread "
+ Thread.currentThread().getName());
return new Integer(1);
}
}
volatile A intermediateTarget;
Object callIntemediateTarget() throws Throwable {
return this.intermediateTarget.m();
}
CyclicBarrier startBarrier = new CyclicBarrier(THREADS + 1);
volatile boolean testDone = false;
@Override
public boolean run() throws Throwable {
final MethodHandle mhB = MethodHandles.lookup().findVirtual(Test.class,
"finalTarget", MethodType.methodType(Object.class));
final Argument finalRetVal = Argument.fromValue(new Integer(0));
finalRetVal.setPreserved(true);
this.intermediateTarget = new A(
MHTransformationGen.createSequence(finalRetVal, Test.this, mhB,
RandomArgumentsGen.createRandomArgs(true, mhB.type())));
final MethodHandle mhM = MethodHandles.lookup().findVirtual(Test.class,
"callIntemediateTarget", MethodType.methodType(Object.class));
final Argument[] finalArgs = RandomArgumentsGen.createRandomArgs(true,
mhM.type());
Thread[] threads = new Thread[THREADS];
for (int t = 0; t < THREADS; t++) {
(threads[t] = new Thread("Stresser " + t) {
public void run() {
try {
MHMacroTF tList = MHTransformationGen.createSequence(
finalRetVal, Test.this, mhM, finalArgs);
Test.this.startBarrier.await();
while ( ! Test.this.testDone) {
int e = (Integer) Test.this.intermediateTarget.m();
int r = (Integer) MHTransformationGen.callSequence(
tList, false);
if (r != e)
Env.traceNormal("Wrong result in thread "
+ getName() + ", but this is OK");
}
Env.traceVerbose("Thread " + getName()+ ": work done");
} catch (Throwable t) {
markTestFailed("Exception in thread " + getName(), t);
}
}
}).start();
}
this.startBarrier.await();
Env.traceImportant("Threads started");
Thread.sleep(3000);
Env.traceImportant("Deoptimizing");
// Force deoptimization in uncommon trap logic
this.intermediateTarget = (A) Test.class.getClassLoader().loadClass(
Test.class.getName() + "$B").newInstance();
Thread.sleep(3000);
this.testDone = true;
for (int t = 0; t < THREADS; t++) {
threads[t].join();
}
return true;
}
public static void main(String[] args) {
MlvmTest.launch(args);
}
}