1 /* 2 * Copyright (c) 2017, 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 #include "precompiled.hpp" 26 #include "classfile/classLoaderDataGraph.hpp" 27 #include "classfile/dictionary.hpp" 28 #include "classfile/protectionDomainCache.hpp" 29 #include "classfile/systemDictionary.hpp" 30 #include "logging/log.hpp" 31 #include "logging/logStream.hpp" 32 #include "memory/iterator.hpp" 33 #include "memory/resourceArea.hpp" 34 #include "oops/oop.inline.hpp" 35 #include "oops/weakHandle.inline.hpp" 36 #include "utilities/hashtable.inline.hpp" 37 38 unsigned int ProtectionDomainCacheTable::compute_hash(Handle protection_domain) { 39 // Identity hash can safepoint, so keep protection domain in a Handle. 40 return (unsigned int)(protection_domain->identity_hash()); 41 } 42 43 int ProtectionDomainCacheTable::index_for(Handle protection_domain) { 44 return hash_to_index(compute_hash(protection_domain)); 45 } 46 47 ProtectionDomainCacheTable::ProtectionDomainCacheTable(int table_size) 48 : Hashtable<WeakHandle<vm_class_loader_data>, mtClass>(table_size, sizeof(ProtectionDomainCacheEntry)) 49 { _dead_entries = false; 50 _total_oops_removed = 0; 51 } 52 53 void ProtectionDomainCacheTable::trigger_cleanup() { 54 MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag); 55 _dead_entries = true; 56 Service_lock->notify_all(); 57 } 58 59 class CleanProtectionDomainEntries : public CLDClosure { 60 void do_cld(ClassLoaderData* data) { 61 Dictionary* dictionary = data->dictionary(); 62 if (dictionary != NULL) { 63 dictionary->clean_cached_protection_domains(); 64 } 65 } 66 }; 67 68 void ProtectionDomainCacheTable::unlink() { 69 { 70 // First clean cached pd lists in loaded CLDs 71 // It's unlikely, but some loaded classes in a dictionary might 72 // point to a protection_domain that has been unloaded. 73 // The dictionary pd_set points at entries in the ProtectionDomainCacheTable. 74 MutexLocker ml(ClassLoaderDataGraph_lock); 75 MutexLocker mldict(SystemDictionary_lock); // need both. 76 CleanProtectionDomainEntries clean; 77 ClassLoaderDataGraph::loaded_cld_do(&clean); 78 } 79 80 MutexLocker ml(SystemDictionary_lock); 81 int oops_removed = 0; 82 for (int i = 0; i < table_size(); ++i) { 83 ProtectionDomainCacheEntry** p = bucket_addr(i); 84 ProtectionDomainCacheEntry* entry = bucket(i); 85 while (entry != NULL) { 86 oop pd = entry->object_no_keepalive(); 87 if (pd != NULL) { 88 p = entry->next_addr(); 89 } else { 90 oops_removed++; 91 LogTarget(Debug, protectiondomain, table) lt; 92 if (lt.is_enabled()) { 93 LogStream ls(lt); 94 ls.print_cr("protection domain unlinked at %d", i); 95 } 96 entry->literal().release(); 97 *p = entry->next(); 98 free_entry(entry); 99 } 100 entry = *p; 101 } 102 } 103 _total_oops_removed += oops_removed; 104 _dead_entries = false; 105 } 106 107 void ProtectionDomainCacheTable::print_on(outputStream* st) const { 108 assert_locked_or_safepoint(SystemDictionary_lock); 109 st->print_cr("Protection domain cache table (table_size=%d, classes=%d)", 110 table_size(), number_of_entries()); 111 for (int index = 0; index < table_size(); index++) { 112 for (ProtectionDomainCacheEntry* probe = bucket(index); 113 probe != NULL; 114 probe = probe->next()) { 115 st->print_cr("%4d: protection_domain: " PTR_FORMAT, index, p2i(probe->object_no_keepalive())); 116 } 117 } 118 } 119 120 void ProtectionDomainCacheTable::verify() { 121 verify_table<ProtectionDomainCacheEntry>("Protection Domain Table"); 122 } 123 124 oop ProtectionDomainCacheEntry::object() { 125 return literal().resolve(); 126 } 127 128 oop ProtectionDomainEntry::object() { 129 return _pd_cache->object(); 130 } 131 132 // The object_no_keepalive() call peeks at the phantomly reachable oop without 133 // keeping it alive. This is okay to do in the VM thread state if it is not 134 // leaked out to become strongly reachable. 135 oop ProtectionDomainCacheEntry::object_no_keepalive() { 136 return literal().peek(); 137 } 138 139 oop ProtectionDomainEntry::object_no_keepalive() { 140 return _pd_cache->object_no_keepalive(); 141 } 142 143 void ProtectionDomainCacheEntry::verify() { 144 guarantee(object_no_keepalive() == NULL || oopDesc::is_oop(object_no_keepalive()), "must be an oop"); 145 } 146 147 ProtectionDomainCacheEntry* ProtectionDomainCacheTable::get(Handle protection_domain) { 148 unsigned int hash = compute_hash(protection_domain); 149 int index = hash_to_index(hash); 150 151 ProtectionDomainCacheEntry* entry = find_entry(index, protection_domain); 152 if (entry == NULL) { 153 entry = add_entry(index, hash, protection_domain); 154 } 155 // keep entry alive 156 (void)entry->object(); 157 return entry; 158 } 159 160 ProtectionDomainCacheEntry* ProtectionDomainCacheTable::find_entry(int index, Handle protection_domain) { 161 assert_locked_or_safepoint(SystemDictionary_lock); 162 for (ProtectionDomainCacheEntry* e = bucket(index); e != NULL; e = e->next()) { 163 if (e->object_no_keepalive() == protection_domain()) { 164 return e; 165 } 166 } 167 168 return NULL; 169 } 170 171 ProtectionDomainCacheEntry* ProtectionDomainCacheTable::add_entry(int index, unsigned int hash, Handle protection_domain) { 172 assert_locked_or_safepoint(SystemDictionary_lock); 173 assert(index == index_for(protection_domain), "incorrect index?"); 174 assert(find_entry(index, protection_domain) == NULL, "no double entry"); 175 176 LogTarget(Debug, protectiondomain, table) lt; 177 if (lt.is_enabled()) { 178 LogStream ls(lt); 179 ls.print("protection domain added "); 180 protection_domain->print_value_on(&ls); 181 ls.cr(); 182 } 183 WeakHandle<vm_class_loader_data> w = WeakHandle<vm_class_loader_data>::create(protection_domain); 184 ProtectionDomainCacheEntry* p = new_entry(hash, w); 185 Hashtable<WeakHandle<vm_class_loader_data>, mtClass>::add_entry(index, p); 186 return p; 187 }