Skip to content

Commit

Permalink
8238236: Add JFR class redefinition events
Browse files Browse the repository at this point in the history
Reviewed-by: mgronlun
  • Loading branch information
egahlin committed Feb 17, 2020
1 parent 74bee68 commit 5d9c59f
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 7 deletions.
19 changes: 18 additions & 1 deletion src/hotspot/share/jfr/metadata/metadata.xml
Expand Up @@ -101,6 +101,22 @@
<Field type="ClassLoader" name="definingClassLoader" label="Defining Class Loader" /> <Field type="ClassLoader" name="definingClassLoader" label="Defining Class Loader" />
</Event> </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"> <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="Class" name="unloadedClass" label="Unloaded Class" />
<Field type="ClassLoader" name="definingClassLoader" label="Defining Class Loader" /> <Field type="ClassLoader" name="definingClassLoader" label="Defining Class Loader" />
Expand Down Expand Up @@ -1236,7 +1252,8 @@
<Relation name="CompileId" /> <Relation name="CompileId" />
<Relation name="SweepId"/> <Relation name="SweepId"/>
<Relation name="FlushId"/> <Relation name="FlushId"/>

<Relation name="ClassRedefinitionId"/>

<XmlType name="Package" parameterType="const PackageEntry*" fieldType="const PackageEntry*"/> <XmlType name="Package" parameterType="const PackageEntry*" fieldType="const PackageEntry*"/>
<XmlType name="Class" javaType="java.lang.Class" parameterType="const Klass*" fieldType="const Klass*"/> <XmlType name="Class" javaType="java.lang.Class" parameterType="const Klass*" fieldType="const Klass*"/>
<XmlType name="Module" parameterType="const ModuleEntry*" fieldType="const ModuleEntry*"/> <XmlType name="Module" parameterType="const ModuleEntry*" fieldType="const ModuleEntry*"/>
Expand Down
19 changes: 17 additions & 2 deletions src/hotspot/share/prims/jvmtiEnv.cpp
Expand Up @@ -31,6 +31,7 @@
#include "classfile/vmSymbols.hpp" #include "classfile/vmSymbols.hpp"
#include "interpreter/bytecodeStream.hpp" #include "interpreter/bytecodeStream.hpp"
#include "interpreter/interpreter.hpp" #include "interpreter/interpreter.hpp"
#include "jfr/jfrEvents.hpp"
#include "jvmtifiles/jvmtiEnv.hpp" #include "jvmtifiles/jvmtiEnv.hpp"
#include "logging/log.hpp" #include "logging/log.hpp"
#include "logging/logConfiguration.hpp" #include "logging/logConfiguration.hpp"
Expand Down Expand Up @@ -446,9 +447,16 @@ JvmtiEnv::RetransformClasses(jint class_count, const jclass* classes) {
} }
class_definitions[index].klass = jcls; class_definitions[index].klass = jcls;
} }
EventRetransformClasses event;
VM_RedefineClasses op(class_count, class_definitions, jvmti_class_load_kind_retransform); VM_RedefineClasses op(class_count, class_definitions, jvmti_class_load_kind_retransform);
VMThread::execute(&op); 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 */ } /* end RetransformClasses */




