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