1 /*
  2  * Copyright (c) 2017, 2026, 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/inlineOop.hpp"
 29 #include "oops/instanceKlass.hpp"
 30 #include "oops/layoutKind.hpp"
 31 #include "oops/oopsHierarchy.hpp"
 32 #include "oops/valuePayload.hpp"
 33 #include "runtime/handles.hpp"
 34 #include "utilities/exceptions.hpp"
 35 #include "utilities/globalDefinitions.hpp"
 36 
 37 template <typename T>
 38 class Array;
 39 class ClassFileParser;
 40 template <typename T>
 41 class GrowableArray;
 42 class Method;
 43 class RegisterMap;
 44 class SigEntry;
 45 
 46 // An InlineKlass is a specialized InstanceKlass for concrete value classes
 47 // (abstract value classes are represented by InstanceKlass)
 48 
 49 class InlineKlass: public InstanceKlass {
 50   friend class VMStructs;
 51   friend class InstanceKlass;
 52 
 53  public:
 54   static const KlassKind Kind = InlineKlassKind;
 55 
 56   // The member fields of the InlineKlass.
 57   //
 58   // All Klass objects have vtables starting at offset `sizeof(InstanceKlass)`.
 59   //
 60   // This has the effect that sub-klasses of InstanceKlass can't have their own
 61   // C++ fields, because those would overlap with the vtables (or some of the
 62   // other dynamically-sized sections).
 63   //
 64   // To work around this we stamp out the block members *after* all
 65   // dynamically-sized sections belonging to the InstanceKlass part of the
 66   // object.
 67   //
 68   // InlineKlass object layout:
 69   //   +-----------------------+
 70   //   | sizeof(InstanceKlass) |
 71   //   +-----------------------+ <= InstanceKlass:header_size()
 72   //   | vtable                |
 73   //   +-----------------------+
 74   //   | other sections        |
 75   //   +-----------------------+ <= end_of_instance_klass()
 76   //   | InlineKlass::Members  |
 77   //   +-----------------------+
 78   //
 79   class Members {
 80     friend class InlineKlass;
 81 
 82     // Addresses used for inline type calling convention
 83     Array<SigEntry>* _extended_sig;
 84     Array<VMRegPair>* _return_regs;
 85 
 86     address _pack_handler;
 87     address _pack_handler_jobject;
 88     address _unpack_handler;
 89 
 90     int _null_reset_value_offset;
 91     int _payload_offset;           // offset of the beginning of the payload in a heap buffered instance
 92     int _payload_size_in_bytes;    // size of payload layout
 93     int _payload_alignment;        // alignment required for payload
 94     int _null_free_non_atomic_size_in_bytes; // size of null-free non-atomic flat layout
 95     int _null_free_non_atomic_alignment;     // alignment requirement for null-free non-atomic layout
 96     int _null_free_atomic_size_in_bytes;     // size and alignment requirement for a null-free atomic layout, -1 if no atomic flat layout is possible
 97     int _nullable_atomic_size_in_bytes;      // size and alignment requirement for a nullable layout (always atomic), -1 if no nullable flat layout is possible
 98     int _nullable_non_atomic_size_in_bytes;  // size and alignment requirement for a nullable non-atomic layout, -1 if not available
 99     int _null_marker_offset;       // expressed as an offset from the beginning of the object for a heap buffered value
100                                    // payload_offset must be subtracted to get the offset from the beginning of the payload
101 
102     // When we can't intrinsify the substitutability check, we can still avoid the call to isSubstitutable at runtime if the
103     // value object is small enough.  If all the fields are contained at once in a single long, we can load such a long from
104     // both operands, use a bitwise mask to remove the extra bits (from header, padding...), and compare these masked long.
105     //
106     // This doesn't always apply, for instance, if there are oops among the fields, we shouldn't carelessly load and compare:
107     // the GC might move the object in between.
108     // To signal this fast path cannot be done on this current class, simply put 0 in _fast_acmp_mask.
109     //
110     // We also should take care of not loading further than the object, even if it means reading part of the header.
111     // For this reason, we can't use _payload_offset, but we need our special offset.
112     // The offset doesn't need to be aligned on word boundary, or anything else.
113     //
114     int _fast_acmp_offset;    // if < 0, fast acmp doesn't apply
115     int64_t _fast_acmp_mask;  // can be 0 for empty value classes
116 
117     Members();
118 
119     void print_on(outputStream* st) const;
120   };
121 
122   InlineKlass();
123 
124  private:
125 
126   // Constructor
127   InlineKlass(const ClassFileParser& parser);
128 
129   // Calculates where the members are supposed to be placed
130   address calculate_members_address() const;
131 
132   Members& members() {
133     assert(_adr_inline_klass_members != nullptr, "Should have been initialized");
134     return *reinterpret_cast<Members*>(_adr_inline_klass_members);
135   }
136 
137   inline const Members& members() const {
138     InlineKlass* ik = const_cast<InlineKlass*>(this);
139     return const_cast<const Members&>(ik->members());
140   }
141 
142  public:
143 
144   bool is_empty_inline_type() const   { return _misc_flags.is_empty_inline_type(); }
145   void set_is_empty_inline_type()     { _misc_flags.set_is_empty_inline_type(true); }
146 
147   // Members access functions
148 
149   const Array<SigEntry>* extended_sig() const                 {return members()._extended_sig; }
150   void set_extended_sig(Array<SigEntry>* extended_sig)        { members()._extended_sig = extended_sig; }
151 
152   const Array<VMRegPair>* return_regs() const                 { return members()._return_regs; }
153   void set_return_regs(Array<VMRegPair>* return_regs)         { members()._return_regs = return_regs; }
154 
155   // pack and unpack handlers for inline types return
156 
157   address pack_handler() const                                { return members()._pack_handler; }
158   void set_pack_handler(address pack_handler)                 { members()._pack_handler = pack_handler; }
159 
160   address pack_handler_jobject() const                        { return members()._pack_handler_jobject; }
161   void set_pack_handler_jobject(address pack_handler_jobject) { members()._pack_handler_jobject = pack_handler_jobject; }
162 
163   address unpack_handler() const                              { return members()._unpack_handler; }
164   void set_unpack_handler(address unpack_handler)             { members()._unpack_handler = unpack_handler; }
165 
166   int null_reset_value_offset() const {
167     int offset = members()._null_reset_value_offset;
168     assert(offset != 0, "must not be called if not initialized");
169     return offset;
170   }
171   void set_null_reset_value_offset(int offset)                { members()._null_reset_value_offset = offset; }
172 
173   int payload_offset() const {
174     int offset = members()._payload_offset;
175     assert(offset != 0, "Must be initialized before use");
176     return offset;
177   }
178   void set_payload_offset(int offset)                         { members()._payload_offset = offset; }
179 
180   int payload_size_in_bytes() const                           { return members()._payload_size_in_bytes; }
181   void set_payload_size_in_bytes(int payload_size)            { members()._payload_size_in_bytes = payload_size; }
182 
183   int payload_alignment() const                               { return members()._payload_alignment; }
184   void set_payload_alignment(int alignment)                   { members()._payload_alignment = alignment; }
185 
186   int null_free_non_atomic_size_in_bytes() const              { return members()._null_free_non_atomic_size_in_bytes; }
187   void set_null_free_non_atomic_size_in_bytes(int size)       { members()._null_free_non_atomic_size_in_bytes = size; }
188   bool has_null_free_non_atomic_layout() const                { return null_free_non_atomic_size_in_bytes() != -1; }
189 
190   int null_free_non_atomic_alignment() const                  { return members()._null_free_non_atomic_alignment; }
191   void set_null_free_non_atomic_alignment(int alignment)      { members()._null_free_non_atomic_alignment = alignment; }
192 
193   int null_free_atomic_size_in_bytes() const                  { return members()._null_free_atomic_size_in_bytes; }
194   void set_null_free_atomic_size_in_bytes(int size)           { members()._null_free_atomic_size_in_bytes = size; }
195   bool has_null_free_atomic_layout() const                    { return null_free_atomic_size_in_bytes() != -1; }
196 
197   int nullable_atomic_size_in_bytes() const                   { return members()._nullable_atomic_size_in_bytes; }
198   void set_nullable_atomic_size_in_bytes(int size)            { members()._nullable_atomic_size_in_bytes = size; }
199   bool has_nullable_atomic_layout() const                     { return nullable_atomic_size_in_bytes() != -1; }
200 
201   int nullable_non_atomic_size_in_bytes() const               { return members()._nullable_non_atomic_size_in_bytes; }
202   void set_nullable_non_atomic_size_in_bytes(int size)        { members()._nullable_non_atomic_size_in_bytes = size; }
203   bool has_nullable_non_atomic_layout() const                 { return nullable_non_atomic_size_in_bytes() != -1; }
204 
205   int null_marker_offset() const                              { return members()._null_marker_offset; }
206   void set_null_marker_offset(int offset)                     { members()._null_marker_offset = offset; }
207   int null_marker_offset_in_payload() const                   { return null_marker_offset() - payload_offset(); }
208 
209   int fast_acmp_offset() const                                { return members()._fast_acmp_offset; }
210   void set_fast_acmp_offset(int offset)                       { members()._fast_acmp_offset = offset; }
211 
212   int64_t fast_acmp_mask() const                              { return members()._fast_acmp_mask; }
213   void set_fast_acmp_mask(int64_t mask)                       { members()._fast_acmp_mask = mask; }
214 
215   bool supports_nullable_layouts() const {
216     return has_nullable_non_atomic_layout() || has_nullable_atomic_layout();
217   }
218 
219   jbyte* null_marker_address(address payload) {
220     assert(supports_nullable_layouts(), " Must do");
221     return (jbyte*)payload + null_marker_offset_in_payload();
222   }
223 
224   bool is_payload_marked_as_null(address payload) {
225     assert(supports_nullable_layouts(), " Must do");
226     return *null_marker_address(payload) == 0;
227   }
228 
229   void mark_payload_as_non_null(address payload) {
230     assert(supports_nullable_layouts(), " Must do");
231     *null_marker_address(payload) = 1;
232   }
233 
234   void mark_payload_as_null(address payload) {
235     assert(supports_nullable_layouts(), " Must do");
236     *null_marker_address(payload) = 0;
237   }
238 
239   inline bool layout_has_null_marker(LayoutKind lk) const;
240 
241   inline bool is_layout_supported(LayoutKind lk) const;
242 
243   inline int layout_alignment(LayoutKind kind) const;
244   inline int layout_size_in_bytes(LayoutKind kind) const;
245 
246 #if INCLUDE_CDS
247   void remove_unshareable_info() override;
248 #endif
249 
250  private:
251   int collect_fields(GrowableArray<SigEntry>* sig, int base_off = 0, int null_marker_offset = -1);
252 
253   void cleanup_blobs();
254 
255  public:
256   // Type testing
257   bool is_inline_klass_slow() const override { return true; }
258 
259   // Casting from Klass*
260 
261   static InlineKlass* cast(Klass* k) {
262     return const_cast<InlineKlass*>(cast(const_cast<const Klass*>(k)));
263   }
264 
265   static const InlineKlass* cast(const Klass* k) {
266     assert(k != nullptr, "k should not be null");
267     assert(k->is_inline_klass(), "cast to InlineKlass");
268     return static_cast<const InlineKlass*>(k);
269   }
270 
271   // Allocates a stand alone value in the Java heap
272   // initialized to default value (cleared memory)
273   inlineOop allocate_instance(TRAPS);
274 
275   address payload_addr(oop o) const;
276 
277   bool maybe_flat_in_array();
278   bool is_always_flat_in_array();
279 
280   bool contains_oops() const { return nonstatic_oop_map_count() > 0; }
281   int nonstatic_oop_count();
282 
283   // oop iterate raw inline type data pointer (where oop_addr may not be an oop, but backing/array-element)
284   template <typename T, class OopClosureType>
285   inline void oop_iterate_specialized(const address oop_addr, OopClosureType* closure);
286 
287   template <typename T, class OopClosureType>
288   inline void oop_iterate_specialized_bounded(const address oop_addr, OopClosureType* closure, uintptr_t lo, uintptr_t hi);
289 
290   // Support for the scalarized calling convention
291   void initialize_calling_convention(TRAPS);
292 
293   bool can_be_passed_as_fields() const;
294   bool can_be_returned_as_fields(bool init = false) const;
295   void save_oop_fields(const RegisterMap& map, GrowableArray<Handle>& handles) const;
296   void restore_oop_results(RegisterMap& map, GrowableArray<Handle>& handles) const;
297   oop realloc_result(const RegisterMap& reg_map, const GrowableArray<Handle>& handles, TRAPS);
298   static InlineKlass* returned_inline_klass(const RegisterMap& reg_map, bool* return_oop = nullptr, Method* method = nullptr);
299 
300   static ByteSize adr_members_offset() {
301     return InstanceKlass::adr_inline_klass_members_offset();
302   }
303 
304   // pack and unpack handlers. Need to be loadable from generated code
305   // so at a fixed offset from the base of the klass pointer.
306   static ByteSize pack_handler_offset() {
307     return byte_offset_of(Members, _pack_handler);
308   }
309 
310   static ByteSize pack_handler_jobject_offset() {
311     return byte_offset_of(Members, _pack_handler_jobject);
312   }
313 
314   static ByteSize unpack_handler_offset() {
315     return byte_offset_of(Members, _unpack_handler);
316   }
317 
318   static ByteSize null_reset_value_offset_offset() {
319     return byte_offset_of(Members, _null_reset_value_offset);
320   }
321 
322   static ByteSize payload_offset_offset() {
323     return byte_offset_of(Members, _payload_offset);
324   }
325 
326   static ByteSize null_marker_offset_offset() {
327     return byte_offset_of(Members, _null_marker_offset);
328   }
329 
330   static ByteSize fast_acmp_offset_offset() {
331     return byte_offset_of(Members, _fast_acmp_offset);
332   }
333 
334   static ByteSize fast_acmp_mask_offset() {
335     return byte_offset_of(Members, _fast_acmp_mask);
336   }
337 
338   oop null_reset_value() const;
339   void set_null_reset_value(oop val);
340 
341   void deallocate_contents(ClassLoaderData* loader_data);
342   static void cleanup(InlineKlass* ik) ;
343 
344   void print_on(outputStream* st) const override;
345 
346   // Verification
347   void verify_on(outputStream* st) override;
348   void oop_verify_on(oop obj, outputStream* st) override;
349 };
350 
351 #endif // SHARE_VM_OOPS_INLINEKLASS_HPP