Skip to content

Commit a9d2267

Browse files
Markus GrönlundD-D-H
andcommitted
8260589: Crash in JfrTraceIdLoadBarrier::load(_jclass*)
Co-authored-by: Denghui Dong <[email protected]> Reviewed-by: jbachorik, egahlin
1 parent 42104e5 commit a9d2267

File tree

9 files changed

+225
-33
lines changed

9 files changed

+225
-33
lines changed

src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp

Lines changed: 94 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "jfr/writers/jfrTypeWriterHost.hpp"
4242
#include "memory/iterator.hpp"
4343
#include "memory/resourceArea.hpp"
44+
#include "memory/universe.hpp"
4445
#include "oops/instanceKlass.inline.hpp"
4546
#include "oops/objArrayKlass.hpp"
4647
#include "oops/oop.inline.hpp"
@@ -63,6 +64,7 @@ static JfrArtifactSet* _artifacts = NULL;
6364
static JfrArtifactClosure* _subsystem_callback = NULL;
6465
static bool _class_unload = false;
6566
static bool _flushpoint = false;
67+
static bool _clear_artifacts = false;
6668

6769
// incremented on each rotation
6870
static u8 checkpoint_id = 1;
@@ -83,6 +85,10 @@ static bool previous_epoch() {
8385
return !current_epoch();
8486
}
8587

88+
static bool is_initial_typeset_for_chunk() {
89+
return _clear_artifacts && !_class_unload;
90+
}
91+
8692
static bool is_complete() {
8793
return !_artifacts->has_klass_entries() && current_epoch();
8894
}
@@ -99,6 +105,35 @@ static traceid get_bootstrap_name(bool leakp) {
99105
return create_symbol_id(_artifacts->bootstrap_name(leakp));
100106
}
101107

