1 /*
  2  * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 #include "precompiled.hpp"
 26 #include "jfr/metadata/jfrSerializer.hpp"
 27 #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
 28 #include "jfr/recorder/checkpoint/types/jfrType.hpp"
 29 #include "jfr/recorder/checkpoint/types/jfrTypeManager.hpp"
 30 #include "jfr/recorder/jfrRecorder.hpp"
 31 #include "jfr/support/jfrThreadLocal.hpp"
 32 #include "jfr/utilities/jfrIterator.hpp"
 33 #include "jfr/utilities/jfrLinkedList.inline.hpp"
 34 #include "memory/resourceArea.hpp"
 35 #include "runtime/handles.inline.hpp"
 36 #include "runtime/safepoint.hpp"
 37 #include "runtime/semaphore.hpp"
 38 #include "runtime/thread.inline.hpp"
 39 #include "utilities/exceptions.hpp"
 40 
 41 class JfrSerializerRegistration : public JfrCHeapObj {
 42  public:
 43   JfrSerializerRegistration* _next; // list support
 44  private:
 45   JfrSerializer* _serializer;
 46   mutable JfrBlobHandle _cache;
 47   JfrTypeId _id;
 48   bool _permit_cache;
 49  public:
 50   JfrSerializerRegistration(JfrTypeId id, bool permit_cache, JfrSerializer* serializer) :
 51     _next(NULL), _serializer(serializer), _cache(), _id(id), _permit_cache(permit_cache) {}
 52   ~JfrSerializerRegistration() {
 53     delete _serializer;
 54   }
 55 
 56   JfrTypeId id() const {
 57     return _id;
 58   }
 59 
 60   void on_rotation() const {
 61     _serializer->on_rotation();
 62   }
 63 
 64   void invoke(JfrCheckpointWriter& writer) const {
 65     if (_cache.valid()) {
 66       writer.increment();
 67       _cache->write(writer);
 68       return;
 69     }
 70     const JfrCheckpointContext ctx = writer.context();
 71     // serialize the type id before invoking callback
 72     writer.write_type(_id);
 73     const intptr_t start = writer.current_offset();
 74     // invoke the serializer routine
 75     _serializer->serialize(writer);
 76     if (start == writer.current_offset()) {
 77       // the serializer implementation did nothing, rewind to restore
 78       writer.set_context(ctx);
 79       return;
 80     }
 81     if (_permit_cache) {
 82       _cache = writer.copy(&ctx);
 83     }
 84   }
 85 };
 86 
 87 static void serialize_threads(JfrCheckpointWriter& writer) {
 88   JfrThreadConstantSet thread_set;
 89   writer.write_type(TYPE_THREAD);
 90   thread_set.serialize(writer);
 91 }
 92 
 93 static void serialize_thread_groups(JfrCheckpointWriter& writer) {
 94   JfrThreadGroupConstant thread_group_set;
 95   writer.write_type(TYPE_THREADGROUP);
 96   thread_group_set.serialize(writer);
 97 }
 98 
 99 void JfrTypeManager::write_threads(JfrCheckpointWriter& writer) {
100   serialize_threads(writer);
101   serialize_thread_groups(writer);
102 }
103 
104 void JfrTypeManager::create_thread_blob(Thread* t) {
105   assert(t != NULL, "invariant");
106   ResourceMark rm(t);
107   HandleMark hm(t);
108   JfrThreadConstant type_thread(t);
109   JfrCheckpointWriter writer(t, true, THREADS, false);
110   writer.write_type(TYPE_THREAD);
111   type_thread.serialize(writer);
112   // create and install a checkpoint blob
113   t->jfr_thread_local()->set_thread_blob(writer.move());
114   assert(t->jfr_thread_local()->has_thread_blob(), "invariant");
115 }
116 
117 void JfrTypeManager::write_thread_checkpoint(Thread* t) {
118   assert(t != NULL, "invariant");
119   if (!t->jfr_thread_local()->has_thread_blob()) {
120     create_thread_blob(t);
121   }
122   JfrCheckpointWriter writer(t, false, THREADS, false);
123   t->jfr_thread_local()->thread_blob()->write(writer);
124 }
125 
126 class SerializerRegistrationGuard : public StackObj {
127  private:
128   static Semaphore _mutex_semaphore;
129  public:
130   SerializerRegistrationGuard() {
131     _mutex_semaphore.wait();
132   }
133   ~SerializerRegistrationGuard() {
134     _mutex_semaphore.signal();
135   }
136 };
137 
138 Semaphore SerializerRegistrationGuard::_mutex_semaphore(1);
139 
140 typedef JfrLinkedList<JfrSerializerRegistration> List;
141 static List types;
142 
143 void JfrTypeManager::destroy() {
144   SerializerRegistrationGuard guard;
145   JfrSerializerRegistration* registration;
146   while (types.is_nonempty()) {
147     registration = types.remove();
148     assert(registration != NULL, "invariant");
149     delete registration;
150   }
151 }
152 
153 class InvokeOnRotation {
154  public:
155   bool process(const JfrSerializerRegistration* r) {
156     assert(r != NULL, "invariant");
157     r->on_rotation();
158     return true;
159   }
160 };
161 
162 void JfrTypeManager::on_rotation() {
163   InvokeOnRotation ior;
164   types.iterate(ior);
165 }
166 
167 #ifdef ASSERT
168 
169 class Diversity {
170  private:
171   const JfrTypeId _id;
172  public:
173   Diversity(JfrTypeId id) : _id(id) {}
174   bool process(const JfrSerializerRegistration* r) {
175     assert(r != NULL, "invariant");
176     assert(r->id() != _id, "invariant");
177     return true;
178   }
179 };
180 
181 static void assert_not_registered_twice(JfrTypeId id, List& list) {
182   Diversity d(id);
183   types.iterate(d);
184 }
185 #endif
186 
187 static bool register_static_type(JfrTypeId id, bool permit_cache, JfrSerializer* serializer) {
188   assert(serializer != NULL, "invariant");
189   JfrSerializerRegistration* const registration = new JfrSerializerRegistration(id, permit_cache, serializer);
190   if (registration == NULL) {
191     delete serializer;
192     return false;
193   }
194   assert(!types.in_list(registration), "invariant");
195   DEBUG_ONLY(assert_not_registered_twice(id, types);)
196   if (JfrRecorder::is_recording()) {
197     JfrCheckpointWriter writer(STATICS);
198     registration->invoke(writer);
199   }
200   types.add(registration);
201   return true;
202 }
203 
204 bool JfrTypeManager::initialize() {
205   SerializerRegistrationGuard guard;
206   register_static_type(TYPE_FLAGVALUEORIGIN, true, new FlagValueOriginConstant());
207   register_static_type(TYPE_INFLATECAUSE, true, new MonitorInflateCauseConstant());
208   register_static_type(TYPE_GCCAUSE, true, new GCCauseConstant());
209   register_static_type(TYPE_GCNAME, true, new GCNameConstant());
210   register_static_type(TYPE_GCWHEN, true, new GCWhenConstant());
211   register_static_type(TYPE_GCTHRESHOLDUPDATER, true, new GCThresholdUpdaterConstant());
212   register_static_type(TYPE_METADATATYPE, true, new MetadataTypeConstant());
213   register_static_type(TYPE_METASPACEOBJECTTYPE, true, new MetaspaceObjectTypeConstant());
214   register_static_type(TYPE_REFERENCETYPE, true, new ReferenceTypeConstant());
215   register_static_type(TYPE_NARROWOOPMODE, true, new NarrowOopModeConstant());
216   register_static_type(TYPE_CODEBLOBTYPE, true, new CodeBlobTypeConstant());
217   register_static_type(TYPE_VMOPERATIONTYPE, true, new VMOperationTypeConstant());
218   register_static_type(TYPE_THREADSTATE, true, new ThreadStateConstant());
219   register_static_type(TYPE_BYTECODE, true, new BytecodeConstant());
220   register_static_type(TYPE_COMPILERTYPE, true, new CompilerTypeConstant());
221   return true;
222 }
223 
224 // implementation for the static registration function exposed in the JfrSerializer api
225 bool JfrSerializer::register_serializer(JfrTypeId id, bool permit_cache, JfrSerializer* serializer) {
226   SerializerRegistrationGuard guard;
227   return register_static_type(id, permit_cache, serializer);
228 }
229 
230 class InvokeSerializer {
231  private:
232    JfrCheckpointWriter& _writer;
233  public:
234   InvokeSerializer(JfrCheckpointWriter& writer) : _writer(writer) {}
235   bool process(const JfrSerializerRegistration* r) {
236     assert(r != NULL, "invariant");
237     r->invoke(_writer);
238     return true;
239   }
240 };
241 
242 void JfrTypeManager::write_static_types(JfrCheckpointWriter& writer) {
243   InvokeSerializer is(writer);
244   SerializerRegistrationGuard guard;
245   types.iterate(is);
246 }