1 /*
  2  * Copyright (c) 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 "classfile/systemDictionary.hpp"
 27 #include "classfile/javaClasses.inline.hpp"
 28 #include "classfile/vmSymbols.hpp"
 29 #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
 30 #include "jfr/recorder/checkpoint/types/traceid/jfrOopTraceId.inline.hpp"
 31 #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp"
 32 #include "jfr/support/jfrJavaThread.hpp"
 33 #include "jfr/support/jfrThreadLocal.hpp"
 34 #include "runtime/thread.inline.hpp"
 35 
 36 static void set_jvmti_notifications(bool notify_vthread_events) {
 37   java_lang_VirtualThread::set_notify_jvmti_events(notify_vthread_events);
 38   java_lang_VirtualThread::init_static_notify_jvmti_events();
 39 }
 40 
 41 bool JfrJavaThread::initialize(bool notify_vthread_events) {
 42   static bool initialized = false;
 43   if (!initialized) {
 44     JavaThread* t = JavaThread::current();
 45     Symbol* const sym = vmSymbols::java_lang_Thread_VirtualThreads();
 46     assert(sym != NULL, "invariant");
 47     Klass* const k = SystemDictionary::resolve_or_fail(sym, false, t);
 48     assert(k != NULL, "invariant");
 49     k->initialize(t);
 50     set_jvmti_notifications(notify_vthread_events);
 51     initialized = true;
 52   }
 53   return initialized;
 54 }
 55 
 56 class ThreadIdAccess : AllStatic {
 57  public:
 58   static traceid load(oop ref) {
 59     return (traceid)java_lang_Thread::thread_id(ref);
 60   }
 61   static traceid store(oop ref, traceid value) {
 62     return (traceid)java_lang_VirtualThread::set_jfrTraceId(ref, (jlong)value);
 63   }
 64 };
 65 
 66 typedef JfrOopTraceId<ThreadIdAccess> AccessThreadTraceId;
 67 
 68 static traceid load_vthread_id(oop vthread, const JavaThread* jt) {
 69   assert(vthread != NULL, "invariant");
 70   assert(jt != NULL, "invariant");
 71   const traceid value = AccessThreadTraceId::load(vthread);
 72   const traceid tid = AccessThreadTraceId::id(value);
 73   if (AccessThreadTraceId::should_write_checkpoint(vthread, value)) {
 74     JfrCheckpointManager::write_checkpoint(const_cast<JavaThread*>(jt), tid, vthread);
 75   }
 76   return tid;
 77 }
 78 
 79 inline traceid load_java_thread_id(oop threadObj, const JavaThread* jt) {
 80   assert(threadObj != NULL, "invariant");
 81   return java_lang_Thread::thread_id(threadObj);
 82 }
 83 
 84 inline oop get_vthread(const JavaThread* jt) {
 85   assert(jt != NULL, "invariant");
 86   return jt->vthread();
 87 }
 88 
 89 inline oop get_threadObj(const JavaThread* jt) {
 90   assert(jt != NULL, "invariant");
 91   return jt->threadObj();
 92 }
 93 
 94 traceid JfrJavaThread::contextual_thread_id(const JavaThread* jt, bool* is_virtual) {
 95   assert(jt != NULL, "invariant");
 96   assert(is_virtual != NULL ? !(*is_virtual) : true, "invariant");
 97   const oop threadObj = get_threadObj(jt);
 98   if (threadObj == NULL) {
 99     // to early
100     return 0;
101   }
102   const oop vthread = get_vthread(jt);
103   if (vthread == threadObj) {
104     return load_java_thread_id(threadObj, jt);
105   }
106   if (is_virtual != NULL) {
107     *is_virtual = true;
108   }
109   return load_vthread_id(vthread, jt);
110 }
111 
112 traceid JfrJavaThread::java_thread_id(const JavaThread* jt) {
113   assert(jt != NULL, "invariant");
114   const oop threadObj = get_threadObj(jt);
115   return threadObj != NULL ? load_java_thread_id(threadObj, jt) : 0;
116 }
117 
118 traceid JfrJavaThread::virtual_thread_id(const oop vthread, const JavaThread* jt) {
119   assert(vthread != NULL, "invariant");
120   assert(jt != NULL, "invariant");
121   return load_vthread_id(vthread, jt);
122 }
123 
124 bool JfrJavaThread::is_virtual(const JavaThread* jt) {
125   assert(jt != NULL, "invariant");
126   const oop threadObj = get_threadObj(jt);
127   return threadObj != get_vthread(jt);
128 }
129 
130 oop JfrJavaThread::virtual_thread(const JavaThread* jt) {
131   assert(is_virtual(jt), "invariant");
132   return get_vthread(jt);
133 }
134