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 }