1 /* 2 * Copyright (c) 2017, 2018, 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/recorder/checkpoint/types/jfrTypeSetUtils.hpp" 27 #include "oops/instanceKlass.hpp" 28 #include "oops/oop.inline.hpp" 29 #include "oops/symbol.hpp" 30 31 JfrSymbolId::JfrSymbolId() : _symbol_id_counter(0), _sym_table(new SymbolTable(this)), _cstring_table(new CStringTable(this)) { 32 assert(_sym_table != NULL, "invariant"); 33 assert(_cstring_table != NULL, "invariant"); 34 initialize(); 35 } 36 37 void JfrSymbolId::initialize() { 38 clear(); 39 assert(_symbol_id_counter == 0, "invariant"); 40 } 41 42 void JfrSymbolId::clear() { 43 assert(_sym_table != NULL, "invariant"); 44 if (_sym_table->has_entries()) { 45 _sym_table->clear_entries(); 46 } 47 assert(!_sym_table->has_entries(), "invariant"); 48 49 assert(_cstring_table != NULL, "invariant"); 50 if (_cstring_table->has_entries()) { 51 _cstring_table->clear_entries(); 52 } 53 assert(!_cstring_table->has_entries(), "invariant"); 54 _symbol_id_counter = 0; 55 } 56 57 JfrSymbolId::~JfrSymbolId() { 58 delete _sym_table; 59 delete _cstring_table; 60 } 61 62 traceid JfrSymbolId::mark_anonymous_klass_name(const Klass* k) { 63 assert(k != NULL, "invariant"); 64 assert(k->is_instance_klass(), "invariant"); 65 assert(is_anonymous_klass(k), "invariant"); 66 67 uintptr_t anonymous_symbol_hash_code = 0; 68 const char* const anonymous_symbol = 69 create_anonymous_klass_symbol((const InstanceKlass*)k, anonymous_symbol_hash_code); 70 71 if (anonymous_symbol == NULL) { 72 return 0; 73 } 74 75 assert(anonymous_symbol_hash_code != 0, "invariant"); 76 traceid symbol_id = mark(anonymous_symbol, anonymous_symbol_hash_code); 77 assert(mark(anonymous_symbol, anonymous_symbol_hash_code) == symbol_id, "invariant"); 78 return symbol_id; 79 } 80 81 const JfrSymbolId::SymbolEntry* JfrSymbolId::map_symbol(const Symbol* symbol) const { 82 return _sym_table->lookup_only(symbol, (uintptr_t)const_cast<Symbol*>(symbol)->identity_hash()); 83 } 84 85 const JfrSymbolId::SymbolEntry* JfrSymbolId::map_symbol(uintptr_t hash) const { 86 return _sym_table->lookup_only(NULL, hash); 87 } 88 89 const JfrSymbolId::CStringEntry* JfrSymbolId::map_cstring(uintptr_t hash) const { 90 return _cstring_table->lookup_only(NULL, hash); 91 } 92 93 void JfrSymbolId::assign_id(SymbolEntry* entry) { 94 assert(entry != NULL, "invariant"); 95 assert(entry->id() == 0, "invariant"); 96 entry->set_id(++_symbol_id_counter); 97 } 98 99 bool JfrSymbolId::equals(const Symbol* query, uintptr_t hash, const SymbolEntry* entry) { 100 // query might be NULL 101 assert(entry != NULL, "invariant"); 102 assert(entry->hash() == hash, "invariant"); 103 return true; 104 } 105 106 void JfrSymbolId::assign_id(CStringEntry* entry) { 107 assert(entry != NULL, "invariant"); 108 assert(entry->id() == 0, "invariant"); 109 entry->set_id(++_symbol_id_counter); 110 } 111 112 bool JfrSymbolId::equals(const char* query, uintptr_t hash, const CStringEntry* entry) { 113 // query might be NULL 114 assert(entry != NULL, "invariant"); 115 assert(entry->hash() == hash, "invariant"); 116 return true; 117 } 118 119 traceid JfrSymbolId::mark(const Klass* k) { 120 assert(k != NULL, "invariant"); 121 traceid symbol_id = 0; 122 if (is_anonymous_klass(k)) { 123 symbol_id = mark_anonymous_klass_name(k); 124 } 125 if (0 == symbol_id) { 126 const Symbol* const sym = k->name(); 127 if (sym != NULL) { 128 symbol_id = mark(sym); 129 } 130 } 131 assert(symbol_id > 0, "a symbol handler must mark the symbol for writing"); 132 return symbol_id; 133 } 134 135 traceid JfrSymbolId::mark(const Symbol* symbol) { 136 assert(symbol != NULL, "invariant"); 137 return mark(symbol, (uintptr_t)const_cast<Symbol*>(symbol)->identity_hash()); 138 } 139 140 traceid JfrSymbolId::mark(const Symbol* data, uintptr_t hash) { 141 assert(data != NULL, "invariant"); 142 assert(_sym_table != NULL, "invariant"); 143 return _sym_table->id(data, hash); 144 } 145 146 traceid JfrSymbolId::mark(const char* str, uintptr_t hash) { 147 assert(str != NULL, "invariant"); 148 return _cstring_table->id(str, hash); 149 } 150 151 bool JfrSymbolId::is_anonymous_klass(const Klass* k) { 152 assert(k != NULL, "invariant"); 153 return k->is_instance_klass() && ((const InstanceKlass*)k)->is_anonymous(); 154 } 155 156 /* 157 * jsr292 anonymous classes symbol is the external name + 158 * the identity_hashcode slash appended: 159 * java.lang.invoke.LambdaForm$BMH/22626602 160 * 161 * caller needs ResourceMark 162 */ 163 164 uintptr_t JfrSymbolId::anonymous_klass_name_hash_code(const InstanceKlass* ik) { 165 assert(ik != NULL, "invariant"); 166 assert(ik->is_anonymous(), "invariant"); 167 const oop mirror = ik->java_mirror(); 168 assert(mirror != NULL, "invariant"); 169 return (uintptr_t)mirror->identity_hash(); 170 } 171 172 const char* JfrSymbolId::create_anonymous_klass_symbol(const InstanceKlass* ik, uintptr_t& hashcode) { 173 assert(ik != NULL, "invariant"); 174 assert(ik->is_anonymous(), "invariant"); 175 assert(0 == hashcode, "invariant"); 176 char* anonymous_symbol = NULL; 177 const oop mirror = ik->java_mirror(); 178 assert(mirror != NULL, "invariant"); 179 char hash_buf[40]; 180 hashcode = anonymous_klass_name_hash_code(ik); 181 sprintf(hash_buf, "/" UINTX_FORMAT, hashcode); 182 const size_t hash_len = strlen(hash_buf); 183 const size_t result_len = ik->name()->utf8_length(); 184 anonymous_symbol = NEW_RESOURCE_ARRAY(char, result_len + hash_len + 1); 185 ik->name()->as_klass_external_name(anonymous_symbol, (int)result_len + 1); 186 assert(strlen(anonymous_symbol) == result_len, "invariant"); 187 strcpy(anonymous_symbol + result_len, hash_buf); 188 assert(strlen(anonymous_symbol) == result_len + hash_len, "invariant"); 189 return anonymous_symbol; 190 } 191 192 uintptr_t JfrSymbolId::regular_klass_name_hash_code(const Klass* k) { 193 assert(k != NULL, "invariant"); 194 const Symbol* const sym = k->name(); 195 assert(sym != NULL, "invariant"); 196 return (uintptr_t)const_cast<Symbol*>(sym)->identity_hash(); 197 } 198 199 JfrArtifactSet::JfrArtifactSet(bool class_unload) : _symbol_id(new JfrSymbolId()), 200 _klass_list(NULL), 201 _class_unload(class_unload) { 202 initialize(class_unload); 203 assert(_klass_list != NULL, "invariant"); 204 } 205 206 static const size_t initial_class_list_size = 200; 207 void JfrArtifactSet::initialize(bool class_unload) { 208 assert(_symbol_id != NULL, "invariant"); 209 _symbol_id->initialize(); 210 assert(!_symbol_id->has_entries(), "invariant"); 211 _symbol_id->mark(BOOTSTRAP_LOADER_NAME, 0); // pre-load "bootstrap" 212 _class_unload = class_unload; 213 // resource allocation 214 _klass_list = new GrowableArray<const Klass*>(initial_class_list_size, false, mtTracing); 215 } 216 217 JfrArtifactSet::~JfrArtifactSet() { 218 clear(); 219 } 220 221 void JfrArtifactSet::clear() { 222 _symbol_id->clear(); 223 // _klass_list will be cleared by a ResourceMark 224 } 225 226 traceid JfrArtifactSet::mark_anonymous_klass_name(const Klass* klass) { 227 return _symbol_id->mark_anonymous_klass_name(klass); 228 } 229 230 traceid JfrArtifactSet::mark(const Symbol* sym, uintptr_t hash) { 231 return _symbol_id->mark(sym, hash); 232 } 233 234 traceid JfrArtifactSet::mark(const Klass* klass) { 235 return _symbol_id->mark(klass); 236 } 237 238 traceid JfrArtifactSet::mark(const Symbol* symbol) { 239 return _symbol_id->mark(symbol); 240 } 241 242 traceid JfrArtifactSet::mark(const char* const str, uintptr_t hash) { 243 return _symbol_id->mark(str, hash); 244 } 245 246 const JfrSymbolId::SymbolEntry* JfrArtifactSet::map_symbol(const Symbol* symbol) const { 247 return _symbol_id->map_symbol(symbol); 248 } 249 250 const JfrSymbolId::SymbolEntry* JfrArtifactSet::map_symbol(uintptr_t hash) const { 251 return _symbol_id->map_symbol(hash); 252 } 253 254 const JfrSymbolId::CStringEntry* JfrArtifactSet::map_cstring(uintptr_t hash) const { 255 return _symbol_id->map_cstring(hash); 256 } 257 258 bool JfrArtifactSet::has_klass_entries() const { 259 return _klass_list->is_nonempty(); 260 } 261 262 int JfrArtifactSet::entries() const { 263 return _klass_list->length(); 264 } 265 266 void JfrArtifactSet::register_klass(const Klass* k) { 267 assert(k != NULL, "invariant"); 268 assert(_klass_list != NULL, "invariant"); 269 assert(_klass_list->find(k) == -1, "invariant"); 270 _klass_list->append(k); 271 }