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
33package compiler.osr;
34
35import jdk.internal.org.objectweb.asm.ClassWriter;
36import jdk.internal.org.objectweb.asm.Label;
37import jdk.internal.org.objectweb.asm.MethodVisitor;
38
39import java.lang.reflect.Constructor;
40import java.lang.reflect.Method;
41
42import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
43import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
44import static jdk.internal.org.objectweb.asm.Opcodes.DUP;
45import static jdk.internal.org.objectweb.asm.Opcodes.IADD;
46import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_0;
47import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_1;
48import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPLT;
49import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD;
50import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
51import static jdk.internal.org.objectweb.asm.Opcodes.ISTORE;
52import static jdk.internal.org.objectweb.asm.Opcodes.POP;
53import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
54
55public 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
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
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
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
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
140    public static void main(String args[]) {
141        new TestOSRWithNonEmptyStack().run();
142    }
143}
144