1 /*
  2  * Copyright (c) 2013, 2019, 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 package gc.metaspace;
 25 
 26 /*
 27  * @test G1AddMetaspaceDependency
 28  * @bug 8010196
 29  * @requires vm.gc.G1
 30  * @library /
 31  * @summary Checks that we don't get locking problems when adding metaspace dependencies with the G1 update buffer monitor
 32  * @run main/othervm -XX:+UseG1GC -XX:G1UpdateBufferSize=1 gc.metaspace.G1AddMetaspaceDependency
 33  */
 34 
 35 import java.io.InputStream;
 36 
 37 public class G1AddMetaspaceDependency {
 38 
 39   static byte[] getClassBytes(String name) {
 40     byte[] b = null;
 41     try (InputStream is = ClassLoader.getSystemResourceAsStream(name)) {
 42       byte[] tmp = new byte[is.available()];
 43       is.read(tmp);
 44       b = tmp;
 45     } finally {
 46       if (b == null) {
 47         throw new RuntimeException("Unable to load class file");
 48       }
 49       return b;
 50     }
 51   }
 52 
 53   static final String a_name = A.class.getName();
 54   static final String b_name = B.class.getName();
 55 
 56   public static void main(String... args) throws Exception {
 57     final byte[] a_bytes = getClassBytes(a_name.replace('.', '/') + ".class");
 58     final byte[] b_bytes = getClassBytes(b_name.replace('.', '/') + ".class");
 59 
 60     for (int i = 0; i < 1000; i += 1) {
 61       runTest(a_bytes, b_bytes);
 62     }
 63   }
 64 
 65   static class Loader extends ClassLoader {
 66     private final String myClass;
 67     private final byte[] myBytes;
 68     private final String friendClass;
 69     private final ClassLoader friendLoader;
 70 
 71     Loader(String myClass, byte[] myBytes,
 72            String friendClass, ClassLoader friendLoader) {
 73       this.myClass = myClass;
 74       this.myBytes = myBytes;
 75       this.friendClass = friendClass;
 76       this.friendLoader = friendLoader;
 77     }
 78 
 79     Loader(String myClass, byte[] myBytes) {
 80       this(myClass, myBytes, null, null);
 81     }
 82 
 83     @Override
 84     public Class<?> loadClass(String name) throws ClassNotFoundException {
 85       Class<?> c = findLoadedClass(name);
 86       if (c != null) {
 87         return c;
 88       }
 89 
 90       if (name.equals(friendClass)) {
 91         return friendLoader.loadClass(name);
 92       }
 93 
 94       if (name.equals(myClass)) {
 95         c = defineClass(name, myBytes, 0, myBytes.length);
 96         resolveClass(c);
 97         return c;
 98       }
 99 
100       return findSystemClass(name);
101     }
102 
103   }
104 
105   private static void runTest(final byte[] a_bytes, final byte[] b_bytes) throws Exception {
106     Loader a_loader = new Loader(a_name, a_bytes);
107     Loader b_loader = new Loader(b_name, b_bytes, a_name, a_loader);
108     Loader c_loader = new Loader(b_name, b_bytes, a_name, a_loader);
109     Loader d_loader = new Loader(b_name, b_bytes, a_name, a_loader);
110     Loader e_loader = new Loader(b_name, b_bytes, a_name, a_loader);
111     Loader f_loader = new Loader(b_name, b_bytes, a_name, a_loader);
112     Loader g_loader = new Loader(b_name, b_bytes, a_name, a_loader);
113 
114     b_loader.loadClass(b_name);
115     c_loader.loadClass(b_name);
116     d_loader.loadClass(b_name);
117     e_loader.loadClass(b_name);
118     f_loader.loadClass(b_name);
119     g_loader.loadClass(b_name);
120   }
121   public class A {
122   }
123   class B extends A {
124   }
125 }