Expand All @@ -457,9 +465,16 @@ JvmtiEnv::RetransformClasses(jint class_count, const jclass* classes) {
jvmtiError jvmtiError
JvmtiEnv::RedefineClasses(jint class_count, const jvmtiClassDefinition* class_definitions) { JvmtiEnv::RedefineClasses(jint class_count, const jvmtiClassDefinition* class_definitions) {
//TODO: add locking //TODO: add locking
EventRedefineClasses event;
VM_RedefineClasses op(class_count, class_definitions, jvmti_class_load_kind_redefine); VM_RedefineClasses op(class_count, class_definitions, jvmti_class_load_kind_redefine);
VMThread::execute(&op); 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 */ } /* end RedefineClasses */




Expand Down
27 changes: 25 additions & 2 deletions src/hotspot/share/prims/jvmtiRedefineClasses.cpp
@@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -35,6 +35,7 @@
#include "compiler/compileBroker.hpp" #include "compiler/compileBroker.hpp"
#include "interpreter/oopMapCache.hpp" #include "interpreter/oopMapCache.hpp"
#include "interpreter/rewriter.hpp" #include "interpreter/rewriter.hpp"
#include "jfr/jfrEvents.hpp"
#include "logging/logStream.hpp" #include "logging/logStream.hpp"
#include "memory/metadataFactory.hpp" #include "memory/metadataFactory.hpp"
#include "memory/metaspaceShared.hpp" #include "memory/metaspaceShared.hpp"
Expand All @@ -51,6 +52,7 @@
#include "prims/jvmtiThreadState.inline.hpp" #include "prims/jvmtiThreadState.inline.hpp"
#include "prims/resolvedMethodTable.hpp" #include "prims/resolvedMethodTable.hpp"
#include "prims/methodComparator.hpp" #include "prims/methodComparator.hpp"
#include "runtime/atomic.hpp"
#include "runtime/deoptimization.hpp" #include "runtime/deoptimization.hpp"
#include "runtime/handles.inline.hpp" #include "runtime/handles.inline.hpp"
#include "runtime/jniHandles.inline.hpp" #include "runtime/jniHandles.inline.hpp"
Expand All @@ -70,7 +72,7 @@ int VM_RedefineClasses::_deleted_methods_length = 0;
int VM_RedefineClasses::_added_methods_length = 0; int VM_RedefineClasses::_added_methods_length = 0;
bool VM_RedefineClasses::_has_redefined_Object = false; bool VM_RedefineClasses::_has_redefined_Object = false;
bool VM_RedefineClasses::_has_null_class_loader = false; bool VM_RedefineClasses::_has_null_class_loader = false;

u8 VM_RedefineClasses::_id_counter = 0;


VM_RedefineClasses::VM_RedefineClasses(jint class_count, VM_RedefineClasses::VM_RedefineClasses(jint class_count,
const jvmtiClassDefinition *class_defs, const jvmtiClassDefinition *class_defs,
Expand All @@ -83,6 +85,7 @@ VM_RedefineClasses::VM_RedefineClasses(jint class_count,
_the_class = NULL; _the_class = NULL;
_has_redefined_Object = false; _has_redefined_Object = false;
_has_null_class_loader = false; _has_null_class_loader = false;
_id = next_id();
} }


static inline InstanceKlass* get_ik(jclass def) { static inline InstanceKlass* get_ik(jclass def) {
Expand Down Expand Up @@ -4294,6 +4297,15 @@ void VM_RedefineClasses::redefine_single_class(jclass the_jclass,
} }


increment_class_counter((InstanceKlass *)the_class, THREAD); 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); ResourceMark rm(THREAD);
// increment the classRedefinedCount field in the_class and in any // increment the classRedefinedCount field in the_class and in any
Expand All @@ -4307,6 +4319,7 @@ void VM_RedefineClasses::redefine_single_class(jclass the_jclass,


} }
_timer_rsc_phase2.stop(); _timer_rsc_phase2.stop();

} // end redefine_single_class() } // end redefine_single_class()




Expand Down Expand Up @@ -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() { void VM_RedefineClasses::dump_methods() {
int j; int j;
Expand Down
11 changes: 10 additions & 1 deletion src/hotspot/share/prims/jvmtiRedefineClasses.hpp
@@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -351,6 +351,9 @@ class VM_RedefineClasses: public VM_Operation {
static bool _has_redefined_Object; static bool _has_redefined_Object;
static bool _has_null_class_loader; 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 // The instance fields are used to pass information from
// doit_prologue() to doit() and doit_epilogue(). // doit_prologue() to doit() and doit_epilogue().
Klass* _the_class; Klass* _the_class;
Expand Down Expand Up @@ -388,6 +391,9 @@ class VM_RedefineClasses: public VM_Operation {
elapsedTimer _timer_rsc_phase2; elapsedTimer _timer_rsc_phase2;
elapsedTimer _timer_vm_op_prologue; elapsedTimer _timer_vm_op_prologue;


// Redefinition id used by JFR
u8 _id;

// These routines are roughly in call order unless otherwise noted. // These routines are roughly in call order unless otherwise noted.


// Load the caller's new class definition(s) into _scratch_classes. // Load the caller's new class definition(s) into _scratch_classes.
Expand Down Expand Up @@ -503,6 +509,8 @@ class VM_RedefineClasses: public VM_Operation {
void lock_classes(); void lock_classes();
void unlock_classes(); void unlock_classes();


u8 next_id();

static void dump_methods(); static void dump_methods();


// Check that there are no old or obsolete methods // Check that there are no old or obsolete methods
Expand Down Expand Up @@ -535,6 +543,7 @@ class VM_RedefineClasses: public VM_Operation {


bool allow_nested_vm_operations() const { return true; } bool allow_nested_vm_operations() const { return true; }
jvmtiError check_error() { return _res; } jvmtiError check_error() { return _res; }
u8 id() { return _id; }


// Modifiable test must be shared between IsModifiableClass query // Modifiable test must be shared between IsModifiableClass query
// and redefine implementation // and redefine implementation
Expand Down
16 changes: 16 additions & 0 deletions src/jdk.jfr/share/conf/jfr/default.jfc
Expand Up @@ -124,6 +124,22 @@
<setting name="stackTrace">true</setting> <setting name="stackTrace">true</setting>
</event> </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"> <event name="jdk.ClassUnload">
<setting name="enabled" control="class-loading-enabled">false</setting> <setting name="enabled" control="class-loading-enabled">false</setting>
</event> </event>
Expand Down
16 changes: 16 additions & 0 deletions src/jdk.jfr/share/conf/jfr/profile.jfc
Expand Up @@ -124,6 +124,22 @@
<setting name="stackTrace">true</setting> <setting name="stackTrace">true</setting>
</event> </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"> <event name="jdk.ClassUnload">
<setting name="enabled" control="class-loading-enabled">false</setting> <setting name="enabled" control="class-loading-enabled">false</setting>
</event> </event>
Expand Down
4 changes: 4 additions & 0 deletions test/lib/jdk/test/lib/jfr/EventNames.java
Expand Up @@ -87,6 +87,10 @@ public class EventNames {
public final static String PlaceholderTableStatistics = PREFIX + "PlaceholderTableStatistics"; public final static String PlaceholderTableStatistics = PREFIX + "PlaceholderTableStatistics";
public final static String LoaderConstraintsTableStatistics = PREFIX + "LoaderConstraintsTableStatistics"; public final static String LoaderConstraintsTableStatistics = PREFIX + "LoaderConstraintsTableStatistics";
public final static String ProtectionDomainCacheTableStatistics = PREFIX + "ProtectionDomainCacheTableStatistics"; 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 // This event is hard to test
public final static String ReservedStackActivation = PREFIX + "ReservedStackActivation"; public final static String ReservedStackActivation = PREFIX + "ReservedStackActivation";


Expand Down
22 changes: 21 additions & 1 deletion test/lib/jdk/test/lib/jfr/Events.java
@@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -48,7 +48,10 @@
import jdk.test.lib.Asserts; import jdk.test.lib.Asserts;
import jdk.jfr.consumer.RecordedClass; import jdk.jfr.consumer.RecordedClass;
import jdk.jfr.consumer.RecordedEvent; import jdk.jfr.consumer.RecordedEvent;
import jdk.jfr.consumer.RecordedFrame;
import jdk.jfr.consumer.RecordedMethod;
import jdk.jfr.consumer.RecordedObject; import jdk.jfr.consumer.RecordedObject;
import jdk.jfr.consumer.RecordedStackTrace;
import jdk.jfr.consumer.RecordedThread; import jdk.jfr.consumer.RecordedThread;
import jdk.jfr.consumer.RecordedThreadGroup; import jdk.jfr.consumer.RecordedThreadGroup;


Expand Down Expand Up @@ -363,4 +366,21 @@ private static boolean containsEvent(List<RecordedEvent> events, String name) {
} }
return false; 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");
}
} }
2 changes: 2 additions & 0 deletions test/lib/jdk/test/lib/util/JavaAgentBuilder.java
Expand Up @@ -73,6 +73,8 @@ public static void build(String agentClass, String agentJar) throws IOException
Manifest mf = new Manifest(); Manifest mf = new Manifest();
Attributes attrs = mf.getMainAttributes(); Attributes attrs = mf.getMainAttributes();
attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0"); 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("Premain-Class", agentClass);
attrs.putValue("Agent-Class", agentClass); attrs.putValue("Agent-Class", agentClass);


Expand Down

0 comments on commit 5d9c59f

Please sign in to comment.