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