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