1 /* 2 * Copyright (c) 2017, 2018, 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 import java.lang.instrument.ClassDefinition; 26 import java.lang.instrument.Instrumentation; 27 import java.lang.instrument.UnmodifiableClassException; 28 import java.net.URL; 29 import java.net.URLClassLoader; 30 import java.io.File; 31 import java.security.CodeSigner; 32 import java.security.CodeSource; 33 import java.security.ProtectionDomain; 34 import sun.hotspot.WhiteBox; 35 36 public class RedefineClassApp { 37 static WhiteBox wb = WhiteBox.getWhiteBox(); 38 39 public static interface Intf { // Loaded from Boot class loader (-Xbootclasspath/a). 40 public String get(); 41 } 42 public static class Bar implements Intf { // Loaded from Boot class loader. 43 public String get() { 44 return "buzz"; 45 } 46 } 47 public static class Foo implements Intf { // Loaded from AppClassLoader 48 public String get() { 49 return "buzz"; 50 } 51 } 52 53 static int numTests = 0; 54 static int failed = 0; 55 static Instrumentation instrumentation; 56 57 public static void main(String args[]) throws Throwable { 58 if (wb.areSharedStringsIgnored()) { 59 System.out.println("Shared strings are ignored."); 60 return; 61 } 62 63 File bootJar = new File(args[0]); 64 File appJar = new File(args[1]); 65 66 instrumentation = InstrumentationRegisterClassFileTransformer.getInstrumentation(); 67 System.out.println("INFO: instrumentation = " + instrumentation); 68 69 testBootstrapCDS("Bootstrap Loader", bootJar); 70 testAppCDSv1("Application Loader", appJar); 71 72 if (failed > 0) { 73 throw new RuntimeException("FINAL RESULT: " + failed + " out of " + numTests + " test case(s) have failed"); 74 } else { 75 System.out.println("FINAL RESULT: All " + numTests + " test case(s) have passed!"); 76 } 77 78 // Full GC. The cached objects in adjustable archive heap regions are 79 // scanned. The archive regions are verified. No error should be 80 // reported. 81 wb.fullGC(); 82 } 83 84 static void testBootstrapCDS(String group, File jar) throws Throwable { 85 doTest(group, new Bar(), jar); 86 } 87 88 static void testAppCDSv1(String group, File jar) throws Throwable { 89 doTest(group, new Foo(), jar); 90 } 91 92 static void checkArchivedMirrorObject(Class klass) { 93 if (wb.areOpenArchiveHeapObjectsMapped()) { 94 if (!wb.isShared(klass)) { 95 failed ++; 96 System.out.println("FAILED. " + klass + " mirror object is not archived"); 97 return; 98 } 99 } 100 } 101 102 static void doTest(String group, Intf object, File jar) throws Throwable { 103 numTests ++; 104 105 Class klass = object.getClass(); 106 System.out.println(); 107 System.out.println("++++++++++++++++++++++++++"); 108 System.out.println("Test group: " + group); 109 System.out.println("Testing with classloader = " + klass.getClassLoader()); 110 System.out.println("Testing with class = " + klass); 111 System.out.println("Test is shared = " + wb.isSharedClass(klass)); 112 System.out.println("++++++++++++++++++++++++++"); 113 114 // Check archived mirror object before redefine 115 checkArchivedMirrorObject(klass); 116 117 // Call get() before redefine. All strings in archived classes are shared. 118 String res = object.get(); 119 System.out.println("get() returns " + res); 120 if (res.equals("buzz") && wb.isShared(res)) { 121 System.out.println("get() returns " + res + ", string is shared"); 122 } else { 123 if (!res.equals("buzz")) { 124 System.out.println("FAILED. buzz is expected but got " + res); 125 } else { 126 System.out.println("FAILED. " + res + " is not shared"); 127 } 128 failed ++; 129 return; 130 } 131 res = null; // release the local reference to the string 132 133 // Run GC 134 System.gc(); 135 System.gc(); 136 System.gc(); 137 138 // Redefine the shared class 139 byte[] buff = Util.getClassFileFromJar(jar, klass.getName()); 140 Util.replace(buff, "buzz", "huzz"); 141 String f = "(failed)"; 142 try { 143 instrumentation.redefineClasses(new ClassDefinition(klass, buff)); 144 f = object.get(); 145 } catch (UnmodifiableClassException|UnsupportedOperationException e) { 146 e.printStackTrace(); 147 } 148 if (f.equals("huzz")) { 149 System.out.println("PASSED: object.get() after redefinition returns " + f); 150 } else { 151 System.out.println("FAILED: object.get() after redefinition returns " + f); 152 failed ++; 153 } 154 155 // Run GC. Should not crash. 156 System.gc(); 157 System.gc(); 158 System.gc(); 159 160 // Check archived mirror object after redefine and GC 161 checkArchivedMirrorObject(klass); 162 163 System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++ (done)\n\n"); 164 } 165 }