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 
  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 }