Skip to content
Permalink
Browse files

8238236: Add JFR class redefinition events

Reviewed-by: mgronlun
  • Loading branch information
Erik Gahlin
Erik Gahlin committed Feb 17, 2020
1 parent 74bee68 commit 5d9c59f2f88cb99c038f0e2b005e694368001c12
@@ -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 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.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 @@ private static boolean containsEvent(List<RecordedEvent> events, String name) {
}
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 static void build(String agentClass, String agentJar) throws IOException
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);

0 comments on commit 5d9c59f

Please sign in to comment.