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 "oops/instanceKlass.hpp"
29 #include "oops/layoutKind.hpp"
30 #include "oops/oopsHierarchy.hpp"
31 #include "utilities/exceptions.hpp"
32 #include "utilities/globalDefinitions.hpp"
33
34 template <typename T>
35 class Array;
36 class ClassFileParser;
37 template <typename T>
38 class GrowableArray;
39 class Method;
40 class RegisterMap;
41 class SigEntry;
42
43 // An InlineKlass is a specialized InstanceKlass for concrete value classes
44 // (abstract value classes are represented by InstanceKlass)
45
46 class InlineKlass: public InstanceKlass {
47 friend class VMStructs;
48 friend class InstanceKlass;
49
50 public:
51 static const KlassKind Kind = InlineKlassKind;
52
53 // The member fields of the InlineKlass.
54 //
55 // All Klass objects have vtables starting at offset `sizeof(InstanceKlass)`.
56 //
57 // This has the effect that sub-klasses of InstanceKlass can't have their own
58 // C++ fields, because those would overlap with the vtables (or some of the
59 // other dynamically-sized sections).
60 //
61 // To work around this we stamp out the block members *after* all
62 // dynamically-sized sections belonging to the InstanceKlass part of the
63 // object.
64 //
65 // InlineKlass object layout:
66 // +-----------------------+
67 // | sizeof(InstanceKlass) |
68 // +-----------------------+ <= InstanceKlass:header_size()
69 // | vtable |
70 // +-----------------------+
71 // | other sections |
72 // +-----------------------+ <= end_of_instance_klass()
73 // | InlineKlass::Members |
74 // +-----------------------+
75 //
76 class Members {
77 friend class InlineKlass;
78
79 // Addresses used for inline type calling convention
80 Array<SigEntry>* _extended_sig;
81 Array<VMRegPair>* _return_regs;
82
83 address _pack_handler;
84 address _pack_handler_jobject;
85 address _unpack_handler;
86
87 int _null_reset_value_offset;
88 int _payload_offset; // offset of the beginning of the payload in a heap buffered instance
89 int _payload_size_in_bytes; // size of payload layout
90 int _payload_alignment; // alignment required for payload
91 int _non_atomic_size_in_bytes; // size of null-free non-atomic flat layout
92 int _non_atomic_alignment; // alignment requirement for null-free non-atomic layout
93 int _atomic_size_in_bytes; // size and alignment requirement for a null-free atomic layout, -1 if no atomic flat layout is possible
94 int _nullable_size_in_bytes; // size and alignment requirement for a nullable layout (always atomic), -1 if no nullable flat layout is possible
95 int _null_marker_offset; // expressed as an offset from the beginning of the object for a heap buffered value
96 // payload_offset must be subtracted to get the offset from the beginning of the payload
97
98 Members();
99 };
100
101 InlineKlass();
102
103 private:
104
105 // Constructor
106 InlineKlass(const ClassFileParser& parser);
107
108 // Calculates where the members are supposed to be placed
109 address calculate_members_address() const;
110
111 Members& members() {
112 assert(_adr_inline_klass_members != nullptr, "Should have been initialized");
113 return *reinterpret_cast<Members*>(_adr_inline_klass_members);
114 }
115
116 inline const Members& members() const {
117 InlineKlass* ik = const_cast<InlineKlass*>(this);
118 return const_cast<const Members&>(ik->members());
119 }
120
121 public:
122
123 bool is_empty_inline_type() const { return _misc_flags.is_empty_inline_type(); }
124 void set_is_empty_inline_type() { _misc_flags.set_is_empty_inline_type(true); }
125
126 // Members access functions
127
128 const Array<SigEntry>* extended_sig() const {return members()._extended_sig; }
129 void set_extended_sig(Array<SigEntry>* extended_sig) { members()._extended_sig = extended_sig; }
130
131 const Array<VMRegPair>* return_regs() const { return members()._return_regs; }
132 void set_return_regs(Array<VMRegPair>* return_regs) { members()._return_regs = return_regs; }
133
134 // pack and unpack handlers for inline types return
135
136 address pack_handler() const { return members()._pack_handler; }
137 void set_pack_handler(address pack_handler) { members()._pack_handler = pack_handler; }
138
139 address pack_handler_jobject() const { return members()._pack_handler_jobject; }
140 void set_pack_handler_jobject(address pack_handler_jobject) { members()._pack_handler_jobject = pack_handler_jobject; }
141
142 address unpack_handler() const { return members()._unpack_handler; }
143 void set_unpack_handler(address unpack_handler) { members()._unpack_handler = unpack_handler; }
144
145 int null_reset_value_offset() {
146 int offset = members()._null_reset_value_offset;
147 assert(offset != 0, "must not be called if not initialized");
148 return offset;
149 }
150 void set_null_reset_value_offset(int offset) { members()._null_reset_value_offset = offset; }
151
152 int payload_offset() const {
153 int offset = members()._payload_offset;
154 assert(offset != 0, "Must be initialized before use");
155 return offset;
156 }
157 void set_payload_offset(int offset) { members()._payload_offset = offset; }
158
159 int payload_size_in_bytes() const { return members()._payload_size_in_bytes; }
160 void set_payload_size_in_bytes(int payload_size) { members()._payload_size_in_bytes = payload_size; }
161
162 int payload_alignment() const { return members()._payload_alignment; }
163 void set_payload_alignment(int alignment) { members()._payload_alignment = alignment; }
164
165 int non_atomic_size_in_bytes() const { return members()._non_atomic_size_in_bytes; }
166 void set_non_atomic_size_in_bytes(int size) { members()._non_atomic_size_in_bytes = size; }
167 bool has_non_atomic_layout() const { return non_atomic_size_in_bytes() != -1; }
168
169 int non_atomic_alignment() const { return members()._non_atomic_alignment; }
170 void set_non_atomic_alignment(int alignment) { members()._non_atomic_alignment = alignment; }
171
172 int atomic_size_in_bytes() const { return members()._atomic_size_in_bytes; }
173 void set_atomic_size_in_bytes(int size) { members()._atomic_size_in_bytes = size; }
174 bool has_atomic_layout() const { return atomic_size_in_bytes() != -1; }
175
176 // FIXME: These names are not consistent w.r.t the atomic part.
177 int nullable_atomic_size_in_bytes() const { return members()._nullable_size_in_bytes; }
178 void set_nullable_size_in_bytes(int size) { members()._nullable_size_in_bytes = size; }
179 bool has_nullable_atomic_layout() const { return nullable_atomic_size_in_bytes() != -1; }
180
181 int null_marker_offset() const { return members()._null_marker_offset; }
182 void set_null_marker_offset(int offset) { members()._null_marker_offset = offset; }
183 int null_marker_offset_in_payload() const { return null_marker_offset() - payload_offset(); }
184
185 jbyte* null_marker_address(address payload) {
186 assert(has_nullable_atomic_layout(), " Must have");
187 return (jbyte*)payload + null_marker_offset_in_payload();
188 }
189
190 bool is_payload_marked_as_null(address payload) {
191 return *null_marker_address(payload) == 0;
192 }
193
194 void mark_payload_as_non_null(address payload) {
195 *null_marker_address(payload) = 1;
196 }
197
198 void mark_payload_as_null(address payload) {
199 *null_marker_address(payload) = 0;
200 }
201
202 bool is_layout_supported(LayoutKind lk);
203
204 int layout_alignment(LayoutKind kind) const;
205 int layout_size_in_bytes(LayoutKind kind) const;
206
207 #if INCLUDE_CDS
208 void remove_unshareable_info() override;
209 #endif
210
211 private:
212 int collect_fields(GrowableArray<SigEntry>* sig, int base_off = 0, int null_marker_offset = -1);
213
214 void cleanup_blobs();
215
216 public:
217 // Type testing
218 bool is_inline_klass_slow() const override { return true; }
219
220 // Casting from Klass*
221
222 static InlineKlass* cast(Klass* k) {
223 return const_cast<InlineKlass*>(cast(const_cast<const Klass*>(k)));
224 }
225
226 static const InlineKlass* cast(const Klass* k) {
227 assert(k != nullptr, "k should not be null");
228 assert(k->is_inline_klass(), "cast to InlineKlass");
229 return static_cast<const InlineKlass*>(k);
230 }
231
232 // Allocates a stand alone value in the Java heap
233 // initialized to default value (cleared memory)
234 instanceOop allocate_instance(TRAPS);
235
236 address payload_addr(oop o) const;
237
238 bool maybe_flat_in_array();
239 bool is_always_flat_in_array();
240
241 bool contains_oops() const { return nonstatic_oop_map_count() > 0; }
242 int nonstatic_oop_count();
243
244 // Methods to copy payload between containers
245 //
246 // Methods taking a LayoutKind argument expect that both the source and the destination
247 // layouts are compatible with the one specified in argument (alignment, size, presence
248 // of a null marker). Reminder: the BUFFERED layout, used in values buffered in heap,
249 // is compatible with all the other layouts.
250
251 void write_value_to_addr(oop src, void* dst, LayoutKind lk, TRAPS);
252 oop read_payload_from_addr(const oop src, size_t offset, LayoutKind lk, TRAPS);
253 void copy_payload_to_addr(void* src, void* dst, LayoutKind lk, bool dest_is_initialized);
254
255 // oop iterate raw inline type data pointer (where oop_addr may not be an oop, but backing/array-element)
256 template <typename T, class OopClosureType>
257 inline void oop_iterate_specialized(const address oop_addr, OopClosureType* closure);
258
259 template <typename T, class OopClosureType>
260 inline void oop_iterate_specialized_bounded(const address oop_addr, OopClosureType* closure, void* lo, void* hi);
261
262 // calling convention support
263 void initialize_calling_convention(TRAPS);
264
265 bool can_be_passed_as_fields() const;
266 bool can_be_returned_as_fields(bool init = false) const;
267 void save_oop_fields(const RegisterMap& map, GrowableArray<Handle>& handles) const;
268 void restore_oop_results(RegisterMap& map, GrowableArray<Handle>& handles) const;
269 oop realloc_result(const RegisterMap& reg_map, const GrowableArray<Handle>& handles, TRAPS);
270 static InlineKlass* returned_inline_klass(const RegisterMap& reg_map, bool* return_oop = nullptr, Method* method = nullptr);
271
272 static ByteSize adr_members_offset() {
273 return InstanceKlass::adr_inline_klass_members_offset();
274 }
275
276 // pack and unpack handlers. Need to be loadable from generated code
277 // so at a fixed offset from the base of the klass pointer.
278 static ByteSize pack_handler_offset() {
279 return byte_offset_of(Members, _pack_handler);
280 }
281
282 static ByteSize pack_handler_jobject_offset() {
283 return byte_offset_of(Members, _pack_handler_jobject);
284 }
285
286 static ByteSize unpack_handler_offset() {
287 return byte_offset_of(Members, _unpack_handler);
288 }
289
290 static ByteSize null_reset_value_offset_offset() {
291 return byte_offset_of(Members, _null_reset_value_offset);
292 }
293
294 static ByteSize payload_offset_offset() {
295 return byte_offset_of(Members, _payload_offset);
296 }
297
298 static ByteSize null_marker_offset_offset() {
299 return byte_offset_of(Members, _null_marker_offset);
300 }
301
302 oop null_reset_value();
303 void set_null_reset_value(oop val);
304
305 void deallocate_contents(ClassLoaderData* loader_data);
306 static void cleanup(InlineKlass* ik) ;
307
308 // Verification
309 void verify_on(outputStream* st) override;
310 void oop_verify_on(oop obj, outputStream* st) override;
311
312 };
313
314 #endif // SHARE_VM_OOPS_INLINEKLASS_HPP