1 | /* |
2 | * Copyright (c) 2003, 2019, 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_CLASSFILE_DICTIONARY_HPP |
26 | #define SHARE_CLASSFILE_DICTIONARY_HPP |
27 | |
28 | #include "classfile/protectionDomainCache.hpp" |
29 | #include "classfile/systemDictionary.hpp" |
30 | #include "oops/instanceKlass.hpp" |
31 | #include "oops/oop.hpp" |
32 | #include "utilities/hashtable.hpp" |
33 | #include "utilities/ostream.hpp" |
34 | |
35 | class DictionaryEntry; |
36 | class BoolObjectClosure; |
37 | |
38 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
39 | // The data structure for the class loader data dictionaries. |
40 | |
41 | class Dictionary : public Hashtable<InstanceKlass*, mtClass> { |
42 | friend class VMStructs; |
43 | |
44 | static bool _some_dictionary_needs_resizing; |
45 | bool _resizable; |
46 | bool _needs_resizing; |
47 | void check_if_needs_resize(); |
48 | |
49 | ClassLoaderData* _loader_data; // backpointer to owning loader |
50 | ClassLoaderData* loader_data() const { return _loader_data; } |
51 | |
52 | DictionaryEntry* get_entry(int index, unsigned int hash, Symbol* name); |
53 | |
54 | public: |
55 | Dictionary(ClassLoaderData* loader_data, int table_size, bool resizable = false); |
56 | Dictionary(ClassLoaderData* loader_data, int table_size, HashtableBucket<mtClass>* t, int number_of_entries, bool resizable = false); |
57 | ~Dictionary(); |
58 | |
59 | static bool does_any_dictionary_needs_resizing(); |
60 | bool resize_if_needed(); |
61 | |
62 | void add_klass(unsigned int hash, Symbol* class_name, InstanceKlass* obj); |
63 | |
64 | InstanceKlass* find_class(int index, unsigned int hash, Symbol* name); |
65 | |
66 | void classes_do(void f(InstanceKlass*)); |
67 | void classes_do(void f(InstanceKlass*, TRAPS), TRAPS); |
68 | void all_entries_do(KlassClosure* closure); |
69 | void classes_do(MetaspaceClosure* it); |
70 | |
71 | void clean_cached_protection_domains(); |
72 | |
73 | // Protection domains |
74 | InstanceKlass* find(unsigned int hash, Symbol* name, Handle protection_domain); |
75 | bool is_valid_protection_domain(unsigned int hash, |
76 | Symbol* name, |
77 | Handle protection_domain); |
78 | void add_protection_domain(int index, unsigned int hash, |
79 | InstanceKlass* klass, |
80 | Handle protection_domain, TRAPS); |
81 | |
82 | void print_on(outputStream* st) const; |
83 | void verify(); |
84 | |
85 | private: |
86 | DictionaryEntry* new_entry(unsigned int hash, InstanceKlass* klass); |
87 | |
88 | DictionaryEntry* bucket(int i) const { |
89 | return (DictionaryEntry*)Hashtable<InstanceKlass*, mtClass>::bucket(i); |
90 | } |
91 | |
92 | // The following method is not MT-safe and must be done under lock. |
93 | DictionaryEntry** bucket_addr(int i) { |
94 | return (DictionaryEntry**)Hashtable<InstanceKlass*, mtClass>::bucket_addr(i); |
95 | } |
96 | |
97 | void add_entry(int index, DictionaryEntry* new_entry) { |
98 | Hashtable<InstanceKlass*, mtClass>::add_entry(index, (HashtableEntry<InstanceKlass*, mtClass>*)new_entry); |
99 | } |
100 | |
101 | void unlink_entry(DictionaryEntry* entry) { |
102 | Hashtable<InstanceKlass*, mtClass>::unlink_entry((HashtableEntry<InstanceKlass*, mtClass>*)entry); |
103 | } |
104 | |
105 | void free_entry(DictionaryEntry* entry); |
106 | }; |
107 | |
108 | // An entry in the class loader data dictionaries, this describes a class as |
109 | // { InstanceKlass*, protection_domain }. |
110 | |
111 | class DictionaryEntry : public HashtableEntry<InstanceKlass*, mtClass> { |
112 | friend class VMStructs; |
113 | private: |
114 | // Contains the set of approved protection domains that can access |
115 | // this dictionary entry. |
116 | // |
117 | // This protection domain set is a set of tuples: |
118 | // |
119 | // (InstanceKlass C, initiating class loader ICL, Protection Domain PD) |
120 | // |
121 | // [Note that C.protection_domain(), which is stored in the java.lang.Class |
122 | // mirror of C, is NOT the same as PD] |
123 | // |
124 | // If such an entry (C, ICL, PD) exists in the table, it means that |
125 | // it is okay for a class Foo to reference C, where |
126 | // |
127 | // Foo.protection_domain() == PD, and |
128 | // Foo's defining class loader == ICL |
129 | // |
130 | // The usage of the PD set can be seen in SystemDictionary::validate_protection_domain() |
131 | // It is essentially a cache to avoid repeated Java up-calls to |
132 | // ClassLoader.checkPackageAccess(). |
133 | // |
134 | ProtectionDomainEntry* volatile _pd_set; |
135 | |
136 | public: |
137 | // Tells whether a protection is in the approved set. |
138 | bool contains_protection_domain(oop protection_domain) const; |
139 | // Adds a protection domain to the approved set. |
140 | void add_protection_domain(Dictionary* dict, Handle protection_domain); |
141 | |
142 | InstanceKlass* instance_klass() const { return literal(); } |
143 | InstanceKlass** klass_addr() { return (InstanceKlass**)literal_addr(); } |
144 | |
145 | DictionaryEntry* next() const { |
146 | return (DictionaryEntry*)HashtableEntry<InstanceKlass*, mtClass>::next(); |
147 | } |
148 | |
149 | DictionaryEntry** next_addr() { |
150 | return (DictionaryEntry**)HashtableEntry<InstanceKlass*, mtClass>::next_addr(); |
151 | } |
152 | |
153 | ProtectionDomainEntry* pd_set() const { return _pd_set; } |
154 | void set_pd_set(ProtectionDomainEntry* new_head) { _pd_set = new_head; } |
155 | |
156 | // Tells whether the initiating class' protection domain can access the klass in this entry |
157 | bool is_valid_protection_domain(Handle protection_domain) { |
158 | if (!ProtectionDomainVerification) return true; |
159 | if (!SystemDictionary::has_checkPackageAccess()) return true; |
160 | |
161 | return protection_domain() == NULL |
162 | ? true |
163 | : contains_protection_domain(protection_domain()); |
164 | } |
165 | |
166 | void verify_protection_domain_set(); |
167 | |
168 | bool equals(const Symbol* class_name) const { |
169 | InstanceKlass* klass = (InstanceKlass*)literal(); |
170 | return (klass->name() == class_name); |
171 | } |
172 | |
173 | void print_count(outputStream *st); |
174 | void verify(); |
175 | }; |
176 | |
177 | // Entry in a SymbolPropertyTable, mapping a single Symbol* |
178 | // to a managed and an unmanaged pointer. |
179 | class SymbolPropertyEntry : public HashtableEntry<Symbol*, mtSymbol> { |
180 | friend class VMStructs; |
181 | private: |
182 | intptr_t _symbol_mode; // secondary key |
183 | Method* _method; |
184 | oop _method_type; |
185 | |
186 | public: |
187 | Symbol* symbol() const { return literal(); } |
188 | |
189 | intptr_t symbol_mode() const { return _symbol_mode; } |
190 | void set_symbol_mode(intptr_t m) { _symbol_mode = m; } |
191 | |
192 | Method* method() const { return _method; } |
193 | void set_method(Method* p) { _method = p; } |
194 | |
195 | oop method_type() const { return _method_type; } |
196 | oop* method_type_addr() { return &_method_type; } |
197 | void set_method_type(oop p) { _method_type = p; } |
198 | |
199 | SymbolPropertyEntry* next() const { |
200 | return (SymbolPropertyEntry*)HashtableEntry<Symbol*, mtSymbol>::next(); |
201 | } |
202 | |
203 | SymbolPropertyEntry** next_addr() { |
204 | return (SymbolPropertyEntry**)HashtableEntry<Symbol*, mtSymbol>::next_addr(); |
205 | } |
206 | |
207 | void print_entry(outputStream* st) const { |
208 | symbol()->print_value_on(st); |
209 | st->print("/mode=" INTX_FORMAT, symbol_mode()); |
210 | st->print(" -> " ); |
211 | bool printed = false; |
212 | if (method() != NULL) { |
213 | method()->print_value_on(st); |
214 | printed = true; |
215 | } |
216 | if (method_type() != NULL) { |
217 | if (printed) st->print(" and " ); |
218 | st->print(INTPTR_FORMAT, p2i((void *)method_type())); |
219 | printed = true; |
220 | } |
221 | st->print_cr(printed ? "" : "(empty)" ); |
222 | } |
223 | }; |
224 | |
225 | // A system-internal mapping of symbols to pointers, both managed |
226 | // and unmanaged. Used to record the auto-generation of each method |
227 | // MethodHandle.invoke(S)T, for all signatures (S)T. |
228 | class SymbolPropertyTable : public Hashtable<Symbol*, mtSymbol> { |
229 | friend class VMStructs; |
230 | private: |
231 | // The following method is not MT-safe and must be done under lock. |
232 | SymbolPropertyEntry** bucket_addr(int i) { |
233 | return (SymbolPropertyEntry**) Hashtable<Symbol*, mtSymbol>::bucket_addr(i); |
234 | } |
235 | |
236 | void add_entry(int index, SymbolPropertyEntry* new_entry) { |
237 | ShouldNotReachHere(); |
238 | } |
239 | void set_entry(int index, SymbolPropertyEntry* new_entry) { |
240 | ShouldNotReachHere(); |
241 | } |
242 | |
243 | SymbolPropertyEntry* new_entry(unsigned int hash, Symbol* symbol, intptr_t symbol_mode) { |
244 | SymbolPropertyEntry* entry = (SymbolPropertyEntry*) Hashtable<Symbol*, mtSymbol>::new_entry(hash, symbol); |
245 | // Hashtable with Symbol* literal must increment and decrement refcount. |
246 | symbol->increment_refcount(); |
247 | entry->set_symbol_mode(symbol_mode); |
248 | entry->set_method(NULL); |
249 | entry->set_method_type(NULL); |
250 | return entry; |
251 | } |
252 | |
253 | public: |
254 | SymbolPropertyTable(int table_size); |
255 | SymbolPropertyTable(int table_size, HashtableBucket<mtSymbol>* t, int number_of_entries); |
256 | |
257 | void free_entry(SymbolPropertyEntry* entry) { |
258 | // decrement Symbol refcount here because hashtable doesn't. |
259 | entry->literal()->decrement_refcount(); |
260 | Hashtable<Symbol*, mtSymbol>::free_entry(entry); |
261 | } |
262 | |
263 | unsigned int compute_hash(Symbol* sym, intptr_t symbol_mode) { |
264 | // Use the regular identity_hash. |
265 | return Hashtable<Symbol*, mtSymbol>::compute_hash(sym) ^ symbol_mode; |
266 | } |
267 | |
268 | int index_for(Symbol* name, intptr_t symbol_mode) { |
269 | return hash_to_index(compute_hash(name, symbol_mode)); |
270 | } |
271 | |
272 | // need not be locked; no state change |
273 | SymbolPropertyEntry* find_entry(int index, unsigned int hash, Symbol* name, intptr_t name_mode); |
274 | |
275 | // must be done under SystemDictionary_lock |
276 | SymbolPropertyEntry* add_entry(int index, unsigned int hash, Symbol* name, intptr_t name_mode); |
277 | |
278 | // GC support |
279 | void oops_do(OopClosure* f); |
280 | |
281 | void methods_do(void f(Method*)); |
282 | |
283 | void verify(); |
284 | |
285 | SymbolPropertyEntry* bucket(int i) { |
286 | return (SymbolPropertyEntry*) Hashtable<Symbol*, mtSymbol>::bucket(i); |
287 | } |
288 | }; |
289 | #endif // SHARE_CLASSFILE_DICTIONARY_HPP |
290 | |