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 "classfile/javaClasses.hpp" 27 #include "classfile/symbolTable.hpp" 28 #include "classfile/systemDictionary.hpp" 29 #include "jfr/leakprofiler/checkpoint/objectSampleDescription.hpp" 30 #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp" 31 #include "oops/oop.inline.hpp" 32 #include "runtime/thread.hpp" 33 #include "utilities/ostream.hpp" 34 35 static Symbol* symbol_size = NULL; 36 37 ObjectDescriptionBuilder::ObjectDescriptionBuilder() { 38 reset(); 39 } 40 41 void ObjectDescriptionBuilder::write_int(jint value) { 42 char buf[20]; 43 jio_snprintf(buf, sizeof(buf), "%d", value); 44 write_text(buf); 45 } 46 47 void ObjectDescriptionBuilder::write_text(const char* text) { 48 if (_index == sizeof(_buffer) - 2) { 49 return; 50 } 51 while (*text != '\0' && _index < sizeof(_buffer) - 2) { 52 _buffer[_index] = *text; 53 _index++; 54 text++; 55 } 56 assert(_index < sizeof(_buffer) - 1, "index should not exceed buffer size"); 57 // add ellipsis if we reached end 58 if (_index == sizeof(_buffer) - 2) { 59 _buffer[_index-3] = '.'; 60 _buffer[_index-2] = '.'; 61 _buffer[_index-1] = '.'; 62 } 63 // terminate string 64 _buffer[_index] = '\0'; 65 } 66 67 void ObjectDescriptionBuilder::reset() { 68 _index = 0; 69 _buffer[0] = '\0'; 70 } 71 72 void ObjectDescriptionBuilder::print_description(outputStream* out) { 73 out->print("%s", (const char*)_buffer); 74 } 75 76 const char* ObjectDescriptionBuilder::description() { 77 if (_buffer[0] == '\0') { 78 return NULL; 79 } 80 const size_t len = strlen(_buffer); 81 char* copy = NEW_RESOURCE_ARRAY(char, len + 1); 82 assert(copy != NULL, "invariant"); 83 strncpy(copy, _buffer, len + 1); 84 return copy; 85 } 86 87 ObjectSampleDescription::ObjectSampleDescription(oop object) : 88 _object(object) { 89 } 90 91 void ObjectSampleDescription::ensure_initialized() { 92 if (symbol_size == NULL) { 93 symbol_size = SymbolTable::new_permanent_symbol("size", Thread::current()); 94 } 95 } 96 97 void ObjectSampleDescription::print_description(outputStream* out) { 98 write_object_to_buffer(); 99 _description.print_description(out); 100 } 101 102 const char* ObjectSampleDescription::description() { 103 write_object_to_buffer(); 104 return _description.description(); 105 } 106 107 void ObjectSampleDescription::write_text(const char* text) { 108 _description.write_text(text); 109 } 110 111 void ObjectSampleDescription::write_int(jint value) { 112 _description.write_int(value); 113 } 114 115 void ObjectSampleDescription::write_object_to_buffer() { 116 ensure_initialized(); 117 _description.reset(); 118 write_object_details(); 119 } 120 121 void ObjectSampleDescription::write_object_details() { 122 Klass* klass = _object->klass(); 123 Symbol* class_name = klass->name(); 124 jint size; 125 126 if (_object->is_a(SystemDictionary::Class_klass())) { 127 write_class_name(); 128 return; 129 } 130 131 if (_object->is_a(SystemDictionary::Thread_klass())) { 132 write_thread_name(); 133 return; 134 } 135 136 if (_object->is_a(SystemDictionary::ThreadGroup_klass())) { 137 write_thread_group_name(); 138 return; 139 } 140 141 if (read_int_size(&size)) { 142 write_size(size); 143 return; 144 } 145 } 146 147 void ObjectSampleDescription::write_class_name() { 148 assert(_object->is_a(SystemDictionary::Class_klass()), "invariant"); 149 Klass* const k = java_lang_Class::as_Klass(_object); 150 if (k == NULL) { 151 // might represent a primitive 152 const Klass* const ak = java_lang_Class::array_klass(_object); 153 // If ak is NULL, this is most likely a mirror associated with a 154 // jvmti redefine/retransform scratch klass. We can't get any additional 155 // information from it. 156 if (ak != NULL) { 157 write_text(type2name(java_lang_Class::primitive_type(_object))); 158 } 159 return; 160 } 161 162 if (k->oop_is_instance()) { 163 const InstanceKlass* ik = InstanceKlass::cast(k); 164 if (ik->is_anonymous()) { 165 return; 166 } 167 assert(!ik->is_anonymous(), "invariant"); 168 const Symbol* name = ik->name(); 169 if (name != NULL) { 170 write_text("Class Name: "); 171 write_text(name->as_klass_external_name()); 172 } 173 } 174 } 175 176 void ObjectSampleDescription::write_thread_group_name() { 177 assert(_object->is_a(SystemDictionary::ThreadGroup_klass()), "invariant"); 178 typeArrayOop tg_name = java_lang_ThreadGroup::name(_object); 179 if (tg_name != NULL) { 180 write_text("Thread Group: "); 181 write_text(UNICODE::as_utf8((jchar*) tg_name->base(T_CHAR), tg_name->length())); 182 } 183 } 184 185 void ObjectSampleDescription::write_thread_name() { 186 assert(_object->is_a(SystemDictionary::Thread_klass()), "invariant"); 187 oop name = java_lang_Thread::name(_object); 188 if (name != NULL) { 189 char* p = java_lang_String::as_utf8_string(name); 190 if (p != NULL) { 191 write_text("Thread Name: "); 192 write_text(p); 193 } 194 } 195 } 196 197 void ObjectSampleDescription::write_size(jint size) { 198 if (size >= 0) { 199 write_text("Size: "); 200 write_int(size); 201 } 202 } 203 204 bool ObjectSampleDescription::read_int_size(jint* result_size) { 205 fieldDescriptor fd; 206 Klass* klass = _object->klass(); 207 if (klass->oop_is_instance()) { 208 InstanceKlass* ik = InstanceKlass::cast(klass); 209 if (ik->find_field(symbol_size, vmSymbols::int_signature(), false, &fd) != NULL) { 210 jint size = _object->int_field(fd.offset()); 211 *result_size = size; 212 return true; 213 } 214 } 215 return false; 216 }