1 /*
   2  * Copyright (c) 2011, 2019, 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/classLoaderData.inline.hpp"
  27 #include "classfile/symbolTable.hpp"
  28 #include "jfr/recorder/checkpoint/constant/traceid/jfrTraceId.inline.hpp"
  29 #include "oops/arrayKlass.hpp"
  30 #include "oops/klass.inline.hpp"
  31 #include "oops/instanceKlass.hpp"
  32 #include "oops/method.hpp"
  33 #include "oops/oop.inline.hpp"
  34 #include "runtime/atomic.hpp"
  35 #include "runtime/orderAccess.inline.hpp"
  36 #include "runtime/vm_version.hpp"
  37 #include "tracefiles/traceEventIds.hpp"
  38 #include "runtime/jniHandles.hpp"
  39 #include "runtime/thread.inline.hpp"
  40 #include "utilities/debug.hpp"
  41 #include "jfr/utilities/jfrLog.hpp"
  42 
  43  // returns updated value
  44 static traceid atomic_inc(traceid volatile* const dest) {
  45   assert(VM_Version::supports_cx8(), "invariant");
  46   traceid compare_value;
  47   traceid exchange_value;
  48   do {
  49     compare_value = OrderAccess::load_acquire(dest);
  50     exchange_value = compare_value + 1;
  51   } while (Atomic::cmpxchg(exchange_value, dest, compare_value) != compare_value);
  52   return exchange_value;
  53 }
  54 
  55 static traceid next_class_id() {
  56   static volatile traceid class_id_counter = MaxTraceEventId + 100;
  57   return atomic_inc(&class_id_counter) << TRACE_ID_SHIFT;
  58 }
  59 
  60 static traceid next_thread_id() {
  61   static volatile traceid thread_id_counter = 0;
  62   return atomic_inc(&thread_id_counter);
  63 }
  64 
  65 static traceid next_class_loader_data_id() {
  66   static volatile traceid cld_id_counter = 1;
  67   return atomic_inc(&cld_id_counter) << TRACE_ID_SHIFT;
  68 }
  69 
  70 static bool found_jdk_jfr_event_klass = false;
  71 
  72 static void check_klass(const Klass* klass) {
  73   assert(klass != NULL, "invariant");
  74   if (found_jdk_jfr_event_klass) {
  75     return;
  76   }
  77   static const Symbol* jdk_jfr_event_sym = NULL;
  78   if (jdk_jfr_event_sym == NULL) {
  79     // setup when loading the first TypeArrayKlass (Universe::genesis) hence single threaded invariant
  80     jdk_jfr_event_sym = SymbolTable::new_permanent_symbol("jdk/jfr/Event", Thread::current());
  81   }
  82   assert(jdk_jfr_event_sym != NULL, "invariant");
  83   if (jdk_jfr_event_sym == klass->name() && klass->class_loader() == NULL) {
  84     found_jdk_jfr_event_klass = true;
  85     JfrTraceId::tag_as_jdk_jfr_event(klass);
  86   }
  87 }
  88 
  89 void JfrTraceId::assign(const Klass* klass) {
  90   assert(klass != NULL, "invariant");
  91   klass->set_trace_id(next_class_id());
  92   check_klass(klass);
  93   const Klass* const super = klass->super();
  94   if (super == NULL) {
  95     return;
  96   }
  97   if (IS_EVENT_KLASS(super)) {
  98     tag_as_jdk_jfr_event_sub(klass);
  99   }
 100 }
 101 
 102 void JfrTraceId::assign(const ClassLoaderData* cld) {
 103   assert(cld != NULL, "invariant");
 104   if (cld->is_anonymous()) {
 105     cld->set_trace_id(0);
 106     return;
 107   }
 108   cld->set_trace_id(next_class_loader_data_id());
 109 }
 110 
 111 traceid JfrTraceId::assign_thread_id() {
 112   return next_thread_id();
 113 }
 114 
 115 // used by CDS / APPCDS as part of "remove_unshareable_info"
 116 void JfrTraceId::remove(const Klass* k) {
 117   assert(k != NULL, "invariant");
 118   // Mask off and store the event flags.
 119   // This mechanism will retain the event specific flags
 120   // in the archive, allowing for event flag restoration
 121   // when renewing the traceid on klass revival.
 122   k->set_trace_id(EVENT_FLAGS_MASK(k));
 123 }
 124 
 125 // used by CDS / APPCDS as part of "restore_unshareable_info"
 126 void JfrTraceId::restore(const Klass* k) {
 127   assert(k != NULL, "invariant");
 128   if (IS_JDK_JFR_EVENT_KLASS(k)) {
 129     found_jdk_jfr_event_klass = true;
 130   }
 131   const traceid event_flags = k->trace_id();
 132   // get a fresh traceid and restore the original event flags
 133   k->set_trace_id(next_class_id() | event_flags);
 134 }
 135 
 136 traceid JfrTraceId::get(jclass jc) {
 137   assert(jc != NULL, "invariant");
 138   assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_vm, "invariant");
 139   const oop my_oop = JNIHandles::resolve(jc);
 140   assert(my_oop != NULL, "invariant");
 141   return get(java_lang_Class::as_Klass(my_oop));
 142 }
 143 
 144 traceid JfrTraceId::use(jclass jc, bool leakp /* false */) {
 145   assert(jc != NULL, "invariant");
 146   assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_vm, "invariant");
 147   const oop my_oop = JNIHandles::resolve(jc);
 148   assert(my_oop != NULL, "invariant");
 149   return use(java_lang_Class::as_Klass(my_oop), leakp);
 150 }
 151 
 152 bool JfrTraceId::in_visible_set(const jclass jc) {
 153   assert(jc != NULL, "invariant");
 154   assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_vm, "invariant");
 155   const oop mirror = JNIHandles::resolve(jc);
 156   assert(mirror != NULL, "invariant");
 157   return in_visible_set(java_lang_Class::as_Klass(mirror));
 158 }
 159 
 160 bool JfrTraceId::in_jdk_jfr_event_hierarchy(const jclass jc) {
 161   assert(jc != NULL, "invariant");
 162   const oop mirror = JNIHandles::resolve(jc);
 163   assert(mirror != NULL, "invariant");
 164   return in_jdk_jfr_event_hierarchy(java_lang_Class::as_Klass(mirror));
 165 }
 166 
 167 bool JfrTraceId::is_jdk_jfr_event_sub(const jclass jc) {
 168   assert(jc != NULL, "invariant");
 169   const oop mirror = JNIHandles::resolve(jc);
 170   assert(mirror != NULL, "invariant");
 171   return is_jdk_jfr_event_sub(java_lang_Class::as_Klass(mirror));
 172 }
 173 
 174 bool JfrTraceId::is_jdk_jfr_event(const jclass jc) {
 175   assert(jc != NULL, "invariant");
 176   const oop mirror = JNIHandles::resolve(jc);
 177   assert(mirror != NULL, "invariant");
 178   return is_jdk_jfr_event(java_lang_Class::as_Klass(mirror));
 179 }
 180 
 181 bool JfrTraceId::is_event_host(const jclass jc) {
 182   assert(jc != NULL, "invariant");
 183   const oop mirror = JNIHandles::resolve(jc);
 184   assert(mirror != NULL, "invariant");
 185   return is_event_host(java_lang_Class::as_Klass(mirror));
 186 }
 187 
 188 void JfrTraceId::tag_as_jdk_jfr_event_sub(const jclass jc) {
 189   assert(jc != NULL, "invariant");
 190   const oop mirror = JNIHandles::resolve(jc);
 191   assert(mirror != NULL, "invariant");
 192   const Klass* const k = java_lang_Class::as_Klass(mirror);
 193   tag_as_jdk_jfr_event_sub(k);
 194   assert(IS_JDK_JFR_EVENT_SUBKLASS(k), "invariant");
 195 }
 196 
 197 void JfrTraceId::tag_as_event_host(const jclass jc) {
 198   assert(jc != NULL, "invariant");
 199   const oop mirror = JNIHandles::resolve(jc);
 200   assert(mirror != NULL, "invariant");
 201   const Klass* const k = java_lang_Class::as_Klass(mirror);
 202   tag_as_event_host(k);
 203   assert(IS_EVENT_HOST_KLASS(k), "invariant");
 204 }