8238236: Add JFR class redefinition events
Reviewed-by: mgronlun
This commit is contained in:
parent
74bee68872
commit
5d9c59f2f8
src
hotspot/share
jdk.jfr/share/conf/jfr
test/lib/jdk/test/lib
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user