1 /*
  2  * Copyright (c) 2016, 2021, 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 "jni.h"
 27 #include "classfile/symbolTable.hpp"
 28 #include "classfile/systemDictionary.hpp"
 29 #include "classfile/vmSymbols.hpp"
 30 #include "jfr/jni/jfrJavaSupport.hpp"
 31 #include "jfr/recorder/storage/jfrStorage.hpp"
 32 #include "jfr/support/jfrThreadId.hpp"
 33 #include "jfr/utilities/jfrTypes.hpp"
 34 #include "jfr/writers/jfrJavaEventWriter.hpp"
 35 #include "memory/iterator.hpp"
 36 #include "oops/instanceKlass.hpp"
 37 #include "oops/oop.inline.hpp"
 38 #include "runtime/fieldDescriptor.inline.hpp"
 39 #include "runtime/handles.inline.hpp"
 40 #include "runtime/jniHandles.inline.hpp"
 41 #include "runtime/thread.inline.hpp"
 42 
 43 static int start_pos_offset = invalid_offset;
 44 static int start_pos_address_offset = invalid_offset;
 45 static int current_pos_offset = invalid_offset;
 46 static int max_pos_offset = invalid_offset;
 47 static int notified_offset = invalid_offset;
 48 static int thread_id_offset = invalid_offset;
 49 static int valid_offset = invalid_offset;
 50 
 51 static bool setup_event_writer_offsets(TRAPS) {
 52   const char class_name[] = "jdk/jfr/internal/EventWriter";
 53   Symbol* const k_sym = SymbolTable::new_symbol(class_name);
 54   assert(k_sym != NULL, "invariant");
 55   Klass* klass = SystemDictionary::resolve_or_fail(k_sym, true, CHECK_false);
 56   assert(klass != NULL, "invariant");
 57 
 58   const char start_pos_name[] = "startPosition";
 59   Symbol* const start_pos_sym = SymbolTable::new_symbol(start_pos_name);
 60   assert(start_pos_sym != NULL, "invariant");
 61   assert(invalid_offset == start_pos_offset, "invariant");
 62   JfrJavaSupport::compute_field_offset(start_pos_offset, klass, start_pos_sym, vmSymbols::long_signature());
 63   assert(start_pos_offset != invalid_offset, "invariant");
 64 
 65   const char start_pos_address_name[] = "startPositionAddress";
 66   Symbol* const start_pos_address_sym = SymbolTable::new_symbol(start_pos_address_name);
 67   assert(start_pos_address_sym != NULL, "invariant");
 68   assert(invalid_offset == start_pos_address_offset, "invariant");
 69   JfrJavaSupport::compute_field_offset(start_pos_address_offset, klass, start_pos_address_sym, vmSymbols::long_signature());
 70   assert(start_pos_address_offset != invalid_offset, "invariant");
 71 
 72   const char event_pos_name[] = "currentPosition";
 73   Symbol* const event_pos_sym = SymbolTable::new_symbol(event_pos_name);
 74   assert(event_pos_sym != NULL, "invariant");
 75   assert(invalid_offset == current_pos_offset, "invariant");
 76   JfrJavaSupport::compute_field_offset(current_pos_offset, klass, event_pos_sym,vmSymbols::long_signature());
 77   assert(current_pos_offset != invalid_offset, "invariant");
 78 
 79   const char max_pos_name[] = "maxPosition";
 80   Symbol* const max_pos_sym = SymbolTable::new_symbol(max_pos_name);
 81   assert(max_pos_sym != NULL, "invariant");
 82   assert(invalid_offset == max_pos_offset, "invariant");
 83   JfrJavaSupport::compute_field_offset(max_pos_offset, klass, max_pos_sym, vmSymbols::long_signature());
 84   assert(max_pos_offset != invalid_offset, "invariant");
 85 
 86   const char notified_name[] = "notified";
 87   Symbol* const notified_sym = SymbolTable::new_symbol(notified_name);
 88   assert (notified_sym != NULL, "invariant");
 89   assert(invalid_offset == notified_offset, "invariant");
 90   JfrJavaSupport::compute_field_offset(notified_offset, klass, notified_sym, vmSymbols::bool_signature());
 91   assert(notified_offset != invalid_offset, "invariant");
 92 
 93   const char threadID_name[] = "threadID";
 94   Symbol * const threadID_sym = SymbolTable::new_symbol(threadID_name);
 95   assert(threadID_sym != NULL, "invariant");
 96   assert(invalid_offset == thread_id_offset, "invariant");
 97   JfrJavaSupport::compute_field_offset(thread_id_offset, klass, threadID_sym, vmSymbols::long_signature());
 98   assert(thread_id_offset != invalid_offset, "invariant");
 99 
100   const char valid_name[] = "valid";
101   Symbol* const valid_sym = SymbolTable::new_symbol(valid_name);
102   assert (valid_sym != NULL, "invariant");
103   assert(invalid_offset == valid_offset, "invariant");
104   JfrJavaSupport::compute_field_offset(valid_offset, klass, valid_sym, vmSymbols::bool_signature());
105   assert(valid_offset != invalid_offset, "invariant");
106   return true;
107 }
108 
109 bool JfrJavaEventWriter::initialize() {
110   static bool initialized = false;
111   if (!initialized) {
112     initialized = setup_event_writer_offsets(JavaThread::current());
113   }
114   return initialized;
115 }
116 
117 jboolean JfrJavaEventWriter::flush(jobject writer, jint used, jint requested, JavaThread* jt) {
118   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));
119   assert(writer != NULL, "invariant");
120   oop const w = JNIHandles::resolve_non_null(writer);
121   assert(w != NULL, "invariant");
122   JfrBuffer* const current = jt->jfr_thread_local()->java_buffer();
123   assert(current != NULL, "invariant");
124   JfrBuffer* const buffer = JfrStorage::flush(current, used, requested, false, jt);
125   assert(buffer != NULL, "invariant");
126   // "validity" is contextually defined here to mean
127   // that some memory location was provided that is
128   // large enough to accommodate the "requested size".
129   const bool is_valid = buffer->free_size() >= (size_t)(used + requested);
130   u1* const new_current_position = is_valid ? buffer->pos() + used : buffer->pos();
131   assert(start_pos_offset != invalid_offset, "invariant");
132   w->long_field_put(start_pos_offset, (jlong)buffer->pos());
133   w->long_field_put(current_pos_offset, (jlong)new_current_position);
134   // only update java writer if underlying memory changed
135   if (buffer != current) {
136     w->long_field_put(start_pos_address_offset, (jlong)buffer->pos_address());
137     w->long_field_put(max_pos_offset, (jlong)buffer->end());
138   }
139   if (!is_valid) {
140     // mark writer as invalid for this write attempt
141     w->release_bool_field_put(valid_offset, JNI_FALSE);
142     return JNI_FALSE;
143   }
144   // An exclusive use of a leased buffer is treated equivalent to
145   // holding a system resource. As such, it should be released as soon as possible.
146   // Returning true here signals that the thread will need to call flush again
147   // on EventWriter.endEvent() and that flush will return the lease.
148   return buffer->lease() ? JNI_TRUE : JNI_FALSE;
149 }
150 
151 class JfrJavaEventWriterNotificationClosure : public ThreadClosure {
152  public:
153    void do_thread(Thread* t) {
154      if (t->is_Java_thread()) {
155        JfrJavaEventWriter::notify(JavaThread::cast(t));
156      }
157    }
158 };
159 
160 void JfrJavaEventWriter::notify() {
161   assert(SafepointSynchronize::is_at_safepoint(), "invariant");
162   JfrJavaEventWriterNotificationClosure closure;
163   Threads::threads_do(&closure);
164 }
165 
166 void JfrJavaEventWriter::notify(JavaThread* jt) {
167   assert(jt != NULL, "invariant");
168   assert(SafepointSynchronize::is_at_safepoint(), "invariant");
169   if (jt->jfr_thread_local()->has_java_event_writer()) {
170     oop buffer_writer = JNIHandles::resolve_non_null(jt->jfr_thread_local()->java_event_writer());
171     assert(buffer_writer != NULL, "invariant");
172     buffer_writer->release_bool_field_put(notified_offset, JNI_TRUE);
173   }
174 }
175 
176 static jobject create_new_event_writer(JfrBuffer* buffer, TRAPS) {
177   assert(buffer != NULL, "invariant");
178   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
179   HandleMark hm(THREAD);
180   static const char klass[] = "jdk/jfr/internal/EventWriter";
181   static const char method[] = "<init>";
182   static const char signature[] = "(JJJJZ)V";
183   JavaValue result(T_OBJECT);
184   JfrJavaArguments args(&result, klass, method, signature, CHECK_NULL);
185   // parameters
186   args.push_long((jlong)buffer->pos());
187   args.push_long((jlong)buffer->end());
188   args.push_long((jlong)buffer->pos_address());
189   args.push_long((jlong)JFR_THREAD_ID(THREAD));
190   args.push_int((int)JNI_TRUE);
191   JfrJavaSupport::new_object_global_ref(&args, CHECK_NULL);
192   return result.get_jobject();
193 }
194 
195 jobject JfrJavaEventWriter::event_writer(JavaThread* t, traceid tid /* 0 */) {
196   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(t));
197   JfrThreadLocal* const tl = t->jfr_thread_local();
198   assert(tl->shelved_buffer() == NULL, "invariant");
199   jobject h_writer = tl->java_event_writer();
200   if (h_writer != NULL) {
201     oop writer = JNIHandles::resolve_non_null(h_writer);
202     assert(writer != NULL, "invariant");
203     // primarily for supporting Virtual Threads
204     const jlong event_writer_tid = writer->long_field(thread_id_offset);
205     const jlong current_tid = tid != 0 ? tid : (jlong)JFR_THREAD_ID(t);
206     if (event_writer_tid != current_tid) {
207       writer->long_field_put(thread_id_offset, current_tid);
208     }
209   }
210   return h_writer;
211 }
212 
213 jobject JfrJavaEventWriter::new_event_writer(TRAPS) {
214   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
215   assert(event_writer(THREAD) == NULL, "invariant");
216   JfrThreadLocal* const tl = THREAD->jfr_thread_local();
217   assert(!tl->has_java_buffer(), "invariant");
218   JfrBuffer* const buffer = tl->java_buffer();
219   if (buffer == NULL) {
220     JfrJavaSupport::throw_out_of_memory_error("OOME for thread local buffer", THREAD);
221     return NULL;
222   }
223   jobject h_writer = create_new_event_writer(buffer, CHECK_NULL);
224   tl->set_java_event_writer(h_writer);
225   assert(tl->has_java_event_writer(), "invariant");
226   return h_writer;
227 }