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