8238236: Add JFR class redefinition events

Reviewed-by: mgronlun
This commit is contained in:
Erik Gahlin 2020-02-17 22:36:13 +01:00
parent 74bee68872
commit 5d9c59f2f8
9 changed files with 129 additions and 7 deletions

@ -101,6 +101,22 @@
<Field type="ClassLoader" name="definingClassLoader" label="Defining Class Loader" />
</Event>
<Event name="ClassRedefinition" category="Java Virtual Machine, Class Loading" label="Class Redefinition" thread="false" stackTrace="false" startTime="false">
<Field type="Class" name="redefinedClass" label="Redefined Class" />
<Field type="int" name="classModificationCount" label="Class Modification Count" description="The number of times the class has changed"/>
<Field type="ulong" name="redefinitionId" label="Class Redefinition Id" relation="ClassRedefinitionId"/>
</Event>
<Event name="RedefineClasses" category="Java Virtual Machine, Class Loading" label="Redefine Classes" thread="true" stackTrace="true">
<Field type="int" name="classCount" label="Class Count" />
<Field type="ulong" name="redefinitionId" label="Class Redefinition Id" relation="ClassRedefinitionId" />
</Event>
<Event name="RetransformClasses" category="Java Virtual Machine, Class Loading" label="Retransform Classes" thread="true" stackTrace="true">
<Field type="int" name="classCount" label="Class Count"/>
<Field type="ulong" name="redefinitionId" label="Class Redefinition Id" relation="ClassRedefinitionId" />
</Event>
<Event name="ClassUnload" category="Java Virtual Machine, Class Loading" label="Class Unload" thread="true" startTime="false">
<Field type="Class" name="unloadedClass" label="Unloaded Class" />
<Field type="ClassLoader" name="definingClassLoader" label="Defining Class Loader" />
@ -1236,7 +1252,8 @@
<Relation name="CompileId" />
<Relation name="SweepId"/>
<Relation name="FlushId"/>
<Relation name="ClassRedefinitionId"/>
<XmlType name="Package" parameterType="const PackageEntry*" fieldType="const PackageEntry*"/>
<XmlType name="Class" javaType="java.lang.Class" parameterType="const Klass*" fieldType="const Klass*"/>
<XmlType name="Module" parameterType="const ModuleEntry*" fieldType="const ModuleEntry*"/>

