1 /* 2 * Copyright (c) 2017, 2025, 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_OOPS_INLINEKLASS_HPP 26 #define SHARE_VM_OOPS_INLINEKLASS_HPP 27 28 #include "classfile/classFileParser.hpp" 29 #include "classfile/javaClasses.hpp" 30 #include "oops/arrayKlass.hpp" 31 #include "oops/instanceKlass.hpp" 32 #include "oops/method.hpp" 33 #include "runtime/registerMap.hpp" 34 35 // An InlineKlass is a specialized InstanceKlass for concrete value classes 36 // (abstract value classes are represented by InstanceKlass) 37 38 39 class InlineKlass: public InstanceKlass { 40 friend class VMStructs; 41 friend class InstanceKlass; 42 friend class ClassFileParser; 43 44 public: 45 static const KlassKind Kind = InlineKlassKind; 46 47 InlineKlass(); 48 49 private: 50 51 // Constructor 52 InlineKlass(const ClassFileParser& parser); 53 54 void init_fixed_block(); 55 inline InlineKlassFixedBlock* inlineklass_static_block() const; 56 inline address adr_return_regs() const; 57 58 address adr_extended_sig() const { 59 assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized"); 60 return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _extended_sig)); 61 } 62 63 // pack and unpack handlers for inline types return 64 address adr_pack_handler() const { 65 assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized"); 66 return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _pack_handler)); 67 } 68 69 address adr_pack_handler_jobject() const { 70 assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized"); 71 return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _pack_handler_jobject)); 72 } 73 74 address adr_unpack_handler() const { 75 assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized"); 76 return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _unpack_handler)); 77 } 78 79 address adr_null_reset_value_offset() const { 80 assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized"); 81 return ((address)_adr_inlineklass_fixed_block) + in_bytes(null_reset_value_offset_offset()); 82 } 83 84 address adr_payload_offset() const { 85 assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized"); 86 return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _payload_offset)); 87 } 88 89 address adr_payload_size_in_bytes() const { 90 assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized"); 91 return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _payload_size_in_bytes)); 92 } 93 94 address adr_payload_alignment() const { 95 assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized"); 96 return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _payload_alignment)); 97 } 98 99 address adr_non_atomic_size_in_bytes() const { 100 assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized"); 101 return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _non_atomic_size_in_bytes)); 102 } 103 104 address adr_non_atomic_alignment() const { 105 assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized"); 106 return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _non_atomic_alignment)); 107 } 108 109 address adr_atomic_size_in_bytes() const { 110 assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized"); 111 return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _atomic_size_in_bytes)); 112 } 113 114 address adr_nullable_atomic_size_in_bytes() const { 115 assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized"); 116 return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _nullable_size_in_bytes)); 117 } 118 119 address adr_null_marker_offset() const { 120 assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized"); 121 return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _null_marker_offset)); 122 } 123 124 public: 125 126 bool is_empty_inline_type() const { return _misc_flags.is_empty_inline_type(); } 127 void set_is_empty_inline_type() { _misc_flags.set_is_empty_inline_type(true); } 128 129 int payload_offset() const { 130 int offset = *(int*)adr_payload_offset(); 131 assert(offset != 0, "Must be initialized before use"); 132 return offset; 133 } 134 135 void set_payload_offset(int offset) { *(int*)adr_payload_offset() = offset; } 136 137 int payload_size_in_bytes() const { return *(int*)adr_payload_size_in_bytes(); } 138 void set_payload_size_in_bytes(int payload_size) { *(int*)adr_payload_size_in_bytes() = payload_size; } 139 140 int payload_alignment() const { return *(int*)adr_payload_alignment(); } 141 void set_payload_alignment(int alignment) { *(int*)adr_payload_alignment() = alignment; } 142 143 bool has_non_atomic_layout() const { return non_atomic_size_in_bytes() != -1; } 144 int non_atomic_size_in_bytes() const { return *(int*)adr_non_atomic_size_in_bytes(); } 145 void set_non_atomic_size_in_bytes(int size) { *(int*)adr_non_atomic_size_in_bytes() = size; } 146 int non_atomic_alignment() const { return *(int*)adr_non_atomic_alignment(); } 147 void set_non_atomic_alignment(int alignment) { *(int*)adr_non_atomic_alignment() = alignment; } 148 149 bool has_atomic_layout() const { return atomic_size_in_bytes() != -1; } 150 int atomic_size_in_bytes() const { return *(int*)adr_atomic_size_in_bytes(); } 151 void set_atomic_size_in_bytes(int size) { *(int*)adr_atomic_size_in_bytes() = size; } 152 153 bool has_nullable_atomic_layout() const { return nullable_atomic_size_in_bytes() != -1; } 154 int nullable_atomic_size_in_bytes() const { return *(int*)adr_nullable_atomic_size_in_bytes(); } 155 void set_nullable_size_in_bytes(int size) { *(int*)adr_nullable_atomic_size_in_bytes() = size; } 156 int null_marker_offset() const { return *(int*)adr_null_marker_offset(); } 157 int null_marker_offset_in_payload() const { return null_marker_offset() - payload_offset(); } 158 void set_null_marker_offset(int offset) { *(int*)adr_null_marker_offset() = offset; } 159 160 bool is_payload_marked_as_null(address payload) { 161 assert(has_nullable_atomic_layout(), " Must have"); 162 return *((jbyte*)payload + null_marker_offset_in_payload()) == 0; 163 } 164 165 void mark_payload_as_non_null(address payload) { 166 assert(has_nullable_atomic_layout(), " Must have"); 167 *((jbyte*)payload + null_marker_offset_in_payload()) = 1; 168 } 169 170 void mark_payload_as_null(address payload) { 171 assert(has_nullable_atomic_layout(), " Must have"); 172 *((jbyte*)payload + null_marker_offset_in_payload()) = 0; 173 } 174 175 bool is_layout_supported(LayoutKind lk); 176 177 int layout_alignment(LayoutKind kind) const; 178 int layout_size_in_bytes(LayoutKind kind) const; 179 180 #if INCLUDE_CDS 181 virtual void remove_unshareable_info(); 182 virtual void remove_java_mirror(); 183 virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, PackageEntry* pkg_entry, TRAPS); 184 virtual void metaspace_pointers_do(MetaspaceClosure* it); 185 #endif 186 187 private: 188 int collect_fields(GrowableArray<SigEntry>* sig, int base_off = 0, int null_marker_offset = -1); 189 190 void cleanup_blobs(); 191 192 public: 193 // Type testing 194 bool is_inline_klass_slow() const { return true; } 195 196 // Casting from Klass* 197 198 static InlineKlass* cast(Klass* k) { 199 return const_cast<InlineKlass*>(cast(const_cast<const Klass*>(k))); 200 } 201 202 static const InlineKlass* cast(const Klass* k) { 203 assert(k != nullptr, "k should not be null"); 204 assert(k->is_inline_klass(), "cast to InlineKlass"); 205 return static_cast<const InlineKlass*>(k); 206 } 207 208 // Use this to return the size of an instance in heap words. 209 // Note that this size only applies to heap allocated stand-alone instances. 210 virtual int size_helper() const { 211 return layout_helper_to_size_helper(layout_helper()); 212 } 213 214 // allocate_instance() allocates a stand alone value in the Java heap 215 // initialized to default value (cleared memory) 216 instanceOop allocate_instance(TRAPS); 217 // allocates a stand alone inline buffer in the Java heap 218 // DOES NOT have memory cleared, user MUST initialize payload before 219 // returning to Java (i.e.: inline_copy) 220 instanceOop allocate_instance_buffer(TRAPS); 221 222 address payload_addr(oop o) const; 223 224 bool maybe_flat_in_array(); 225 226 bool contains_oops() const { return nonstatic_oop_map_count() > 0; } 227 int nonstatic_oop_count(); 228 229 // Methods to copy payload between containers 230 // Methods taking a LayoutKind argument expect that both the source and the destination 231 // layouts are compatible with the one specified in argument (alignment, size, presence 232 // of a null marker). Reminder: the BUFFERED layout, used in values buffered in heap, 233 // is compatible with all the other layouts. 234 235 void write_value_to_addr(oop src, void* dst, LayoutKind lk, bool dest_is_initialized, TRAPS); 236 oop read_payload_from_addr(const oop src, int offset, LayoutKind lk, TRAPS); 237 void copy_payload_to_addr(void* src, void* dst, LayoutKind lk, bool dest_is_initialized); 238 239 // oop iterate raw inline type data pointer (where oop_addr may not be an oop, but backing/array-element) 240 template <typename T, class OopClosureType> 241 inline void oop_iterate_specialized(const address oop_addr, OopClosureType* closure); 242 243 template <typename T, class OopClosureType> 244 inline void oop_iterate_specialized_bounded(const address oop_addr, OopClosureType* closure, void* lo, void* hi); 245 246 // calling convention support 247 void initialize_calling_convention(TRAPS); 248 Array<SigEntry>* extended_sig() const { 249 return *((Array<SigEntry>**)adr_extended_sig()); 250 } 251 inline Array<VMRegPair>* return_regs() const; 252 bool can_be_passed_as_fields() const; 253 bool can_be_returned_as_fields(bool init = false) const; 254 void save_oop_fields(const RegisterMap& map, GrowableArray<Handle>& handles) const; 255 void restore_oop_results(RegisterMap& map, GrowableArray<Handle>& handles) const; 256 oop realloc_result(const RegisterMap& reg_map, const GrowableArray<Handle>& handles, TRAPS); 257 static InlineKlass* returned_inline_klass(const RegisterMap& reg_map, bool* return_oop = nullptr, Method* method = nullptr); 258 259 address pack_handler() const { 260 return *(address*)adr_pack_handler(); 261 } 262 263 address unpack_handler() const { 264 return *(address*)adr_unpack_handler(); 265 } 266 267 // pack and unpack handlers. Need to be loadable from generated code 268 // so at a fixed offset from the base of the klass pointer. 269 static ByteSize pack_handler_offset() { 270 return byte_offset_of(InlineKlassFixedBlock, _pack_handler); 271 } 272 273 static ByteSize pack_handler_jobject_offset() { 274 return byte_offset_of(InlineKlassFixedBlock, _pack_handler_jobject); 275 } 276 277 static ByteSize unpack_handler_offset() { 278 return byte_offset_of(InlineKlassFixedBlock, _unpack_handler); 279 } 280 281 static ByteSize null_reset_value_offset_offset() { 282 return byte_offset_of(InlineKlassFixedBlock, _null_reset_value_offset); 283 } 284 285 static ByteSize payload_offset_offset() { 286 return byte_offset_of(InlineKlassFixedBlock, _payload_offset); 287 } 288 289 static ByteSize null_marker_offset_offset() { 290 return byte_offset_of(InlineKlassFixedBlock, _null_marker_offset); 291 } 292 293 void set_null_reset_value_offset(int offset) { 294 *((int*)adr_null_reset_value_offset()) = offset; 295 } 296 297 int null_reset_value_offset() { 298 int offset = *((int*)adr_null_reset_value_offset()); 299 assert(offset != 0, "must not be called if not initialized"); 300 return offset; 301 } 302 303 void set_null_reset_value(oop val); 304 305 oop null_reset_value() { 306 assert(is_initialized() || is_being_initialized() || is_in_error_state(), "null reset value is set at the beginning of initialization"); 307 oop val = java_mirror()->obj_field_acquire(null_reset_value_offset()); 308 assert(val != nullptr, "Sanity check"); 309 return val; 310 } 311 312 void deallocate_contents(ClassLoaderData* loader_data); 313 static void cleanup(InlineKlass* ik) ; 314 315 // Verification 316 void verify_on(outputStream* st); 317 void oop_verify_on(oop obj, outputStream* st); 318 319 }; 320 321 #endif /* SHARE_VM_OOPS_INLINEKLASS_HPP */