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 */