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 }