| /* | |
| * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| * | |
| */ | |
| #ifndef SHARE_OOPS_RESOLVEDFIELDENTRY_HPP | |
| #define SHARE_OOPS_RESOLVEDFIELDENTRY_HPP | |
| #include "interpreter/bytecodes.hpp" | |
| #include "oops/instanceKlass.hpp" | |
| #include "runtime/atomic.hpp" | |
| #include "utilities/checkedCast.hpp" | |
| #include "utilities/sizes.hpp" | |
| // ResolvedFieldEntry contains the resolution information for field related bytecodes like | |
| // like getfield, putfield, getstatic, and putstatic. A member of this class can be initialized | |
| // with the constant pool index associated with the bytecode before any resolution is done, where | |
| // "resolution" refers to populating the getcode and putcode fields and other relevant information. | |
| // The field's type (TOS), offset, holder klass, and index within that class can all be acquired | |
| // together and are used to populate this structure. These entries are contained | |
| // within the ConstantPoolCache and are accessed with indices added to the bytecode after | |
| // rewriting. | |
| // Field bytecodes start with a constant pool index as their operand, which is then rewritten to | |
| // a "field index", which is an index into the array of ResolvedFieldEntry. | |
| //class InstanceKlass; | |
| class ResolvedFieldEntry { | |
| friend class VMStructs; | |
| InstanceKlass* _field_holder; // Field holder klass | |
| int _field_offset; // Field offset in bytes | |
| u2 _field_index; // Index into field information in holder InstanceKlass | |
| u2 _cpool_index; // Constant pool index | |
| u1 _tos_state; // TOS state | |
| u1 _flags; // Flags: [0000|00|is_final|is_volatile] | |
| u1 _get_code, _put_code; // Get and Put bytecodes of the field | |
| void copy_from(const ResolvedFieldEntry& other) { | |
| _field_holder = other._field_holder; | |
| _field_offset = other._field_offset; | |
| _field_index = other._field_index; | |
| _cpool_index = other._cpool_index; | |
| _tos_state = other._tos_state; | |
| _flags = other._flags; | |
| _get_code = other._get_code; | |
| _put_code = other._put_code; | |
| } | |
| public: | |
| ResolvedFieldEntry(u2 cpi) : | |
| _field_holder(nullptr), | |
| _field_offset(0), | |
| _field_index(0), | |
| _cpool_index(cpi), | |
| _tos_state(0), | |
| _flags(0), | |
| _get_code(0), | |
| _put_code(0) {} | |
| ResolvedFieldEntry() : | |
| ResolvedFieldEntry(0) {} | |
| ResolvedFieldEntry(const ResolvedFieldEntry& other) { | |
| copy_from(other); | |
| } | |
| ResolvedFieldEntry& operator=(const ResolvedFieldEntry& other) { | |
| copy_from(other); | |
| return *this; | |
| } | |
| // Bit shift to get flags | |
| // Note: Only two flags exists at the moment but more could be added | |
| enum { | |
| is_volatile_shift = 0, | |
| is_final_shift = 1, // unused | |
| }; | |
| // Getters | |
| InstanceKlass* field_holder() const { return _field_holder; } | |
| int field_offset() const { return _field_offset; } | |
| u2 field_index() const { return _field_index; } | |
| u2 constant_pool_index() const { return _cpool_index; } | |
| u1 tos_state() const { return _tos_state; } | |
| u1 get_code() const { return Atomic::load_acquire(&_get_code); } | |
| u1 put_code() const { return Atomic::load_acquire(&_put_code); } | |
| bool is_final() const { return (_flags & (1 << is_final_shift)) != 0; } | |
| bool is_volatile () const { return (_flags & (1 << is_volatile_shift)) != 0; } | |
| bool is_resolved(Bytecodes::Code code) const { | |
| switch(code) { | |
| case Bytecodes::_getstatic: | |
| case Bytecodes::_getfield: | |
| return (get_code() == code); | |
| case Bytecodes::_putstatic: | |
| case Bytecodes::_putfield: | |
| return (put_code() == code); | |
| default: | |
| ShouldNotReachHere(); | |
| return false; | |
| } | |
| } | |
| // Printing | |
| void print_on(outputStream* st) const; | |
| void set_flags(bool is_final_flag, bool is_volatile_flag) { | |
| int new_flags = (is_final_flag << is_final_shift) | static_cast<int>(is_volatile_flag); | |
| _flags = checked_cast<u1>(new_flags); | |
| assert(is_final() == is_final_flag, "Must be"); | |
| assert(is_volatile() == is_volatile_flag, "Must be"); | |
| } | |
| inline void set_bytecode(u1* code, u1 new_code) { | |
| #ifdef ASSERT | |
| // Read once. | |
| volatile Bytecodes::Code c = (Bytecodes::Code)*code; | |
| assert(c == 0 || c == new_code || new_code == 0, "update must be consistent"); | |
| #endif | |
| Atomic::release_store(code, new_code); | |
| } | |
| // Populate the strucutre with resolution information | |
| void fill_in(InstanceKlass* klass, int offset, u2 index, u1 tos_state, u1 b1, u1 b2) { | |
| _field_holder = klass; | |
| _field_offset = offset; | |
| _field_index = index; | |
| _tos_state = tos_state; | |
| // These must be set after the other fields | |
| set_bytecode(&_get_code, b1); | |
| set_bytecode(&_put_code, b2); | |
| } | |
| // CDS | |
| #if INCLUDE_CDS | |
| void remove_unshareable_info(); | |
| void mark_and_relocate(); | |
| #endif | |
| // Offsets | |
| static ByteSize field_holder_offset() { return byte_offset_of(ResolvedFieldEntry, _field_holder); } | |
| static ByteSize field_offset_offset() { return byte_offset_of(ResolvedFieldEntry, _field_offset); } | |
| static ByteSize field_index_offset() { return byte_offset_of(ResolvedFieldEntry, _field_index); } | |
| static ByteSize get_code_offset() { return byte_offset_of(ResolvedFieldEntry, _get_code); } | |
| static ByteSize put_code_offset() { return byte_offset_of(ResolvedFieldEntry, _put_code); } | |
| static ByteSize type_offset() { return byte_offset_of(ResolvedFieldEntry, _tos_state); } | |
| static ByteSize flags_offset() { return byte_offset_of(ResolvedFieldEntry, _flags); } | |
| }; | |
| #endif //SHARE_OOPS_RESOLVEDFIELDENTRY_HPP |