1 /* 2 * Copyright (c) 2023, 2024, 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/atomic.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 ResolvedFieldEntry(const ResolvedFieldEntry& other) { 84 copy_from(other); 85 } 86 87 ResolvedFieldEntry& operator=(const ResolvedFieldEntry& other) { 88 copy_from(other); 89 return *this; 90 } 91 92 // Bit shift to get flags 93 // Note: Only two flags exists at the moment but more could be added 94 enum { 95 is_volatile_shift = 0, 96 is_final_shift = 1, // unused 97 is_flat_shift = 2, 98 is_null_free_inline_type_shift = 3, 99 has_null_marker_shift = 4, 100 max_flag_shift = has_null_marker_shift 101 }; 102 103 // Getters 104 InstanceKlass* field_holder() const { return _field_holder; } 105 int field_offset() const { return _field_offset; } 106 u2 field_index() const { return _field_index; } 107 u2 constant_pool_index() const { return _cpool_index; } 108 u1 tos_state() const { return _tos_state; } 109 u1 get_code() const { return Atomic::load_acquire(&_get_code); } 110 u1 put_code() const { return Atomic::load_acquire(&_put_code); } 111 bool is_final() const { return (_flags & (1 << is_final_shift)) != 0; } 112 bool is_volatile () const { return (_flags & (1 << is_volatile_shift)) != 0; } 113 bool is_flat() const { return (_flags & (1 << is_flat_shift)) != 0; } 114 bool is_null_free_inline_type() const { return (_flags & (1 << is_null_free_inline_type_shift)) != 0; } 115 bool has_null_marker() const { return (_flags & (1 << has_null_marker_shift)) != 0; } 116 bool is_resolved(Bytecodes::Code code) const { 117 switch(code) { 118 case Bytecodes::_getstatic: 119 case Bytecodes::_getfield: 120 return (get_code() == code); 121 case Bytecodes::_putstatic: 122 case Bytecodes::_putfield: 123 return (put_code() == code); 124 default: 125 ShouldNotReachHere(); 126 return false; 127 } 128 } 129 130 // Printing 131 void print_on(outputStream* st) const; 132 133 void set_flags(bool is_final_flag, bool is_volatile_flag, bool is_flat_flag, bool is_null_free_inline_type_flag, 134 bool has_null_marker_flag) { 135 u1 new_flags = ((is_final_flag ? 1 : 0) << is_final_shift) | static_cast<int>(is_volatile_flag) | 136 ((is_flat_flag ? 1 : 0) << is_flat_shift) | 137 ((is_null_free_inline_type_flag ? 1 : 0) << is_null_free_inline_type_shift) | 138 ((has_null_marker_flag ? 1 : 0) << has_null_marker_shift); 139 _flags = checked_cast<u1>(new_flags); 140 assert(is_final() == is_final_flag, "Must be"); 141 assert(is_volatile() == is_volatile_flag, "Must be"); 142 assert(is_flat() == is_flat_flag, "Must be"); 143 assert(is_null_free_inline_type() == is_null_free_inline_type_flag, "Must be"); 144 assert(has_null_marker() == has_null_marker_flag, "Must be"); 145 } 146 147 inline void set_bytecode(u1* code, u1 new_code) { 148 #ifdef ASSERT 149 // Read once. 150 volatile Bytecodes::Code c = (Bytecodes::Code)*code; 151 assert(c == 0 || c == new_code || new_code == 0, "update must be consistent"); 152 #endif 153 Atomic::release_store(code, new_code); 154 } 155 156 // Populate the structure with resolution information 157 void fill_in(InstanceKlass* klass, int offset, u2 index, u1 tos_state, u1 b1, u1 b2) { 158 _field_holder = klass; 159 _field_offset = offset; 160 _field_index = index; 161 _tos_state = tos_state; 162 163 // These must be set after the other fields 164 set_bytecode(&_get_code, b1); 165 set_bytecode(&_put_code, b2); 166 assert(is_valid(), "invalid"); 167 } 168 169 // CDS 170 #if INCLUDE_CDS 171 void remove_unshareable_info(); 172 void mark_and_relocate(); 173 #endif 174 175 // Offsets 176 static ByteSize field_holder_offset() { return byte_offset_of(ResolvedFieldEntry, _field_holder); } 177 static ByteSize field_offset_offset() { return byte_offset_of(ResolvedFieldEntry, _field_offset); } 178 static ByteSize field_index_offset() { return byte_offset_of(ResolvedFieldEntry, _field_index); } 179 static ByteSize get_code_offset() { return byte_offset_of(ResolvedFieldEntry, _get_code); } 180 static ByteSize put_code_offset() { return byte_offset_of(ResolvedFieldEntry, _put_code); } 181 static ByteSize type_offset() { return byte_offset_of(ResolvedFieldEntry, _tos_state); } 182 static ByteSize flags_offset() { return byte_offset_of(ResolvedFieldEntry, _flags); } 183 184 // Debug help 185 bool is_valid() const; 186 }; 187 188 #endif //SHARE_OOPS_RESOLVEDFIELDENTRY_HPP