1 /*
  2  * Copyright (c) 2023, 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_RESOLVEDINDYENTRY_HPP
 26 #define SHARE_OOPS_RESOLVEDINDYENTRY_HPP
 27 
 28 // ResolvedIndyEntry contains the resolution information for invokedynamic bytecodes.
 29 // A member of this class can be initialized with the resolved references index and
 30 // constant pool index before any resolution is done, where "resolution" refers to finding the target
 31 // method and its relevant information, like number of parameters and return type. These entries are contained
 32 // within the ConstantPoolCache and are accessed with indices added to the invokedynamic bytecode after
 33 // rewriting.
 34 
 35 // The invokedynamic bytecode starts with an Constant Pool index as its operand which is then rewritten
 36 // to become an "indy index", an index into the array of ResolvedIndyEntry. The method here is an adapter method
 37 // which will be something like linkToTargetMethod. When an indy call is resolved, we no longer need to invoke
 38 // the bootstrap method (BSM) and we can get the target method (the method actually doing stuff, i.e. a string concat)
 39 // from the CallSite. The CallSite is generated when the BSM is invoked and it simply contains a MethodHandle for
 40 // the target method. The adapter will propagate information to and from the target method and the JVM.
 41 
 42 
 43 class Method;
 44 class ResolvedIndyEntry {
 45   friend class VMStructs;
 46 
 47   Method* _method;               // Adapter method for indy call
 48   u2 _resolved_references_index; // Index of resolved references array that holds the appendix oop
 49   u2 _cpool_index;               // Constant pool index
 50   u2 _number_of_parameters;      // Number of arguments for adapter method
 51   u1 _return_type;               // Adapter method return type
 52   u1 _flags;                     // Flags: [0000|00|has_appendix|resolution_failed]
 53 
 54 public:
 55   ResolvedIndyEntry() :
 56     _method(nullptr),
 57     _resolved_references_index(0),
 58     _cpool_index(0),
 59     _number_of_parameters(0),
 60     _return_type(0),
 61     _flags(0) {}
 62   ResolvedIndyEntry(u2 resolved_references_index, u2 cpool_index) :
 63     _method(nullptr),
 64     _resolved_references_index(resolved_references_index),
 65     _cpool_index(cpool_index),
 66     _number_of_parameters(0),
 67     _return_type(0),
 68     _flags(0) {}
 69 
 70   // Bit shift to get flags
 71   // Note: Only two flags exists at the moment but more could be added
 72   enum {
 73       has_appendix_shift        = 1,
 74   };
 75 
 76   // Getters
 77   Method* method()               const { return Atomic::load_acquire(&_method); }
 78   u2 resolved_references_index() const { return _resolved_references_index;     }
 79   u2 constant_pool_index()       const { return _cpool_index;                   }
 80   u2 num_parameters()            const { return _number_of_parameters;          }
 81   u1 return_type()               const { return _return_type;                   }
 82   bool is_resolved()             const { return method() != nullptr;            }
 83   bool has_appendix()            const { return (_flags & (1 << has_appendix_shift)) != 0; }
 84   bool resolution_failed()       const { return (_flags & 1) != 0; }
 85   bool is_vfinal()               const { return false; }
 86   bool is_final()                const { return false; }
 87   bool has_local_signature()     const { return true;  }
 88 
 89   // Printing
 90   void print_on(outputStream* st) const;
 91 
 92   // Initialize with fields available before resolution
 93   void init(u2 resolved_references_index, u2 cpool_index) {
 94     _resolved_references_index = resolved_references_index;
 95     _cpool_index = cpool_index;
 96   }
 97 
 98   void set_num_parameters(int value) {
 99     assert(_number_of_parameters == 0 || _number_of_parameters == value,
100       "size must not change: parameter_size=%d, value=%d", _number_of_parameters, value);
101     Atomic::store(&_number_of_parameters, (u2)value);
102     guarantee(_number_of_parameters == value,
103       "size must not change: parameter_size=%d, value=%d", _number_of_parameters, value);
104   }
105 
106   // Populate structure with resolution information
107   void fill_in(Method* m, u2 num_params, u1 return_type, bool has_appendix) {
108     set_num_parameters(num_params);
109     _return_type = return_type;
110     set_flags(has_appendix);
111     // Set the method last since it is read lock free.
112     // Resolution is indicated by whether or not the method is set.
113     Atomic::release_store(&_method, m);
114   }
115 
116   // has_appendix is currently the only other flag besides resolution_failed
117   void set_flags(bool has_appendix) {
118     u1 new_flags = (has_appendix << has_appendix_shift);
119     assert((new_flags & 1) == 0, "New flags should not change resolution flag");
120     // Preserve the resolution_failed bit
121     _flags = (_flags & 1) | new_flags;
122   }
123 
124   void set_resolution_failed() {
125     _flags = _flags | 1;
126   }
127 
128   void adjust_method_entry(Method* new_method) { _method = new_method; }
129   bool check_no_old_or_obsolete_entry();
130 
131   // CDS
132   void remove_unshareable_info();
133 
134   // Offsets
135   static ByteSize method_offset()                    { return byte_offset_of(ResolvedIndyEntry, _method);                    }
136   static ByteSize resolved_references_index_offset() { return byte_offset_of(ResolvedIndyEntry, _resolved_references_index); }
137   static ByteSize result_type_offset()               { return byte_offset_of(ResolvedIndyEntry, _return_type);               }
138   static ByteSize num_parameters_offset()            { return byte_offset_of(ResolvedIndyEntry, _number_of_parameters);      }
139   static ByteSize flags_offset()                     { return byte_offset_of(ResolvedIndyEntry, _flags);                     }
140 };
141 
142 #endif // SHARE_OOPS_RESOLVEDINDYENTRY_HPP