8331877: JFR: Remove JIInliner framework
Reviewed-by: mgronlun
This commit is contained in:
parent
d9e7b7e7da
commit
5abc02927b
@ -23,35 +23,26 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal.instrument;
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.event.JFRTracing;
|
||||
import jdk.internal.event.ThrowableTracer;
|
||||
import jdk.internal.platform.Container;
|
||||
import jdk.internal.platform.Metrics;
|
||||
import jdk.jfr.Event;
|
||||
import jdk.jfr.events.ActiveRecordingEvent;
|
||||
import jdk.jfr.events.ActiveSettingEvent;
|
||||
import jdk.jfr.events.ContainerIOUsageEvent;
|
||||
import jdk.jfr.events.ContainerConfigurationEvent;
|
||||
import jdk.jfr.events.ContainerCPUUsageEvent;
|
||||
import jdk.jfr.events.ContainerCPUThrottlingEvent;
|
||||
import jdk.jfr.events.ContainerCPUUsageEvent;
|
||||
import jdk.jfr.events.ContainerConfigurationEvent;
|
||||
import jdk.jfr.events.ContainerIOUsageEvent;
|
||||
import jdk.jfr.events.ContainerMemoryUsageEvent;
|
||||
import jdk.jfr.events.DirectBufferStatisticsEvent;
|
||||
import jdk.jfr.events.FileForceEvent;
|
||||
import jdk.jfr.events.InitialSecurityPropertyEvent;
|
||||
|
||||
import jdk.jfr.internal.JVM;
|
||||
import jdk.jfr.internal.LogLevel;
|
||||
import jdk.jfr.internal.LogTag;
|
||||
import jdk.jfr.internal.Logger;
|
||||
import jdk.jfr.internal.SecuritySupport;
|
||||
import jdk.jfr.internal.periodic.PeriodicEvents;
|
||||
import jdk.internal.platform.Container;
|
||||
import jdk.internal.platform.Metrics;
|
||||
|
||||
public final class JDKEvents {
|
||||
|
||||
@ -85,11 +76,6 @@ public final class JDKEvents {
|
||||
InitialSecurityPropertyEvent.class,
|
||||
};
|
||||
|
||||
// This is a list of the classes with instrumentation code that should be applied.
|
||||
private static final Class<?>[] instrumentationClasses = new Class<?>[] {
|
||||
};
|
||||
|
||||
private static final Class<?>[] targetClasses = new Class<?>[instrumentationClasses.length];
|
||||
private static final Runnable emitExceptionStatistics = JDKEvents::emitExceptionStatistics;
|
||||
private static final Runnable emitDirectBufferStatistics = JDKEvents::emitDirectBufferStatistics;
|
||||
private static final Runnable emitContainerConfiguration = JDKEvents::emitContainerConfiguration;
|
||||
@ -121,24 +107,6 @@ public final class JDKEvents {
|
||||
}
|
||||
}
|
||||
|
||||
public static void addInstrumentation() {
|
||||
try {
|
||||
List<Class<?>> list = new ArrayList<>();
|
||||
for (int i = 0; i < instrumentationClasses.length; i++) {
|
||||
JIInstrumentationTarget tgt = instrumentationClasses[i].getAnnotation(JIInstrumentationTarget.class);
|
||||
Class<?> clazz = Class.forName(tgt.value());
|
||||
targetClasses[i] = clazz;
|
||||
list.add(clazz);
|
||||
}
|
||||
Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Retransformed JDK classes");
|
||||
JVM.retransformClasses(list.toArray(new Class<?>[list.size()]));
|
||||
} catch (IllegalStateException ise) {
|
||||
throw ise;
|
||||
} catch (Exception e) {
|
||||
Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Could not add instrumentation for JDK events. " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static void initializeContainerEvents() {
|
||||
if (JVM.isContainerized() ) {
|
||||
Logger.log(LogTag.JFR_SYSTEM, LogLevel.DEBUG, "JVM is containerized");
|
||||
@ -225,20 +193,6 @@ public final class JDKEvents {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static byte[] retransformCallback(Class<?> klass, byte[] oldBytes) throws Throwable {
|
||||
for (int i = 0; i < targetClasses.length; i++) {
|
||||
if (targetClasses[i].equals(klass)) {
|
||||
Class<?> c = instrumentationClasses[i];
|
||||
if (Logger.shouldLog(LogTag.JFR_SYSTEM, LogLevel.TRACE)) {
|
||||
Logger.log(LogTag.JFR_SYSTEM, LogLevel.TRACE, "Processing instrumentation class: " + c);
|
||||
}
|
||||
return new JIClassInstrumentation(instrumentationClasses[i], klass, oldBytes).getNewBytes();
|
||||
}
|
||||
}
|
||||
return oldBytes;
|
||||
}
|
||||
|
||||
public static void remove() {
|
||||
PeriodicEvents.removeEvent(emitExceptionStatistics);
|
||||
PeriodicEvents.removeEvent(emitDirectBufferStatistics);
|
@ -27,7 +27,6 @@ package jdk.jfr.internal;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import jdk.jfr.internal.event.EventConfiguration;
|
||||
import jdk.jfr.internal.instrument.JDKEvents;
|
||||
import jdk.jfr.internal.util.Bytecode;
|
||||
/**
|
||||
* All upcalls from the JVM should go through this class.
|
||||
@ -78,7 +77,7 @@ final class JVMUpcalls {
|
||||
Bytecode.log(clazz.getName(), bytes);
|
||||
return bytes;
|
||||
}
|
||||
return JDKEvents.retransformCallback(clazz, oldBytes);
|
||||
return oldBytes;
|
||||
} catch (Throwable t) {
|
||||
Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Unexpected error when adding instrumentation to event class " + clazz.getName());
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -57,7 +57,6 @@ import jdk.jfr.events.ActiveSettingEvent;
|
||||
import jdk.jfr.internal.SecuritySupport.SafePath;
|
||||
import jdk.jfr.internal.SecuritySupport.SecureRecorderListener;
|
||||
import jdk.jfr.internal.consumer.EventLog;
|
||||
import jdk.jfr.internal.instrument.JDKEvents;
|
||||
import jdk.jfr.internal.periodic.PeriodicEvents;
|
||||
import jdk.jfr.internal.util.Utils;
|
||||
|
||||
@ -83,7 +82,6 @@ public final class PlatformRecorder {
|
||||
Logger.log(JFR_SYSTEM, INFO, "Created native");
|
||||
JDKEvents.initialize();
|
||||
Logger.log(JFR_SYSTEM, INFO, "Registered JDK events");
|
||||
JDKEvents.addInstrumentation();
|
||||
startDiskMonitor();
|
||||
shutdownHook = SecuritySupport.createThreadWitNoPermissions("JFR Shutdown Hook", new ShutdownHook(this));
|
||||
SecuritySupport.setUncaughtExceptionHandler(shutdownHook, new ShutdownHook.ExceptionHandler());
|
||||
|
@ -73,7 +73,6 @@ import jdk.jfr.internal.consumer.FileAccess;
|
||||
*/
|
||||
public final class SecuritySupport {
|
||||
private static final String EVENTS_PACKAGE_NAME = "jdk.jfr.events";
|
||||
private static final String INSTRUMENT_PACKAGE_NAME = "jdk.jfr.internal.instrument";
|
||||
private static final String EVENT_PACKAGE_NAME = "jdk.jfr.internal.event";
|
||||
|
||||
public static final String REGISTER_EVENT = "registerEvent";
|
||||
@ -89,7 +88,6 @@ public final class SecuritySupport {
|
||||
addReadEdge(Object.class);
|
||||
addInternalEventExport(Object.class);
|
||||
addEventsExport(Object.class);
|
||||
addInstrumentExport(Object.class);
|
||||
}
|
||||
|
||||
static final class SecureRecorderListener implements FlightRecorderListener {
|
||||
@ -323,10 +321,6 @@ public final class SecuritySupport {
|
||||
Modules.addExports(JFR_MODULE, EVENTS_PACKAGE_NAME, clazz.getModule());
|
||||
}
|
||||
|
||||
static void addInstrumentExport(Class<?> clazz) {
|
||||
Modules.addExports(JFR_MODULE, INSTRUMENT_PACKAGE_NAME, clazz.getModule());
|
||||
}
|
||||
|
||||
static void addReadEdge(Class<?> clazz) {
|
||||
Modules.addReads(clazz.getModule(), JFR_MODULE);
|
||||
}
|
||||
|
@ -1,130 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal.instrument;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.ClassReader;
|
||||
import jdk.internal.org.objectweb.asm.ClassVisitor;
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.tree.ClassNode;
|
||||
import jdk.jfr.internal.SecuritySupport;
|
||||
|
||||
/**
|
||||
* This class will perform byte code instrumentation given an "instrumentor" class.
|
||||
*
|
||||
* @see JITracer
|
||||
*
|
||||
* @author Staffan Larsen
|
||||
*/
|
||||
@Deprecated
|
||||
final class JIClassInstrumentation {
|
||||
private final Class<?> instrumentor;
|
||||
private final String targetName;
|
||||
private final String instrumentorName;
|
||||
private final byte[] newBytes;
|
||||
private final ClassReader targetClassReader;
|
||||
private final ClassReader instrClassReader;
|
||||
|
||||
/**
|
||||
* Creates an instance and performs the instrumentation.
|
||||
*
|
||||
* @param instrumentor instrumentor class
|
||||
* @param target target class
|
||||
* @param old_target_bytes bytes in target
|
||||
*
|
||||
* @throws ClassNotFoundException
|
||||
* @throws IOException
|
||||
*/
|
||||
JIClassInstrumentation(Class<?> instrumentor, Class<?> target, byte[] old_target_bytes) throws ClassNotFoundException, IOException {
|
||||
instrumentorName = instrumentor.getName();
|
||||
this.targetName = target.getName();
|
||||
this.instrumentor = instrumentor;
|
||||
this.targetClassReader = new ClassReader(old_target_bytes);
|
||||
this.instrClassReader = new ClassReader(getOriginalClassBytes(instrumentor));
|
||||
this.newBytes = makeBytecode();
|
||||
}
|
||||
|
||||
private static byte[] getOriginalClassBytes(Class<?> clazz) throws IOException {
|
||||
String name = "/" + clazz.getName().replace(".", "/") + ".class";
|
||||
try (InputStream is = SecuritySupport.getResourceAsStream(name)) {
|
||||
return is.readAllBytes();
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] makeBytecode() throws IOException, ClassNotFoundException {
|
||||
|
||||
// Find the methods to instrument and inline
|
||||
|
||||
final List<Method> instrumentationMethods = new ArrayList<>();
|
||||
for (final Method m : instrumentor.getDeclaredMethods()) {
|
||||
JIInstrumentationMethod im = m.getAnnotation(JIInstrumentationMethod.class);
|
||||
if (im != null) {
|
||||
instrumentationMethods.add(m);
|
||||
}
|
||||
}
|
||||
|
||||
// We begin by inlining the target's methods into the instrumentor
|
||||
|
||||
ClassNode temporary = new ClassNode();
|
||||
ClassVisitor inliner = new JIInliner(
|
||||
Opcodes.ASM7,
|
||||
temporary,
|
||||
targetName,
|
||||
instrumentorName,
|
||||
targetClassReader,
|
||||
instrumentationMethods);
|
||||
instrClassReader.accept(inliner, ClassReader.EXPAND_FRAMES);
|
||||
|
||||
// Now we have the target's methods inlined into the instrumentation code (in 'temporary').
|
||||
// We now need to replace the target's method with the code in the
|
||||
// instrumentation method.
|
||||
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||
JIMethodMergeAdapter ma = new JIMethodMergeAdapter(
|
||||
cw,
|
||||
temporary,
|
||||
instrumentationMethods,
|
||||
instrumentor.getAnnotationsByType(JITypeMapping.class));
|
||||
targetClassReader.accept(ma, ClassReader.EXPAND_FRAMES);
|
||||
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the instrumented byte codes that can be used to retransform the class.
|
||||
*
|
||||
* @return bytes
|
||||
*/
|
||||
public byte[] getNewBytes() {
|
||||
return newBytes.clone();
|
||||
}
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal.instrument;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.ClassReader;
|
||||
import jdk.internal.org.objectweb.asm.ClassVisitor;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import jdk.internal.org.objectweb.asm.tree.ClassNode;
|
||||
import jdk.internal.org.objectweb.asm.tree.MethodNode;
|
||||
import jdk.jfr.internal.LogLevel;
|
||||
import jdk.jfr.internal.LogTag;
|
||||
import jdk.jfr.internal.Logger;
|
||||
|
||||
@Deprecated
|
||||
final class JIInliner extends ClassVisitor {
|
||||
private final String targetClassName;
|
||||
private final String instrumentationClassName;
|
||||
private final ClassNode targetClassNode;
|
||||
private final List<Method> instrumentationMethods;
|
||||
|
||||
/**
|
||||
* A ClassVisitor which will check all methods of the class it visits against the instrumentationMethods
|
||||
* list. If a method is on that list, the method will be further processed for inlining into that
|
||||
* method.
|
||||
*/
|
||||
JIInliner(int api, ClassVisitor cv, String targetClassName, String instrumentationClassName,
|
||||
ClassReader targetClassReader,
|
||||
List<Method> instrumentationMethods) {
|
||||
super(api, cv);
|
||||
this.targetClassName = targetClassName;
|
||||
this.instrumentationClassName = instrumentationClassName;
|
||||
this.instrumentationMethods = instrumentationMethods;
|
||||
|
||||
ClassNode cn = new ClassNode(Opcodes.ASM7);
|
||||
targetClassReader.accept(cn, ClassReader.EXPAND_FRAMES);
|
||||
this.targetClassNode = cn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
||||
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
|
||||
|
||||
if (isInstrumentationMethod(name, desc)) {
|
||||
MethodNode methodToInline = findTargetMethodNode(name, desc);
|
||||
if (methodToInline == null) {
|
||||
throw new IllegalArgumentException("Could not find the method to instrument in the target class");
|
||||
}
|
||||
if (Modifier.isNative(methodToInline.access)) {
|
||||
throw new IllegalArgumentException("Cannot instrument native methods: " + targetClassNode.name + "." + methodToInline.name + methodToInline.desc);
|
||||
}
|
||||
|
||||
Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG, "Inliner processing method " + name + desc);
|
||||
|
||||
JIMethodCallInliner mci = new JIMethodCallInliner(access,
|
||||
desc,
|
||||
mv,
|
||||
methodToInline,
|
||||
targetClassName,
|
||||
instrumentationClassName);
|
||||
return mci;
|
||||
}
|
||||
|
||||
return mv;
|
||||
}
|
||||
|
||||
private boolean isInstrumentationMethod(String name, String desc) {
|
||||
for(Method m : instrumentationMethods) {
|
||||
if (m.getName().equals(name) && Type.getMethodDescriptor(m).equals(desc)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private MethodNode findTargetMethodNode(String name, String desc) {
|
||||
for (MethodNode mn : targetClassNode.methods) {
|
||||
if (mn.desc.equals(desc) && mn.name.equals(name)) {
|
||||
return mn;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("could not find MethodNode for "
|
||||
+ name + desc);
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal.instrument;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface JIInstrumentationMethod {
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal.instrument;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface JIInstrumentationTarget {
|
||||
String value();
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal.instrument;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.Label;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.commons.LocalVariablesSorter;
|
||||
import jdk.internal.org.objectweb.asm.commons.Remapper;
|
||||
import jdk.internal.org.objectweb.asm.commons.SimpleRemapper;
|
||||
import jdk.internal.org.objectweb.asm.tree.MethodNode;
|
||||
import jdk.jfr.internal.LogLevel;
|
||||
import jdk.jfr.internal.LogTag;
|
||||
import jdk.jfr.internal.Logger;
|
||||
|
||||
/**
|
||||
* Class responsible for finding the call to inline and inlining it.
|
||||
*
|
||||
* This code is heavily influenced by section 3.2.6 "Inline Method" in
|
||||
* "Using ASM framework to implement common bytecode transformation patterns",
|
||||
* E. Kuleshov, AOSD.07, March 2007, Vancouver, Canada.
|
||||
* http://asm.ow2.org/index.html
|
||||
*/
|
||||
@Deprecated
|
||||
final class JIMethodCallInliner extends LocalVariablesSorter {
|
||||
|
||||
private final String oldClass;
|
||||
private final String newClass;
|
||||
private final MethodNode inlineTarget;
|
||||
private final List<CatchBlock> blocks = new ArrayList<>();
|
||||
private boolean inlining;
|
||||
|
||||
/**
|
||||
* inlineTarget defines the method to inline and also contains the actual
|
||||
* code to inline.
|
||||
*
|
||||
* @param access
|
||||
* @param desc
|
||||
* @param mv
|
||||
* @param inlineTarget
|
||||
* @param oldClass
|
||||
* @param newClass
|
||||
* @param logger
|
||||
*/
|
||||
public JIMethodCallInliner(int access, String desc, MethodVisitor mv,
|
||||
MethodNode inlineTarget, String oldClass, String newClass) {
|
||||
super(Opcodes.ASM7, access, desc, mv);
|
||||
this.oldClass = oldClass;
|
||||
this.newClass = newClass;
|
||||
this.inlineTarget = inlineTarget;
|
||||
|
||||
if (Logger.shouldLog(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG)) {
|
||||
Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG,
|
||||
"MethodCallInliner: targetMethod=" + newClass + "."
|
||||
+ inlineTarget.name + inlineTarget.desc);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(int opcode, String owner, String name,
|
||||
String desc, boolean itf) {
|
||||
// Now we are looking at method call in the source method
|
||||
if (!shouldBeInlined(owner, name, desc)) {
|
||||
// If this method call should not be inlined, just keep it
|
||||
mv.visitMethodInsn(opcode, owner, name, desc, itf);
|
||||
return;
|
||||
}
|
||||
// If the call should be inlined, we create a MethodInliningAdapter
|
||||
// The MIA will walk the instructions in the inlineTarget and add them
|
||||
// to the current method, doing the necessary name remappings.
|
||||
Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG, "Inlining call to " + name + desc);
|
||||
Remapper remapper = new SimpleRemapper(oldClass, newClass);
|
||||
Label end = new Label();
|
||||
inlining = true;
|
||||
inlineTarget.instructions.resetLabels();
|
||||
JIMethodInliningAdapter mia = new JIMethodInliningAdapter(this, end,
|
||||
opcode == Opcodes.INVOKESTATIC ? Opcodes.ACC_STATIC : 0, desc,
|
||||
remapper);
|
||||
inlineTarget.accept(mia);
|
||||
inlining = false;
|
||||
super.visitLabel(end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the method should be inlined or not.
|
||||
*/
|
||||
private boolean shouldBeInlined(String owner, String name, String desc) {
|
||||
return inlineTarget.desc.equals(desc) && inlineTarget.name.equals(name)
|
||||
&& owner.equals(newClass.replace('.', '/'));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTryCatchBlock(Label start, Label end, Label handler,
|
||||
String type) {
|
||||
if (!inlining) {
|
||||
// try-catch blocks are saved here and replayed at the end
|
||||
// of the method (in visitMaxs)
|
||||
blocks.add(new CatchBlock(start, end, handler, type));
|
||||
} else {
|
||||
super.visitTryCatchBlock(start, end, handler, type);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMaxs(int stack, int locals) {
|
||||
for (CatchBlock b : blocks) {
|
||||
super.visitTryCatchBlock(b.start, b.end, b.handler, b.type);
|
||||
}
|
||||
super.visitMaxs(stack, locals);
|
||||
}
|
||||
|
||||
static final class CatchBlock {
|
||||
|
||||
final Label start;
|
||||
final Label end;
|
||||
final Label handler;
|
||||
final String type;
|
||||
|
||||
CatchBlock(Label start, Label end, Label handler, String type) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.handler = handler;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal.instrument;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.Label;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import jdk.internal.org.objectweb.asm.commons.LocalVariablesSorter;
|
||||
import jdk.internal.org.objectweb.asm.commons.Remapper;
|
||||
import jdk.internal.org.objectweb.asm.commons.RemappingMethodAdapter;
|
||||
|
||||
@Deprecated
|
||||
final class JIMethodInliningAdapter extends RemappingMethodAdapter {
|
||||
private final LocalVariablesSorter lvs;
|
||||
private final Label end;
|
||||
|
||||
public JIMethodInliningAdapter(LocalVariablesSorter mv, Label end, int acc, String desc, Remapper remapper) {
|
||||
super(acc, desc, mv, remapper);
|
||||
this.lvs = mv;
|
||||
this.end = end;
|
||||
int offset = isStatic(acc) ? 0 : 1;
|
||||
Type[] args = Type.getArgumentTypes(desc);
|
||||
for (int i = args.length - 1; i >= 0; i--) {
|
||||
super.visitVarInsn(args[i].getOpcode(Opcodes.ISTORE), i + offset);
|
||||
}
|
||||
if (offset > 0) {
|
||||
super.visitVarInsn(Opcodes.ASTORE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isStatic(int acc) {
|
||||
return (acc & Opcodes.ACC_STATIC) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInsn(int opcode) {
|
||||
if (opcode == Opcodes.RETURN || opcode == Opcodes.IRETURN
|
||||
|| opcode == Opcodes.ARETURN || opcode == Opcodes.LRETURN) {
|
||||
super.visitJumpInsn(Opcodes.GOTO, end);
|
||||
} else {
|
||||
super.visitInsn(opcode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMaxs(int stack, int locals) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int newLocalMapping(Type type) {
|
||||
return lvs.newLocal(type);
|
||||
}
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal.instrument;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.ClassVisitor;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import jdk.internal.org.objectweb.asm.commons.RemappingMethodAdapter;
|
||||
import jdk.internal.org.objectweb.asm.commons.SimpleRemapper;
|
||||
import jdk.internal.org.objectweb.asm.tree.ClassNode;
|
||||
import jdk.internal.org.objectweb.asm.tree.MethodNode;
|
||||
import jdk.jfr.internal.LogLevel;
|
||||
import jdk.jfr.internal.LogTag;
|
||||
import jdk.jfr.internal.Logger;
|
||||
|
||||
/**
|
||||
* This class will merge (some) methods from one class into another one.
|
||||
*
|
||||
* @author Staffan Larsen
|
||||
*/
|
||||
@Deprecated
|
||||
final class JIMethodMergeAdapter extends ClassVisitor {
|
||||
|
||||
private final ClassNode cn;
|
||||
private final List<Method> methodFilter;
|
||||
private final Map<String, String> typeMap;
|
||||
|
||||
/**
|
||||
* Methods in methodFilter that exist in cn will be merged into cv. If the method already exists,
|
||||
* the original method will be deleted.
|
||||
*
|
||||
* @param cv
|
||||
* @param cn - a ClassNode with Methods that will be merged into this class
|
||||
* @param methodFilter - only methods in this list will be merged
|
||||
* @param typeMappings - while merging, type references in the methods will be changed according to this map
|
||||
*/
|
||||
public JIMethodMergeAdapter(ClassVisitor cv, ClassNode cn, List<Method> methodFilter, JITypeMapping[] typeMappings) {
|
||||
super(Opcodes.ASM7, cv);
|
||||
this.cn = cn;
|
||||
this.methodFilter = methodFilter;
|
||||
|
||||
this.typeMap = new HashMap<>();
|
||||
for (JITypeMapping tm : typeMappings) {
|
||||
typeMap.put(tm.from().replace('.', '/'), tm.to().replace('.', '/'));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
typeMap.put(cn.name, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
||||
if(methodInFilter(name, desc)) {
|
||||
// If the method is one that we will be replacing, delete the method
|
||||
Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG, "Deleting " + name + desc);
|
||||
return null;
|
||||
}
|
||||
return super.visitMethod(access, name, desc, signature, exceptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
SimpleRemapper remapper = new SimpleRemapper(typeMap);
|
||||
for (MethodNode mn : cn.methods) {
|
||||
// Check if the method is in the list of methods to copy
|
||||
if (methodInFilter(mn.name, mn.desc)) {
|
||||
if (Logger.shouldLog(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG)) {
|
||||
Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG, "Copying method: " + mn.name + mn.desc);
|
||||
Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG, " with mapper: " + typeMap);
|
||||
}
|
||||
|
||||
String[] exceptions = new String[mn.exceptions.size()];
|
||||
mn.exceptions.toArray(exceptions);
|
||||
MethodVisitor mv = cv.visitMethod(mn.access, mn.name, mn.desc, mn.signature, exceptions);
|
||||
mn.instructions.resetLabels();
|
||||
mn.accept(new RemappingMethodAdapter(mn.access, mn.desc, mv, remapper));
|
||||
}
|
||||
}
|
||||
super.visitEnd();
|
||||
}
|
||||
|
||||
private boolean methodInFilter(String name, String desc) {
|
||||
for(Method m : methodFilter) {
|
||||
if (m.getName().equals(name) && Type.getMethodDescriptor(m).equals(desc)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal.instrument;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface JITypeMapping {
|
||||
String from();
|
||||
String to();
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -41,6 +41,7 @@ import jdk.jfr.EventSettings;
|
||||
import jdk.jfr.EventType;
|
||||
import jdk.jfr.Recording;
|
||||
import jdk.jfr.consumer.EventStream;
|
||||
import jdk.jfr.internal.JDKEvents;
|
||||
import jdk.jfr.internal.JVMSupport;
|
||||
import jdk.jfr.internal.LogLevel;
|
||||
import jdk.jfr.internal.LogTag;
|
||||
@ -57,7 +58,6 @@ import jdk.jfr.internal.WriteableUserPath;
|
||||
import jdk.jfr.internal.consumer.AbstractEventStream;
|
||||
import jdk.jfr.internal.consumer.EventDirectoryStream;
|
||||
import jdk.jfr.internal.consumer.FileAccess;
|
||||
import jdk.jfr.internal.instrument.JDKEvents;
|
||||
|
||||
/**
|
||||
* The management API in module jdk.management.jfr should be built on top of the
|
||||
|
Loading…
Reference in New Issue
Block a user