From e692363d1fedd32efcea2217d021bbba5972315a Mon Sep 17 00:00:00 2001 From: erik_gahlin Date: Thu, 17 Apr 2025 16:06:28 +0200 Subject: [PATCH 1/4] Initial --- .../jdk/jfr/internal/ClassInspector.java | 368 +++++++++ .../jfr/internal/EventInstrumentation.java | 754 ++++++------------ .../classes/jdk/jfr/internal/JVMUpcalls.java | 16 +- .../jdk/jfr/internal/util/Bytecode.java | 4 +- .../jdk/jfr/internal/util/ImplicitFields.java | 5 +- 5 files changed, 618 insertions(+), 529 deletions(-) create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/ClassInspector.java diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/ClassInspector.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/ClassInspector.java new file mode 100644 index 0000000000000..9b02d386fecaf --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/ClassInspector.java @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2016, 2025, 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; + +import static jdk.jfr.internal.util.Bytecode.classDesc; + +import java.lang.classfile.Annotation; +import java.lang.classfile.AnnotationElement; +import java.lang.classfile.AnnotationValue; +import java.lang.classfile.Attribute; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassModel; +import java.lang.classfile.FieldModel; +import java.lang.classfile.MethodModel; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import jdk.jfr.Enabled; +import jdk.jfr.Name; +import jdk.jfr.Registered; +import jdk.jfr.SettingControl; +import jdk.jfr.SettingDefinition; +import jdk.jfr.internal.util.Bytecode; +import jdk.jfr.internal.util.ImplicitFields; +import jdk.jfr.internal.util.Bytecode.FieldDesc; +import jdk.jfr.internal.util.Bytecode.MethodDesc; +import jdk.jfr.internal.util.Bytecode.SettingDesc; +import jdk.jfr.internal.util.Utils; + +final class ClassInspector { + private static final ClassDesc TYPE_SETTING_DEFINITION = Bytecode.classDesc(SettingDefinition.class); + private static final ClassDesc ANNOTATION_REGISTERED = classDesc(Registered.class); + private static final ClassDesc ANNOTATION_NAME = classDesc(Name.class); + private static final ClassDesc ANNOTATION_ENABLED = classDesc(Enabled.class); + private static final ClassDesc ANNOTATION_REMOVE_FIELDS = classDesc(RemoveFields.class); + + private final ClassModel classModel; + private final Class superClass; + private final boolean isJDK; + private final ImplicitFields implicitFields; + private final List settingsDescs; + private final List fieldDescs; + private final String className; + + ClassInspector(Class superClass, byte[] bytes, boolean isJDK) { + this.superClass = superClass; + this.classModel = ClassFile.of().parse(bytes); + this.isJDK = isJDK; + this.className = classModel.thisClass().asInternalName().replace("/", "."); + this.implicitFields = determineImplicitFields(); + this.settingsDescs = buildSettingDescs(); + this.fieldDescs = buildFieldDescs(); + } + + String getClassName() { + return className; + } + + MethodDesc findStaticCommitMethod() { + if (!isJDK) { + return null; + } + + StringBuilder sb = new StringBuilder(); + sb.append("("); + for (FieldDesc field : fieldDescs) { + sb.append(field.type().descriptorString()); + } + sb.append(")V"); + MethodDesc m = MethodDesc.of("commit", sb.toString()); + for (MethodModel method : classModel.methods()) { + String d = method.methodTypeSymbol().descriptorString(); + if (method.methodName().equalsString("commit") && m.descriptor().descriptorString().equals(d)) { + return m; + } + } + return null; + } + + String getEventName() { + String name = annotationValue(ANNOTATION_NAME, String.class); + return name == null ? getClassName() : name; + } + + boolean isRegistered() { + Boolean result = annotationValue(ANNOTATION_REGISTERED, Boolean.class); + if (result != null) { + return result.booleanValue(); + } + if (superClass != null) { + Registered r = superClass.getAnnotation(Registered.class); + if (r != null) { + return r.value(); + } + } + return true; + } + + boolean isEnabled() { + Boolean result = annotationValue(ANNOTATION_ENABLED, Boolean.class); + if (result != null) { + return result.booleanValue(); + } + if (superClass != null) { + Enabled e = superClass.getAnnotation(Enabled.class); + if (e != null) { + return e.value(); + } + } + return true; + } + + boolean hasStaticMethod(MethodDesc method) { + for (MethodModel m : classModel.methods()) { + if (m.methodName().equalsString(method.name()) && m.methodTypeSymbol().equals(method.descriptor())) { + return Modifier.isStatic(m.flags().flagsMask()); + } + } + return false; + } + + static boolean isValidField(int access, ClassDesc classDesc) { + String className = classDesc.packageName(); + if (!className.isEmpty()) { + className = className + "."; + } + className += classDesc.displayName(); + return isValidField(access, className); + } + + static boolean isValidField(int access, String className) { + if (Modifier.isTransient(access) || Modifier.isStatic(access)) { + return false; + } + return Type.isValidJavaFieldType(className); + } + + List getSettingDescs() { + return settingsDescs; + } + + List getFieldDescs() { + return fieldDescs; + } + + boolean hasDuration() { + return implicitFields.hasDuration(); + } + + boolean hasStackTrace() { + return implicitFields.hasStackTrace(); + } + + boolean hasEventThread() { + return implicitFields.hasEventThread(); + } + + ClassDesc getClassDesc() { + return classModel.thisClass().asSymbol(); + } + + ClassModel getClassModel() { + return classModel; + } + + boolean isJDK() { + return isJDK; + } + + private ImplicitFields determineImplicitFields() { + if (isJDK) { + Class eventClass = MirrorEvents.find(isJDK, getClassName()); + if (eventClass != null) { + return new ImplicitFields(eventClass); + } + } + ImplicitFields ifs = new ImplicitFields(superClass); + String[] value = annotationValue(ANNOTATION_REMOVE_FIELDS, String[].class); + if (value != null) { + ifs.removeFields(value); + } + return ifs; + } + + private List getAnnotationValues(ClassDesc classDesc) { + List list = new ArrayList<>(); + for (Attribute attribute: classModel.attributes()) { + if (attribute instanceof RuntimeVisibleAnnotationsAttribute rvaa) { + for (Annotation a : rvaa.annotations()) { + if (a.classSymbol().equals(classDesc) && a.elements().size() == 1) { + AnnotationElement ae = a.elements().getFirst(); + if (ae.name().equalsString("value")) { + list.add(ae.value()); + } + } + } + } + } + return list; + } + + @SuppressWarnings("unchecked") + // Only supports String, String[] and Boolean values + private T annotationValue(ClassDesc classDesc, Class type) { + for (AnnotationValue a : getAnnotationValues(classDesc)) { + if (a instanceof AnnotationValue.OfBoolean ofb && type.equals(Boolean.class)) { + Boolean b = ofb.booleanValue(); + return (T) b; + } + if (a instanceof AnnotationValue.OfString ofs && type.equals(String.class)) { + String s = ofs.stringValue(); + return (T) s; + } + if (a instanceof AnnotationValue.OfArray ofa && type.equals(String[].class)) { + List list = ofa.values(); + String[] array = new String[list.size()]; + int index = 0; + for (AnnotationValue av : list) { + var avs = (AnnotationValue.OfString) av; + array[index++] = avs.stringValue(); + } + return (T) array; + } + } + return null; + } + + private List buildSettingDescs() { + Set foundMethods = new HashSet<>(); + List settingDescs = new ArrayList<>(); + settingDescs.addAll(collectClassSettings(foundMethods)); + settingDescs.addAll(collectSuperClassSettings(foundMethods)); + return settingDescs; + } + + private List collectClassSettings(Set foundMethods) { + List list = new ArrayList<>(); + for (MethodModel m : classModel.methods()) { + for (Attribute attribute : m.attributes()) { + if (attribute instanceof RuntimeVisibleAnnotationsAttribute rvaa) { + for (Annotation a : rvaa.annotations()) { + // We can't really validate the method at this + // stage. We would need to check that the parameter + // is an instance of SettingControl. + if (a.classSymbol().equals(TYPE_SETTING_DEFINITION)) { + String name = m.methodName().stringValue(); + // Use @Name if it exists + for (Annotation nameCandidate : rvaa.annotations()) { + if (nameCandidate.className().equalsString(ANNOTATION_NAME.descriptorString())) { + if (nameCandidate.elements().size() == 1) { + AnnotationElement ae = nameCandidate.elements().getFirst(); + if (ae.name().equalsString("value")) { + if (ae.value() instanceof AnnotationValue.OfString s) { + name = Utils.validJavaIdentifier(s.stringValue(), name); + } + } + } + } + } + // Add setting if method returns boolean and has one parameter + MethodTypeDesc mtd = m.methodTypeSymbol(); + if ("Z".equals(mtd.returnType().descriptorString())) { + if (mtd.parameterList().size() == 1) { + ClassDesc type = mtd.parameterList().getFirst(); + if (type.isClassOrInterface()) { + String methodName = m.methodName().stringValue(); + foundMethods.add(methodName); + list.add(new SettingDesc(type, methodName)); + } + } + } + } + } + } + } + } + return list; + } + + private List collectSuperClassSettings(Set foundMethods) { + List list = new ArrayList<>(); + for (Class c = superClass; jdk.internal.event.Event.class != c; c = c.getSuperclass()) { + for (java.lang.reflect.Method method : c.getDeclaredMethods()) { + if (!foundMethods.contains(method.getName())) { + // Skip private methods in base classes + if (!Modifier.isPrivate(method.getModifiers())) { + if (method.getReturnType().equals(Boolean.TYPE)) { + if (method.getParameterCount() == 1) { + Class type = method.getParameters()[0].getType(); + if (SettingControl.class.isAssignableFrom(type)) { + ClassDesc paramType = Bytecode.classDesc(type); + foundMethods.add(method.getName()); + list.add(new SettingDesc(paramType, method.getName())); + } + } + } + } + } + } + } + return list; + } + + private List buildFieldDescs() { + Set fieldSet = new HashSet<>(); + List fieldDescs = new ArrayList<>(classModel.fields().size()); + // These two fields are added by native as 'transient' so they will be + // ignored by the loop below. + // The benefit of adding them manually is that we can + // control in which order they occur and we can add @Name, @Description + // in Java, instead of in native. It also means code for adding implicit + // fields for native can be reused by Java. + fieldDescs.add(ImplicitFields.FIELD_START_TIME); + if (implicitFields.hasDuration()) { + fieldDescs.add(ImplicitFields.FIELD_DURATION); + } + for (FieldModel field : classModel.fields()) { + if (!fieldSet.contains(field.fieldName().stringValue()) && isValidField(field.flags().flagsMask(), field.fieldTypeSymbol())) { + fieldDescs.add(FieldDesc.of(field.fieldTypeSymbol(), field.fieldName().stringValue())); + fieldSet.add(field.fieldName().stringValue()); + } + } + for (Class c = superClass; jdk.internal.event.Event.class != c; c = c.getSuperclass()) { + for (Field field : c.getDeclaredFields()) { + // Skip private fields in base classes + if (!Modifier.isPrivate(field.getModifiers())) { + if (isValidField(field.getModifiers(), field.getType().getName())) { + String fieldName = field.getName(); + if (!fieldSet.contains(fieldName)) { + fieldDescs.add(FieldDesc.of(field.getType(), fieldName)); + fieldSet.add(fieldName); + } + } + } + } + } + return fieldDescs; + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java index 7567aea664cb7..cb5b88d538cb1 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java @@ -25,71 +25,49 @@ package jdk.jfr.internal; -import java.lang.constant.ClassDesc; -import java.lang.constant.MethodTypeDesc; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Consumer; +import static jdk.jfr.internal.util.Bytecode.classDesc; +import static jdk.jfr.internal.util.Bytecode.getfield; +import static jdk.jfr.internal.util.Bytecode.invokestatic; +import static jdk.jfr.internal.util.Bytecode.invokevirtual; +import static jdk.jfr.internal.util.Bytecode.putfield; -import java.lang.classfile.Annotation; -import java.lang.classfile.AnnotationElement; -import java.lang.classfile.AnnotationValue; +import java.lang.classfile.ClassBuilder; import java.lang.classfile.ClassElement; -import java.lang.classfile.ClassModel; import java.lang.classfile.ClassFile; import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeBuilder.BlockCodeBuilder; import java.lang.classfile.FieldModel; import java.lang.classfile.Label; import java.lang.classfile.MethodModel; +import java.lang.classfile.MethodTransform; import java.lang.classfile.TypeKind; -import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; -import jdk.jfr.internal.event.EventConfiguration; -import jdk.jfr.internal.event.EventWriter; -import jdk.jfr.Enabled; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.util.List; +import java.util.function.Consumer; + import jdk.jfr.Event; -import jdk.jfr.Name; -import jdk.jfr.Registered; import jdk.jfr.SettingControl; -import jdk.jfr.SettingDefinition; -import jdk.jfr.internal.util.Utils; +import jdk.jfr.internal.event.EventConfiguration; +import jdk.jfr.internal.event.EventWriter; import jdk.jfr.internal.util.Bytecode; -import jdk.jfr.internal.util.ImplicitFields; import jdk.jfr.internal.util.Bytecode.FieldDesc; import jdk.jfr.internal.util.Bytecode.MethodDesc; -import static jdk.jfr.internal.util.Bytecode.invokevirtual; -import static jdk.jfr.internal.util.Bytecode.invokestatic; -import static jdk.jfr.internal.util.Bytecode.getfield; -import static jdk.jfr.internal.util.Bytecode.putfield; -import static jdk.jfr.internal.util.Bytecode.classDesc; +import jdk.jfr.internal.util.Bytecode.SettingDesc; +import jdk.jfr.internal.util.ImplicitFields; /** * Class responsible for adding instrumentation to a subclass of {@link Event}. * */ final class EventInstrumentation { + private static final FieldDesc FIELD_EVENT_CONFIGURATION = FieldDesc.of(Object.class, "eventConfiguration"); - private record SettingDesc(ClassDesc paramType, String methodName) { - } - - private static final FieldDesc FIELD_DURATION = FieldDesc.of(long.class, ImplicitFields.DURATION); - private static final FieldDesc FIELD_EVENT_CONFIGURATION = FieldDesc.of(Object.class, "eventConfiguration");; - private static final FieldDesc FIELD_START_TIME = FieldDesc.of(long.class, ImplicitFields.START_TIME); - private static final ClassDesc ANNOTATION_ENABLED = classDesc(Enabled.class); - private static final ClassDesc ANNOTATION_NAME = classDesc(Name.class); - private static final ClassDesc ANNOTATION_REGISTERED = classDesc(Registered.class); - private static final ClassDesc ANNOTATION_REMOVE_FIELDS = classDesc(RemoveFields.class); private static final ClassDesc TYPE_EVENT_CONFIGURATION = classDesc(EventConfiguration.class); - private static final ClassDesc TYPE_ISE = Bytecode.classDesc(IllegalStateException.class); + private static final ClassDesc TYPE_ISE = classDesc(IllegalStateException.class); private static final ClassDesc TYPE_EVENT_WRITER = classDesc(EventWriter.class); - private static final ClassDesc TYPE_OBJECT = Bytecode.classDesc(Object.class); - private static final ClassDesc TYPE_SETTING_DEFINITION = Bytecode.classDesc(SettingDefinition.class); + private static final ClassDesc TYPE_OBJECT = classDesc(Object.class); + private static final MethodDesc METHOD_BEGIN = MethodDesc.of("begin", "()V"); private static final MethodDesc METHOD_COMMIT = MethodDesc.of("commit", "()V"); private static final MethodDesc METHOD_DURATION = MethodDesc.of("duration", "(J)J"); @@ -104,446 +82,237 @@ private record SettingDesc(ClassDesc paramType, String methodName) { private static final MethodDesc METHOD_SHOULD_COMMIT_LONG = MethodDesc.of("shouldCommit", "(J)Z"); private static final MethodDesc METHOD_TIME_STAMP = MethodDesc.of("timestamp", "()J"); - private final ClassModel classModel; - private final List settingDescs; - private final List fieldDescs;; - private final String eventName; - private final String className; - private final Class superClass; - private final boolean untypedEventConfiguration; - private final MethodDesc staticCommitMethod; + private final ClassInspector inspector; private final long eventTypeId; + private final ClassDesc eventClassDesc; + private final MethodDesc staticCommitMethod; + private final boolean untypedEventConfiguration; private final boolean guardEventConfiguration; - private final boolean isJDK; - private final Map> methodUpdates = new LinkedHashMap<>(); - private final ImplicitFields implicitFields; - EventInstrumentation(Class superClass, byte[] bytes, long id, boolean isJDK, boolean guardEventConfiguration) { + /** + * Creates an EventInstrumentation object. + * + * @param inspector class inspector + * @param id the event type ID to use + * @param guardEventConfiguration guard against event configuration being null. + * Needed when instrumentation is added before + * registration (bytesForEagerInstrumentation) + */ + EventInstrumentation(ClassInspector inspector, long id, boolean guardEventConfiguration) { + this.inspector = inspector; this.eventTypeId = id; - this.superClass = superClass; - this.isJDK = isJDK; - this.classModel = createClassModel(bytes); - this.className = classModel.thisClass().asInternalName().replace("/", "."); - String name = annotationValue(classModel, ANNOTATION_NAME, String.class); - this.eventName = name == null ? className : name; - this.implicitFields = determineImplicitFields(); - this.settingDescs = buildSettingDescs(superClass, classModel); - this.fieldDescs = buildFieldDescs(superClass, classModel); - this.staticCommitMethod = isJDK ? findStaticCommitMethod(classModel, fieldDescs) : null; - this.untypedEventConfiguration = hasUntypedConfiguration(); - // Corner case when we are forced to generate bytecode - // (bytesForEagerInstrumentation) - // We can't reference EventConfiguration::isEnabled() before event class has - // been registered, - // so we add a guard against a null reference. this.guardEventConfiguration = guardEventConfiguration; + this.eventClassDesc = inspector.getClassDesc(); + this.staticCommitMethod = inspector.findStaticCommitMethod(); + this.untypedEventConfiguration = hasUntypedConfiguration(); } - private ImplicitFields determineImplicitFields() { - if (isJDK) { - Class eventClass = MirrorEvents.find(isJDK, className); - if (eventClass != null) { - return new ImplicitFields(eventClass); - } - } - ImplicitFields ifs = new ImplicitFields(superClass); - String[] value = annotationValue(classModel, ANNOTATION_REMOVE_FIELDS, String[].class); - if (value != null) { - ifs.removeFields(value); - } - return ifs; + byte[] buildInstrumented() { + return ClassFile.of().transformClass(inspector.getClassModel(), this::transform); } - static MethodDesc findStaticCommitMethod(ClassModel classModel, List fields) { - StringBuilder sb = new StringBuilder(); - sb.append("("); - for (FieldDesc field : fields) { - sb.append(field.type().descriptorString()); - } - sb.append(")V"); - MethodDesc m = MethodDesc.of("commit", sb.toString()); - for (MethodModel method : classModel.methods()) { - String d = method.methodTypeSymbol().descriptorString(); - if (method.methodName().equalsString("commit") && m.descriptor().descriptorString().equals(d)) { - return m; - } + private void transform(ClassBuilder clb, ClassElement cle) { + if (cle instanceof MethodModel method && instrumentable(method) instanceof Consumer modification) { + clb.transformMethod(method, MethodTransform.transformingCode((codeBuilder, _) -> modification.accept(codeBuilder))); + } else { + clb.with(cle); } - return null; } - private boolean hasUntypedConfiguration() { - for (FieldModel f : classModel.fields()) { - if (f.fieldName().equalsString(FIELD_EVENT_CONFIGURATION.name())) { - return f.fieldType().equalsString(TYPE_OBJECT.descriptorString()); - } + private Consumer instrumentable(MethodModel method) { + if (isMethod(method, METHOD_IS_ENABLED)) { + return this::methodIsEnabled; } - throw new InternalError("Class missing configuration field"); - } - - public String getClassName() { - return classModel.thisClass().asInternalName().replace("/", "."); - } - - private ClassModel createClassModel(byte[] bytes) { - return ClassFile.of().parse(bytes); - } - - boolean isRegistered() { - Boolean result = annotationValue(classModel, ANNOTATION_REGISTERED, Boolean.class); - if (result != null) { - return result.booleanValue(); + if (isMethod(method, METHOD_BEGIN)) { + return this::methodBegin; } - if (superClass != null) { - Registered r = superClass.getAnnotation(Registered.class); - if (r != null) { - return r.value(); - } + if (isMethod(method, METHOD_END)) { + return this::methodEnd; } - return true; - } - - boolean isEnabled() { - Boolean result = annotationValue(classModel, ANNOTATION_ENABLED, Boolean.class); - if (result != null) { - return result.booleanValue(); + if (isMethod(method, METHOD_EVENT_SHOULD_COMMIT)) { + return this::methodShouldCommit; } - if (superClass != null) { - Enabled e = superClass.getAnnotation(Enabled.class); - if (e != null) { - return e.value(); - } + if (staticCommitMethod == null && isMethod(method, METHOD_COMMIT)) { + return this::methodCommit; } - return true; - } - - @SuppressWarnings("unchecked") - // Only supports String, String[] and Boolean values - private static T annotationValue(ClassModel classModel, ClassDesc classDesc, Class type) { - String typeDescriptor = classDesc.descriptorString(); - for (ClassElement ce : classModel) { - if (ce instanceof RuntimeVisibleAnnotationsAttribute rvaa) { - for (Annotation a : rvaa.annotations()) { - if (a.className().equalsString(typeDescriptor)) { - if (a.elements().size() == 1) { - AnnotationElement ae = a.elements().getFirst(); - if (ae.name().equalsString("value")) { - if (ae.value() instanceof AnnotationValue.OfBoolean ofb && type.equals(Boolean.class)) { - Boolean b = ofb.booleanValue(); - return (T)b; - } - if (ae.value() instanceof AnnotationValue.OfString ofs && type.equals(String.class)) { - String s = ofs.stringValue(); - return (T)s; - } - if (ae.value() instanceof AnnotationValue.OfArray ofa && type.equals(String[].class)) { - List list = ofa.values(); - String[] array = new String[list.size()]; - int index = 0; - for (AnnotationValue av : list) { - var avs = (AnnotationValue.OfString)av; - array[index++] = avs.stringValue(); - } - return (T)array; - } - } - } - } - } + if (inspector.isJDK() && isStatic(method)) { + if (isMethod(method, METHOD_ENABLED)) { + return this::methodEnabledStatic; } - } - return null; - } - - private static List buildSettingDescs(Class superClass, ClassModel classModel) { - Set methodSet = new HashSet<>(); - List settingDescs = new ArrayList<>(); - for (MethodModel m : classModel.methods()) { - for (var me : m) { - if (me instanceof RuntimeVisibleAnnotationsAttribute rvaa) { - for (Annotation a : rvaa.annotations()) { - // We can't really validate the method at this - // stage. We would need to check that the parameter - // is an instance of SettingControl. - if (a.className().equalsString(TYPE_SETTING_DEFINITION.descriptorString())) { - String name = m.methodName().stringValue(); - // Use @Name if it exists - for (Annotation nameCandidate : rvaa.annotations()) { - if (nameCandidate.className().equalsString(ANNOTATION_NAME.descriptorString())) { - if (nameCandidate.elements().size() == 1) { - AnnotationElement ae = nameCandidate.elements().getFirst(); - if (ae.name().equalsString("value")) { - if (ae.value() instanceof AnnotationValue.OfString s) { - name = Utils.validJavaIdentifier(s.stringValue(), name); - } - } - } - } - } - // Add setting if method returns boolean and has one parameter - MethodTypeDesc mtd = m.methodTypeSymbol(); - if ("Z".equals(mtd.returnType().descriptorString())) { - if (mtd.parameterList().size() == 1) { - ClassDesc type = mtd.parameterList().getFirst(); - if (type.isClassOrInterface()) { - String methodName = m.methodName().stringValue(); - methodSet.add(methodName); - settingDescs.add(new SettingDesc(type, methodName)); - } - } - } - } - } - } + if (isMethod(method, METHOD_SHOULD_COMMIT_LONG)) { + return this::methodShouldCommitStatic; } - } - for (Class c = superClass; jdk.internal.event.Event.class != c; c = c.getSuperclass()) { - for (java.lang.reflect.Method method : c.getDeclaredMethods()) { - if (!methodSet.contains(method.getName())) { - // skip private method in base classes - if (!Modifier.isPrivate(method.getModifiers())) { - if (method.getReturnType().equals(Boolean.TYPE)) { - if (method.getParameterCount() == 1) { - Class type = method.getParameters()[0].getType(); - if (SettingControl.class.isAssignableFrom(type)) { - ClassDesc paramType = Bytecode.classDesc(type); - methodSet.add(method.getName()); - settingDescs.add(new SettingDesc(paramType, method.getName())); - } - } - } - } - } + if (isMethod(method, METHOD_TIME_STAMP)) { + return this::methodTimestamp; + } + if (staticCommitMethod != null && isMethod(method, staticCommitMethod)) { + return this::methodCommit; } } - return settingDescs; + return null; } - private List buildFieldDescs(Class superClass, ClassModel classModel) { - Set fieldSet = new HashSet<>(); - List fieldDescs = new ArrayList<>(classModel.fields().size()); - // These two fields are added by native as 'transient' so they will be - // ignored by the loop below. - // The benefit of adding them manually is that we can - // control in which order they occur and we can add @Name, @Description - // in Java, instead of in native. It also means code for adding implicit - // fields for native can be reused by Java. - fieldDescs.add(FIELD_START_TIME); - if (implicitFields.hasDuration()) { - fieldDescs.add(FIELD_DURATION); - } - for (FieldModel field : classModel.fields()) { - if (!fieldSet.contains(field.fieldName().stringValue()) && isValidField(field.flags().flagsMask(), field.fieldTypeSymbol())) { - FieldDesc fi = FieldDesc.of(field.fieldTypeSymbol(), field.fieldName().stringValue()); - fieldDescs.add(fi); - fieldSet.add(field.fieldName().stringValue()); - } + private void methodIsEnabled(CodeBuilder codeBuilder) { + Label nullLabel = codeBuilder.newLabel(); + if (guardEventConfiguration) { + getEventConfiguration(codeBuilder); + codeBuilder.ifnull(nullLabel); } - for (Class c = superClass; jdk.internal.event.Event.class != c; c = c.getSuperclass()) { - for (Field field : c.getDeclaredFields()) { - // skip private field in base classes - if (!Modifier.isPrivate(field.getModifiers())) { - if (isValidField(field.getModifiers(), field.getType().getName())) { - String fieldName = field.getName(); - if (!fieldSet.contains(fieldName)) { - fieldDescs.add(FieldDesc.of(field.getType(), fieldName)); - fieldSet.add(fieldName); - } - } - } - } + getEventConfiguration(codeBuilder); + invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_IS_ENABLED); + codeBuilder.ireturn(); + if (guardEventConfiguration) { + codeBuilder.labelBinding(nullLabel); + codeBuilder.iconst_0(); + codeBuilder.ireturn(); } - return fieldDescs; } - public static boolean isValidField(int access, ClassDesc classDesc) { - String className = classDesc.packageName(); - if (!className.isEmpty()) { - className = className + "."; + private void methodBegin(CodeBuilder codeBuilder) { + if (!inspector.hasDuration()) { + throwMissingDuration(codeBuilder, "begin"); + } else { + codeBuilder.aload(0); + invokestatic(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_TIME_STAMP); + putfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_START_TIME); + codeBuilder.return_(); } - className += classDesc.displayName(); - return isValidField(access, className); } - public static boolean isValidField(int access, String className) { - if (Modifier.isTransient(access) || Modifier.isStatic(access)) { - return false; + private void methodEnd(CodeBuilder codeBuilder) { + if (!inspector.hasDuration()) { + throwMissingDuration(codeBuilder, "end"); + } else { + codeBuilder.aload(0); + codeBuilder.aload(0); + getfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_START_TIME); + invokestatic(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_DURATION); + putfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION); + codeBuilder.return_(); } - return Type.isValidJavaFieldType(className); } - public byte[] buildInstrumented() { - makeInstrumented(); - return toByteArray(); - } - - byte[] toByteArray() { - return ClassFile.of().build(classModel.thisClass().asSymbol(), classBuilder -> { - for (ClassElement ce : classModel) { - boolean updated = false; - if (ce instanceof MethodModel method) { - Consumer methodUpdate = findMethodUpdate(method); - if (methodUpdate != null) { - classBuilder.withMethod(method.methodName().stringValue(), method.methodTypeSymbol(), method.flags().flagsMask(), methodBuilder -> { - methodBuilder.withCode(methodUpdate); - }); - updated = true; - } - } - if (!updated) { - classBuilder.with(ce); - } - } - }); - } - - public byte[] buildUninstrumented() { - makeUninstrumented(); - return toByteArray(); - } - - private void throwMissingDuration(CodeBuilder codeBuilder, String method) { - String message = "Cannot use method " + method + " when event lacks duration field"; - Bytecode.throwException(codeBuilder, TYPE_ISE, message); - } - - private void makeInstrumented() { - // MyEvent#isEnabled() - updateEnabledMethod(METHOD_IS_ENABLED); - - // MyEvent#begin() - updateMethod(METHOD_BEGIN, codeBuilder -> { - if (!implicitFields.hasDuration()) { - throwMissingDuration(codeBuilder, "begin"); - } else { - codeBuilder.aload(0); - invokestatic(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_TIME_STAMP); - putfield(codeBuilder, getEventClassDesc(), FIELD_START_TIME); - codeBuilder.return_(); - } - }); - - // MyEvent#end() - updateMethod(METHOD_END, codeBuilder -> { - if (!implicitFields.hasDuration()) { - throwMissingDuration(codeBuilder, "end"); + private void methodShouldCommit(CodeBuilder codeBuilder) { + Label fail = codeBuilder.newLabel(); + if (guardEventConfiguration) { + getEventConfiguration(codeBuilder); + codeBuilder.ifnull(fail); + } + // if (!eventConfiguration.shouldCommit(duration) goto fail; + getEventConfiguration(codeBuilder); + codeBuilder.aload(0); + getfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION); + invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT); + codeBuilder.ifeq(fail); + List settingDescs = inspector.getSettingDescs(); + for (int index = 0; index < settingDescs.size(); index++) { + SettingDesc sd = settingDescs.get(index); + // if (!settingsMethod(eventConfiguration.settingX)) goto fail; + codeBuilder.aload(0); + getEventConfiguration(codeBuilder); + codeBuilder.loadConstant(index); + invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_GET_SETTING); + MethodTypeDesc mdesc = MethodTypeDesc.ofDescriptor("(" + sd.paramType().descriptorString() + ")Z"); + codeBuilder.checkcast(sd.paramType()); + codeBuilder.invokevirtual(eventClassDesc, sd.methodName(), mdesc); + codeBuilder.ifeq(fail); + } + // return true + codeBuilder.iconst_1(); + codeBuilder.ireturn(); + // return false + codeBuilder.labelBinding(fail); + codeBuilder.iconst_0(); + codeBuilder.ireturn(); + } + + private void methodCommit(CodeBuilder codeBuilder) { + Label excluded = codeBuilder.newLabel(); + Label end = codeBuilder.newLabel(); + codeBuilder.trying(blockCodeBuilder -> { + if (staticCommitMethod != null) { + updateStaticCommit(blockCodeBuilder, excluded); } else { - codeBuilder.aload(0); - codeBuilder.aload(0); - getfield(codeBuilder, getEventClassDesc(), FIELD_START_TIME); - invokestatic(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_DURATION); - putfield(codeBuilder, getEventClassDesc(), FIELD_DURATION); - codeBuilder.return_(); + updateInstanceCommit(blockCodeBuilder, end, excluded); } - }); - - // MyEvent#commit() or static MyEvent#commit(...) - MethodDesc m = staticCommitMethod == null ? METHOD_COMMIT : staticCommitMethod; - updateMethod(m, codeBuilder -> { - Label excluded = codeBuilder.newLabel(); - Label end = codeBuilder.newLabel(); - codeBuilder.trying(blockCodeBuilder -> { - if (staticCommitMethod != null) { - updateStaticCommit(blockCodeBuilder, excluded); - } else { - updateInstanceCommit(blockCodeBuilder, end, excluded); - } - // stack: [integer] - // notified -> restart event write attempt - blockCodeBuilder.ifeq(blockCodeBuilder.startLabel()); - // stack: [] - blockCodeBuilder.goto_(end); - }, catchBuilder -> { - catchBuilder.catchingAll(catchAllHandler -> { - getEventWriter(catchAllHandler); - // stack: [ex] [EW] - catchAllHandler.dup(); - // stack: [ex] [EW] [EW] - Label rethrow = catchAllHandler.newLabel(); - catchAllHandler.ifnull(rethrow); - // stack: [ex] [EW] - catchAllHandler.dup(); - // stack: [ex] [EW] [EW] - invokevirtual(catchAllHandler, TYPE_EVENT_WRITER, METHOD_RESET); - catchAllHandler.labelBinding(rethrow); - // stack:[ex] [EW] - catchAllHandler.pop(); - // stack:[ex] - catchAllHandler.athrow(); - }); - }); - codeBuilder.labelBinding(excluded); - // stack: [EW] - codeBuilder.pop(); - codeBuilder.labelBinding(end); + // stack: [integer] + // notified -> restart event write attempt + blockCodeBuilder.ifeq(blockCodeBuilder.startLabel()); // stack: [] - codeBuilder.return_(); + blockCodeBuilder.goto_(end); + }, catchBuilder -> { + catchBuilder.catchingAll(catchAllHandler -> { + getEventWriter(catchAllHandler); + // stack: [ex] [EW] + catchAllHandler.dup(); + // stack: [ex] [EW] [EW] + Label rethrow = catchAllHandler.newLabel(); + catchAllHandler.ifnull(rethrow); + // stack: [ex] [EW] + catchAllHandler.dup(); + // stack: [ex] [EW] [EW] + invokevirtual(catchAllHandler, TYPE_EVENT_WRITER, METHOD_RESET); + catchAllHandler.labelBinding(rethrow); + // stack:[ex] [EW] + catchAllHandler.pop(); + // stack:[ex] + catchAllHandler.athrow(); + }); }); + codeBuilder.labelBinding(excluded); + // stack: [EW] + codeBuilder.pop(); + codeBuilder.labelBinding(end); + // stack: [] + codeBuilder.return_(); + } - // MyEvent#shouldCommit() - updateMethod(METHOD_EVENT_SHOULD_COMMIT, codeBuilder -> { - Label fail = codeBuilder.newLabel(); - if (guardEventConfiguration) { - getEventConfiguration(codeBuilder); - codeBuilder.ifnull(fail); - } - // if (!eventConfiguration.shouldCommit(duration) goto fail; + private void methodEnabledStatic(CodeBuilder codeBuilder) { + Label nullLabel = codeBuilder.newLabel(); + if (guardEventConfiguration) { getEventConfiguration(codeBuilder); - codeBuilder.aload(0); - getfield(codeBuilder, getEventClassDesc(), FIELD_DURATION); - invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT); - codeBuilder.ifeq(fail); - for (int index = 0; index < settingDescs.size(); index++) { - SettingDesc sd = settingDescs.get(index); - // if (!settingsMethod(eventConfiguration.settingX)) goto fail; - codeBuilder.aload(0); - getEventConfiguration(codeBuilder); - codeBuilder.loadConstant(index); - invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_GET_SETTING); - MethodTypeDesc mdesc = MethodTypeDesc.ofDescriptor("(" + sd.paramType().descriptorString() + ")Z"); - codeBuilder.checkcast(sd.paramType()); - codeBuilder.invokevirtual(getEventClassDesc(), sd.methodName(), mdesc); - codeBuilder.ifeq(fail); - } - // return true - codeBuilder.iconst_1(); - codeBuilder.ireturn(); - // return false - codeBuilder.labelBinding(fail); + codeBuilder.ifnull(nullLabel); + } + getEventConfiguration(codeBuilder); + invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_IS_ENABLED); + codeBuilder.ireturn(); + if (guardEventConfiguration) { + codeBuilder.labelBinding(nullLabel); codeBuilder.iconst_0(); codeBuilder.ireturn(); - }); + } + } - if (isJDK) { - if (hasStaticMethod(METHOD_ENABLED)) { - updateEnabledMethod(METHOD_ENABLED); - } + private void methodTimestamp(CodeBuilder codeBuilder) { + invokestatic(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_TIME_STAMP); + codeBuilder.lreturn(); + } - updateIfStaticMethodExists(METHOD_SHOULD_COMMIT_LONG, codeBuilder -> { - Label fail = codeBuilder.newLabel(); - if (guardEventConfiguration) { - // if (eventConfiguration == null) goto fail; - getEventConfiguration(codeBuilder); - codeBuilder.ifnull(fail); - } - // return eventConfiguration.shouldCommit(duration); - getEventConfiguration(codeBuilder); - codeBuilder.lload(0); - codeBuilder.invokevirtual(TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT.name(), METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT.descriptor()); - codeBuilder.ireturn(); - // fail: - codeBuilder.labelBinding(fail); - // return false - codeBuilder.iconst_0(); - codeBuilder.ireturn(); - }); - updateIfStaticMethodExists(METHOD_TIME_STAMP, codeBuilder -> { - invokestatic(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_TIME_STAMP); - codeBuilder.lreturn(); - }); + private void methodShouldCommitStatic(CodeBuilder codeBuilder) { + Label fail = codeBuilder.newLabel(); + if (guardEventConfiguration) { + // if (eventConfiguration == null) goto fail; + getEventConfiguration(codeBuilder); + codeBuilder.ifnull(fail); } + // return eventConfiguration.shouldCommit(duration); + getEventConfiguration(codeBuilder); + codeBuilder.lload(0); + codeBuilder.invokevirtual(TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT.name(), METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT.descriptor()); + codeBuilder.ireturn(); + // fail: + codeBuilder.labelBinding(fail); + // return false + codeBuilder.iconst_0(); + codeBuilder.ireturn(); + } + + private void throwMissingDuration(CodeBuilder codeBuilder, String method) { + String message = "Cannot use method " + method + " when event lacks duration field"; + Bytecode.throwException(codeBuilder, TYPE_ISE, message); } - void updateStaticCommit(BlockCodeBuilder blockCodeBuilder, Label excluded) { + private void updateStaticCommit(BlockCodeBuilder blockCodeBuilder, Label excluded) { // indexes the argument type array, the argument type array does not include // 'this' int argIndex = 0; @@ -576,7 +345,7 @@ void updateStaticCommit(BlockCodeBuilder blockCodeBuilder, Label excluded) { invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.method()); fieldIndex++; // stack: [EW] - if (implicitFields.hasDuration()) { + if (inspector.hasDuration()) { // write duration blockCodeBuilder.dup(); // stack: [EW], [EW] @@ -588,14 +357,14 @@ void updateStaticCommit(BlockCodeBuilder blockCodeBuilder, Label excluded) { fieldIndex++; } // stack: [EW] - if (implicitFields.hasEventThread()) { + if (inspector.hasEventThread()) { // write eventThread blockCodeBuilder.dup(); // stack: [EW], [EW] invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.PUT_EVENT_THREAD.method()); } // stack: [EW] - if (implicitFields.hasStackTrace()) { + if (inspector.hasStackTrace()) { // write stackTrace blockCodeBuilder.dup(); // stack: [EW], [EW] @@ -603,6 +372,7 @@ void updateStaticCommit(BlockCodeBuilder blockCodeBuilder, Label excluded) { } // stack: [EW] // write custom fields + List fieldDescs = inspector.getFieldDescs(); while (fieldIndex < fieldDescs.size()) { blockCodeBuilder.dup(); // stack: [EW], [EW] @@ -622,19 +392,19 @@ void updateStaticCommit(BlockCodeBuilder blockCodeBuilder, Label excluded) { // stack: [int] } - void updateInstanceCommit(BlockCodeBuilder blockCodeBuilder, Label end, Label excluded) { + private void updateInstanceCommit(BlockCodeBuilder blockCodeBuilder, Label end, Label excluded) { // if (!isEnable()) { // return; // } blockCodeBuilder.aload(0); - invokevirtual(blockCodeBuilder, getEventClassDesc(), METHOD_IS_ENABLED); + invokevirtual(blockCodeBuilder, eventClassDesc, METHOD_IS_ENABLED); Label l0 = blockCodeBuilder.newLabel(); blockCodeBuilder.ifne(l0); blockCodeBuilder.return_(); blockCodeBuilder.labelBinding(l0); // long startTime = this.startTime blockCodeBuilder.aload(0); - getfield(blockCodeBuilder, getEventClassDesc(), FIELD_START_TIME); + getfield(blockCodeBuilder, eventClassDesc, ImplicitFields.FIELD_START_TIME); blockCodeBuilder.lstore(1); // if (startTime == 0) { // startTime = EventWriter.timestamp(); @@ -654,7 +424,7 @@ void updateInstanceCommit(BlockCodeBuilder blockCodeBuilder, Label end, Label ex // } blockCodeBuilder.labelBinding(durationEvent); blockCodeBuilder.aload(0); - getfield(blockCodeBuilder, getEventClassDesc(), FIELD_DURATION); + getfield(blockCodeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION); blockCodeBuilder.lconst_0(); blockCodeBuilder.lcmp(); blockCodeBuilder.ifne(commit); @@ -662,11 +432,11 @@ void updateInstanceCommit(BlockCodeBuilder blockCodeBuilder, Label end, Label ex invokestatic(blockCodeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_TIME_STAMP); blockCodeBuilder.lload(1); blockCodeBuilder.lsub(); - putfield(blockCodeBuilder, getEventClassDesc(), FIELD_DURATION); + putfield(blockCodeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION); blockCodeBuilder.labelBinding(commit); // if (shouldCommit()) { blockCodeBuilder.aload(0); - invokevirtual(blockCodeBuilder, getEventClassDesc(), METHOD_EVENT_SHOULD_COMMIT); + invokevirtual(blockCodeBuilder, eventClassDesc, METHOD_EVENT_SHOULD_COMMIT); blockCodeBuilder.ifeq(end); getEventWriter(blockCodeBuilder); // stack: [EW] @@ -687,39 +457,40 @@ void updateInstanceCommit(BlockCodeBuilder blockCodeBuilder, Label end, Label ex invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.method()); fieldIndex++; // stack: [EW] - if (implicitFields.hasDuration()) { + if (inspector.hasDuration()) { // write duration blockCodeBuilder.dup(); // stack: [EW] [EW] blockCodeBuilder.aload(0); // stack: [EW] [EW] [this] - getfield(blockCodeBuilder, getEventClassDesc(), FIELD_DURATION); + getfield(blockCodeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION); // stack: [EW] [EW] [long] invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.method()); fieldIndex++; } // stack: [EW] - if (implicitFields.hasEventThread()) { + if (inspector.hasEventThread()) { // write eventThread blockCodeBuilder.dup(); // stack: [EW] [EW] invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.PUT_EVENT_THREAD.method()); } // stack: [EW] - if (implicitFields.hasStackTrace()) { + if (inspector.hasStackTrace()) { // write stack trace blockCodeBuilder.dup(); // stack: [EW] [EW] invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.PUT_STACK_TRACE.method()); } // stack: [EW] + List fieldDescs = inspector.getFieldDescs(); while (fieldIndex < fieldDescs.size()) { FieldDesc field = fieldDescs.get(fieldIndex); blockCodeBuilder.dup(); // stack: [EW] [EW] blockCodeBuilder.aload(0); // stack: [EW] [EW] [this] - getfield(blockCodeBuilder, getEventClassDesc(), field); + getfield(blockCodeBuilder, eventClassDesc, field); // stack: [EW] [EW] EventWriterMethod eventMethod = EventWriterMethod.lookupMethod(field); invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, eventMethod.method()); @@ -731,90 +502,33 @@ void updateInstanceCommit(BlockCodeBuilder blockCodeBuilder, Label end, Label ex // stack:[int] } - private void updateEnabledMethod(MethodDesc method) { - updateMethod(method, codeBuilder -> { - Label nullLabel = codeBuilder.newLabel(); - if (guardEventConfiguration) { - getEventConfiguration(codeBuilder); - codeBuilder.ifnull(nullLabel); - } - getEventConfiguration(codeBuilder); - invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_IS_ENABLED); - codeBuilder.ireturn(); - if (guardEventConfiguration) { - codeBuilder.labelBinding(nullLabel); - codeBuilder.iconst_0(); - codeBuilder.ireturn(); - } - }); - } - - private void updateIfStaticMethodExists(MethodDesc method, Consumer code) { - if (hasStaticMethod(method)) { - updateMethod(method, code); - } + private static boolean isStatic(MethodModel method) { + return (method.flags().flagsMask() & ClassFile.ACC_STATIC) != 0; } - private boolean hasStaticMethod(MethodDesc method) { - for (MethodModel m : classModel.methods()) { - if (m.methodName().equalsString(method.name()) && m.methodTypeSymbol().equals(method.descriptor())) { - return Modifier.isStatic(m.flags().flagsMask()); - } - } - return false; + private static boolean isMethod(MethodModel m, MethodDesc desc) { + return m.methodName().equalsString(desc.name()) && m.methodTypeSymbol().equals(desc.descriptor()); } - private void getEventWriter(CodeBuilder codeBuilder) { + private static void getEventWriter(CodeBuilder codeBuilder) { invokestatic(codeBuilder, TYPE_EVENT_WRITER, METHOD_GET_EVENT_WRITER); } private void getEventConfiguration(CodeBuilder codeBuilder) { if (untypedEventConfiguration) { - codeBuilder.getstatic(getEventClassDesc(), FIELD_EVENT_CONFIGURATION.name(), TYPE_OBJECT); + codeBuilder.getstatic(eventClassDesc, FIELD_EVENT_CONFIGURATION.name(), TYPE_OBJECT); codeBuilder.checkcast(TYPE_EVENT_CONFIGURATION); } else { - codeBuilder.getstatic(getEventClassDesc(), FIELD_EVENT_CONFIGURATION.name(), TYPE_EVENT_CONFIGURATION); + codeBuilder.getstatic(eventClassDesc, FIELD_EVENT_CONFIGURATION.name(), TYPE_EVENT_CONFIGURATION); } } - private void makeUninstrumented() { - updateExistingWithReturnFalse(METHOD_EVENT_SHOULD_COMMIT); - updateExistingWithReturnFalse(METHOD_IS_ENABLED); - updateExistingWithEmptyVoidMethod(METHOD_COMMIT); - if (staticCommitMethod != null) { - updateExistingWithEmptyVoidMethod(staticCommitMethod); + private boolean hasUntypedConfiguration() { + for (FieldModel f : inspector.getClassModel().fields()) { + if (f.fieldName().equalsString(FIELD_EVENT_CONFIGURATION.name())) { + return f.fieldType().equalsString(TYPE_OBJECT.descriptorString()); + } } - updateExistingWithEmptyVoidMethod(METHOD_BEGIN); - updateExistingWithEmptyVoidMethod(METHOD_END); - } - - private final void updateExistingWithEmptyVoidMethod(MethodDesc voidMethod) { - updateMethod(voidMethod, codeBuilder -> { - codeBuilder.return_(); - }); - } - - private final void updateExistingWithReturnFalse(MethodDesc voidMethod) { - updateMethod(voidMethod, codeBuilder -> { - codeBuilder.iconst_0(); - codeBuilder.ireturn(); - }); - } - - private Consumer findMethodUpdate(MethodModel mm) { - MethodDesc m = MethodDesc.of(mm.methodName().stringValue(), mm.methodType().stringValue()); - return methodUpdates.get(m); - } - - private void updateMethod(MethodDesc method, Consumer codeBuilder) { - methodUpdates.put(method, codeBuilder); - } - - private ClassDesc getEventClassDesc() { - return classModel.thisClass().asSymbol(); - } - - public String getEventName() { - return eventName; + throw new InternalError("Class missing configuration field"); } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java index 36dc2259be944..18b76cc3ff9fb 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java @@ -72,7 +72,8 @@ static byte[] onRetransform(long traceId, boolean dummy1, boolean dummy2, Class< } boolean jdkClass = Utils.isJDKClass(clazz); Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Adding instrumentation to event class " + clazz.getName() + " using retransform"); - EventInstrumentation ei = new EventInstrumentation(clazz.getSuperclass(), oldBytes, traceId, jdkClass, false); + ClassInspector c = new ClassInspector(clazz.getSuperclass(), oldBytes, jdkClass); + EventInstrumentation ei = new EventInstrumentation(c, traceId, false); byte[] bytes = ei.buildInstrumented(); Bytecode.log(clazz.getName(), bytes); return bytes; @@ -105,9 +106,9 @@ static byte[] bytesForEagerInstrumentation(long traceId, boolean forceInstrument } String eventName = ""; try { - EventInstrumentation ei = new EventInstrumentation(superClass, oldBytes, traceId, bootClassLoader, true); - eventName = ei.getEventName(); - if (!JVMSupport.shouldInstrument(bootClassLoader, ei.getEventName())) { + ClassInspector c = new ClassInspector(superClass, oldBytes, bootClassLoader); + eventName = c.getEventName(); + if (!JVMSupport.shouldInstrument(bootClassLoader, c.getEventName())) { Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Skipping instrumentation for " + eventName + " since container support is missing"); return oldBytes; } @@ -118,14 +119,15 @@ static byte[] bytesForEagerInstrumentation(long traceId, boolean forceInstrument // No need to generate bytecode if: // 1) Event class is disabled, and there is not an external configuration that overrides. // 2) Event class has @Registered(false) - if (!mr.isEnabled(ei.getEventName()) && !ei.isEnabled() || !ei.isRegistered()) { + if (!mr.isEnabled(c.getEventName()) && !c.isEnabled() || !c.isRegistered()) { Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Skipping instrumentation for event type " + eventName + " since event was disabled on class load"); return oldBytes; } } - Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Adding " + (forceInstrumentation ? "forced " : "") + "instrumentation for event type " + eventName + " during initial class load"); + EventInstrumentation ei = new EventInstrumentation(c, traceId, true); byte[] bytes = ei.buildInstrumented(); - Bytecode.log(ei.getClassName() + "(" + traceId + ")", bytes); + Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Adding " + (forceInstrumentation ? "forced " : "") + "instrumentation for event type " + eventName + " during initial class load"); + Bytecode.log(c.getClassName() + "(" + traceId + ")", bytes); return bytes; } catch (Throwable t) { Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Unexpected error when adding instrumentation for event type " + eventName + ". " + t.getMessage()); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Bytecode.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Bytecode.java index 1241993e762bc..79c3936a748a8 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Bytecode.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Bytecode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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 @@ -75,6 +75,8 @@ public static MethodDesc of(String methodName, Class returnType, Class... return new MethodDesc(methodName, mtd); } } + public record SettingDesc(ClassDesc paramType, String methodName) { + } public static ClassDesc classDesc(ValueDescriptor v) { String typeName = v.getTypeName(); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ImplicitFields.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ImplicitFields.java index c97efe0bdb9f0..4c82569a83f8c 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ImplicitFields.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ImplicitFields.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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 @@ -28,6 +28,7 @@ import java.util.List; import jdk.jfr.internal.RemoveFields; +import jdk.jfr.internal.util.Bytecode.FieldDesc; /** * Class that describes fields that was not directly named * in the event definition. @@ -37,6 +38,8 @@ public final class ImplicitFields { public static final String DURATION = "duration"; public static final String EVENT_THREAD = "eventThread"; public static final String STACK_TRACE = "stackTrace"; + public static final FieldDesc FIELD_DURATION = FieldDesc.of(long.class, DURATION); + public static final FieldDesc FIELD_START_TIME = FieldDesc.of(long.class, START_TIME); private final List fields = new ArrayList<>(4); From 8ecb27325063ce20d0ca532d288e733bf3b3dccd Mon Sep 17 00:00:00 2001 From: erik_gahlin Date: Thu, 17 Apr 2025 22:09:12 +0200 Subject: [PATCH 2/4] Build settings and fields only when needed --- .../jdk/jfr/internal/ClassInspector.java | 71 +++++++++---------- .../jfr/internal/EventInstrumentation.java | 11 ++- .../classes/jdk/jfr/internal/JVMUpcalls.java | 2 + 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/ClassInspector.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/ClassInspector.java index 9b02d386fecaf..628c6d41dd769 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/ClassInspector.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/ClassInspector.java @@ -67,8 +67,8 @@ final class ClassInspector { private final Class superClass; private final boolean isJDK; private final ImplicitFields implicitFields; - private final List settingsDescs; - private final List fieldDescs; + private final List settingsDescs = new ArrayList<>(); + private final List fieldDescs = new ArrayList<>(); private final String className; ClassInspector(Class superClass, byte[] bytes, boolean isJDK) { @@ -77,8 +77,6 @@ final class ClassInspector { this.isJDK = isJDK; this.className = classModel.thisClass().asInternalName().replace("/", "."); this.implicitFields = determineImplicitFields(); - this.settingsDescs = buildSettingDescs(); - this.fieldDescs = buildFieldDescs(); } String getClassName() { @@ -89,7 +87,6 @@ MethodDesc findStaticCommitMethod() { if (!isJDK) { return null; } - StringBuilder sb = new StringBuilder(); sb.append("("); for (FieldDesc field : fieldDescs) { @@ -164,11 +161,11 @@ static boolean isValidField(int access, String className) { return Type.isValidJavaFieldType(className); } - List getSettingDescs() { + List getSettings() { return settingsDescs; } - List getFieldDescs() { + List getFields() { return fieldDescs; } @@ -254,16 +251,13 @@ private T annotationValue(ClassDesc classDesc, Class type) { return null; } - private List buildSettingDescs() { + void buildSettings() { Set foundMethods = new HashSet<>(); - List settingDescs = new ArrayList<>(); - settingDescs.addAll(collectClassSettings(foundMethods)); - settingDescs.addAll(collectSuperClassSettings(foundMethods)); - return settingDescs; + buildClassSettings(foundMethods); + buildSuperClassSettings(foundMethods); } - private List collectClassSettings(Set foundMethods) { - List list = new ArrayList<>(); + private void buildClassSettings(Set foundMethods) { for (MethodModel m : classModel.methods()) { for (Attribute attribute : m.attributes()) { if (attribute instanceof RuntimeVisibleAnnotationsAttribute rvaa) { @@ -294,7 +288,7 @@ private List collectClassSettings(Set foundMethods) { if (type.isClassOrInterface()) { String methodName = m.methodName().stringValue(); foundMethods.add(methodName); - list.add(new SettingDesc(type, methodName)); + settingsDescs.add(new SettingDesc(type, methodName)); } } } @@ -303,36 +297,36 @@ private List collectClassSettings(Set foundMethods) { } } } - return list; } - private List collectSuperClassSettings(Set foundMethods) { - List list = new ArrayList<>(); + private void buildSuperClassSettings(Set foundMethods) { for (Class c = superClass; jdk.internal.event.Event.class != c; c = c.getSuperclass()) { for (java.lang.reflect.Method method : c.getDeclaredMethods()) { if (!foundMethods.contains(method.getName())) { - // Skip private methods in base classes - if (!Modifier.isPrivate(method.getModifiers())) { - if (method.getReturnType().equals(Boolean.TYPE)) { - if (method.getParameterCount() == 1) { - Class type = method.getParameters()[0].getType(); - if (SettingControl.class.isAssignableFrom(type)) { - ClassDesc paramType = Bytecode.classDesc(type); - foundMethods.add(method.getName()); - list.add(new SettingDesc(paramType, method.getName())); - } - } - } + buildSettingsMethod(foundMethods, method); + } + } + } + } + + private void buildSettingsMethod(Set foundMethods, java.lang.reflect.Method method) { + // Skip private methods in base classes + if (!Modifier.isPrivate(method.getModifiers())) { + if (method.getReturnType().equals(Boolean.TYPE)) { + if (method.getParameterCount() == 1) { + Class type = method.getParameters()[0].getType(); + if (SettingControl.class.isAssignableFrom(type)) { + ClassDesc paramType = Bytecode.classDesc(type); + foundMethods.add(method.getName()); + settingsDescs.add(new SettingDesc(paramType, method.getName())); } } } } - return list; } - private List buildFieldDescs() { - Set fieldSet = new HashSet<>(); - List fieldDescs = new ArrayList<>(classModel.fields().size()); + void buildFields() { + Set foundFields = new HashSet<>(); // These two fields are added by native as 'transient' so they will be // ignored by the loop below. // The benefit of adding them manually is that we can @@ -344,9 +338,9 @@ private List buildFieldDescs() { fieldDescs.add(ImplicitFields.FIELD_DURATION); } for (FieldModel field : classModel.fields()) { - if (!fieldSet.contains(field.fieldName().stringValue()) && isValidField(field.flags().flagsMask(), field.fieldTypeSymbol())) { + if (!foundFields.contains(field.fieldName().stringValue()) && isValidField(field.flags().flagsMask(), field.fieldTypeSymbol())) { fieldDescs.add(FieldDesc.of(field.fieldTypeSymbol(), field.fieldName().stringValue())); - fieldSet.add(field.fieldName().stringValue()); + foundFields.add(field.fieldName().stringValue()); } } for (Class c = superClass; jdk.internal.event.Event.class != c; c = c.getSuperclass()) { @@ -355,14 +349,13 @@ private List buildFieldDescs() { if (!Modifier.isPrivate(field.getModifiers())) { if (isValidField(field.getModifiers(), field.getType().getName())) { String fieldName = field.getName(); - if (!fieldSet.contains(fieldName)) { + if (!foundFields.contains(fieldName)) { fieldDescs.add(FieldDesc.of(field.getType(), fieldName)); - fieldSet.add(fieldName); + foundFields.add(fieldName); } } } } } - return fieldDescs; } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java index cb5b88d538cb1..3e424084d3795 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java @@ -99,6 +99,11 @@ final class EventInstrumentation { * registration (bytesForEagerInstrumentation) */ EventInstrumentation(ClassInspector inspector, long id, boolean guardEventConfiguration) { + inspector.buildFields(); + if (!inspector.isJDK()) { + // Only user-defined events have custom settings. + inspector.buildSettings(); + } this.inspector = inspector; this.eventTypeId = id; this.guardEventConfiguration = guardEventConfiguration; @@ -204,7 +209,7 @@ private void methodShouldCommit(CodeBuilder codeBuilder) { getfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION); invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT); codeBuilder.ifeq(fail); - List settingDescs = inspector.getSettingDescs(); + List settingDescs = inspector.getSettings(); for (int index = 0; index < settingDescs.size(); index++) { SettingDesc sd = settingDescs.get(index); // if (!settingsMethod(eventConfiguration.settingX)) goto fail; @@ -372,7 +377,7 @@ private void updateStaticCommit(BlockCodeBuilder blockCodeBuilder, Label exclude } // stack: [EW] // write custom fields - List fieldDescs = inspector.getFieldDescs(); + List fieldDescs = inspector.getFields(); while (fieldIndex < fieldDescs.size()) { blockCodeBuilder.dup(); // stack: [EW], [EW] @@ -483,7 +488,7 @@ private void updateInstanceCommit(BlockCodeBuilder blockCodeBuilder, Label end, invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.PUT_STACK_TRACE.method()); } // stack: [EW] - List fieldDescs = inspector.getFieldDescs(); + List fieldDescs = inspector.getFields(); while (fieldIndex < fieldDescs.size()) { FieldDesc field = fieldDescs.get(fieldIndex); blockCodeBuilder.dup(); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java index 18b76cc3ff9fb..b4f7b6ef804d6 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java @@ -80,6 +80,7 @@ static byte[] onRetransform(long traceId, boolean dummy1, boolean dummy2, Class< } return oldBytes; } catch (Throwable t) { + t.printStackTrace(); Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Unexpected error when adding instrumentation to event class " + clazz.getName()); } return oldBytes; @@ -130,6 +131,7 @@ static byte[] bytesForEagerInstrumentation(long traceId, boolean forceInstrument Bytecode.log(c.getClassName() + "(" + traceId + ")", bytes); return bytes; } catch (Throwable t) { + t.printStackTrace(); Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Unexpected error when adding instrumentation for event type " + eventName + ". " + t.getMessage()); return oldBytes; } From 07a56859337edb101f618a96c06178b195d4fbf0 Mon Sep 17 00:00:00 2001 From: erik_gahlin Date: Fri, 18 Apr 2025 13:58:30 +0200 Subject: [PATCH 3/4] Minor fixes --- .../share/classes/jdk/jfr/internal/ClassInspector.java | 10 +++++----- .../classes/jdk/jfr/internal/EventInstrumentation.java | 2 +- .../share/classes/jdk/jfr/internal/util/Bytecode.java | 5 +++++ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/ClassInspector.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/ClassInspector.java index 628c6d41dd769..e7e0eac54ff60 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/ClassInspector.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/ClassInspector.java @@ -39,6 +39,7 @@ import java.lang.constant.MethodTypeDesc; import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.lang.constant.ConstantDescs; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -95,8 +96,7 @@ MethodDesc findStaticCommitMethod() { sb.append(")V"); MethodDesc m = MethodDesc.of("commit", sb.toString()); for (MethodModel method : classModel.methods()) { - String d = method.methodTypeSymbol().descriptorString(); - if (method.methodName().equalsString("commit") && m.descriptor().descriptorString().equals(d)) { + if (m.matches(method)) { return m; } } @@ -138,8 +138,8 @@ boolean isEnabled() { boolean hasStaticMethod(MethodDesc method) { for (MethodModel m : classModel.methods()) { - if (m.methodName().equalsString(method.name()) && m.methodTypeSymbol().equals(method.descriptor())) { - return Modifier.isStatic(m.flags().flagsMask()); + if (Modifier.isStatic(m.flags().flagsMask())) { + return method.matches(m); } } return false; @@ -282,7 +282,7 @@ private void buildClassSettings(Set foundMethods) { } // Add setting if method returns boolean and has one parameter MethodTypeDesc mtd = m.methodTypeSymbol(); - if ("Z".equals(mtd.returnType().descriptorString())) { + if (ConstantDescs.CD_boolean.equals(mtd.returnType())) { if (mtd.parameterList().size() == 1) { ClassDesc type = mtd.parameterList().getFirst(); if (type.isClassOrInterface()) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java index 3e424084d3795..96e6f36e5c849 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java @@ -512,7 +512,7 @@ private static boolean isStatic(MethodModel method) { } private static boolean isMethod(MethodModel m, MethodDesc desc) { - return m.methodName().equalsString(desc.name()) && m.methodTypeSymbol().equals(desc.descriptor()); + return desc.matches(m); } private static void getEventWriter(CodeBuilder codeBuilder) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Bytecode.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Bytecode.java index 79c3936a748a8..3cea5e8064388 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Bytecode.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Bytecode.java @@ -33,6 +33,7 @@ import jdk.jfr.internal.LogLevel; import jdk.jfr.internal.LogTag; import java.lang.classfile.CodeBuilder; +import java.lang.classfile.MethodModel; import java.lang.classfile.ClassModel; import java.lang.classfile.ClassFile; import jdk.internal.classfile.components.ClassPrinter; @@ -74,6 +75,10 @@ public static MethodDesc of(String methodName, Class returnType, Class... MethodTypeDesc mtd = MethodTypeDesc.of(returnDesc, parameterDesc); return new MethodDesc(methodName, mtd); } + + public boolean matches(MethodModel m) { + return this.descriptor().equals(m.methodTypeSymbol()) && m.methodName().equalsString(this.name()); + } } public record SettingDesc(ClassDesc paramType, String methodName) { } From d6de26659f058bd98660cd1e75491dd8caabe61d Mon Sep 17 00:00:00 2001 From: erik_gahlin Date: Fri, 18 Apr 2025 14:04:33 +0200 Subject: [PATCH 4/4] Remove accidentally added printStackTrace() --- src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java index b4f7b6ef804d6..18b76cc3ff9fb 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java @@ -80,7 +80,6 @@ static byte[] onRetransform(long traceId, boolean dummy1, boolean dummy2, Class< } return oldBytes; } catch (Throwable t) { - t.printStackTrace(); Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Unexpected error when adding instrumentation to event class " + clazz.getName()); } return oldBytes; @@ -131,7 +130,6 @@ static byte[] bytesForEagerInstrumentation(long traceId, boolean forceInstrument Bytecode.log(c.getClassName() + "(" + traceId + ")", bytes); return bytes; } catch (Throwable t) { - t.printStackTrace(); Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Unexpected error when adding instrumentation for event type " + eventName + ". " + t.getMessage()); return oldBytes; }