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_null_reset_value_offset() const {
 79     assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized");
 80     return ((address)_adr_inlineklass_fixed_block) + in_bytes(null_reset_value_offset_offset());
 81   }
 82 
 83   FlatArrayKlass* volatile* adr_non_atomic_flat_array_klass() const {
 84     assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized");
 85     return (FlatArrayKlass* volatile*) ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _non_atomic_flat_array_klass));
 86   }
 87 
 88   FlatArrayKlass* non_atomic_flat_array_klass() const {
 89     return *adr_non_atomic_flat_array_klass();
 90   }
 91 
 92   FlatArrayKlass* volatile* adr_atomic_flat_array_klass() const {
 93     assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized");
 94     return (FlatArrayKlass* volatile*) ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _atomic_flat_array_klass));
 95   }
 96 
 97   FlatArrayKlass* atomic_flat_array_klass() const {
 98     return *adr_atomic_flat_array_klass();
 99   }
100 
101   FlatArrayKlass* volatile* adr_nullable_atomic_flat_array_klass() const {
102     assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized");
103     return (FlatArrayKlass* volatile*) ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _nullable_atomic_flat_array_klass));
104   }
105 
106   FlatArrayKlass* nullable_atomic_flat_array_klass() const {
107     return *adr_nullable_atomic_flat_array_klass();
108   }
109 
110   ObjArrayKlass* volatile* adr_null_free_reference_array_klass() const {
111     assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized");
112     return (ObjArrayKlass* volatile*) ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _null_free_reference_array_klass));
113   }
114 
115   ObjArrayKlass* null_free_reference_array_klass() const {
116     return *adr_null_free_reference_array_klass();
117   }
118 
119   address adr_payload_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, _payload_offset));
122   }
123 
124   address adr_payload_size_in_bytes() 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, _payload_size_in_bytes));
127   }
128 
129   address adr_payload_alignment() 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_alignment));
132   }
133 
134   address adr_non_atomic_size_in_bytes() 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, _non_atomic_size_in_bytes));
137   }
138 
139   address adr_non_atomic_alignment() 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_alignment));
142   }
143 
144   address adr_atomic_size_in_bytes() 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, _atomic_size_in_bytes));
147   }
148 
149   address adr_nullable_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, _nullable_size_in_bytes));
152   }
153 
154   address adr_null_marker_offset() 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, _null_marker_offset));
157   }
158 
159  public:
160 
161   bool is_empty_inline_type() const   { return _misc_flags.is_empty_inline_type(); }
162   void set_is_empty_inline_type()     { _misc_flags.set_is_empty_inline_type(true); }
163 
164   int payload_offset() const {
165     int offset = *(int*)adr_payload_offset();
166     assert(offset != 0, "Must be initialized before use");
167     return *(int*)adr_payload_offset();
168   }
169 
170   void set_payload_offset(int offset) { *(int*)adr_payload_offset() = offset; }
171 
172   int payload_size_in_bytes() const { return *(int*)adr_payload_size_in_bytes(); }
173   void set_payload_size_in_bytes(int payload_size) { *(int*)adr_payload_size_in_bytes() = payload_size; }
174 
175   int payload_alignment() const { return *(int*)adr_payload_alignment(); }
176   void set_payload_alignment(int alignment) { *(int*)adr_payload_alignment() = alignment; }
177 
178   bool has_non_atomic_layout() const { return non_atomic_size_in_bytes() != -1; }
179   int non_atomic_size_in_bytes() const { return *(int*)adr_non_atomic_size_in_bytes(); }
180   void set_non_atomic_size_in_bytes(int size) { *(int*)adr_non_atomic_size_in_bytes() = size; }
181   int non_atomic_alignment() const { return *(int*)adr_non_atomic_alignment(); }
182   void set_non_atomic_alignment(int alignment) { *(int*)adr_non_atomic_alignment() = alignment; }
183 
184   bool has_atomic_layout() const { return atomic_size_in_bytes() != -1; }
185   int atomic_size_in_bytes() const { return *(int*)adr_atomic_size_in_bytes(); }
186   void set_atomic_size_in_bytes(int size) { *(int*)adr_atomic_size_in_bytes() = size; }
187 
188   bool has_nullable_atomic_layout() const { return nullable_atomic_size_in_bytes() != -1; }
189   int nullable_atomic_size_in_bytes() const { return *(int*)adr_nullable_atomic_size_in_bytes(); }
190   void set_nullable_size_in_bytes(int size) { *(int*)adr_nullable_atomic_size_in_bytes() = size; }
191   int null_marker_offset() const { return *(int*)adr_null_marker_offset(); }
192   int null_marker_offset_in_payload() const { return null_marker_offset() - payload_offset(); }
193   void set_null_marker_offset(int offset) { *(int*)adr_null_marker_offset() = offset; }
194 
195   bool is_payload_marked_as_null(address payload) {
196     assert(has_nullable_atomic_layout(), " Must have");
197     return *((jbyte*)payload + null_marker_offset_in_payload()) == 0;
198   }
199 
200   void mark_payload_as_non_null(address payload) {
201     assert(has_nullable_atomic_layout(), " Must have");
202     *((jbyte*)payload + null_marker_offset_in_payload()) = 1;
203   }
204 
205   void mark_payload_as_null(address payload) {
206     assert(has_nullable_atomic_layout(), " Must have");
207     *((jbyte*)payload + null_marker_offset_in_payload()) = 0;
208   }
209 
210   bool is_layout_supported(LayoutKind lk);
211 
212   int layout_alignment(LayoutKind kind) const;
213   int layout_size_in_bytes(LayoutKind kind) const;
214 
215   virtual void remove_unshareable_info();
216   virtual void remove_java_mirror();
217   virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, PackageEntry* pkg_entry, TRAPS);
218   virtual void metaspace_pointers_do(MetaspaceClosure* it);
219 
220  private:
221   int collect_fields(GrowableArray<SigEntry>* sig, float& max_offset, int base_off = 0, int null_marker_offset = -1);
222 
223   void cleanup_blobs();
224 
225  public:
226   // Type testing
227   bool is_inline_klass_slow() const        { return true; }
228 
229   // Casting from Klass*
230 
231   static InlineKlass* cast(Klass* k) {
232     return const_cast<InlineKlass*>(cast(const_cast<const Klass*>(k)));
233   }
234 
235   static const InlineKlass* cast(const Klass* k) {
236     assert(k != nullptr, "k should not be null");
237     assert(k->is_inline_klass(), "cast to InlineKlass");
238     return static_cast<const InlineKlass*>(k);
239   }
240 
241   // Use this to return the size of an instance in heap words.
242   // Note that this size only applies to heap allocated stand-alone instances.
243   virtual int size_helper() const {
244     return layout_helper_to_size_helper(layout_helper());
245   }
246 
247   // allocate_instance() allocates a stand alone value in the Java heap
248   // initialized to default value (cleared memory)
249   instanceOop allocate_instance(TRAPS);
250   // allocates a stand alone inline buffer in the Java heap
251   // DOES NOT have memory cleared, user MUST initialize payload before
252   // returning to Java (i.e.: inline_copy)
253   instanceOop allocate_instance_buffer(TRAPS);
254 
255   address payload_addr(oop o) const;
256 
257   bool flat_array();
258 
259   bool contains_oops() const { return nonstatic_oop_map_count() > 0; }
260   int nonstatic_oop_count();
261 
262   // null free inline arrays...
263   //
264 
265   FlatArrayKlass* flat_array_klass(LayoutKind lk, TRAPS);
266   FlatArrayKlass* flat_array_klass_or_null(LayoutKind lk);
267   ObjArrayKlass* null_free_reference_array(TRAPS);
268 
269   // Methods to copy payload between containers
270   // Methods taking a LayoutKind argument expect that both the source and the destination
271   // layouts are compatible with the one specified in argument (alignment, size, presence
272   // of a null marker). Reminder: the BUFFERED layout, used in values buffered in heap,
273   // is compatible with all the other layouts.
274 
275   void write_value_to_addr(oop src, void* dst, LayoutKind lk, bool dest_is_initialized, TRAPS);
276   oop read_payload_from_addr(oop src, int offset, LayoutKind lk, TRAPS);
277   void copy_payload_to_addr(void* src, void* dst, LayoutKind lk, bool dest_is_initialized);
278 
279   // oop iterate raw inline type data pointer (where oop_addr may not be an oop, but backing/array-element)
280   template <typename T, class OopClosureType>
281   inline void oop_iterate_specialized(const address oop_addr, OopClosureType* closure);
282 
283   template <typename T, class OopClosureType>
284   inline void oop_iterate_specialized_bounded(const address oop_addr, OopClosureType* closure, void* lo, void* hi);
285 
286   // calling convention support
287   void initialize_calling_convention(TRAPS);
288   Array<SigEntry>* extended_sig() const {
289     return *((Array<SigEntry>**)adr_extended_sig());
290   }
291   inline Array<VMRegPair>* return_regs() const;
292   bool can_be_passed_as_fields() const;
293   bool can_be_returned_as_fields(bool init = false) const;
294   void save_oop_fields(const RegisterMap& map, GrowableArray<Handle>& handles) const;
295   void restore_oop_results(RegisterMap& map, GrowableArray<Handle>& handles) const;
296   oop realloc_result(const RegisterMap& reg_map, const GrowableArray<Handle>& handles, TRAPS);
297   static InlineKlass* returned_inline_klass(const RegisterMap& reg_map);
298 
299   address pack_handler() const {
300     return *(address*)adr_pack_handler();
301   }
302 
303   address unpack_handler() const {
304     return *(address*)adr_unpack_handler();
305   }
306 
307   // pack and unpack handlers. Need to be loadable from generated code
308   // so at a fixed offset from the base of the klass pointer.
309   static ByteSize pack_handler_offset() {
310     return byte_offset_of(InlineKlassFixedBlock, _pack_handler);
311   }
312 
313   static ByteSize pack_handler_jobject_offset() {
314     return byte_offset_of(InlineKlassFixedBlock, _pack_handler_jobject);
315   }
316 
317   static ByteSize unpack_handler_offset() {
318     return byte_offset_of(InlineKlassFixedBlock, _unpack_handler);
319   }
320 
321   static ByteSize null_reset_value_offset_offset() {
322     return byte_offset_of(InlineKlassFixedBlock, _null_reset_value_offset);
323   }
324 
325   static ByteSize payload_offset_offset() {
326     return byte_offset_of(InlineKlassFixedBlock, _payload_offset);
327   }
328 
329   static ByteSize null_marker_offset_offset() {
330     return byte_offset_of(InlineKlassFixedBlock, _null_marker_offset);
331   }
332 
333   void set_null_reset_value_offset(int offset) {
334     *((int*)adr_null_reset_value_offset()) = offset;
335   }
336 
337   int null_reset_value_offset() {
338     int offset = *((int*)adr_null_reset_value_offset());
339     assert(offset != 0, "must not be called if not initialized");
340     return offset;
341   }
342 
343   void set_null_reset_value(oop val);
344 
345   oop null_reset_value() {
346     assert(is_initialized() || is_being_initialized() || is_in_error_state(), "null reset value is set at the beginning of initialization");
347     oop val = java_mirror()->obj_field_acquire(null_reset_value_offset());
348     assert(val != nullptr, "Sanity check");
349     return val;
350   }
351 
352   void deallocate_contents(ClassLoaderData* loader_data);
353   static void cleanup(InlineKlass* ik) ;
354 
355   // Verification
356   void verify_on(outputStream* st);
357   void oop_verify_on(oop obj, outputStream* st);
358 
359 };
360 
361 #endif /* SHARE_VM_OOPS_INLINEKLASS_HPP */