/* * Copyright (c) 2023, 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_RESOLVEDMETHODENTRY_HPP #define SHARE_OOPS_RESOLVEDMETHODENTRY_HPP #include "interpreter/bytecodes.hpp" #include "runtime/atomic.hpp" #include "utilities/sizes.hpp" // ResolvedMethodEntry contains the resolution information for the invoke bytecodes // invokestatic, invokespecial, invokeinterface, invokevirtual, and invokehandle but // NOT invokedynamic (see resolvedIndyEntry.hpp). 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 bytecode1 and bytecode2 fields and other // relevant information. These entries are contained within the ConstantPoolCache and are // accessed with indices added to the bytecode after rewriting. // Invoke bytecodes start with a constant pool index as their operand, which is then // rewritten to a "method index", which is an index into the array of ResolvedMethodEntry. // This structure has fields for every type of invoke bytecode but each entry may only // use some of the fields. All entries have a TOS state, number of parameters, flags, // and a constant pool index. // Types of invokes // invokestatic // invokespecial // Method* // invokehandle // Method* // resolved references index // invokevirtual // Method* (if vfinal is true) // vtable/itable index // invokeinterface // Klass* // Method* // Note: invokevirtual & invokespecial bytecodes can share the same constant // pool entry and thus the same resolved method entry. // The is_vfinal flag indicates method pointer for a final method or an index. class InstanceKlass; class ResolvedMethodEntry { friend class VMStructs; Method* _method; // Method for non virtual calls, adapter method for invokevirtual, final method for virtual union { // These fields are mutually exclusive and are only used by some invoke codes InstanceKlass* _interface_klass; // for interface and static u2 _resolved_references_index; // Index of resolved references array that holds the appendix oop for invokehandle u2 _table_index; // vtable/itable index for virtual and interface calls } _entry_specific; u2 _cpool_index; // Constant pool index u2 _number_of_parameters; // Number of arguments for method u1 _tos_state; // TOS state u1 _flags; // Flags: [00|has_resolved_ref_index|has_local_signature|has_appendix|forced_virtual|final|virtual_final] u1 _bytecode1, _bytecode2; // Resolved invoke codes // Constructors public: ResolvedMethodEntry(u2 cpi) : _method(nullptr), _cpool_index(cpi), _number_of_parameters(0), _tos_state(0), _flags(0), _bytecode1(0), _bytecode2(0) { _entry_specific._interface_klass = nullptr; } ResolvedMethodEntry() : ResolvedMethodEntry(0) {} // Bit shift to get flags enum { is_vfinal_shift = 0, is_final_shift = 1, is_forced_virtual_shift = 2, has_appendix_shift = 3, has_local_signature_shift = 4, has_resolved_ref_shift = 5 }; // Getters Method* method() const { return Atomic::load_acquire(&_method); } InstanceKlass* interface_klass() const { assert(_bytecode1 == Bytecodes::_invokeinterface, "Only invokeinterface has a klass %d", _bytecode1); return _entry_specific._interface_klass; } u2 resolved_references_index() const { // This index may be read before resolution completes return _entry_specific._resolved_references_index; } u2 table_index() const { assert(_bytecode2 == Bytecodes::_invokevirtual, "Only invokevirtual has a vtable/itable index %d", _bytecode2); return _entry_specific._table_index; } u2 constant_pool_index() const { return _cpool_index; } u1 tos_state() const { return _tos_state; } u2 number_of_parameters() const { return _number_of_parameters; } u1 bytecode1() const { return Atomic::load_acquire(&_bytecode1); } u1 bytecode2() const { return Atomic::load_acquire(&_bytecode2); } // Flags bool is_vfinal() const { return (_flags & (1 << is_vfinal_shift)) != 0; } bool is_final() const { return (_flags & (1 << is_final_shift)) != 0; } bool is_forced_virtual() const { return (_flags & (1 << is_forced_virtual_shift)) != 0; } bool has_appendix() const { return (_flags & (1 << has_appendix_shift)) != 0; } bool has_local_signature() const { return (_flags & (1 << has_local_signature_shift)) != 0; } bool has_resolved_ref_index() const { return (_flags & (1 << has_resolved_ref_shift)) != 0; } bool is_resolved(Bytecodes::Code code) const { switch(code) { case Bytecodes::_invokeinterface: case Bytecodes::_invokehandle: case Bytecodes::_invokespecial: case Bytecodes::_invokestatic: return (bytecode1() == code); case Bytecodes::_invokevirtual: return (bytecode2() == code); default: ShouldNotReachHere(); return false; } } void adjust_method_entry(Method* new_method) { // this is done during the redefinition safepoint _method = new_method; } bool check_no_old_or_obsolete_entry(); // Printing void print_on(outputStream* st) const; // Setters void set_flags(u1 flags) { _flags |= flags; } 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 old: %d, new: %d", c, new_code); #endif Atomic::release_store(code, new_code); } void set_bytecode1(u1 b1) { set_bytecode(&_bytecode1, b1); } void set_bytecode2(u1 b2) { set_bytecode(&_bytecode2, b2); } void set_method(Method* m) { Atomic::release_store(&_method, m); } void set_klass(InstanceKlass* klass) { _entry_specific._interface_klass = klass; } void set_resolved_references_index(u2 ref_index) { set_flags(1 << has_resolved_ref_shift); _entry_specific._resolved_references_index = ref_index; } void set_table_index(u2 table_index) { _entry_specific._table_index = table_index; } void set_num_parameters(u2 num_params) { _number_of_parameters = num_params; } void fill_in(u1 tos_state, u2 num_params) { _tos_state = tos_state; _number_of_parameters = num_params; } void reset_entry(); // CDS void remove_unshareable_info(); // Offsets static ByteSize klass_offset() { return byte_offset_of(ResolvedMethodEntry, _entry_specific._interface_klass); } static ByteSize method_offset() { return byte_offset_of(ResolvedMethodEntry, _method); } static ByteSize resolved_references_index_offset() { return byte_offset_of(ResolvedMethodEntry, _entry_specific._resolved_references_index); } static ByteSize table_index_offset() { return byte_offset_of(ResolvedMethodEntry, _entry_specific._table_index); } static ByteSize num_parameters_offset() { return byte_offset_of(ResolvedMethodEntry, _number_of_parameters); } static ByteSize type_offset() { return byte_offset_of(ResolvedMethodEntry, _tos_state); } static ByteSize flags_offset() { return byte_offset_of(ResolvedMethodEntry, _flags); } static ByteSize bytecode1_offset() { return byte_offset_of(ResolvedMethodEntry, _bytecode1); } static ByteSize bytecode2_offset() { return byte_offset_of(ResolvedMethodEntry, _bytecode2); } }; #endif //SHARE_OOPS_RESOLVEDMETHODENTRY_HPP