1 /* 2 * Copyright (c) 2020, 2024, 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 #ifndef SHARE_VM_PRIMS_TAGMAPTABLE_HPP 26 #define SHARE_VM_PRIMS_TAGMAPTABLE_HPP 27 28 #include "gc/shared/collectedHeap.hpp" 29 #include "memory/allocation.hpp" 30 #include "oops/layoutKind.hpp" 31 #include "oops/weakHandle.hpp" 32 #include "utilities/resizeableResourceHash.hpp" 33 34 class JvmtiEnv; 35 36 // Describes an object which can be tagged during heap walk operation. 37 // - generic heap object: _obj: oop, offset == 0, _inline_klass == nullptr; 38 // - value heap object: _obj: oop, offset == 0, _inline_klass == _obj.klass(); 39 // - flat value object: _obj: holder object, offset == offset in the holder, _inline_klass == klass of the flattened object; 40 class JvmtiHeapwalkObject { 41 oop _obj; // for flattened value object this is holder object 42 int _offset; // == 0 for heap objects 43 InlineKlass* _inline_klass; // for value object, nullptr otherwise 44 LayoutKind _layout_kind; // layout kind in holder object, used only for flat->heap conversion 45 46 static InlineKlass* inline_klass_or_null(oop obj) { 47 Klass* k = obj->klass(); 48 return k->is_inline_klass() ? InlineKlass::cast(k) : nullptr; 49 } 50 public: 51 JvmtiHeapwalkObject(): _obj(nullptr), _offset(0), _inline_klass(nullptr), _layout_kind(LayoutKind::UNKNOWN) {} 52 JvmtiHeapwalkObject(oop obj): _obj(obj), _offset(0), _inline_klass(inline_klass_or_null(obj)), _layout_kind(LayoutKind::REFERENCE) {} 53 JvmtiHeapwalkObject(oop obj, int offset, InlineKlass* ik, LayoutKind lk): _obj(obj), _offset(offset), _inline_klass(ik), _layout_kind(lk) {} 54 55 inline bool is_empty() const { return _obj == nullptr; } 56 inline bool is_value() const { return _inline_klass != nullptr; } 57 inline bool is_flat() const { return _offset != 0; } 58 59 inline oop obj() const { return _obj; } 60 inline int offset() const { return _offset; } 61 inline InlineKlass* inline_klass() const { return _inline_klass; } 62 inline LayoutKind layout_kind() const { return _layout_kind; } 63 64 inline Klass* klass() const { return is_value() ? _inline_klass : obj()->klass(); } 65 66 static bool equals(const JvmtiHeapwalkObject& obj1, const JvmtiHeapwalkObject& obj2); 67 68 bool operator==(const JvmtiHeapwalkObject& other) const { 69 // need to compare inline_klass too to handle the case when flat object has flat field at offset 0 70 return _obj == other._obj && _offset == other._offset && _inline_klass == other._inline_klass; 71 } 72 bool operator!=(const JvmtiHeapwalkObject& other) const { 73 return !(*this == other); 74 } 75 }; 76 77 78 // The oop is needed for lookup rather than creating a WeakHandle during 79 // lookup because the HeapWalker may walk soon to be dead objects and 80 // creating a WeakHandle for an otherwise dead object makes G1 unhappy. 81 // 82 // This class is the Key type for inserting in ResizeableResourceHashTable 83 // Its get_hash() and equals() methods are also used for getting the hash 84 // value of a Key and comparing two Keys, respectively. 85 // 86 // Value objects: keep just one tag for all equal value objects including heap allocated value objects. 87 // We have to keep a strong reference to each unique value object with a non-zero tag. 88 // During heap walking flattened value object tags stored in separate JvmtiFlatTagMapTable, 89 // converted to standard strong entries in JvmtiTagMapTable outside of sefepoint. 90 // All equal value objects should have the same tag. 91 // Keep value objects alive (1 copy for each "value") until their tags are removed. 92 93 class JvmtiTagMapKey : public CHeapObj<mtServiceability> { 94 union { 95 WeakHandle _wh; 96 OopHandle _h; // for value objects (_is_weak == false) 97 }; 98 bool _is_weak; 99 // temporarily hold obj while searching 100 const JvmtiHeapwalkObject* _obj; 101 102 public: 103 JvmtiTagMapKey(const JvmtiHeapwalkObject* obj); 104 // Copy ctor is called when we put entry to the hash table. 105 JvmtiTagMapKey(const JvmtiTagMapKey& src); 106 107 JvmtiTagMapKey& operator=(const JvmtiTagMapKey&) = delete; 108 109 JvmtiHeapwalkObject heapwalk_object() const; 110 111 oop object() const; 112 oop object_no_keepalive() const; 113 void release_handle(); 114 115 static unsigned get_hash(const JvmtiTagMapKey& entry); 116 static bool equals(const JvmtiTagMapKey& lhs, const JvmtiTagMapKey& rhs); 117 }; 118 119 typedef 120 ResizeableResourceHashtable <JvmtiTagMapKey, jlong, 121 AnyObj::C_HEAP, mtServiceability, 122 JvmtiTagMapKey::get_hash, 123 JvmtiTagMapKey::equals> ResizableResourceHT; 124 125 // A supporting class for iterating over all entries in Hashmap 126 class JvmtiTagMapKeyClosure { 127 public: 128 virtual bool do_entry(JvmtiTagMapKey& key, jlong& value) = 0; 129 }; 130 131 class JvmtiTagMapTable : public CHeapObj<mtServiceability> { 132 private: 133 ResizableResourceHT _table; 134 135 jlong* lookup(const JvmtiHeapwalkObject& obj) const; 136 137 public: 138 JvmtiTagMapTable(); 139 ~JvmtiTagMapTable(); 140 141 int number_of_entries() const { return _table.number_of_entries(); } 142 143 jlong find(const JvmtiHeapwalkObject& obj) const; 144 // obj cannot be flat 145 void add(const JvmtiHeapwalkObject& obj, jlong tag); 146 // update the tag if the entry exists, returns false otherwise 147 bool update(const JvmtiHeapwalkObject& obj, jlong tag); 148 149 bool remove(const JvmtiHeapwalkObject& obj); 150 151 // iterate over all entries in the hashmap 152 void entry_iterate(JvmtiTagMapKeyClosure* closure); 153 154 bool is_empty() const { return _table.number_of_entries() == 0; } 155 156 // Cleanup cleared entries and store dead object tags in objects array 157 void remove_dead_entries(GrowableArray<jlong>* objects); 158 void clear(); 159 }; 160 161 162 // This class is the Key type for hash table to keep flattened value objects during heap walk operations. 163 // The objects needs to be moved to JvmtiTagMapTable outside of safepoint. 164 class JvmtiFlatTagMapKey: public CHeapObj<mtServiceability> { 165 private: 166 // holder object 167 OopHandle _h; 168 // temporarily holds holder object while searching 169 oop _holder; 170 int _offset; 171 InlineKlass* _inline_klass; 172 LayoutKind _layout_kind; 173 public: 174 JvmtiFlatTagMapKey(const JvmtiHeapwalkObject& obj); 175 // Copy ctor is called when we put entry to the hash table. 176 JvmtiFlatTagMapKey(const JvmtiFlatTagMapKey& src); 177 178 JvmtiFlatTagMapKey& operator=(const JvmtiFlatTagMapKey&) = delete; 179 180 JvmtiHeapwalkObject heapwalk_object() const; 181 182 oop holder() const; 183 oop holder_no_keepalive() const; 184 int offset() const { return _offset; } 185 InlineKlass* inline_klass() const { return _inline_klass; } 186 LayoutKind layout_kind() const { return _layout_kind; } 187 188 void release_handle(); 189 190 static unsigned get_hash(const JvmtiFlatTagMapKey& entry); 191 static bool equals(const JvmtiFlatTagMapKey& lhs, const JvmtiFlatTagMapKey& rhs); 192 }; 193 194 typedef 195 ResizeableResourceHashtable <JvmtiFlatTagMapKey, jlong, 196 AnyObj::C_HEAP, mtServiceability, 197 JvmtiFlatTagMapKey::get_hash, 198 JvmtiFlatTagMapKey::equals> FlatObjectHashtable; 199 200 // A supporting class for iterating over all entries in JvmtiFlatTagMapTable. 201 class JvmtiFlatTagMapKeyClosure { 202 public: 203 virtual bool do_entry(JvmtiFlatTagMapKey& key, jlong& value) = 0; 204 }; 205 206 class JvmtiFlatTagMapTable: public CHeapObj<mtServiceability> { 207 private: 208 FlatObjectHashtable _table; 209 210 public: 211 JvmtiFlatTagMapTable(); 212 ~JvmtiFlatTagMapTable(); 213 214 int number_of_entries() const { return _table.number_of_entries(); } 215 216 jlong find(const JvmtiHeapwalkObject& obj) const; 217 // obj must be flat 218 void add(const JvmtiHeapwalkObject& obj, jlong tag); 219 220 // returns tag for the entry, 0 is not found 221 jlong remove(const JvmtiHeapwalkObject& obj); 222 223 // iterate over entries in the hashmap 224 void entry_iterate(JvmtiFlatTagMapKeyClosure* closure); 225 226 bool is_empty() const { return _table.number_of_entries() == 0; } 227 228 void clear(); 229 }; 230 231 #endif // SHARE_VM_PRIMS_TAGMAPTABLE_HPP