1 /*
2  * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /**
25  * @test
26  * @bug 8051344
27  * @summary Force OSR compilation with non-empty stack at the OSR entry point.
28  * @modules java.base/jdk.internal.org.objectweb.asm
29  * @run main/othervm -XX:CompileCommand=compileonly,TestCase::test
30  *                   compiler.osr.TestOSRWithNonEmptyStack
31  */
32 
33 package compiler.osr;
34 
35 import jdk.internal.org.objectweb.asm.ClassWriter;
36 import jdk.internal.org.objectweb.asm.Label;
37 import jdk.internal.org.objectweb.asm.MethodVisitor;
38 
39 import java.lang.reflect.Constructor;
40 import java.lang.reflect.Method;
41 
42 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
43 import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
44 import static jdk.internal.org.objectweb.asm.Opcodes.DUP;
45 import static jdk.internal.org.objectweb.asm.Opcodes.IADD;
46 import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_0;
47 import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_1;
48 import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPLT;
49 import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD;
50 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
51 import static jdk.internal.org.objectweb.asm.Opcodes.ISTORE;
52 import static jdk.internal.org.objectweb.asm.Opcodes.POP;
53 import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
54 
55 public class TestOSRWithNonEmptyStack extends ClassLoader {
56     private static final int CLASS_FILE_VERSION = 52;
57     private static final String CLASS_NAME = "TestCase";
58     private static final String METHOD_NAME = "test";
59     private static final int ITERATIONS = 1_000_000;
60 
generateTestClass()61     private static byte[] generateTestClass() {
62         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
63 
64         cw.visit(TestOSRWithNonEmptyStack.CLASS_FILE_VERSION, ACC_PUBLIC,
65                 TestOSRWithNonEmptyStack.CLASS_NAME, null, "java/lang/Object",
66                 null);
67 
68         TestOSRWithNonEmptyStack.generateConstructor(cw);
69         TestOSRWithNonEmptyStack.generateTestMethod(cw);
70 
71         cw.visitEnd();
72         return cw.toByteArray();
73     }
74 
generateConstructor(ClassWriter classWriter)75     private static void generateConstructor(ClassWriter classWriter) {
76         MethodVisitor mv = classWriter.visitMethod(ACC_PUBLIC, "<init>", "()V",
77                 null, null);
78 
79         mv.visitCode();
80 
81         mv.visitVarInsn(ALOAD, 0);
82         mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V",
83                 false);
84         mv.visitInsn(RETURN);
85 
86         mv.visitMaxs(0, 0);
87         mv.visitEnd();
88     }
89 
generateTestMethod(ClassWriter classWriter)90     private static void generateTestMethod(ClassWriter classWriter) {
91         MethodVisitor mv = classWriter.visitMethod(ACC_PUBLIC,
92                 TestOSRWithNonEmptyStack.METHOD_NAME, "()V", null, null);
93         Label osrEntryPoint = new Label();
94 
95         mv.visitCode();
96         // Push 'this' into stack before OSR entry point to bail out compilation
97         mv.visitVarInsn(ALOAD, 0);
98         // Setup loop counter
99         mv.visitInsn(ICONST_0);
100         mv.visitVarInsn(ISTORE, 1);
101         // Begin loop
102         mv.visitLabel(osrEntryPoint);
103         // Increment loop counter
104         mv.visitVarInsn(ILOAD, 1);
105         mv.visitInsn(ICONST_1);
106         mv.visitInsn(IADD);
107         // Duplicate it for loop condition check
108         mv.visitInsn(DUP);
109         mv.visitVarInsn(ISTORE, 1);
110         // Check loop condition
111         mv.visitLdcInsn(TestOSRWithNonEmptyStack.ITERATIONS);
112         mv.visitJumpInsn(IF_ICMPLT, osrEntryPoint);
113         // Pop 'this'.
114         mv.visitInsn(POP);
115         mv.visitInsn(RETURN);
116 
117         mv.visitMaxs(0, 0);
118         mv.visitEnd();
119     }
120 
run()121     private void run() {
122         byte[] bytecode = TestOSRWithNonEmptyStack.generateTestClass();
123 
124         try {
125             Class klass = defineClass(TestOSRWithNonEmptyStack.CLASS_NAME,
126                     bytecode, 0, bytecode.length);
127 
128             Constructor ctor = klass.getConstructor();
129             Method method = klass.getDeclaredMethod(
130                     TestOSRWithNonEmptyStack.METHOD_NAME);
131 
132             Object testCase = ctor.newInstance();
133             method.invoke(testCase);
134         } catch (Exception e) {
135             throw new RuntimeException(
136                     "Test bug: generated class should be valid.", e);
137         }
138     }
139 
main(String args[])140     public static void main(String args[]) {
141         new TestOSRWithNonEmptyStack().run();
142     }
143 }
144