1 /*
  2  * Copyright (c) 2020, 2025, 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 #include "ci/ciMethod.hpp"
 25 #include "compiler/compilerEvent.hpp"
 26 #include "jfr/jfr.hpp"
 27 #include "jfr/jfrEvents.hpp"
 28 #include "jfr/metadata/jfrSerializer.hpp"
 29 #include "runtime/interfaceSupport.inline.hpp"
 30 #include "runtime/javaThread.hpp"
 31 #include "runtime/os.hpp"
 32 #include "runtime/semaphore.inline.hpp"
 33 #include "utilities/growableArray.hpp"
 34 
 35 // Synchronizes access to phases_names.
 36 class PhaseTypeGuard : public StackObj {
 37  private:
 38   static Semaphore _mutex_semaphore;
 39   bool _enabled;
 40  public:
 41   PhaseTypeGuard(bool enabled=true) {
 42     if (enabled) {
 43       _mutex_semaphore.wait();
 44       _enabled = true;
 45     } else {
 46       _enabled = false;
 47     }
 48   }
 49   ~PhaseTypeGuard() {
 50     if (_enabled) {
 51       _mutex_semaphore.signal();
 52     }
 53   }
 54 };
 55 
 56 Semaphore PhaseTypeGuard::_mutex_semaphore(1);
 57 
 58 // Table for mapping compiler phases names to int identifiers.
 59 static GrowableArray<const char*>* _phase_names = nullptr;
 60 
 61 class CompilerPhaseTypeConstant : public JfrSerializer {
 62  public:
 63   void serialize(JfrCheckpointWriter& writer) {
 64     PhaseTypeGuard guard;
 65     assert(_phase_names != nullptr, "invariant");
 66     assert(_phase_names->is_nonempty(), "invariant");
 67     const u4 nof_entries = _phase_names->length();
 68     writer.write_count(nof_entries);
 69     for (u4 i = 0; i < nof_entries; i++) {
 70       writer.write_key(i);
 71       writer.write(_phase_names->at(i));
 72     }
 73   }
 74 };
 75 
 76 static int lookup_phase(const char* phase_name) {
 77   for (int i = 0; i < _phase_names->length(); i++) {
 78     const char* name = _phase_names->at(i);
 79     if (strcmp(name, phase_name) == 0) {
 80       return i;
 81     }
 82   }
 83   return -1;
 84 }
 85 
 86 int CompilerEvent::PhaseEvent::get_phase_id(const char* phase_name, bool may_exist, bool use_strdup, bool sync) {
 87   int index;
 88   bool register_jfr_serializer = false;
 89   {
 90     PhaseTypeGuard guard(sync);
 91     if (_phase_names == nullptr) {
 92       _phase_names = new (mtInternal) GrowableArray<const char*>(100, mtCompiler);
 93       register_jfr_serializer = true;
 94     } else if (may_exist) {
 95       index = lookup_phase(phase_name);
 96       if (index != -1) {
 97         return index;
 98       }
 99     } else {
100       assert((index = lookup_phase(phase_name)) == -1, "phase name \"%s\" already registered: %d", phase_name, index);
101     }
102 
103     index = _phase_names->length();
104     _phase_names->append(use_strdup ? os::strdup(phase_name) : phase_name);
105   }
106   if (register_jfr_serializer) {
107     JfrSerializer::register_serializer(TYPE_COMPILERPHASETYPE, false, new CompilerPhaseTypeConstant());
108   } else if (Jfr::is_recording()) {
109     // serialize new phase.
110     JfrCheckpointWriter writer;
111     writer.write_type(TYPE_COMPILERPHASETYPE);
112     writer.write_count(1);
113     writer.write_key(index);
114     writer.write(phase_name);
115   }
116   return index;
117 }
118 
119 // As part of event commit, a Method* is tagged as a function of an epoch.
120 // Epochs evolve during safepoints. To ensure the event is tagged in the correct epoch,
121 // that is, to avoid a race, the thread will participate in the safepoint protocol
122 // by doing the commit while the thread is _thread_in_vm.
123 template <typename EventType>
124 static inline void commit(EventType& event) {
125   JavaThread* thread = JavaThread::current();
126   JavaThreadState state = thread->thread_state();
127   if (state == _thread_in_native) {
128     ThreadInVMfromNative transition(thread);
129     event.commit();
130   } else {
131     assert(state == _thread_in_vm, "coming from wrong thread state %d", state);
132     event.commit();
133   }
134  }
135 
136 void CompilerEvent::CompilationEvent::post(EventCompilation& event, int compile_id, CompilerType compiler_type, Method* method,
137     int compile_level, bool success, bool is_osr, int code_size,
138     int inlined_bytecodes, size_t arenaBytes) {
139   event.set_compileId(compile_id);
140   event.set_compiler(compiler_type);
141   event.set_method(method);
142   event.set_compileLevel((short)compile_level);
143   event.set_succeded(success);
144   event.set_isOsr(is_osr);
145   event.set_codeSize(code_size);
146   event.set_inlinedBytes(inlined_bytecodes);
147   event.set_arenaBytes(arenaBytes);
148   commit(event);
149 }
150 
151 void CompilerEvent::CompilationFailureEvent::post(EventCompilationFailure& event, int compile_id, const char* reason) {
152   event.set_compileId(compile_id);
153   event.set_failureMessage(reason);
154   event.commit();
155 }
156 
157 void CompilerEvent::PhaseEvent::post(EventCompilerPhase& event, const Ticks& start_time, int phase, int compile_id, int level) {
158   event.set_starttime(start_time);
159   event.set_phase((u1) phase);
160   event.set_compileId(compile_id);
161   event.set_phaseLevel((short)level);
162   event.commit();
163 }
164 
165 void CompilerEvent::InlineEvent::post(EventCompilerInlining& event, int compile_id, Method* caller, const JfrStructCalleeMethod& callee, bool success, const char* msg, int bci) {
166   event.set_compileId(compile_id);
167   event.set_caller(caller);
168   event.set_callee(callee);
169   event.set_succeeded(success);
170   event.set_message(msg);
171   event.set_bci(bci);
172   commit(event);
173 }
174 
175 void CompilerEvent::InlineEvent::post(EventCompilerInlining& event, int compile_id, Method* caller, Method* callee, bool success, const char* msg, int bci) {
176   JfrStructCalleeMethod callee_struct;
177   callee_struct.set_type(callee->klass_name()->as_utf8());
178   callee_struct.set_name(callee->name()->as_utf8());
179   callee_struct.set_descriptor(callee->signature()->as_utf8());
180   post(event, compile_id, caller, callee_struct, success, msg, bci);
181 }
182 
183 void CompilerEvent::InlineEvent::post(EventCompilerInlining& event, int compile_id, Method* caller, ciMethod* callee, bool success, const char* msg, int bci) {
184   JfrStructCalleeMethod callee_struct;
185   callee_struct.set_type(callee->holder()->name()->as_utf8());
186   callee_struct.set_name(callee->name()->as_utf8());
187   callee_struct.set_descriptor(callee->signature()->as_symbol()->as_utf8());
188   post(event, compile_id, caller, callee_struct, success, msg, bci);
189 }
--- EOF ---