1 /*
  2  * Copyright (c) 2021, 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_CDS_LAMBDAPROXYCLASSINFO_HPP
 26 #define SHARE_CDS_LAMBDAPROXYCLASSINFO_HPP
 27 #include "cds/metaspaceShared.hpp"
 28 #include "classfile/javaClasses.hpp"
 29 #include "utilities/growableArray.hpp"
 30 #include "utilities/resourceHash.hpp"
 31 
 32 class InstanceKlass;
 33 class Method;
 34 class Symbol;
 35 class outputStream;
 36 
 37 class LambdaProxyClassKey {
 38   InstanceKlass* _caller_ik;
 39   Symbol*        _invoked_name;
 40   Symbol*        _invoked_type;
 41   Symbol*        _method_type;
 42   Method*        _member_method;
 43   Symbol*        _instantiated_method_type;
 44 
 45 public:
 46   LambdaProxyClassKey(InstanceKlass* caller_ik,
 47                       Symbol*        invoked_name,
 48                       Symbol*        invoked_type,
 49                       Symbol*        method_type,
 50                       Method*        member_method,
 51                       Symbol*        instantiated_method_type) :
 52     _caller_ik(caller_ik),
 53     _invoked_name(invoked_name),
 54     _invoked_type(invoked_type),
 55     _method_type(method_type),
 56     _member_method(member_method),
 57     _instantiated_method_type(instantiated_method_type) {}
 58 
 59   void metaspace_pointers_do(MetaspaceClosure* it) {
 60     it->push(&_caller_ik);
 61     it->push(&_invoked_name);
 62     it->push(&_invoked_type);
 63     it->push(&_method_type);
 64     it->push(&_member_method);
 65     it->push(&_instantiated_method_type);
 66   }
 67 
 68   bool equals(LambdaProxyClassKey const& other) const {
 69     return _caller_ik == other._caller_ik &&
 70            _invoked_name == other._invoked_name &&
 71            _invoked_type == other._invoked_type &&
 72            _method_type == other._method_type &&
 73            _member_method == other._member_method &&
 74            _instantiated_method_type == other._instantiated_method_type;
 75   }
 76 
 77   unsigned int hash() const;
 78 
 79   static unsigned int dumptime_hash(Symbol* sym)  {
 80     if (sym == nullptr) {
 81       // _invoked_name maybe null
 82       return 0;
 83     }
 84     return java_lang_String::hash_code((const jbyte*)sym->bytes(), sym->utf8_length());
 85   }
 86 
 87   unsigned int dumptime_hash() const {
 88     return dumptime_hash(_caller_ik->name()) +
 89            dumptime_hash(_invoked_name) +
 90            dumptime_hash(_invoked_type) +
 91            dumptime_hash(_method_type) +
 92            dumptime_hash(_instantiated_method_type);
 93   }
 94 
 95   static inline unsigned int DUMPTIME_HASH(LambdaProxyClassKey const& key) {
 96     return (key.dumptime_hash());
 97   }
 98 
 99   static inline bool DUMPTIME_EQUALS(
100       LambdaProxyClassKey const& k1, LambdaProxyClassKey const& k2) {
101     return (k1.equals(k2));
102   }
103 
104   InstanceKlass* caller_ik()         const { return _caller_ik; }
105   Symbol* invoked_name()             const { return _invoked_name; }
106   Symbol* invoked_type()             const { return _invoked_type; }
107   Symbol* method_type()              const { return _method_type; }
108   Method* member_method()            const { return _member_method; }
109   Symbol* instantiated_method_type() const { return _instantiated_method_type; }
110 
111 #ifndef PRODUCT
112   void print_on(outputStream* st) const;
113 #endif
114 };
115 
116 class RunTimeLambdaProxyClassKey {
117   u4 _caller_ik;
118   u4 _invoked_name;
119   u4 _invoked_type;
120   u4 _method_type;
121   u4 _member_method;
122   u4 _instantiated_method_type;
123 
124   RunTimeLambdaProxyClassKey(u4 caller_ik,
125                              u4 invoked_name,
126                              u4 invoked_type,
127                              u4 method_type,
128                              u4 member_method,
129                              u4 instantiated_method_type) :
130     _caller_ik(caller_ik),
131     _invoked_name(invoked_name),
132     _invoked_type(invoked_type),
133     _method_type(method_type),
134     _member_method(member_method),
135     _instantiated_method_type(instantiated_method_type) {}
136 
137 public:
138   static RunTimeLambdaProxyClassKey init_for_dumptime(LambdaProxyClassKey& key) {
139     assert(ArchiveBuilder::is_active(), "sanity");
140     ArchiveBuilder* b = ArchiveBuilder::current();
141 
142     u4 caller_ik                = b->any_to_offset_u4(key.caller_ik());
143     u4 invoked_name             = b->any_to_offset_u4(key.invoked_name());
144     u4 invoked_type             = b->any_to_offset_u4(key.invoked_type());
145     u4 method_type              = b->any_to_offset_u4(key.method_type());
146     u4 member_method            = b->any_to_offset_u4(key.member_method());
147     u4 instantiated_method_type = b->any_to_offset_u4(key.instantiated_method_type());
148 
149     return RunTimeLambdaProxyClassKey(caller_ik, invoked_name, invoked_type, method_type,
150                                       member_method, instantiated_method_type);
151   }
152 
153   static RunTimeLambdaProxyClassKey init_for_runtime(InstanceKlass* caller_ik,
154                                                      Symbol*        invoked_name,
155                                                      Symbol*        invoked_type,
156                                                      Symbol*        method_type,
157                                                      Method*        member_method,
158                                                      Symbol*        instantiated_method_type) {
159     // All parameters must be in shared space, or else you'd get an assert in
160     // ArchiveUtils::to_offset().
161     return RunTimeLambdaProxyClassKey(ArchiveUtils::to_offset(caller_ik),
162                                       ArchiveUtils::to_offset(invoked_name),
163                                       ArchiveUtils::to_offset(invoked_type),
164                                       ArchiveUtils::to_offset(method_type),
165                                       ArchiveUtils::to_offset(member_method),
166                                       ArchiveUtils::to_offset(instantiated_method_type));
167   }
168 
169   unsigned int hash() const;
170   bool equals(RunTimeLambdaProxyClassKey const& other) const {
171     return _caller_ik == other._caller_ik &&
172            _invoked_name == other._invoked_name &&
173            _invoked_type == other._invoked_type &&
174            _method_type == other._method_type &&
175            _member_method == other._member_method &&
176            _instantiated_method_type == other._instantiated_method_type;
177   }
178 
179 #ifndef PRODUCT
180   void print_on(outputStream* st) const;
181 #endif
182 };
183 
184 class DumpTimeLambdaProxyClassInfo {
185 public:
186   GrowableArray<InstanceKlass*>* _proxy_klasses;
187   DumpTimeLambdaProxyClassInfo() : _proxy_klasses(nullptr) {}
188   DumpTimeLambdaProxyClassInfo& operator=(const DumpTimeLambdaProxyClassInfo&) = delete;
189   ~DumpTimeLambdaProxyClassInfo();
190 
191   void add_proxy_klass(InstanceKlass* proxy_klass) {
192     if (_proxy_klasses == nullptr) {
193       _proxy_klasses = new (mtClassShared) GrowableArray<InstanceKlass*>(5, mtClassShared);
194     }
195     assert(_proxy_klasses != nullptr, "sanity");
196     _proxy_klasses->append(proxy_klass);
197   }
198 
199   void metaspace_pointers_do(MetaspaceClosure* it) {
200     for (int i=0; i<_proxy_klasses->length(); i++) {
201       it->push(_proxy_klasses->adr_at(i));
202     }
203   }
204 };
205 
206 class RunTimeLambdaProxyClassInfo {
207   RunTimeLambdaProxyClassKey _key;
208   InstanceKlass* _proxy_klass_head;
209 public:
210   RunTimeLambdaProxyClassInfo(RunTimeLambdaProxyClassKey key, InstanceKlass* proxy_klass_head) :
211     _key(key), _proxy_klass_head(proxy_klass_head) {}
212 
213   InstanceKlass* proxy_klass_head() const { return _proxy_klass_head; }
214 
215   // Used by LambdaProxyClassDictionary to implement OffsetCompactHashtable::EQUALS
216   static inline bool EQUALS(
217        const RunTimeLambdaProxyClassInfo* value, RunTimeLambdaProxyClassKey* key, int len_unused) {
218     return (value->_key.equals(*key));
219   }
220   void init(LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info);
221 
222   unsigned int hash() const {
223     return _key.hash();
224   }
225   RunTimeLambdaProxyClassKey key() const {
226     return _key;
227   }
228 #ifndef PRODUCT
229   void print_on(outputStream* st) const;
230 #endif
231 };
232 
233 class DumpTimeLambdaProxyClassDictionary
234   : public ResourceHashtable<LambdaProxyClassKey,
235                              DumpTimeLambdaProxyClassInfo,
236                              137, // prime number
237                              AnyObj::C_HEAP,
238                              mtClassShared,
239                              LambdaProxyClassKey::DUMPTIME_HASH,
240                              LambdaProxyClassKey::DUMPTIME_EQUALS> {
241 public:
242   DumpTimeLambdaProxyClassDictionary() : _count(0) {}
243   int _count;
244 };
245 
246 class LambdaProxyClassDictionary : public OffsetCompactHashtable<
247   RunTimeLambdaProxyClassKey*,
248   const RunTimeLambdaProxyClassInfo*,
249   RunTimeLambdaProxyClassInfo::EQUALS> {};
250 
251 #endif // SHARE_CDS_LAMBDAPROXYCLASSINFO_HPP