1 /* 2 * Copyright (c) 2014, 2020, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.jfr.event.runtime; 27 28 import java.io.File; 29 import java.io.FileInputStream; 30 import java.io.IOException; 31 import java.lang.reflect.Method; 32 import java.nio.ByteBuffer; 33 import java.nio.channels.FileChannel; 34 import java.util.List; 35 36 import jdk.jfr.Recording; 37 import jdk.jfr.consumer.RecordedClassLoader; 38 import jdk.jfr.consumer.RecordedEvent; 39 import jdk.test.lib.Asserts; 40 import jdk.test.lib.jfr.EventNames; 41 import jdk.test.lib.jfr.Events; 42 43 import jdk.test.lib.compiler.InMemoryJavaCompiler; 44 45 /** 46 * @test 47 * @key jfr 48 * @requires vm.hasJFR 49 * @library /test/lib /test/jdk 50 * @modules java.base/jdk.internal.misc 51 * jdk.compiler 52 * jdk.jfr 53 * @build jdk.jfr.event.runtime.TestClasses 54 * @run main/othervm jdk.jfr.event.runtime.TestClassLoaderStatsEvent 55 */ 56 public class TestClassLoaderStatsEvent { 57 private final static String EVENT_NAME = EventNames.ClassLoaderStatistics; 58 private final static String CLASS_LOADER_NAME = "MyDummyClassLoader"; 59 private final static String CLASSLOADER_TYPE_NAME = "jdk.jfr.event.runtime.TestClassLoaderStatsEvent$DummyClassLoader"; 60 public static DummyClassLoader dummyloader; 61 62 public static void main(String[] args) throws Throwable { 63 createDummyClassLoader(CLASS_LOADER_NAME); 64 65 Recording recording = new Recording(); 66 recording.enable(EVENT_NAME); 67 recording.start(); 68 recording.stop(); 69 List<RecordedEvent> consumer = Events.fromRecording(recording); 70 Events.hasEvents(consumer); 71 72 boolean isAnyFound = false; 73 for (RecordedEvent event : consumer) { 74 System.out.println("Event:" + event); 75 if (Events.assertField(event, "classLoader").getValue() == null) { 76 continue; 77 } 78 RecordedClassLoader recordedClassLoader = event.getValue("classLoader"); 79 if (CLASSLOADER_TYPE_NAME.equals(recordedClassLoader.getType().getName())) { 80 Asserts.assertEquals(CLASS_LOADER_NAME, recordedClassLoader.getName(), 81 "Expected class loader name " + CLASS_LOADER_NAME + ", got name " + recordedClassLoader.getName()); 82 Events.assertField(event, "classCount").equal(2L); 83 Events.assertField(event, "chunkSize").above(1L); 84 Events.assertField(event, "blockSize").above(1L); 85 // Hidden classes stats include both hidden and unsafe anonymous classes. 86 Events.assertField(event, "hiddenClassCount").equal(4L); 87 Events.assertField(event, "hiddenChunkSize").above(0L); 88 Events.assertField(event, "hiddenBlockSize").above(0L); 89 isAnyFound = true; 90 } 91 } 92 Asserts.assertTrue(isAnyFound, "No events found"); 93 } 94 95 private static void createDummyClassLoader(String name) throws Throwable { 96 dummyloader = new DummyClassLoader(name); 97 Class<?> c = Class.forName(TestClass.class.getName(), true, dummyloader); 98 if (c.getClassLoader() != dummyloader) { 99 throw new RuntimeException("TestClass defined by wrong classloader: " + c.getClassLoader()); 100 } 101 102 // Compile a class for method createNonFindableClasses() to use to create both a 103 // weak hidden class and an anonymous class. 104 byte klassbuf[] = InMemoryJavaCompiler.compile("jdk.jfr.event.runtime.TestClass", 105 "package jdk.jfr.event.runtime; " + 106 "public class TestClass { " + 107 " public static void concat(String one, String two) throws Throwable { " + 108 " } } "); 109 110 Method m = c.getDeclaredMethod("createNonFindableClasses", byte[].class); 111 m.setAccessible(true); 112 m.invoke(null, klassbuf); 113 } 114 115 public static class DummyClassLoader extends ClassLoader { 116 117 static ByteBuffer readClassFile(String name) { 118 String testClasses = System.getProperty("test.classes"); 119 File f = new File(testClasses, name); 120 try (FileInputStream fin = new FileInputStream(f)) { 121 FileChannel fc = fin.getChannel(); 122 return fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()); 123 } catch (IOException e) { 124 throw new RuntimeException("Can't open file: " + f, e); 125 } 126 } 127 128 protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { 129 Class<?> c; 130 if (TestClass.class.getName().equals(name)) { 131 c = findClass(name); 132 if (resolve) { 133 resolveClass(c); 134 } 135 } else { 136 c = super.loadClass(name, resolve); 137 } 138 return c; 139 } 140 141 protected Class<?> findClass(String name) throws ClassNotFoundException { 142 if (!TestClass.class.getName().equals(name)) { 143 throw new ClassNotFoundException("Unexpected class: " + name); 144 } 145 return defineClass(name, readClassFile(TestClass.class.getName().replace(".", File.separator) + ".class"), null); 146 } 147 148 public DummyClassLoader(String name) { 149 super(name, ClassLoader.getSystemClassLoader()); 150 } 151 } 152 }