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