| /* |
| * 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_RESOLVEDINDYENTRY_HPP |
| #define SHARE_OOPS_RESOLVEDINDYENTRY_HPP |
| |
| // ResolvedIndyEntry contains the resolution information for invokedynamic bytecodes. |
| // A member of this class can be initialized with the resolved references index and |
| // constant pool index before any resolution is done, where "resolution" refers to finding the target |
| // method and its relevant information, like number of parameters and return type. These entries are contained |
| // within the ConstantPoolCache and are accessed with indices added to the invokedynamic bytecode after |
| // rewriting. |
| |
| // The invokedynamic bytecode starts with an Constant Pool index as its operand which is then rewritten |
| // to become an "indy index", an index into the array of ResolvedIndyEntry. The method here is an adapter method |
| // which will be something like linkToTargetMethod. When an indy call is resolved, we no longer need to invoke |
| // the bootstrap method (BSM) and we can get the target method (the method actually doing stuff, i.e. a string concat) |
| // from the CallSite. The CallSite is generated when the BSM is invoked and it simply contains a MethodHandle for |
| // the target method. The adapter will propagate information to and from the target method and the JVM. |
| |
| |
| class Method; |
| class ResolvedIndyEntry { |
| friend class VMStructs; |
| |
| Method* _method; // Adapter method for indy call |
| u2 _resolved_references_index; // Index of resolved references array that holds the appendix oop |
| u2 _cpool_index; // Constant pool index |
| u2 _number_of_parameters; // Number of arguments for adapter method |
| u1 _return_type; // Adapter method return type |
| u1 _flags; // Flags: [0000|00|has_appendix|resolution_failed] |
| |
| public: |
| ResolvedIndyEntry() : |
| _method(nullptr), |
| _resolved_references_index(0), |
| _cpool_index(0), |
| _number_of_parameters(0), |
| _return_type(0), |
| _flags(0) {} |
| ResolvedIndyEntry(u2 resolved_references_index, u2 cpool_index) : |
| _method(nullptr), |
| _resolved_references_index(resolved_references_index), |
| _cpool_index(cpool_index), |
| _number_of_parameters(0), |
| _return_type(0), |
| _flags(0) {} |
| |
| // Bit shift to get flags |
| // Note: Only two flags exists at the moment but more could be added |
| enum { |
| has_appendix_shift = 1, |
| }; |
| |
| // Getters |
| Method* method() const { return Atomic::load_acquire(&_method); } |
| u2 resolved_references_index() const { return _resolved_references_index; } |
| u2 constant_pool_index() const { return _cpool_index; } |
| u2 num_parameters() const { return _number_of_parameters; } |
| u1 return_type() const { return _return_type; } |
| bool is_resolved() const { return method() != nullptr; } |
| bool has_appendix() const { return (_flags & (1 << has_appendix_shift)) != 0; } |
| bool resolution_failed() const { return (_flags & 1) != 0; } |
| bool is_vfinal() const { return false; } |
| bool is_final() const { return false; } |
| bool has_local_signature() const { return true; } |
| |
| // Printing |
| void print_on(outputStream* st) const; |
| |
| // Initialize with fields available before resolution |
| void init(u2 resolved_references_index, u2 cpool_index) { |
| _resolved_references_index = resolved_references_index; |
| _cpool_index = cpool_index; |
| } |
| |
| void set_num_parameters(int value) { |
| assert(_number_of_parameters == 0 || _number_of_parameters == value, |
| "size must not change: parameter_size=%d, value=%d", _number_of_parameters, value); |
| Atomic::store(&_number_of_parameters, (u2)value); |
| guarantee(_number_of_parameters == value, |
| "size must not change: parameter_size=%d, value=%d", _number_of_parameters, value); |
| } |
| |
| // Populate structure with resolution information |
| void fill_in(Method* m, u2 num_params, u1 return_type, bool has_appendix) { |
| set_num_parameters(num_params); |
| _return_type = return_type; |
| set_flags(has_appendix); |
| // Set the method last since it is read lock free. |
| // Resolution is indicated by whether or not the method is set. |
| Atomic::release_store(&_method, m); |
| } |
| |
| // has_appendix is currently the only other flag besides resolution_failed |
| void set_flags(bool has_appendix) { |
| u1 new_flags = (has_appendix << has_appendix_shift); |
| assert((new_flags & 1) == 0, "New flags should not change resolution flag"); |
| // Preserve the resolution_failed bit |
| _flags = (_flags & 1) | new_flags; |
| } |
| |
| void set_resolution_failed() { |
| _flags = _flags | 1; |
| } |
| |
| void adjust_method_entry(Method* new_method) { _method = new_method; } |
| bool check_no_old_or_obsolete_entry(); |
| |
| // CDS |
| void remove_unshareable_info(); |
| |
| // Offsets |
| static ByteSize method_offset() { return byte_offset_of(ResolvedIndyEntry, _method); } |
| static ByteSize resolved_references_index_offset() { return byte_offset_of(ResolvedIndyEntry, _resolved_references_index); } |
| static ByteSize result_type_offset() { return byte_offset_of(ResolvedIndyEntry, _return_type); } |
| static ByteSize num_parameters_offset() { return byte_offset_of(ResolvedIndyEntry, _number_of_parameters); } |
| static ByteSize flags_offset() { return byte_offset_of(ResolvedIndyEntry, _flags); } |
| }; |
| |
| #endif // SHARE_OOPS_RESOLVEDINDYENTRY_HPP |