1 /*
  2  * Copyright (c) 2023, 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_OOPS_RESOLVEDFIELDENTRY_HPP
 26 #define SHARE_OOPS_RESOLVEDFIELDENTRY_HPP
 27 
 28 #include "interpreter/bytecodes.hpp"
 29 #include "oops/instanceKlass.hpp"
 30 #include "runtime/atomicAccess.hpp"
 31 #include "utilities/checkedCast.hpp"
 32 #include "utilities/sizes.hpp"
 33 
 34 // ResolvedFieldEntry contains the resolution information for field related bytecodes like
 35 // like getfield, putfield, getstatic, and putstatic. A member of this class can be initialized
 36 // with the constant pool index associated with the bytecode before any resolution is done, where
 37 // "resolution" refers to populating the getcode and putcode fields and other relevant information.
 38 // The field's type (TOS), offset, holder klass, and index within that class can all be acquired
 39 // together and are used to populate this structure. These entries are contained
 40 // within the ConstantPoolCache and are accessed with indices added to the bytecode after
 41 // rewriting.
 42 
 43 // Field bytecodes start with a constant pool index as their operand, which is then rewritten to
 44 // a "field index", which is an index into the array of ResolvedFieldEntry.
 45 
 46 //class InstanceKlass;
 47 class ResolvedFieldEntry {
 48   friend class VMStructs;
 49 
 50   InstanceKlass* _field_holder; // Field holder klass
 51   int _field_offset;            // Field offset in bytes
 52   u2 _field_index;              // Index into field information in holder InstanceKlass
 53   u2 _cpool_index;              // Constant pool index
 54   u1 _tos_state;                // TOS state
 55   u1 _flags;                    // Flags: [000|has_null_marker|is_null_free_inline_type|is_flat|is_final|is_volatile]
 56   u1 _get_code, _put_code;      // Get and Put bytecodes of the field
 57 
 58   void copy_from(const ResolvedFieldEntry& other) {
 59     _field_holder = other._field_holder;
 60     _field_offset = other._field_offset;
 61     _field_index = other._field_index;
 62     _cpool_index = other._cpool_index;
 63     _tos_state = other._tos_state;
 64     _flags = other._flags;
 65     _get_code = other._get_code;
 66     _put_code = other._put_code;
 67   }
 68 
 69 public:
 70   ResolvedFieldEntry(u2 cpi) :
 71     _field_holder(nullptr),
 72     _field_offset(0),
 73     _field_index(0),
 74     _cpool_index(cpi),
 75     _tos_state(0),
 76     _flags(0),
 77     _get_code(0),
 78     _put_code(0) {}
 79 
 80   ResolvedFieldEntry() :
 81     ResolvedFieldEntry(0) {}
 82 
 83   // Notes on copy constructor, copy assignment operator, and copy_from().
 84   // These are necessary for generating deterministic CDS archives.
 85   //
 86   // We have some unused padding on 64-bit platforms (4 bytes at the tail end).
 87   //
 88   // When ResolvedFieldEntries in a ConstantPoolCache are allocated from the metaspace,
 89   // their entire content (including the padding) is filled with zeros. They are
 90   // then initialized with initialize_resolved_entries_array() in cpCache.cpp from a
 91   // GrowableArray.
 92   //
 93   // The GrowableArray is initialized in rewriter.cpp, using ResolvedFieldEntries that
 94   // are originally allocated from the C++ stack. Functions like GrowableArray::expand_to()
 95   // will also allocate ResolvedFieldEntries from the stack. These may have random bits
 96   // in the padding as the C++ compiler is allowed to leave the padding in uninitialized
 97   // states.
 98   //
 99   // If we use the default copy constructor and/or default copy assignment operator,
100   // the random padding will be copied into the GrowableArray, from there
101   // to the ConstantPoolCache, and eventually to the CDS archive. As a result, the
102   // CDS archive will contain random bits, causing failures in
103   // test/hotspot/jtreg/runtime/cds/DeterministicDump.java (usually on Windows).
104   //
105   // By using copy_from(), we can prevent the random padding from being copied,
106   // ensuring that the ResolvedFieldEntries in a ConstantPoolCache (and thus the
107   // CDS archive) will have all zeros in the padding.
108 
109   // Copy constructor
110   ResolvedFieldEntry(const ResolvedFieldEntry& other) {
111     copy_from(other);
112   }
113 
114   // Copy assignment operator
115   ResolvedFieldEntry& operator=(const ResolvedFieldEntry& other) {
116     copy_from(other);
117     return *this;
118   }
119 
120   // Bit shift to get flags
121   // Note: Only two flags exists at the moment but more could be added
122   enum {
123       is_volatile_shift     = 0,
124       is_final_shift        = 1, // unused
125       is_flat_shift         = 2,
126       is_null_free_inline_type_shift = 3,
127       has_null_marker_shift = 4,
128       max_flag_shift = has_null_marker_shift
129   };
130 
131   // Getters
132   InstanceKlass* field_holder() const { return _field_holder; }
133   int field_offset()            const { return _field_offset; }
134   u2 field_index()              const { return _field_index;  }
135   u2 constant_pool_index()      const { return _cpool_index;  }
136   u1 tos_state()                const { return _tos_state;    }
137   u1 get_code()                 const { return AtomicAccess::load_acquire(&_get_code);      }
138   u1 put_code()                 const { return AtomicAccess::load_acquire(&_put_code);      }
139   bool is_final()               const { return (_flags & (1 << is_final_shift))    != 0; }
140   bool is_volatile ()           const { return (_flags & (1 << is_volatile_shift)) != 0; }
141   bool is_flat()                const { return (_flags & (1 << is_flat_shift))     != 0; }
142   bool is_null_free_inline_type() const { return (_flags & (1 << is_null_free_inline_type_shift)) != 0; }
143   bool has_null_marker()        const { return (_flags & (1 << has_null_marker_shift)) != 0; }
144   bool is_resolved(Bytecodes::Code code) const {
145     switch(code) {
146     case Bytecodes::_getstatic:
147     case Bytecodes::_getfield:
148       return (get_code() == code);
149     case Bytecodes::_putstatic:
150     case Bytecodes::_putfield:
151       return (put_code() == code);
152     default:
153       ShouldNotReachHere();
154       return false;
155     }
156   }
157 
158   // Printing
159   void print_on(outputStream* st) const;
160 
161   void set_flags(bool is_final_flag, bool is_volatile_flag, bool is_flat_flag, bool is_null_free_inline_type_flag,
162                  bool has_null_marker_flag) {
163     u1 new_flags = ((is_final_flag ? 1 : 0) << is_final_shift) | static_cast<int>(is_volatile_flag) |
164       ((is_flat_flag ? 1 : 0) << is_flat_shift) |
165       ((is_null_free_inline_type_flag ? 1 : 0) << is_null_free_inline_type_shift) |
166       ((has_null_marker_flag ? 1 : 0) << has_null_marker_shift);
167     _flags = checked_cast<u1>(new_flags);
168     assert(is_final() == is_final_flag, "Must be");
169     assert(is_volatile() == is_volatile_flag, "Must be");
170     assert(is_flat() == is_flat_flag, "Must be");
171     assert(is_null_free_inline_type() == is_null_free_inline_type_flag, "Must be");
172     assert(has_null_marker() == has_null_marker_flag, "Must be");
173   }
174 
175   inline void set_bytecode(u1* code, u1 new_code) {
176   #ifdef ASSERT
177     // Read once.
178     volatile Bytecodes::Code c = (Bytecodes::Code)*code;
179     assert(c == 0 || c == new_code || new_code == 0, "update must be consistent");
180   #endif
181     AtomicAccess::release_store(code, new_code);
182   }
183 
184   // Populate the structure with resolution information
185   void fill_in(InstanceKlass* klass, int offset, u2 index, u1 tos_state, u1 b1, u1 b2) {
186     _field_holder = klass;
187     _field_offset = offset;
188     _field_index = index;
189     _tos_state = tos_state;
190 
191     // These must be set after the other fields
192     set_bytecode(&_get_code, b1);
193     set_bytecode(&_put_code, b2);
194     assert(is_valid(), "invalid");
195   }
196 
197   // CDS
198 #if INCLUDE_CDS
199   void remove_unshareable_info();
200   void mark_and_relocate();
201 #endif
202 
203   // Offsets
204   static ByteSize field_holder_offset() { return byte_offset_of(ResolvedFieldEntry, _field_holder); }
205   static ByteSize field_offset_offset() { return byte_offset_of(ResolvedFieldEntry, _field_offset); }
206   static ByteSize field_index_offset()  { return byte_offset_of(ResolvedFieldEntry, _field_index);  }
207   static ByteSize get_code_offset()     { return byte_offset_of(ResolvedFieldEntry, _get_code);     }
208   static ByteSize put_code_offset()     { return byte_offset_of(ResolvedFieldEntry, _put_code);     }
209   static ByteSize type_offset()         { return byte_offset_of(ResolvedFieldEntry, _tos_state);    }
210   static ByteSize flags_offset()        { return byte_offset_of(ResolvedFieldEntry, _flags);        }
211 
212   // Debug help
213   bool is_valid() const;
214 };
215 
216 #endif //SHARE_OOPS_RESOLVEDFIELDENTRY_HPP