1 /* 2 * Copyright (c) 2016, 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. 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 package jdk.jfr.internal; 26 27 import java.lang.reflect.Modifier; 28 29 import jdk.jfr.Event; 30 import jdk.jfr.internal.handlers.EventHandler; 31 import jdk.jfr.internal.instrument.JDKEvents; 32 33 /** 34 * All upcalls from the JVM should go through this class. 35 * 36 */ 37 // Called by native 38 final class JVMUpcalls { 39 /** 40 * Called by the JVM when a retransform happens on a tagged class 41 * 42 * @param traceId 43 * Id of the class 44 * @param dummy 45 * (not used but needed since invoke infrastructure in native 46 * uses same signature bytesForEagerInstrumentation) 47 * @param clazz 48 * class being retransformed 49 * @param oldBytes 50 * byte code 51 * @return byte code to use 52 * @throws Throwable 53 */ 54 static byte[] onRetransform(long traceId, boolean dummy, Class<?> clazz, byte[] oldBytes) throws Throwable { 55 try { 56 if (Event.class.isAssignableFrom(clazz) && !Modifier.isAbstract(clazz.getModifiers())) { 57 EventHandler handler = Utils.getHandler(clazz.asSubclass(Event.class)); 58 if (handler == null) { 59 Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "No event handler found for " + clazz.getName() + ". Ignoring instrumentation request."); 60 // Probably triggered by some other agent 61 return oldBytes; 62 } 63 Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Adding instrumentation to event class " + clazz.getName() + " using retransform"); 64 EventInstrumentation ei = new EventInstrumentation(clazz.getSuperclass(), oldBytes, traceId); 65 byte[] bytes = ei.buildInstrumented(); 66 ASMToolkit.logASM(clazz.getName(), bytes); 67 return bytes; 68 } 69 return JDKEvents.retransformCallback(clazz, oldBytes); 70 } catch (Throwable t) { 71 Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Unexpected error when adding instrumentation to event class " + clazz.getName()); 72 } 73 return oldBytes; 74 75 } 76 77 /** 78 * Called by the JVM when requested to do an "eager" instrumentation. Would 79 * normally happen when JVMTI retransform capabilities are not available. 80 * 81 * @param traceId 82 * Id of the class 83 * @param forceInstrumentation 84 * add instrumentation regardless if event is enabled or not. 85 * @param superClazz 86 * the super class of the class being processed 87 * @param oldBytes 88 * byte code 89 * @return byte code to use 90 * @throws Throwable 91 */ 92 static byte[] bytesForEagerInstrumentation(long traceId, boolean forceInstrumentation, Class<?> superClass, byte[] oldBytes) throws Throwable { 93 if (JVMSupport.isNotAvailable()) { 94 return oldBytes; 95 } 96 String eventName = "<Unknown>"; 97 try { 98 EventInstrumentation ei = new EventInstrumentation(superClass, oldBytes, traceId); 99 eventName = ei.getEventName(); 100 if (!forceInstrumentation) { 101 // Assume we are recording 102 MetadataRepository mr = MetadataRepository.getInstance(); 103 // No need to generate bytecode if: 104 // 1) Event class is disabled, and there is not an external configuration that overrides. 105 // 2) Event class has @Registered(false) 106 if (!mr.isEnabled(ei.getEventName()) && !ei.isEnabled() || !ei.isRegistered()) { 107 Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Skipping instrumentation for event type " + eventName + " since event was disabled on class load"); 108 return oldBytes; 109 } 110 } 111 // Corner case when we are forced to generate bytecode. We can't reference the event 112 // handler in #isEnabled() before event class has been registered, so we add a 113 // guard against a null reference. 114 ei.setGuardHandler(true); 115 Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Adding " + (forceInstrumentation ? "forced " : "") + "instrumentation for event type " + eventName + " during initial class load"); 116 EventHandlerCreator eh = new EventHandlerCreator(traceId, ei.getSettingInfos(), ei.getFieldInfos()); 117 // Handler class must be loaded before instrumented event class can 118 // be used 119 eh.makeEventHandlerClass(); 120 byte[] bytes = ei.buildInstrumented(); 121 ASMToolkit.logASM(ei.getClassName() + "(" + traceId + ")", bytes); 122 return bytes; 123 } catch (Throwable t) { 124 Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Unexpected error when adding instrumentation for event type " + eventName); 125 return oldBytes; 126 } 127 } 128 129 /** 130 * Called by the JVM to create the recorder thread. 131 * 132 * @param systemThreadGroup 133 * the system thread group 134 * 135 * @param contextClassLoader 136 * the context class loader. 137 * 138 * @return a new thread 139 */ 140 static Thread createRecorderThread(ThreadGroup systemThreadGroup, ClassLoader contextClassLoader) { 141 return SecuritySupport.createRecorderThread(systemThreadGroup, contextClassLoader); 142 } 143 }