| /* |
| * 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); |
| } |
| } |