108+
static const char* primitive_name(KlassPtr type_array_klass) {
109+
switch (type_array_klass->name()->base()[1]) {
110+
case JVM_SIGNATURE_BOOLEAN: return "boolean";
111+
case JVM_SIGNATURE_BYTE: return "byte";
112+
case JVM_SIGNATURE_CHAR: return "char";
113+
case JVM_SIGNATURE_SHORT: return "short";
114+
case JVM_SIGNATURE_INT: return "int";
115+
case JVM_SIGNATURE_LONG: return "long";
116+
case JVM_SIGNATURE_FLOAT: return "float";
117+
case JVM_SIGNATURE_DOUBLE: return "double";
118+
}
119+
assert(false, "invalid type array klass");
120+
return NULL;
121+
}
122+
123+
static Symbol* primitive_symbol(KlassPtr type_array_klass) {
124+
if (type_array_klass == NULL) {
125+
// void.class
126+
static Symbol* const void_class_name = SymbolTable::probe("void", 4);
127+
assert(void_class_name != NULL, "invariant");
128+
return void_class_name;
129+
}
130+
const char* const primitive_type_str = primitive_name(type_array_klass);
131+
assert(primitive_type_str != NULL, "invariant");
132+
Symbol* const primitive_type_sym = SymbolTable::probe(primitive_type_str, (int)strlen(primitive_type_str));
133+
assert(primitive_type_sym != NULL, "invariant");
134+
return primitive_type_sym;
135+
}
136+
102137
template <typename T>
103138
static traceid artifact_id(const T* ptr) {
104139
assert(ptr != NULL, "invariant");
@@ -154,6 +189,11 @@ static s4 get_flags(const T* ptr) {
154189
return ptr->access_flags().get_flags();
155190
}
156191

192+
// Same as JVM_GetClassModifiers
193+
static u4 get_primitive_flags() {
194+
return JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC;
195+
}
196+
157197
static bool is_unsafe_anonymous(const Klass* klass) {
158198
assert(klass != NULL, "invariant");
159199
assert(!klass->is_objArray_klass(), "invariant");
@@ -225,6 +265,27 @@ static void do_klass(Klass* klass) {
225265
_subsystem_callback->do_artifact(klass);
226266
}
227267

268+
269+
static traceid primitive_id(KlassPtr array_klass) {
270+
if (array_klass == NULL) {
271+
// The first klass id is reserved for the void.class.
272+
return LAST_TYPE_ID + 1;
273+
}
274+
// Derive the traceid for a primitive mirror from its associated array klass (+1).
275+
return JfrTraceId::load_raw(array_klass) + 1;
276+
}
277+
278+
static void write_primitive(JfrCheckpointWriter* writer, KlassPtr type_array_klass) {
279+
assert(writer != NULL, "invariant");
280+
assert(_artifacts != NULL, "invariant");
281+
writer->write(primitive_id(type_array_klass));
282+
writer->write(cld_id(get_cld(Universe::boolArrayKlassObj()), false));
283+
writer->write(mark_symbol(primitive_symbol(type_array_klass), false));
284+
writer->write(package_id(Universe::boolArrayKlassObj(), false));
285+
writer->write(get_primitive_flags());
286+
writer->write<bool>(false);
287+
}
288+
228289
static void do_loader_klass(const Klass* klass) {
229290
if (klass != NULL && _artifacts->should_do_loader_klass(klass)) {
230291
if (_leakp_writer != NULL) {
@@ -295,6 +356,28 @@ static void do_classloaders() {
295356
assert(mark_stack.is_empty(), "invariant");
296357
}
297358

359+
static int primitives_count = 9;
360+
361+
// A mirror representing a primitive class (e.g. int.class) has no reified Klass*,
362+
// instead it has an associated TypeArrayKlass* (e.g. int[].class).
363+
// We can use the TypeArrayKlass* as a proxy for deriving the id of the primitive class.
364+
// The exception is the void.class, which has neither a Klass* nor a TypeArrayKlass*.
365+
// It will use a reserved constant.
366+
static void do_primitives() {
367+
// Only write the primitive classes once per chunk.
368+
if (is_initial_typeset_for_chunk()) {
369+
write_primitive(_writer, Universe::boolArrayKlassObj());
370+
write_primitive(_writer, Universe::byteArrayKlassObj());
371+
write_primitive(_writer, Universe::charArrayKlassObj());
372+
write_primitive(_writer, Universe::shortArrayKlassObj());
373+
write_primitive(_writer, Universe::intArrayKlassObj());
374+
write_primitive(_writer, Universe::longArrayKlassObj());
375+
write_primitive(_writer, Universe::floatArrayKlassObj());
376+
write_primitive(_writer, Universe::doubleArrayKlassObj());
377+
write_primitive(_writer, NULL); // void.class
378+
}
379+
}
380+
298381
static void do_object() {
299382
SET_TRANSIENT(vmClasses::Object_klass());
300383
do_klass(vmClasses::Object_klass());
@@ -307,6 +390,7 @@ static void do_klasses() {
307390
}
308391
JfrTraceIdLoadBarrier::do_klasses(&do_klass, previous_epoch());
309392
do_classloaders();
393+
do_primitives();
310394
do_object();
311395
}
312396

@@ -352,6 +436,11 @@ static bool write_klasses() {
352436
_subsystem_callback = &callback;
353437
do_klasses();
354438
}
439+
if (is_initial_typeset_for_chunk()) {
440+
// Because the set of primitives is written outside the callback,
441+
// their count is not automatically incremented.
442+
kw.add(primitives_count);
443+
}
355444
if (is_complete()) {
356445
return false;
357446
}
@@ -979,8 +1068,6 @@ typedef Wrapper<KlassPtr, ClearArtifact> ClearKlassBits;
9791068
typedef Wrapper<MethodPtr, ClearArtifact> ClearMethodFlag;
9801069
typedef MethodIteratorHost<ClearMethodFlag, ClearKlassBits, AlwaysTrue, false> ClearKlassAndMethods;
9811070

982-
static bool clear_artifacts = false;
983-
9841071
static void clear_klasses_and_methods() {
9851072
ClearKlassAndMethods clear(_writer);
9861073
_artifacts->iterate_klasses(clear);
@@ -992,8 +1079,10 @@ static size_t teardown() {
9921079
if (previous_epoch()) {
9931080
clear_klasses_and_methods();
9941081
JfrKlassUnloading::clear();
995-
clear_artifacts = true;
1082+
_clear_artifacts = true;
9961083
++checkpoint_id;
1084+
} else {
1085+
_clear_artifacts = false;
9971086
}
9981087
return total_count;
9991088
}
@@ -1006,12 +1095,11 @@ static void setup(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer
10061095
if (_artifacts == NULL) {
10071096
_artifacts = new JfrArtifactSet(class_unload);
10081097
} else {
1009-
_artifacts->initialize(class_unload, clear_artifacts);
1098+
_artifacts->initialize(class_unload, _clear_artifacts);
10101099
}
10111100
if (!_class_unload) {
10121101
JfrKlassUnloading::sort(previous_epoch());
10131102
}
1014-
clear_artifacts = false;
10151103
assert(_artifacts != NULL, "invariant");
10161104
assert(!_artifacts->has_klass_entries(), "invariant");
10171105
}
@@ -1042,7 +1130,7 @@ size_t JfrTypeSet::serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* l
10421130
void JfrTypeSet::clear() {
10431131
ResourceMark rm;
10441132
JfrKlassUnloading::clear();
1045-
clear_artifacts = true;
1133+
_clear_artifacts = true;
10461134
setup(NULL, NULL, false, false);
10471135
register_klasses();
10481136
clear_packages();

src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -52,7 +52,7 @@ static traceid atomic_inc(traceid volatile* const dest) {
5252
}
5353

5454
static traceid next_class_id() {
55-
static volatile traceid class_id_counter = LAST_TYPE_ID;
55+
static volatile traceid class_id_counter = LAST_TYPE_ID + 1; // + 1 is for the void.class primitive
5656
return atomic_inc(&class_id_counter) << TRACE_ID_SHIFT;
5757
}
5858

@@ -148,16 +148,44 @@ void JfrTraceId::assign(const ClassLoaderData* cld) {
148148
cld->set_trace_id(next_class_loader_data_id());
149149
}
150150

151+
traceid JfrTraceId::assign_primitive_klass_id() {
152+
return next_class_id();
153+
}
154+
151155
traceid JfrTraceId::assign_thread_id() {
152156
return next_thread_id();
153157
}
154158

155-
traceid JfrTraceId::load_raw(jclass jc) {
159+
// A mirror representing a primitive class (e.g. int.class) has no reified Klass*,
160+
// instead it has an associated TypeArrayKlass* (e.g. int[].class).
161+
// We can use the TypeArrayKlass* as a proxy for deriving the id of the primitive class.
162+
// The exception is the void.class, which has neither a Klass* nor a TypeArrayKlass*.
163+
// It will use a reserved constant.
164+
static traceid load_primitive(const oop mirror) {
165+
assert(java_lang_Class::is_primitive(mirror), "invariant");
166+
const Klass* const tak = java_lang_Class::array_klass_acquire(mirror);
167+
traceid id;
168+
if (tak == NULL) {
169+
// The first klass id is reserved for the void.class
170+
id = LAST_TYPE_ID + 1;
171+
} else {
172+
id = JfrTraceId::load_raw(tak) + 1;
173+
}
174+
JfrTraceIdEpoch::set_changed_tag_state();
175+
return id;
176+
}
177+
178+
traceid JfrTraceId::load(jclass jc, bool raw /* false */) {
156179
assert(jc != NULL, "invariant");
157180
assert(JavaThread::current()->thread_state() == _thread_in_vm, "invariant");
158-
const oop my_oop = JNIHandles::resolve(jc);
159-
assert(my_oop != NULL, "invariant");
160-
return load_raw(java_lang_Class::as_Klass(my_oop));
181+
const oop mirror = JNIHandles::resolve(jc);
182+
assert(mirror != NULL, "invariant");
183+
const Klass* const k = java_lang_Class::as_Klass(mirror);
184+
return k != NULL ? (raw ? load_raw(k) : load(k)) : load_primitive(mirror);
185+
}
186+
187+
traceid JfrTraceId::load_raw(jclass jc) {
188+
return load(jc, true);
161189
}
162190

163191
// used by CDS / APPCDS as part of "remove_unshareable_info"
@@ -186,6 +214,10 @@ void JfrTraceId::restore(const Klass* k) {
186214
const traceid event_flags = k->trace_id();
187215
// get a fresh traceid and restore the original event flags
188216
k->set_trace_id(next_class_id() | event_flags);
217+
if (k->is_typeArray_klass()) {
218+
// the next id is reserved for the corresponding primitive class
219+
next_class_id();
220+
}
189221
}
190222

191223
bool JfrTraceId::in_visible_set(const jclass jc) {

src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,12 @@ class JfrTraceId : public AllStatic {
8383
static void assign(const ModuleEntry* module);
8484
static void assign(const PackageEntry* package);
8585
static void assign(const ClassLoaderData* cld);
86+
static traceid assign_primitive_klass_id();
8687
static traceid assign_thread_id();
8788

8889
// through load barrier
8990
static traceid load(const Klass* klass);
90-
static traceid load(jclass jc);
91+
static traceid load(jclass jc, bool raw = false);
9192
static traceid load(const Method* method);
9293
static traceid load(const Klass* klass, const Method* method);
9394
static traceid load(const ModuleEntry* module);

src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -35,10 +35,6 @@
3535
#include "runtime/thread.inline.hpp"
3636
#include "utilities/debug.hpp"
3737

38-
inline traceid JfrTraceId::load(jclass jc) {
39-
return JfrTraceIdLoadBarrier::load(jc);
40-
}
41-
4238
inline traceid JfrTraceId::load(const Klass* klass) {
4339
return JfrTraceIdLoadBarrier::load(klass);
4440
}

src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.cpp

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -23,12 +23,10 @@
2323
*/
2424

2525
#include "precompiled.hpp"
26-
#include "classfile/javaClasses.inline.hpp"
2726
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp"
2827
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdKlassQueue.hpp"
2928
#include "jfr/support/jfrThreadLocal.hpp"
3029
#include "jfr/utilities/jfrEpochQueue.inline.hpp"
31-
#include "runtime/jniHandles.inline.hpp"
3230
#include "runtime/thread.inline.hpp"
3331
#include "runtime/mutexLocker.hpp"
3432

@@ -70,11 +68,3 @@ void JfrTraceIdLoadBarrier::do_klasses(klass_callback callback, bool previous_ep
7068
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
7169
klass_queue().iterate(callback, previous_epoch);
7270
}
73-
74-
traceid JfrTraceIdLoadBarrier::load(jclass jc) {
75-
assert(jc != NULL, "invariant");
76-
assert(JavaThread::current()->thread_state() == _thread_in_vm, "invariant");
77-
const oop my_oop = JNIHandles::resolve(jc);
78-
assert(my_oop != NULL, "invariant");
79-
return load(java_lang_Class::as_Klass(my_oop));
80-
}

src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.hpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,6 @@
2525
#ifndef SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDLOADBARRIER_HPP
2626
#define SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDLOADBARRIER_HPP
2727

28-
#include "jni.h"
2928
#include "jfr/utilities/jfrTypes.hpp"
3029
#include "memory/allocation.hpp"
3130

@@ -78,7 +77,6 @@ class JfrTraceIdLoadBarrier : AllStatic {
7877
static traceid load(const ClassLoaderData* cld);
7978
static traceid load(const Klass* klass);
8079
static traceid load(const Klass* klass, const Method* method);
81-
static traceid load(jclass jc);
8280
static traceid load(const Method* method);
8381
static traceid load(const ModuleEntry* module);
8482
static traceid load(const PackageEntry* package);

src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
static size_t trace_id_size() { return sizeof(traceid); }
4040

4141
#define INIT_ID(data) JfrTraceId::assign(data)
42+
#define ASSIGN_PRIMITIVE_CLASS_ID(data) JfrTraceId::assign_primitive_klass_id()
4243
#define REMOVE_ID(k) JfrTraceId::remove(k);
4344
#define REMOVE_METHOD_ID(method) JfrTraceId::remove(method);
4445
#define RESTORE_ID(k) JfrTraceId::restore(k);

src/hotspot/share/oops/typeArrayKlass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ TypeArrayKlass* TypeArrayKlass::create_klass(BasicType type,
6262
// mirror creation fails, loaded_classes_do() doesn't find
6363
// an array class without a mirror.
6464
null_loader_data->add_class(ak);
65-
65+
JFR_ONLY(ASSIGN_PRIMITIVE_CLASS_ID(ak);)
6666
return ak;
6767
}
6868

0 commit comments

Comments
 (0)