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;
6364static JfrArtifactClosure* _subsystem_callback = NULL ;
6465static bool _class_unload = false ;
6566static bool _flushpoint = false ;
67+ static bool _clear_artifacts = false ;
6668
6769// incremented on each rotation
6870static 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+
8692static 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+
102137template <typename T>
103138static 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+
157197static 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+
228289static 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+
298381static 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;
9791068typedef Wrapper<MethodPtr, ClearArtifact> ClearMethodFlag;
9801069typedef MethodIteratorHost<ClearMethodFlag, ClearKlassBits, AlwaysTrue, false > ClearKlassAndMethods;
9811070
982- static bool clear_artifacts = false ;
983-
9841071static 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
10421130void 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 ();
0 commit comments