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: [0000|00|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 };
126
127 // Getters
128 InstanceKlass* field_holder() const { return _field_holder; }
129 int field_offset() const { return _field_offset; }
130 u2 field_index() const { return _field_index; }
131 u2 constant_pool_index() const { return _cpool_index; }
132 u1 tos_state() const { return _tos_state; }
133 u1 get_code() const { return AtomicAccess::load_acquire(&_get_code); }
134 u1 put_code() const { return AtomicAccess::load_acquire(&_put_code); }
135 bool is_final() const { return (_flags & (1 << is_final_shift)) != 0; }
136 bool is_volatile () const { return (_flags & (1 << is_volatile_shift)) != 0; }
137 bool is_resolved(Bytecodes::Code code) const {
138 switch(code) {
139 case Bytecodes::_getstatic:
140 case Bytecodes::_getfield:
141 return (get_code() == code);
142 case Bytecodes::_putstatic:
143 case Bytecodes::_putfield:
144 return (put_code() == code);
145 default:
146 ShouldNotReachHere();
147 return false;
148 }
149 }
150
151 // Printing
152 void print_on(outputStream* st) const;
153
154 void set_flags(bool is_final_flag, bool is_volatile_flag) {
155 int new_flags = (is_final_flag << is_final_shift) | static_cast<int>(is_volatile_flag);
156 _flags = checked_cast<u1>(new_flags);
157 assert(is_final() == is_final_flag, "Must be");
158 assert(is_volatile() == is_volatile_flag, "Must be");
159 }
160
161 inline void set_bytecode(u1* code, u1 new_code) {
162 #ifdef ASSERT
163 // Read once.
164 volatile Bytecodes::Code c = (Bytecodes::Code)*code;
165 assert(c == 0 || c == new_code || new_code == 0, "update must be consistent");
166 #endif
167 AtomicAccess::release_store(code, new_code);
168 }
169
170 // Populate the strucutre with resolution information
171 void fill_in(InstanceKlass* klass, int offset, u2 index, u1 tos_state, u1 b1, u1 b2) {
172 _field_holder = klass;
173 _field_offset = offset;
174 _field_index = index;
175 _tos_state = tos_state;
176
177 // These must be set after the other fields
178 set_bytecode(&_get_code, b1);
179 set_bytecode(&_put_code, b2);
180 }
181
182 // CDS
183 #if INCLUDE_CDS
184 void remove_unshareable_info();
185 void mark_and_relocate();
186 #endif
187
188 // Offsets
189 static ByteSize field_holder_offset() { return byte_offset_of(ResolvedFieldEntry, _field_holder); }
190 static ByteSize field_offset_offset() { return byte_offset_of(ResolvedFieldEntry, _field_offset); }
191 static ByteSize field_index_offset() { return byte_offset_of(ResolvedFieldEntry, _field_index); }
192 static ByteSize get_code_offset() { return byte_offset_of(ResolvedFieldEntry, _get_code); }
193 static ByteSize put_code_offset() { return byte_offset_of(ResolvedFieldEntry, _put_code); }
194 static ByteSize type_offset() { return byte_offset_of(ResolvedFieldEntry, _tos_state); }
195 static ByteSize flags_offset() { return byte_offset_of(ResolvedFieldEntry, _flags); }
196
197 };
198
199 #endif //SHARE_OOPS_RESOLVEDFIELDENTRY_HPP