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/arrayKlass.hpp"
 31 #include "oops/instanceKlass.hpp"
 32 #include "oops/method.hpp"
 33 #include "runtime/registerMap.hpp"
 34 
 35 // An InlineKlass is a specialized InstanceKlass for concrete value classes
 36 // (abstract value classes are represented by InstanceKlass)
 37 
 38 
 39 class InlineKlass: public InstanceKlass {
 40   friend class VMStructs;
 41   friend class InstanceKlass;
 42   friend class ClassFileParser;
 43 
 44  public:
 45   static const KlassKind Kind = InlineKlassKind;
 46 
 47   InlineKlass();
 48 
 49  private:
 50 
 51   // Constructor
 52   InlineKlass(const ClassFileParser& parser);
 53 
 54   void init_fixed_block();
 55   inline InlineKlassFixedBlock* inlineklass_static_block() const;
 56   inline address adr_return_regs() const;
 57 
 58   address adr_extended_sig() const {
 59     assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized");
 60     return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _extended_sig));
 61   }
 62 
 63   // pack and unpack handlers for inline types return
 64   address adr_pack_handler() const {
 65     assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized");
 66     return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _pack_handler));
 67   }
 68 
 69   address adr_pack_handler_jobject() const {
 70     assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized");
 71     return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _pack_handler_jobject));
 72   }
 73 
 74   address adr_unpack_handler() const {
 75     assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized");
 76     return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _unpack_handler));
 77   }
 78 
 79   address adr_null_reset_value_offset() const {
 80     assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized");
 81     return ((address)_adr_inlineklass_fixed_block) + in_bytes(null_reset_value_offset_offset());
 82   }
 83 
 84   address adr_payload_offset() const {
 85     assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized");
 86     return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _payload_offset));
 87   }
 88 
 89   address adr_payload_size_in_bytes() const {
 90     assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized");
 91     return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _payload_size_in_bytes));
 92   }
 93 
 94   address adr_payload_alignment() const {
 95     assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized");
 96     return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _payload_alignment));
 97   }
 98 
 99   address adr_non_atomic_size_in_bytes() const {
100     assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized");
101     return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _non_atomic_size_in_bytes));
102   }
103 
104   address adr_non_atomic_alignment() const {
105     assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized");
106     return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _non_atomic_alignment));
107   }
108 
109   address adr_atomic_size_in_bytes() const {
110     assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized");
111     return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _atomic_size_in_bytes));
112   }
113 
114   address adr_nullable_atomic_size_in_bytes() const {
115     assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized");
116     return ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _nullable_size_in_bytes));
117   }
118 
119   address adr_null_marker_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, _null_marker_offset));
122   }
123 
124  public:
125 
126   bool is_empty_inline_type() const   { return _misc_flags.is_empty_inline_type(); }
127   void set_is_empty_inline_type()     { _misc_flags.set_is_empty_inline_type(true); }
128 
129   int payload_offset() const {
130     int offset = *(int*)adr_payload_offset();
131     assert(offset != 0, "Must be initialized before use");
132     return offset;
133   }
134 
135   void set_payload_offset(int offset) { *(int*)adr_payload_offset() = offset; }
136 
137   int payload_size_in_bytes() const { return *(int*)adr_payload_size_in_bytes(); }
138   void set_payload_size_in_bytes(int payload_size) { *(int*)adr_payload_size_in_bytes() = payload_size; }
139 
140   int payload_alignment() const { return *(int*)adr_payload_alignment(); }
141   void set_payload_alignment(int alignment) { *(int*)adr_payload_alignment() = alignment; }
142 
143   bool has_non_atomic_layout() const { return non_atomic_size_in_bytes() != -1; }
144   int non_atomic_size_in_bytes() const { return *(int*)adr_non_atomic_size_in_bytes(); }
145   void set_non_atomic_size_in_bytes(int size) { *(int*)adr_non_atomic_size_in_bytes() = size; }
146   int non_atomic_alignment() const { return *(int*)adr_non_atomic_alignment(); }
147   void set_non_atomic_alignment(int alignment) { *(int*)adr_non_atomic_alignment() = alignment; }
148 
149   bool has_atomic_layout() const { return atomic_size_in_bytes() != -1; }
150   int atomic_size_in_bytes() const { return *(int*)adr_atomic_size_in_bytes(); }
151   void set_atomic_size_in_bytes(int size) { *(int*)adr_atomic_size_in_bytes() = size; }
152 
153   bool has_nullable_atomic_layout() const { return nullable_atomic_size_in_bytes() != -1; }
154   int nullable_atomic_size_in_bytes() const { return *(int*)adr_nullable_atomic_size_in_bytes(); }
155   void set_nullable_size_in_bytes(int size) { *(int*)adr_nullable_atomic_size_in_bytes() = size; }
156   int null_marker_offset() const { return *(int*)adr_null_marker_offset(); }
157   int null_marker_offset_in_payload() const { return null_marker_offset() - payload_offset(); }
158   void set_null_marker_offset(int offset) { *(int*)adr_null_marker_offset() = offset; }
159 
160   bool is_payload_marked_as_null(address payload) {
161     assert(has_nullable_atomic_layout(), " Must have");
162     return *((jbyte*)payload + null_marker_offset_in_payload()) == 0;
163   }
164 
165   void mark_payload_as_non_null(address payload) {
166     assert(has_nullable_atomic_layout(), " Must have");
167     *((jbyte*)payload + null_marker_offset_in_payload()) = 1;
168   }
169 
170   void mark_payload_as_null(address payload) {
171     assert(has_nullable_atomic_layout(), " Must have");
172     *((jbyte*)payload + null_marker_offset_in_payload()) = 0;
173   }
174 
175   bool is_layout_supported(LayoutKind lk);
176 
177   int layout_alignment(LayoutKind kind) const;
178   int layout_size_in_bytes(LayoutKind kind) const;
179 
180 #if INCLUDE_CDS
181   virtual void remove_unshareable_info();
182   virtual void remove_java_mirror();
183   virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, PackageEntry* pkg_entry, TRAPS);
184   virtual void metaspace_pointers_do(MetaspaceClosure* it);
185 #endif
186 
187  private:
188   int collect_fields(GrowableArray<SigEntry>* sig, int base_off = 0, int null_marker_offset = -1);
189 
190   void cleanup_blobs();
191 
192  public:
193   // Type testing
194   bool is_inline_klass_slow() const        { return true; }
195 
196   // Casting from Klass*
197 
198   static InlineKlass* cast(Klass* k) {
199     return const_cast<InlineKlass*>(cast(const_cast<const Klass*>(k)));
200   }
201 
202   static const InlineKlass* cast(const Klass* k) {
203     assert(k != nullptr, "k should not be null");
204     assert(k->is_inline_klass(), "cast to InlineKlass");
205     return static_cast<const InlineKlass*>(k);
206   }
207 
208   // Use this to return the size of an instance in heap words.
209   // Note that this size only applies to heap allocated stand-alone instances.
210   virtual int size_helper() const {
211     return layout_helper_to_size_helper(layout_helper());
212   }
213 
214   // allocate_instance() allocates a stand alone value in the Java heap
215   // initialized to default value (cleared memory)
216   instanceOop allocate_instance(TRAPS);
217   // allocates a stand alone inline buffer in the Java heap
218   // DOES NOT have memory cleared, user MUST initialize payload before
219   // returning to Java (i.e.: inline_copy)
220   instanceOop allocate_instance_buffer(TRAPS);
221 
222   address payload_addr(oop o) const;
223 
224   bool maybe_flat_in_array();
225   bool is_always_flat_in_array();
226 
227   bool contains_oops() const { return nonstatic_oop_map_count() > 0; }
228   int nonstatic_oop_count();
229 
230   // Methods to copy payload between containers
231   // Methods taking a LayoutKind argument expect that both the source and the destination
232   // layouts are compatible with the one specified in argument (alignment, size, presence
233   // of a null marker). Reminder: the BUFFERED layout, used in values buffered in heap,
234   // is compatible with all the other layouts.
235 
236   void write_value_to_addr(oop src, void* dst, LayoutKind lk, bool dest_is_initialized, TRAPS);
237   oop read_payload_from_addr(const oop src, size_t offset, LayoutKind lk, TRAPS);
238   void copy_payload_to_addr(void* src, void* dst, LayoutKind lk, bool dest_is_initialized);
239 
240   // oop iterate raw inline type data pointer (where oop_addr may not be an oop, but backing/array-element)
241   template <typename T, class OopClosureType>
242   inline void oop_iterate_specialized(const address oop_addr, OopClosureType* closure);
243 
244   template <typename T, class OopClosureType>
245   inline void oop_iterate_specialized_bounded(const address oop_addr, OopClosureType* closure, void* lo, void* hi);
246 
247   // calling convention support
248   void initialize_calling_convention(TRAPS);
249   Array<SigEntry>* extended_sig() const {
250     return *((Array<SigEntry>**)adr_extended_sig());
251   }
252   inline Array<VMRegPair>* return_regs() const;
253   bool can_be_passed_as_fields() const;
254   bool can_be_returned_as_fields(bool init = false) const;
255   void save_oop_fields(const RegisterMap& map, GrowableArray<Handle>& handles) const;
256   void restore_oop_results(RegisterMap& map, GrowableArray<Handle>& handles) const;
257   oop realloc_result(const RegisterMap& reg_map, const GrowableArray<Handle>& handles, TRAPS);
258   static InlineKlass* returned_inline_klass(const RegisterMap& reg_map, bool* return_oop = nullptr, Method* method = nullptr);
259 
260   address pack_handler() const {
261     return *(address*)adr_pack_handler();
262   }
263 
264   address unpack_handler() const {
265     return *(address*)adr_unpack_handler();
266   }
267 
268   // pack and unpack handlers. Need to be loadable from generated code
269   // so at a fixed offset from the base of the klass pointer.
270   static ByteSize pack_handler_offset() {
271     return byte_offset_of(InlineKlassFixedBlock, _pack_handler);
272   }
273 
274   static ByteSize pack_handler_jobject_offset() {
275     return byte_offset_of(InlineKlassFixedBlock, _pack_handler_jobject);
276   }
277 
278   static ByteSize unpack_handler_offset() {
279     return byte_offset_of(InlineKlassFixedBlock, _unpack_handler);
280   }
281 
282   static ByteSize null_reset_value_offset_offset() {
283     return byte_offset_of(InlineKlassFixedBlock, _null_reset_value_offset);
284   }
285 
286   static ByteSize payload_offset_offset() {
287     return byte_offset_of(InlineKlassFixedBlock, _payload_offset);
288   }
289 
290   static ByteSize null_marker_offset_offset() {
291     return byte_offset_of(InlineKlassFixedBlock, _null_marker_offset);
292   }
293 
294   void set_null_reset_value_offset(int offset) {
295     *((int*)adr_null_reset_value_offset()) = offset;
296   }
297 
298   int null_reset_value_offset() {
299     int offset = *((int*)adr_null_reset_value_offset());
300     assert(offset != 0, "must not be called if not initialized");
301     return offset;
302   }
303 
304   void set_null_reset_value(oop val);
305 
306   oop null_reset_value() {
307     assert(is_initialized() || is_being_initialized() || is_in_error_state(), "null reset value is set at the beginning of initialization");
308     oop val = java_mirror()->obj_field_acquire(null_reset_value_offset());
309     assert(val != nullptr, "Sanity check");
310     return val;
311   }
312 
313   void deallocate_contents(ClassLoaderData* loader_data);
314   static void cleanup(InlineKlass* ik) ;
315 
316   // Verification
317   void verify_on(outputStream* st);
318   void oop_verify_on(oop obj, outputStream* st);
319 
320 };
321 
322 #endif /* SHARE_VM_OOPS_INLINEKLASS_HPP */