Skip to content

Commit fcc0cf9

Browse files
committed
8292375: Convert ProtectionDomainCacheTable to ResourceHashtable
Reviewed-by: dholmes, iklam
1 parent 6fc58b8 commit fcc0cf9

File tree

9 files changed

+133
-202
lines changed

9 files changed

+133
-202
lines changed

src/hotspot/share/classfile/dictionary.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,9 @@ bool DictionaryEntry::contains_protection_domain(oop protection_domain) const {
166166
void DictionaryEntry::add_protection_domain(ClassLoaderData* loader_data, Handle protection_domain) {
167167
assert_lock_strong(SystemDictionary_lock);
168168
if (!contains_protection_domain(protection_domain())) {
169-
ProtectionDomainCacheEntry* entry = SystemDictionary::pd_cache_table()->get(protection_domain);
169+
WeakHandle obj = ProtectionDomainCacheTable::add_if_absent(protection_domain);
170170
// Additions and deletions hold the SystemDictionary_lock, readers are lock-free
171-
ProtectionDomainEntry* new_head = new ProtectionDomainEntry(entry, _pd_set);
171+
ProtectionDomainEntry* new_head = new ProtectionDomainEntry(obj, _pd_set);
172172
release_set_pd_set(new_head);
173173
}
174174
LogTarget(Trace, protectiondomain) lt;

src/hotspot/share/classfile/protectionDomainCache.cpp

+78-89
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -35,23 +35,28 @@
3535
#include "oops/oop.inline.hpp"
3636
#include "oops/weakHandle.inline.hpp"
3737
#include "runtime/atomic.hpp"
38+
#include "runtime/mutexLocker.hpp"
3839
#include "utilities/growableArray.hpp"
39-
#include "utilities/hashtable.inline.hpp"
40+
#include "utilities/resourceHash.hpp"
4041

41-
unsigned int ProtectionDomainCacheTable::compute_hash(Handle protection_domain) {
42-
// Identity hash can safepoint, so keep protection domain in a Handle.
43-
return (unsigned int)(protection_domain->identity_hash());
42+
unsigned int ProtectionDomainCacheTable::compute_hash(const WeakHandle& protection_domain) {
43+
// The protection domain in the hash computation is passed from a Handle so cannot resolve to null.
44+
assert(protection_domain.peek() != nullptr, "Must be live");
45+
return (unsigned int)(protection_domain.resolve()->identity_hash());
4446
}
4547

46-
int ProtectionDomainCacheTable::index_for(Handle protection_domain) {
47-
return hash_to_index(compute_hash(protection_domain));
48+
bool ProtectionDomainCacheTable::equals(const WeakHandle& protection_domain1, const WeakHandle& protection_domain2) {
49+
return protection_domain1.peek() == protection_domain2.peek();
4850
}
4951

50-
ProtectionDomainCacheTable::ProtectionDomainCacheTable(int table_size)
51-
: Hashtable<WeakHandle, mtClass>(table_size, sizeof(ProtectionDomainCacheEntry))
52-
{ _dead_entries = false;
53-
_total_oops_removed = 0;
54-
}
52+
// WeakHandle is both the key and the value. We need it as the key to compare the oops that each point to
53+
// for equality. We need it as the value to return the one that already exists to link in the DictionaryEntry.
54+
ResourceHashtable<WeakHandle, WeakHandle, 1009, ResourceObj::C_HEAP, mtClass,
55+
ProtectionDomainCacheTable::compute_hash,
56+
ProtectionDomainCacheTable::equals> _pd_cache_table;
57+
58+
bool ProtectionDomainCacheTable::_dead_entries = false;
59+
int ProtectionDomainCacheTable::_total_oops_removed = 0;
5560

5661
void ProtectionDomainCacheTable::trigger_cleanup() {
5762
MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
@@ -129,107 +134,91 @@ void ProtectionDomainCacheTable::unlink() {
129134
// Purge any deleted entries outside of the SystemDictionary_lock.
130135
purge_deleted_entries();
131136

137+
// Reacquire the lock to remove entries from the hashtable.
132138
MutexLocker ml(SystemDictionary_lock);
133-
int oops_removed = 0;
134-
for (int i = 0; i < table_size(); ++i) {
135-
ProtectionDomainCacheEntry** p = bucket_addr(i);
136-
ProtectionDomainCacheEntry* entry = bucket(i);
137-
while (entry != NULL) {
138-
oop pd = entry->object_no_keepalive();
139-
if (pd != NULL) {
140-
p = entry->next_addr();
141-
} else {
142-
oops_removed++;
139+
140+
struct Deleter {
141+
int _oops_removed;
142+
Deleter() : _oops_removed(0) {}
143+
144+
bool do_entry(WeakHandle& key, WeakHandle& value) {
145+
oop pd = value.peek();
146+
if (value.peek() == nullptr) {
147+
_oops_removed++;
143148
LogTarget(Debug, protectiondomain, table) lt;
144149
if (lt.is_enabled()) {
145150
LogStream ls(lt);
146-
ls.print_cr("protection domain unlinked at %d", i);
151+
ls.print_cr("protection domain unlinked %d", _oops_removed);
147152
}
148-
entry->literal().release(Universe::vm_weak());
149-
*p = entry->next();
150-
free_entry(entry);
153+
value.release(Universe::vm_weak());
154+
return true;
155+
} else {
156+
return false;
151157
}
152-
entry = *p;
153158
}
154-
}
155-
_total_oops_removed += oops_removed;
159+
};
160+
161+
Deleter deleter;
162+
_pd_cache_table.unlink(&deleter);
163+
164+
_total_oops_removed += deleter._oops_removed;
156165
_dead_entries = false;
157166
}
158167

159-
void ProtectionDomainCacheTable::print_on(outputStream* st) const {
168+
void ProtectionDomainCacheTable::print_on(outputStream* st) {
160169
assert_locked_or_safepoint(SystemDictionary_lock);
161-
st->print_cr("Protection domain cache table (table_size=%d, classes=%d)",
162-
table_size(), number_of_entries());
163-
for (int index = 0; index < table_size(); index++) {
164-
for (ProtectionDomainCacheEntry* probe = bucket(index);
165-
probe != NULL;
166-
probe = probe->next()) {
167-
st->print_cr("%4d: protection_domain: " PTR_FORMAT, index, p2i(probe->object_no_keepalive()));
168-
}
169-
}
170+
auto printer = [&] (WeakHandle& key, WeakHandle& value) {
171+
st->print_cr(" protection_domain: " PTR_FORMAT, p2i(value.peek()));
172+
};
173+
st->print_cr("Protection domain cache table (table_size=%d, protection domains=%d)",
174+
_pd_cache_table.table_size(), _pd_cache_table.number_of_entries());
175+
_pd_cache_table.iterate_all(printer);
170176
}
171177

172178
void ProtectionDomainCacheTable::verify() {
173-
verify_table<ProtectionDomainCacheEntry>("Protection Domain Table");
174-
}
175-
176-
oop ProtectionDomainCacheEntry::object() {
177-
return literal().resolve();
179+
auto verifier = [&] (WeakHandle& key, WeakHandle& value) {
180+
guarantee(value.peek() == nullptr || oopDesc::is_oop(value.peek()), "must be an oop");
181+
};
182+
_pd_cache_table.iterate_all(verifier);
178183
}
179184

180185
// The object_no_keepalive() call peeks at the phantomly reachable oop without
181-
// keeping it alive. This is okay to do in the VM thread state if it is not
182-
// leaked out to become strongly reachable.
183-
oop ProtectionDomainCacheEntry::object_no_keepalive() {
184-
return literal().peek();
185-
}
186-
186+
// keeping it alive. This is used for traversing DictionaryEntry pd_set.
187187
oop ProtectionDomainEntry::object_no_keepalive() {
188-
return _pd_cache->object_no_keepalive();
189-
}
190-
191-
void ProtectionDomainCacheEntry::verify() {
192-
guarantee(object_no_keepalive() == NULL || oopDesc::is_oop(object_no_keepalive()), "must be an oop");
188+
return _object.peek();
193189
}
194190

195-
ProtectionDomainCacheEntry* ProtectionDomainCacheTable::get(Handle protection_domain) {
196-
unsigned int hash = compute_hash(protection_domain);
197-
int index = hash_to_index(hash);
198-
199-
ProtectionDomainCacheEntry* entry = find_entry(index, protection_domain);
200-
if (entry == NULL) {
201-
entry = add_entry(index, hash, protection_domain);
202-
}
203-
// keep entry alive
204-
(void)entry->object();
205-
return entry;
206-
}
207-
208-
ProtectionDomainCacheEntry* ProtectionDomainCacheTable::find_entry(int index, Handle protection_domain) {
191+
WeakHandle ProtectionDomainCacheTable::add_if_absent(Handle protection_domain) {
209192
assert_locked_or_safepoint(SystemDictionary_lock);
210-
for (ProtectionDomainCacheEntry* e = bucket(index); e != NULL; e = e->next()) {
211-
if (e->object_no_keepalive() == protection_domain()) {
212-
return e;
193+
WeakHandle w(Universe::vm_weak(), protection_domain);
194+
bool created;
195+
WeakHandle* wk = _pd_cache_table.put_if_absent(w, w, &created);
196+
if (!created) {
197+
// delete the one created since we already had it in the table
198+
w.release(Universe::vm_weak());
199+
} else {
200+
LogTarget(Debug, protectiondomain, table) lt;
201+
if (lt.is_enabled()) {
202+
LogStream ls(lt);
203+
ls.print("protection domain added ");
204+
protection_domain->print_value_on(&ls);
205+
ls.cr();
213206
}
214207
}
208+
// Keep entry alive
209+
(void)wk->resolve();
210+
return *wk;
211+
}
215212

216-
return NULL;
213+
void ProtectionDomainCacheTable::print_table_statistics(outputStream* st) {
214+
auto size = [&] (WeakHandle& key, WeakHandle& value) {
215+
// The only storage is in OopStorage for an oop
216+
return sizeof(oop);
217+
};
218+
TableStatistics ts = _pd_cache_table.statistics_calculate(size);
219+
ts.print(st, "ProtectionDomainCacheTable");
217220
}
218221

219-
ProtectionDomainCacheEntry* ProtectionDomainCacheTable::add_entry(int index, unsigned int hash, Handle protection_domain) {
220-
assert_locked_or_safepoint(SystemDictionary_lock);
221-
assert(index == index_for(protection_domain), "incorrect index?");
222-
assert(find_entry(index, protection_domain) == NULL, "no double entry");
223-
224-
LogTarget(Debug, protectiondomain, table) lt;
225-
if (lt.is_enabled()) {
226-
LogStream ls(lt);
227-
ls.print("protection domain added ");
228-
protection_domain->print_value_on(&ls);
229-
ls.cr();
230-
}
231-
WeakHandle w(Universe::vm_weak(), protection_domain);
232-
ProtectionDomainCacheEntry* p = new_entry(hash, w);
233-
Hashtable<WeakHandle, mtClass>::add_entry(index, p);
234-
return p;
222+
int ProtectionDomainCacheTable::number_of_entries() {
223+
return _pd_cache_table.number_of_entries();
235224
}

src/hotspot/share/classfile/protectionDomainCache.hpp

+20-65
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -28,88 +28,43 @@
2828
#include "oops/oop.hpp"
2929
#include "oops/weakHandle.hpp"
3030
#include "runtime/atomic.hpp"
31-
#include "utilities/hashtable.hpp"
3231

33-
// This class caches the approved protection domains that can access loaded classes.
34-
// Dictionary entry pd_set point to entries in this hashtable. Please refer
35-
// to dictionary.hpp pd_set for more information about how protection domain entries
36-
// are used.
37-
// This table is walked during GC, rather than the class loader data graph dictionaries.
38-
class ProtectionDomainCacheEntry : public HashtableEntry<WeakHandle, mtClass> {
39-
friend class VMStructs;
40-
public:
41-
oop object();
42-
oop object_no_keepalive();
43-
44-
ProtectionDomainCacheEntry* next() {
45-
return (ProtectionDomainCacheEntry*)HashtableEntry<WeakHandle, mtClass>::next();
46-
}
47-
48-
ProtectionDomainCacheEntry** next_addr() {
49-
return (ProtectionDomainCacheEntry**)HashtableEntry<WeakHandle, mtClass>::next_addr();
50-
}
51-
52-
void verify();
53-
};
54-
55-
// The ProtectionDomainCacheTable contains all protection domain oops. The
56-
// dictionary entries reference its entries instead of having references to oops
57-
// directly.
58-
// This is used to speed up system dictionary iteration: the oops in the
59-
// protection domain are the only ones referring the Java heap. So when there is
60-
// need to update these, instead of going over every entry of the system dictionary,
61-
// we only need to iterate over this set.
32+
// The ProtectionDomainCacheTable maps all java.security.ProtectionDomain objects that are
33+
// registered by DictionaryEntry::add_protection_domain() to a unique WeakHandle.
6234
// The amount of different protection domains used is typically magnitudes smaller
6335
// than the number of system dictionary entries (loaded classes).
64-
class ProtectionDomainCacheTable : public Hashtable<WeakHandle, mtClass> {
65-
ProtectionDomainCacheEntry* bucket(int i) const {
66-
return (ProtectionDomainCacheEntry*) Hashtable<WeakHandle, mtClass>::bucket(i);
67-
}
68-
69-
// The following method is not MT-safe and must be done under lock.
70-
ProtectionDomainCacheEntry** bucket_addr(int i) {
71-
return (ProtectionDomainCacheEntry**) Hashtable<WeakHandle, mtClass>::bucket_addr(i);
72-
}
73-
74-
ProtectionDomainCacheEntry* new_entry(unsigned int hash, WeakHandle protection_domain) {
75-
ProtectionDomainCacheEntry* entry = (ProtectionDomainCacheEntry*)
76-
Hashtable<WeakHandle, mtClass>::new_entry(hash, protection_domain);
77-
return entry;
78-
}
79-
80-
static unsigned int compute_hash(Handle protection_domain);
81-
82-
int index_for(Handle protection_domain);
83-
ProtectionDomainCacheEntry* add_entry(int index, unsigned int hash, Handle protection_domain);
84-
ProtectionDomainCacheEntry* find_entry(int index, Handle protection_domain);
36+
class ProtectionDomainCacheTable : public AllStatic {
8537

86-
bool _dead_entries;
87-
int _total_oops_removed;
38+
static bool _dead_entries;
39+
static int _total_oops_removed;
8840

8941
public:
90-
ProtectionDomainCacheTable(int table_size);
91-
ProtectionDomainCacheEntry* get(Handle protection_domain);
42+
static unsigned int compute_hash(const WeakHandle& protection_domain);
43+
static bool equals(const WeakHandle& protection_domain1, const WeakHandle& protection_domain2);
9244

93-
void unlink();
45+
static WeakHandle add_if_absent(Handle protection_domain);
46+
static void unlink();
9447

95-
void print_on(outputStream* st) const;
96-
void verify();
48+
static void print_on(outputStream* st);
49+
static void verify();
9750

98-
bool has_work() { return _dead_entries; }
99-
void trigger_cleanup();
51+
static bool has_work() { return _dead_entries; }
52+
static void trigger_cleanup();
10053

101-
int removed_entries_count() { return _total_oops_removed; };
54+
static int removed_entries_count() { return _total_oops_removed; };
55+
static int number_of_entries();
56+
static void print_table_statistics(outputStream* st);
10257
};
10358

10459

10560
// This describes the linked list protection domain for each DictionaryEntry in pd_set.
10661
class ProtectionDomainEntry :public CHeapObj<mtClass> {
107-
ProtectionDomainCacheEntry* _pd_cache;
62+
WeakHandle _object;
10863
ProtectionDomainEntry* volatile _next;
10964
public:
11065

111-
ProtectionDomainEntry(ProtectionDomainCacheEntry* pd_cache,
112-
ProtectionDomainEntry* head) : _pd_cache(pd_cache), _next(head) {}
66+
ProtectionDomainEntry(WeakHandle obj,
67+
ProtectionDomainEntry* head) : _object(obj), _next(head) {}
11368

11469
ProtectionDomainEntry* next_acquire() { return Atomic::load_acquire(&_next); }
11570
void release_set_next(ProtectionDomainEntry* entry) { Atomic::release_store(&_next, entry); }

0 commit comments

Comments
 (0)