@ -31,6 +31,7 @@
#include "classfile/vmSymbols.hpp"
#include "interpreter/bytecodeStream.hpp"
#include "interpreter/interpreter.hpp"
#include "jfr/jfrEvents.hpp"
#include "jvmtifiles/jvmtiEnv.hpp"
#include "logging/log.hpp"
#include "logging/logConfiguration.hpp"
@ -446,9 +447,16 @@ JvmtiEnv::RetransformClasses(jint class_count, const jclass* classes) {
}
class_definitions[index].klass = jcls;
}
EventRetransformClasses event;
VM_RedefineClasses op(class_count, class_definitions, jvmti_class_load_kind_retransform);
VMThread::execute(&op);
return (op.check_error());
jvmtiError error = op.check_error();
if (error == JVMTI_ERROR_NONE) {
event.set_classCount(class_count);
event.set_redefinitionId(op.id());
event.commit();
}
return error;
} /* end RetransformClasses */
@ -457,9 +465,16 @@ JvmtiEnv::RetransformClasses(jint class_count, const jclass* classes) {
jvmtiError
JvmtiEnv::RedefineClasses(jint class_count, const jvmtiClassDefinition* class_definitions) {
//TODO: add locking
EventRedefineClasses event;
VM_RedefineClasses op(class_count, class_definitions, jvmti_class_load_kind_redefine);
VMThread::execute(&op);
return (op.check_error());
jvmtiError error = op.check_error();
if (error == JVMTI_ERROR_NONE) {
event.set_classCount(class_count);
event.set_redefinitionId(op.id());
event.commit();
}
return error;
} /* end RedefineClasses */

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2020, 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
@ -35,6 +35,7 @@
#include "compiler/compileBroker.hpp"
#include "interpreter/oopMapCache.hpp"
#include "interpreter/rewriter.hpp"
#include "jfr/jfrEvents.hpp"
#include "logging/logStream.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceShared.hpp"
@ -51,6 +52,7 @@
#include "prims/jvmtiThreadState.inline.hpp"
#include "prims/resolvedMethodTable.hpp"
#include "prims/methodComparator.hpp"
#include "runtime/atomic.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/jniHandles.inline.hpp"
@ -70,7 +72,7 @@ int VM_RedefineClasses::_deleted_methods_length = 0;
int VM_RedefineClasses::_added_methods_length = 0;
bool VM_RedefineClasses::_has_redefined_Object = false;
bool VM_RedefineClasses::_has_null_class_loader = false;
u8 VM_RedefineClasses::_id_counter = 0;
VM_RedefineClasses::VM_RedefineClasses(jint class_count,
const jvmtiClassDefinition *class_defs,
@ -83,6 +85,7 @@ VM_RedefineClasses::VM_RedefineClasses(jint class_count,
_the_class = NULL;
_has_redefined_Object = false;
_has_null_class_loader = false;
_id = next_id();
}
static inline InstanceKlass* get_ik(jclass def) {
@ -4294,6 +4297,15 @@ void VM_RedefineClasses::redefine_single_class(jclass the_jclass,
}
increment_class_counter((InstanceKlass *)the_class, THREAD);
if (EventClassRedefinition::is_enabled()) {
EventClassRedefinition event;
event.set_classModificationCount(java_lang_Class::classRedefinedCount(the_class->java_mirror()));
event.set_redefinedClass(the_class);
event.set_redefinitionId(_id);
event.commit();
}
{
ResourceMark rm(THREAD);
// increment the classRedefinedCount field in the_class and in any
@ -4307,6 +4319,7 @@ void VM_RedefineClasses::redefine_single_class(jclass the_jclass,
}
_timer_rsc_phase2.stop();
} // end redefine_single_class()
@ -4393,6 +4406,16 @@ void VM_RedefineClasses::CheckClass::do_klass(Klass* k) {
}
}
u8 VM_RedefineClasses::next_id() {
while (true) {
u8 id = _id_counter;
u8 next_id = id + 1;
u8 result = Atomic::cmpxchg(&_id_counter, id, next_id);
if (result == id) {
return next_id;
}
}
}
void VM_RedefineClasses::dump_methods() {
int j;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2020, 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
@ -351,6 +351,9 @@ class VM_RedefineClasses: public VM_Operation {
static bool _has_redefined_Object;
static bool _has_null_class_loader;
// Used by JFR to group class redefininition events together.
static u8 _id_counter;
// The instance fields are used to pass information from
// doit_prologue() to doit() and doit_epilogue().
Klass* _the_class;
@ -388,6 +391,9 @@ class VM_RedefineClasses: public VM_Operation {
elapsedTimer _timer_rsc_phase2;
elapsedTimer _timer_vm_op_prologue;
// Redefinition id used by JFR
u8 _id;
// These routines are roughly in call order unless otherwise noted.
// Load the caller's new class definition(s) into _scratch_classes.
@ -503,6 +509,8 @@ class VM_RedefineClasses: public VM_Operation {
void lock_classes();
void unlock_classes();
u8 next_id();
static void dump_methods();
// Check that there are no old or obsolete methods
@ -535,6 +543,7 @@ class VM_RedefineClasses: public VM_Operation {
bool allow_nested_vm_operations() const { return true; }
jvmtiError check_error() { return _res; }
u8 id() { return _id; }
// Modifiable test must be shared between IsModifiableClass query
// and redefine implementation

@ -124,6 +124,22 @@
<setting name="stackTrace">true</setting>
</event>
<event name="jdk.RedefineClasses">
<setting name="enabled">true</setting>
<setting name="stackTrace">true</setting>
<setting name="threshold">0 ms</setting>
</event>
<event name="jdk.RetransformClasses">
<setting name="enabled">true</setting>
<setting name="stackTrace">true</setting>
<setting name="threshold">0 ms</setting>
</event>
<event name="jdk.ClassRedefinition">
<setting name="enabled" control="class-loading-enabled">true</setting>
</event>
<event name="jdk.ClassUnload">
<setting name="enabled" control="class-loading-enabled">false</setting>
</event>

@ -124,6 +124,22 @@
<setting name="stackTrace">true</setting>
</event>
<event name="jdk.RedefineClasses">
<setting name="enabled">true</setting>
<setting name="stackTrace">true</setting>
<setting name="threshold">0 ms</setting>
</event>
<event name="jdk.RetransformClasses">
<setting name="enabled">true</setting>
<setting name="stackTrace">true</setting>
<setting name="threshold">0 ms</setting>
</event>
<event name="jdk.ClassRedefinition">
<setting name="enabled" control="class-loading-enabled">true</setting>
</event>
<event name="jdk.ClassUnload">
<setting name="enabled" control="class-loading-enabled">false</setting>
</event>

@ -87,6 +87,10 @@ public class EventNames {
public final static String PlaceholderTableStatistics = PREFIX + "PlaceholderTableStatistics";
public final static String LoaderConstraintsTableStatistics = PREFIX + "LoaderConstraintsTableStatistics";
public final static String ProtectionDomainCacheTableStatistics = PREFIX + "ProtectionDomainCacheTableStatistics";
public static final String RedefineClasses = PREFIX + "RedefineClasses";
public static final String RetransformClasses = PREFIX + "RetransformClasses";
public static final String ClassRedefinition = PREFIX + "ClassRedefinition";
// This event is hard to test
public final static String ReservedStackActivation = PREFIX + "ReservedStackActivation";

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2020, 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
@ -48,7 +48,10 @@ import jdk.jfr.consumer.RecordingFile;
import jdk.test.lib.Asserts;
import jdk.jfr.consumer.RecordedClass;
import jdk.jfr.consumer.RecordedEvent;
import jdk.jfr.consumer.RecordedFrame;
import jdk.jfr.consumer.RecordedMethod;
import jdk.jfr.consumer.RecordedObject;
import jdk.jfr.consumer.RecordedStackTrace;
import jdk.jfr.consumer.RecordedThread;
import jdk.jfr.consumer.RecordedThreadGroup;
@ -363,4 +366,21 @@ public class Events {
}
return false;
}
public static void assertFrame(RecordedEvent event, Class<?> expectedClass, String expectedMethodName) {
RecordedStackTrace stackTrace = event.getStackTrace();
Asserts.assertNotNull(stackTrace, "Missing stack trace");
for (RecordedFrame frame : stackTrace.getFrames()) {
if (frame.isJavaFrame()) {
RecordedMethod method = frame.getMethod();
RecordedClass type = method.getType();
if (expectedClass.getName().equals(type.getName())) {
if (expectedMethodName.equals(method.getName())) {
return;
}
}
}
}
Asserts.fail("Expected " + expectedClass.getName() + "::"+ expectedMethodName + " in stack trace");
}
}

@ -73,6 +73,8 @@ public class JavaAgentBuilder {
Manifest mf = new Manifest();
Attributes attrs = mf.getMainAttributes();
attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0");
attrs.putValue("Can-Redefine-Classes", "true");
attrs.putValue("Can-Retransform-Classes", "true");
attrs.putValue("Premain-Class", agentClass);
attrs.putValue("Agent-Class", agentClass);