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 8076110 27 * @summary Redefine running methods that have cached resolution errors 28 * @library /testlibrary 29 * @modules java.instrument 30 * java.base/jdk.internal.org.objectweb.asm 31 * @build RedefineClassHelper 32 * @run main RedefineClassHelper 33 * @run main/othervm -javaagent:redefineagent.jar -XX:TraceRedefineClasses=0x600 RedefineRunningMethodsWithResolutionErrors 34 */ 35 36 import jdk.internal.org.objectweb.asm.ClassWriter; 37 import jdk.internal.org.objectweb.asm.Label; 38 import jdk.internal.org.objectweb.asm.MethodVisitor; 39 import jdk.internal.org.objectweb.asm.Opcodes; 40 41 import java.lang.reflect.InvocationTargetException; 42 43 public class RedefineRunningMethodsWithResolutionErrors extends ClassLoader implements Opcodes { 44 45 @Override 46 protected Class<?> findClass(String name) throws ClassNotFoundException { 47 if (name.equals("C")) { 48 byte[] b = loadC(false); 49 return defineClass(name, b, 0, b.length); 50 } else { 51 return super.findClass(name); 52 } 53 } 54 55 private static byte[] loadC(boolean redefine) { 56 ClassWriter cw = new ClassWriter(0); 57 58 cw.visit(52, ACC_SUPER | ACC_PUBLIC, "C", null, "java/lang/Object", null); 59 { 60 MethodVisitor mv; 61 62 mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "m", "()V", null, null); 63 mv.visitCode(); 64 65 // First time we run we will: 66 // 1) Cache resolution errors 67 // 2) Redefine the class / method 68 // 3) Try to read the resolution errors that were cached 69 // 70 // The redefined method will never run, throw error to be sure 71 if (redefine) { 72 createThrowRuntimeExceptionCode(mv, "The redefined method was called"); 73 } else { 74 createMethodBody(mv); 75 } 76 mv.visitMaxs(3, 0); 77 mv.visitEnd(); 78 } 79 cw.visitEnd(); 80 return cw.toByteArray(); 81 } 82 83 private static void createMethodBody(MethodVisitor mv) { 84 Label classExists = new Label(); 85 86 // Cache resolution errors 87 createLoadNonExistentClassCode(mv, classExists); 88 89 // Redefine our own class and method 90 mv.visitMethodInsn(INVOKESTATIC, "RedefineRunningMethodsWithResolutionErrors", "redefine", "()V"); 91 92 // Provoke the same error again to make sure the resolution error cache works 93 createLoadNonExistentClassCode(mv, classExists); 94 95 // Test passed 96 mv.visitInsn(RETURN); 97 98 mv.visitFrame(F_SAME, 0, new Object[0], 0, new Object[0]); 99 mv.visitLabel(classExists); 100 101 createThrowRuntimeExceptionCode(mv, "Loaded class that shouldn't exist (\"NonExistentClass\")"); 102 } 103 104 private static void createLoadNonExistentClassCode(MethodVisitor mv, Label classExists) { 105 Label tryLoadBegin = new Label(); 106 Label tryLoadEnd = new Label(); 107 Label catchLoadBlock = new Label(); 108 mv.visitTryCatchBlock(tryLoadBegin, tryLoadEnd, catchLoadBlock, "java/lang/NoClassDefFoundError"); 109 110 // Try to load a class that does not exist to provoke resolution errors 111 mv.visitLabel(tryLoadBegin); 112 mv.visitMethodInsn(INVOKESTATIC, "NonExistentClass", "nonExistentMethod", "()V"); 113 mv.visitLabel(tryLoadEnd); 114 115 // No NoClassDefFoundError means NonExistentClass existed, which shouldn't happen 116 mv.visitJumpInsn(GOTO, classExists); 117 118 mv.visitFrame(F_SAME1, 0, new Object[0], 1, new Object[] { "java/lang/NoClassDefFoundError" }); 119 mv.visitLabel(catchLoadBlock); 120 121 // Ignore the expected NoClassDefFoundError 122 mv.visitInsn(POP); 123 } 124 125 private static void createThrowRuntimeExceptionCode(MethodVisitor mv, String msg) { 126 mv.visitTypeInsn(NEW, "java/lang/RuntimeException"); 127 mv.visitInsn(DUP); 128 mv.visitLdcInsn(msg); 129 mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V"); 130 mv.visitInsn(ATHROW); 131 } 132 133 private static Class<?> c; 134 135 public static void redefine() throws Exception { 136 RedefineClassHelper.redefineClass(c, loadC(true)); 137 } 138 139 public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { 140 c = Class.forName("C", true, new RedefineRunningMethodsWithResolutionErrors()); 141 c.getMethod("m").invoke(null); 142 } 143 }