1 /*
   2  * Copyright (c) 2010, 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 /**
  26  * @test
  27  * @bug 6932496
  28  * @summary incorrect deopt of jsr subroutine on 64 bit c1
  29  * @modules java.base/jdk.internal.org.objectweb.asm
  30  *
  31  * @run main/othervm -Xcomp
  32  *      -XX:CompileCommand=compileonly,compiler.c1.Test6932496::test
  33  *      compiler.c1.Test6932496
  34  */
  35 
  36 package compiler.c1;
  37 
  38 import jdk.internal.org.objectweb.asm.ClassWriter;
  39 import jdk.internal.org.objectweb.asm.FieldVisitor;
  40 import jdk.internal.org.objectweb.asm.Label;
  41 import jdk.internal.org.objectweb.asm.MethodVisitor;
  42 import jdk.internal.org.objectweb.asm.Opcodes;
  43 import jdk.internal.org.objectweb.asm.Type;
  44 
  45 import java.io.IOException;
  46 import java.lang.reflect.Method;
  47 import java.nio.file.Files;
  48 import java.nio.file.Paths;
  49 
  50 public class Test6932496 extends ClassLoader {
  51     private static final int CLASS_FILE_VERSION = 49;
  52     private static final String CLASS_TEST = "Test";
  53     private static final String CLASS_OBJECT = "java/lang/Object";
  54     private static final String METHOD_INIT = "<init>";
  55     private static final String METHOD_TEST = "test";
  56     private static final String DESC_VOID_METHOD = "()V";
  57     private static final String FIELD_FLAG = "flag";
  58 
  59     public static void main(String[] args) {
  60         Test6932496 test = new Test6932496();
  61         test.execute();
  62     }
  63 
  64     private void execute() {
  65         byte[] bytecode = Test6932496.generateTestClass();
  66 
  67         try {
  68             Files.write(Paths.get("Test.class.dump"), bytecode);
  69         } catch (IOException e) {
  70             System.err.println("classfile dump failed : " + e.getMessage());
  71             e.printStackTrace();
  72         }
  73         try {
  74             Class aClass = defineClass(CLASS_TEST, bytecode, 0, bytecode.length);
  75             Method test = aClass.getDeclaredMethod(METHOD_TEST);
  76             test.invoke(null);
  77         } catch (ClassFormatError | IllegalArgumentException
  78                     | ReflectiveOperationException e) {
  79             throw new RuntimeException("TESTBUG : generated class is invalid", e);
  80         }
  81     }
  82 
  83     /*
  84         public class Test {
  85             volatile boolean flag = false;
  86             public static void m() {
  87                 try {
  88                 } finally {
  89                     Test test = new Test();
  90                     test.flag = true;
  91                 }
  92             }
  93         }
  94     */
  95     private static byte[] generateTestClass() {
  96         ClassWriter cw = new ClassWriter(0);
  97         cw.visit(CLASS_FILE_VERSION, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER,
  98                 CLASS_TEST, null, CLASS_OBJECT, null);
  99         // volatile boolean flag;
 100         {
 101             FieldVisitor fv = cw.visitField(Opcodes.ACC_VOLATILE, FIELD_FLAG,
 102                     Type.BOOLEAN_TYPE.getDescriptor(),
 103                     /* signature = */ null, /* value = */ null);
 104         }
 105 
 106         /*
 107             public Test() {
 108                 flag = false;
 109             }
 110         */
 111         {
 112             MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC,
 113                     METHOD_INIT, DESC_VOID_METHOD,
 114                     /* signature = */ null, /* exceptions = */ null);
 115 
 116             mv.visitCode();
 117             mv.visitVarInsn(Opcodes.ALOAD, 0);
 118             mv.visitMethodInsn(Opcodes.INVOKESPECIAL, CLASS_OBJECT, METHOD_INIT,
 119                     DESC_VOID_METHOD, false);
 120 
 121             mv.visitVarInsn(Opcodes.ALOAD, 0);
 122             mv.visitInsn(Opcodes.ICONST_0);
 123             mv.visitFieldInsn(Opcodes.PUTFIELD, CLASS_TEST, FIELD_FLAG,
 124                     Type.BOOLEAN_TYPE.getDescriptor());
 125 
 126             mv.visitInsn(Opcodes.RETURN);
 127             mv.visitMaxs(/* stack = */ 2, /* locals = */ 1);
 128             mv.visitEnd();
 129         }
 130 
 131         /*
 132             public static void m() {
 133                 try {
 134                 } finally {
 135                     Test test = new Test();
 136                     test.flag = true;
 137                 }
 138             }
 139         */
 140         {
 141             MethodVisitor mv = cw.visitMethod(
 142                     Opcodes.ACC_STATIC + Opcodes.ACC_PUBLIC,
 143                     METHOD_TEST, DESC_VOID_METHOD,
 144                     /* signature = */ null, /* exceptions = */ null);
 145             Label beginLabel = new Label();
 146             Label block1EndLabel = new Label();
 147             Label handlerLabel = new Label();
 148             Label block2EndLabel = new Label();
 149             Label label = new Label();
 150             Label endLabel = new Label();
 151 
 152             mv.visitCode();
 153             mv.visitTryCatchBlock(beginLabel, block1EndLabel, handlerLabel,
 154                     /* type = <any> */ null);
 155             mv.visitTryCatchBlock(handlerLabel, block2EndLabel, handlerLabel,
 156                     /* type = <any> */ null);
 157 
 158             mv.visitLabel(beginLabel);
 159             mv.visitJumpInsn(Opcodes.JSR, label);
 160             mv.visitLabel(block1EndLabel);
 161             mv.visitJumpInsn(Opcodes.GOTO, endLabel);
 162 
 163             mv.visitLabel(handlerLabel);
 164             mv.visitVarInsn(Opcodes.ASTORE, 0);
 165             mv.visitJumpInsn(Opcodes.JSR, label);
 166             mv.visitLabel(block2EndLabel);
 167             mv.visitVarInsn(Opcodes.ALOAD, 0);
 168             mv.visitInsn(Opcodes.ATHROW);
 169 
 170             mv.visitLabel(label);
 171             mv.visitVarInsn(Opcodes.ASTORE, 1);
 172             mv.visitTypeInsn(Opcodes.NEW, CLASS_TEST);
 173             mv.visitInsn(Opcodes.DUP);
 174             mv.visitMethodInsn(Opcodes.INVOKESPECIAL, CLASS_TEST, METHOD_INIT,
 175                     DESC_VOID_METHOD);
 176             mv.visitVarInsn(Opcodes.ASTORE, 2);
 177 
 178             mv.visitVarInsn(Opcodes.ALOAD, 2);
 179             mv.visitInsn(Opcodes.ICONST_1);
 180             mv.visitFieldInsn(Opcodes.PUTFIELD, CLASS_TEST, FIELD_FLAG,
 181                     Type.BOOLEAN_TYPE.getDescriptor());
 182 
 183             mv.visitVarInsn(Opcodes.RET, 1);
 184 
 185             mv.visitLabel(endLabel);
 186             mv.visitInsn(Opcodes.RETURN);
 187             mv.visitMaxs(/* stack = */ 2, /* locals = */ 3);
 188             mv.visitEnd();
 189         }
 190 
 191         cw.visitEnd();
 192         return cw.toByteArray();
 193     }
 194 }