mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
8178336: Unnecessary SystemDictionary walk for Protection domain liveness
Remove system dictionary walk and pass strong closure for !ClassUnloading Reviewed-by: jiangli, iklam
This commit is contained in:
parent
9b2ddab04f
commit
3784f04568
4 changed files with 278 additions and 303 deletions
|
@ -26,6 +26,7 @@
|
||||||
#include "classfile/classLoaderData.inline.hpp"
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
#include "classfile/sharedClassUtil.hpp"
|
#include "classfile/sharedClassUtil.hpp"
|
||||||
#include "classfile/dictionary.hpp"
|
#include "classfile/dictionary.hpp"
|
||||||
|
#include "classfile/protectionDomainCache.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "classfile/systemDictionaryShared.hpp"
|
#include "classfile/systemDictionaryShared.hpp"
|
||||||
#include "memory/iterator.hpp"
|
#include "memory/iterator.hpp"
|
||||||
|
@ -147,7 +148,6 @@ void Dictionary::do_unloading() {
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
|
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
|
||||||
|
|
||||||
// Remove unloadable entries and classes from system dictionary
|
// Remove unloadable entries and classes from system dictionary
|
||||||
// The placeholder array has been handled in always_strong_oops_do.
|
|
||||||
DictionaryEntry* probe = NULL;
|
DictionaryEntry* probe = NULL;
|
||||||
for (int index = 0; index < table_size(); index++) {
|
for (int index = 0; index < table_size(); index++) {
|
||||||
for (DictionaryEntry** p = bucket_addr(index); *p != NULL; ) {
|
for (DictionaryEntry** p = bucket_addr(index); *p != NULL; ) {
|
||||||
|
@ -157,7 +157,7 @@ void Dictionary::do_unloading() {
|
||||||
|
|
||||||
InstanceKlass* ik = InstanceKlass::cast(e);
|
InstanceKlass* ik = InstanceKlass::cast(e);
|
||||||
|
|
||||||
// Non-unloadable classes were handled in always_strong_oops_do
|
// Only unload classes that are not strongly reachable
|
||||||
if (!is_strongly_reachable(loader_data, e)) {
|
if (!is_strongly_reachable(loader_data, e)) {
|
||||||
// Entry was not visited in phase1 (negated test from phase1)
|
// Entry was not visited in phase1 (negated test from phase1)
|
||||||
assert(!loader_data->is_the_null_class_loader_data(), "unloading entry with null class loader");
|
assert(!loader_data->is_the_null_class_loader_data(), "unloading entry with null class loader");
|
||||||
|
@ -202,26 +202,19 @@ void Dictionary::do_unloading() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dictionary::roots_oops_do(OopClosure* strong, OopClosure* weak) {
|
void Dictionary::roots_oops_do(OopClosure* strong, OopClosure* weak) {
|
||||||
// Skip the strong roots probe marking if the closures are the same.
|
// Do strong roots marking if the closures are the same.
|
||||||
if (strong == weak) {
|
if (strong == weak || !ClassUnloading) {
|
||||||
oops_do(strong);
|
// Only the protection domain oops contain references into the heap. Iterate
|
||||||
return;
|
// over all of them.
|
||||||
|
_pd_cache_table->oops_do(strong);
|
||||||
|
} else {
|
||||||
|
if (weak != NULL) {
|
||||||
|
_pd_cache_table->oops_do(weak);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int index = 0; index < table_size(); index++) {
|
|
||||||
for (DictionaryEntry *probe = bucket(index);
|
|
||||||
probe != NULL;
|
|
||||||
probe = probe->next()) {
|
|
||||||
Klass* e = probe->klass();
|
|
||||||
ClassLoaderData* loader_data = probe->loader_data();
|
|
||||||
if (is_strongly_reachable(loader_data, e)) {
|
|
||||||
probe->set_strongly_reachable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_pd_cache_table->roots_oops_do(strong, weak);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Dictionary::remove_classes_in_error_state() {
|
void Dictionary::remove_classes_in_error_state() {
|
||||||
assert(DumpSharedSpaces, "supported only when dumping");
|
assert(DumpSharedSpaces, "supported only when dumping");
|
||||||
DictionaryEntry* probe = NULL;
|
DictionaryEntry* probe = NULL;
|
||||||
|
@ -245,27 +238,6 @@ void Dictionary::remove_classes_in_error_state() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dictionary::always_strong_oops_do(OopClosure* blk) {
|
|
||||||
// Follow all system classes and temporary placeholders in dictionary; only
|
|
||||||
// protection domain oops contain references into the heap. In a first
|
|
||||||
// pass over the system dictionary determine which need to be treated as
|
|
||||||
// strongly reachable and mark them as such.
|
|
||||||
for (int index = 0; index < table_size(); index++) {
|
|
||||||
for (DictionaryEntry *probe = bucket(index);
|
|
||||||
probe != NULL;
|
|
||||||
probe = probe->next()) {
|
|
||||||
Klass* e = probe->klass();
|
|
||||||
ClassLoaderData* loader_data = probe->loader_data();
|
|
||||||
if (is_strongly_reachable(loader_data, e)) {
|
|
||||||
probe->set_strongly_reachable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Then iterate over the protection domain cache to apply the closure on the
|
|
||||||
// previously marked ones.
|
|
||||||
_pd_cache_table->always_strong_oops_do(blk);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Just the classes from defining class loaders
|
// Just the classes from defining class loaders
|
||||||
void Dictionary::classes_do(void f(Klass*)) {
|
void Dictionary::classes_do(void f(Klass*)) {
|
||||||
for (int index = 0; index < table_size(); index++) {
|
for (int index = 0; index < table_size(); index++) {
|
||||||
|
@ -474,153 +446,6 @@ void Dictionary::reorder_dictionary() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned int ProtectionDomainCacheTable::compute_hash(Handle protection_domain) {
|
|
||||||
// Identity hash can safepoint, so keep protection domain in a Handle.
|
|
||||||
return (unsigned int)(protection_domain->identity_hash());
|
|
||||||
}
|
|
||||||
|
|
||||||
int ProtectionDomainCacheTable::index_for(Handle protection_domain) {
|
|
||||||
return hash_to_index(compute_hash(protection_domain));
|
|
||||||
}
|
|
||||||
|
|
||||||
ProtectionDomainCacheTable::ProtectionDomainCacheTable(int table_size)
|
|
||||||
: Hashtable<oop, mtClass>(table_size, sizeof(ProtectionDomainCacheEntry))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProtectionDomainCacheTable::unlink(BoolObjectClosure* is_alive) {
|
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "must be");
|
|
||||||
for (int i = 0; i < table_size(); ++i) {
|
|
||||||
ProtectionDomainCacheEntry** p = bucket_addr(i);
|
|
||||||
ProtectionDomainCacheEntry* entry = bucket(i);
|
|
||||||
while (entry != NULL) {
|
|
||||||
if (is_alive->do_object_b(entry->literal())) {
|
|
||||||
p = entry->next_addr();
|
|
||||||
} else {
|
|
||||||
*p = entry->next();
|
|
||||||
free_entry(entry);
|
|
||||||
}
|
|
||||||
entry = *p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProtectionDomainCacheTable::oops_do(OopClosure* f) {
|
|
||||||
for (int index = 0; index < table_size(); index++) {
|
|
||||||
for (ProtectionDomainCacheEntry* probe = bucket(index);
|
|
||||||
probe != NULL;
|
|
||||||
probe = probe->next()) {
|
|
||||||
probe->oops_do(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProtectionDomainCacheTable::roots_oops_do(OopClosure* strong, OopClosure* weak) {
|
|
||||||
for (int index = 0; index < table_size(); index++) {
|
|
||||||
for (ProtectionDomainCacheEntry* probe = bucket(index);
|
|
||||||
probe != NULL;
|
|
||||||
probe = probe->next()) {
|
|
||||||
if (probe->is_strongly_reachable()) {
|
|
||||||
probe->reset_strongly_reachable();
|
|
||||||
probe->oops_do(strong);
|
|
||||||
} else {
|
|
||||||
if (weak != NULL) {
|
|
||||||
probe->oops_do(weak);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint ProtectionDomainCacheTable::bucket_size() {
|
|
||||||
return sizeof(ProtectionDomainCacheEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void ProtectionDomainCacheTable::print() {
|
|
||||||
tty->print_cr("Protection domain cache table (table_size=%d, classes=%d)",
|
|
||||||
table_size(), number_of_entries());
|
|
||||||
for (int index = 0; index < table_size(); index++) {
|
|
||||||
for (ProtectionDomainCacheEntry* probe = bucket(index);
|
|
||||||
probe != NULL;
|
|
||||||
probe = probe->next()) {
|
|
||||||
probe->print();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProtectionDomainCacheEntry::print() {
|
|
||||||
tty->print_cr("entry " PTR_FORMAT " value " PTR_FORMAT " strongly_reachable %d next " PTR_FORMAT,
|
|
||||||
p2i(this), p2i(literal()), _strongly_reachable, p2i(next()));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void ProtectionDomainCacheTable::verify() {
|
|
||||||
int element_count = 0;
|
|
||||||
for (int index = 0; index < table_size(); index++) {
|
|
||||||
for (ProtectionDomainCacheEntry* probe = bucket(index);
|
|
||||||
probe != NULL;
|
|
||||||
probe = probe->next()) {
|
|
||||||
probe->verify();
|
|
||||||
element_count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
guarantee(number_of_entries() == element_count,
|
|
||||||
"Verify of protection domain cache table failed");
|
|
||||||
DEBUG_ONLY(verify_lookup_length((double)number_of_entries() / table_size(), "Domain Cache Table"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProtectionDomainCacheEntry::verify() {
|
|
||||||
guarantee(literal()->is_oop(), "must be an oop");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProtectionDomainCacheTable::always_strong_oops_do(OopClosure* f) {
|
|
||||||
// the caller marked the protection domain cache entries that we need to apply
|
|
||||||
// the closure on. Only process them.
|
|
||||||
for (int index = 0; index < table_size(); index++) {
|
|
||||||
for (ProtectionDomainCacheEntry* probe = bucket(index);
|
|
||||||
probe != NULL;
|
|
||||||
probe = probe->next()) {
|
|
||||||
if (probe->is_strongly_reachable()) {
|
|
||||||
probe->reset_strongly_reachable();
|
|
||||||
probe->oops_do(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ProtectionDomainCacheEntry* ProtectionDomainCacheTable::get(Handle protection_domain) {
|
|
||||||
unsigned int hash = compute_hash(protection_domain);
|
|
||||||
int index = hash_to_index(hash);
|
|
||||||
|
|
||||||
ProtectionDomainCacheEntry* entry = find_entry(index, protection_domain);
|
|
||||||
if (entry == NULL) {
|
|
||||||
entry = add_entry(index, hash, protection_domain);
|
|
||||||
}
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProtectionDomainCacheEntry* ProtectionDomainCacheTable::find_entry(int index, Handle protection_domain) {
|
|
||||||
for (ProtectionDomainCacheEntry* e = bucket(index); e != NULL; e = e->next()) {
|
|
||||||
if (e->protection_domain() == protection_domain()) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProtectionDomainCacheEntry* ProtectionDomainCacheTable::add_entry(int index, unsigned int hash, Handle protection_domain) {
|
|
||||||
assert_locked_or_safepoint(SystemDictionary_lock);
|
|
||||||
assert(index == index_for(protection_domain), "incorrect index?");
|
|
||||||
assert(find_entry(index, protection_domain) == NULL, "no double entry");
|
|
||||||
|
|
||||||
ProtectionDomainCacheEntry* p = new_entry(hash, protection_domain);
|
|
||||||
Hashtable<oop, mtClass>::add_entry(index, p);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SymbolPropertyTable::SymbolPropertyTable(int table_size)
|
SymbolPropertyTable::SymbolPropertyTable(int table_size)
|
||||||
: Hashtable<Symbol*, mtSymbol>(table_size, sizeof(SymbolPropertyEntry))
|
: Hashtable<Symbol*, mtSymbol>(table_size, sizeof(SymbolPropertyEntry))
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#ifndef SHARE_VM_CLASSFILE_DICTIONARY_HPP
|
#ifndef SHARE_VM_CLASSFILE_DICTIONARY_HPP
|
||||||
#define SHARE_VM_CLASSFILE_DICTIONARY_HPP
|
#define SHARE_VM_CLASSFILE_DICTIONARY_HPP
|
||||||
|
|
||||||
|
#include "classfile/protectionDomainCache.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "oops/instanceKlass.hpp"
|
#include "oops/instanceKlass.hpp"
|
||||||
#include "oops/oop.hpp"
|
#include "oops/oop.hpp"
|
||||||
|
@ -32,9 +33,6 @@
|
||||||
#include "utilities/ostream.hpp"
|
#include "utilities/ostream.hpp"
|
||||||
|
|
||||||
class DictionaryEntry;
|
class DictionaryEntry;
|
||||||
class PSPromotionManager;
|
|
||||||
class ProtectionDomainCacheTable;
|
|
||||||
class ProtectionDomainCacheEntry;
|
|
||||||
class BoolObjectClosure;
|
class BoolObjectClosure;
|
||||||
|
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -89,7 +87,6 @@ public:
|
||||||
|
|
||||||
// GC support
|
// GC support
|
||||||
void oops_do(OopClosure* f);
|
void oops_do(OopClosure* f);
|
||||||
void always_strong_oops_do(OopClosure* blk);
|
|
||||||
void roots_oops_do(OopClosure* strong, OopClosure* weak);
|
void roots_oops_do(OopClosure* strong, OopClosure* weak);
|
||||||
|
|
||||||
void classes_do(void f(Klass*));
|
void classes_do(void f(Klass*));
|
||||||
|
@ -131,110 +128,6 @@ public:
|
||||||
void verify();
|
void verify();
|
||||||
};
|
};
|
||||||
|
|
||||||
// The following classes can be in dictionary.cpp, but we need these
|
|
||||||
// to be in header file so that SA's vmStructs can access them.
|
|
||||||
class ProtectionDomainCacheEntry : public HashtableEntry<oop, mtClass> {
|
|
||||||
friend class VMStructs;
|
|
||||||
private:
|
|
||||||
// Flag indicating whether this protection domain entry is strongly reachable.
|
|
||||||
// Used during iterating over the system dictionary to remember oops that need
|
|
||||||
// to be updated.
|
|
||||||
bool _strongly_reachable;
|
|
||||||
public:
|
|
||||||
oop protection_domain() { return literal(); }
|
|
||||||
|
|
||||||
void init() {
|
|
||||||
_strongly_reachable = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProtectionDomainCacheEntry* next() {
|
|
||||||
return (ProtectionDomainCacheEntry*)HashtableEntry<oop, mtClass>::next();
|
|
||||||
}
|
|
||||||
|
|
||||||
ProtectionDomainCacheEntry** next_addr() {
|
|
||||||
return (ProtectionDomainCacheEntry**)HashtableEntry<oop, mtClass>::next_addr();
|
|
||||||
}
|
|
||||||
|
|
||||||
void oops_do(OopClosure* f) {
|
|
||||||
f->do_oop(literal_addr());
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_strongly_reachable() { _strongly_reachable = true; }
|
|
||||||
bool is_strongly_reachable() { return _strongly_reachable; }
|
|
||||||
void reset_strongly_reachable() { _strongly_reachable = false; }
|
|
||||||
|
|
||||||
void print() PRODUCT_RETURN;
|
|
||||||
void verify();
|
|
||||||
};
|
|
||||||
|
|
||||||
// The ProtectionDomainCacheTable contains all protection domain oops. The system
|
|
||||||
// dictionary entries reference its entries instead of having references to oops
|
|
||||||
// directly.
|
|
||||||
// This is used to speed up system dictionary iteration: the oops in the
|
|
||||||
// protection domain are the only ones referring the Java heap. So when there is
|
|
||||||
// need to update these, instead of going over every entry of the system dictionary,
|
|
||||||
// we only need to iterate over this set.
|
|
||||||
// The amount of different protection domains used is typically magnitudes smaller
|
|
||||||
// than the number of system dictionary entries (loaded classes).
|
|
||||||
class ProtectionDomainCacheTable : public Hashtable<oop, mtClass> {
|
|
||||||
friend class VMStructs;
|
|
||||||
private:
|
|
||||||
ProtectionDomainCacheEntry* bucket(int i) {
|
|
||||||
return (ProtectionDomainCacheEntry*) Hashtable<oop, mtClass>::bucket(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The following method is not MT-safe and must be done under lock.
|
|
||||||
ProtectionDomainCacheEntry** bucket_addr(int i) {
|
|
||||||
return (ProtectionDomainCacheEntry**) Hashtable<oop, mtClass>::bucket_addr(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
ProtectionDomainCacheEntry* new_entry(unsigned int hash, Handle protection_domain) {
|
|
||||||
ProtectionDomainCacheEntry* entry = (ProtectionDomainCacheEntry*) Hashtable<oop, mtClass>::new_entry(hash, protection_domain());
|
|
||||||
entry->init();
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int compute_hash(Handle protection_domain);
|
|
||||||
|
|
||||||
int index_for(Handle protection_domain);
|
|
||||||
ProtectionDomainCacheEntry* add_entry(int index, unsigned int hash, Handle protection_domain);
|
|
||||||
ProtectionDomainCacheEntry* find_entry(int index, Handle protection_domain);
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
ProtectionDomainCacheTable(int table_size);
|
|
||||||
|
|
||||||
ProtectionDomainCacheEntry* get(Handle protection_domain);
|
|
||||||
|
|
||||||
void unlink(BoolObjectClosure* cl);
|
|
||||||
|
|
||||||
// GC support
|
|
||||||
void oops_do(OopClosure* f);
|
|
||||||
void always_strong_oops_do(OopClosure* f);
|
|
||||||
void roots_oops_do(OopClosure* strong, OopClosure* weak);
|
|
||||||
|
|
||||||
static uint bucket_size();
|
|
||||||
|
|
||||||
void print() PRODUCT_RETURN;
|
|
||||||
void verify();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class ProtectionDomainEntry :public CHeapObj<mtClass> {
|
|
||||||
friend class VMStructs;
|
|
||||||
public:
|
|
||||||
ProtectionDomainEntry* _next;
|
|
||||||
ProtectionDomainCacheEntry* _pd_cache;
|
|
||||||
|
|
||||||
ProtectionDomainEntry(ProtectionDomainCacheEntry* pd_cache, ProtectionDomainEntry* next) {
|
|
||||||
_pd_cache = pd_cache;
|
|
||||||
_next = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProtectionDomainEntry* next() { return _next; }
|
|
||||||
oop protection_domain() { return _pd_cache->protection_domain(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
// An entry in the system dictionary, this describes a class as
|
// An entry in the system dictionary, this describes a class as
|
||||||
// { InstanceKlass*, loader, protection_domain }.
|
// { InstanceKlass*, loader, protection_domain }.
|
||||||
|
|
||||||
|
@ -296,14 +189,6 @@ class DictionaryEntry : public HashtableEntry<InstanceKlass*, mtClass> {
|
||||||
: contains_protection_domain(protection_domain());
|
: contains_protection_domain(protection_domain());
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_strongly_reachable() {
|
|
||||||
for (ProtectionDomainEntry* current = _pd_set;
|
|
||||||
current != NULL;
|
|
||||||
current = current->_next) {
|
|
||||||
current->_pd_cache->set_strongly_reachable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void verify_protection_domain_set() {
|
void verify_protection_domain_set() {
|
||||||
for (ProtectionDomainEntry* current = _pd_set;
|
for (ProtectionDomainEntry* current = _pd_set;
|
||||||
current != NULL;
|
current != NULL;
|
||||||
|
|
147
hotspot/src/share/vm/classfile/protectionDomainCache.cpp
Normal file
147
hotspot/src/share/vm/classfile/protectionDomainCache.cpp
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "precompiled.hpp"
|
||||||
|
#include "classfile/protectionDomainCache.hpp"
|
||||||
|
#include "classfile/systemDictionary.hpp"
|
||||||
|
#include "memory/iterator.hpp"
|
||||||
|
#include "memory/resourceArea.hpp"
|
||||||
|
#include "oops/oop.inline.hpp"
|
||||||
|
#include "utilities/hashtable.inline.hpp"
|
||||||
|
|
||||||
|
unsigned int ProtectionDomainCacheTable::compute_hash(Handle protection_domain) {
|
||||||
|
// Identity hash can safepoint, so keep protection domain in a Handle.
|
||||||
|
return (unsigned int)(protection_domain->identity_hash());
|
||||||
|
}
|
||||||
|
|
||||||
|
int ProtectionDomainCacheTable::index_for(Handle protection_domain) {
|
||||||
|
return hash_to_index(compute_hash(protection_domain));
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtectionDomainCacheTable::ProtectionDomainCacheTable(int table_size)
|
||||||
|
: Hashtable<oop, mtClass>(table_size, sizeof(ProtectionDomainCacheEntry))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProtectionDomainCacheTable::unlink(BoolObjectClosure* is_alive) {
|
||||||
|
assert(SafepointSynchronize::is_at_safepoint(), "must be");
|
||||||
|
for (int i = 0; i < table_size(); ++i) {
|
||||||
|
ProtectionDomainCacheEntry** p = bucket_addr(i);
|
||||||
|
ProtectionDomainCacheEntry* entry = bucket(i);
|
||||||
|
while (entry != NULL) {
|
||||||
|
if (is_alive->do_object_b(entry->literal())) {
|
||||||
|
p = entry->next_addr();
|
||||||
|
} else {
|
||||||
|
if (log_is_enabled(Debug, protectiondomain)) {
|
||||||
|
outputStream* log = Log(protectiondomain)::debug_stream();
|
||||||
|
log->print("protection domain unlinked: ");
|
||||||
|
entry->literal()->print_value_on(log);
|
||||||
|
log->cr();
|
||||||
|
}
|
||||||
|
*p = entry->next();
|
||||||
|
free_entry(entry);
|
||||||
|
}
|
||||||
|
entry = *p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProtectionDomainCacheTable::oops_do(OopClosure* f) {
|
||||||
|
for (int index = 0; index < table_size(); index++) {
|
||||||
|
for (ProtectionDomainCacheEntry* probe = bucket(index);
|
||||||
|
probe != NULL;
|
||||||
|
probe = probe->next()) {
|
||||||
|
probe->oops_do(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef PRODUCT
|
||||||
|
void ProtectionDomainCacheTable::print() {
|
||||||
|
tty->print_cr("Protection domain cache table (table_size=%d, classes=%d)",
|
||||||
|
table_size(), number_of_entries());
|
||||||
|
for (int index = 0; index < table_size(); index++) {
|
||||||
|
for (ProtectionDomainCacheEntry* probe = bucket(index);
|
||||||
|
probe != NULL;
|
||||||
|
probe = probe->next()) {
|
||||||
|
probe->print();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProtectionDomainCacheEntry::print() {
|
||||||
|
tty->print_cr("entry " PTR_FORMAT " value " PTR_FORMAT " next " PTR_FORMAT,
|
||||||
|
p2i(this), p2i(literal()), p2i(next()));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void ProtectionDomainCacheTable::verify() {
|
||||||
|
int element_count = 0;
|
||||||
|
for (int index = 0; index < table_size(); index++) {
|
||||||
|
for (ProtectionDomainCacheEntry* probe = bucket(index);
|
||||||
|
probe != NULL;
|
||||||
|
probe = probe->next()) {
|
||||||
|
probe->verify();
|
||||||
|
element_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
guarantee(number_of_entries() == element_count,
|
||||||
|
"Verify of protection domain cache table failed");
|
||||||
|
DEBUG_ONLY(verify_lookup_length((double)number_of_entries() / table_size(), "Domain Cache Table"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProtectionDomainCacheEntry::verify() {
|
||||||
|
guarantee(literal()->is_oop(), "must be an oop");
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtectionDomainCacheEntry* ProtectionDomainCacheTable::get(Handle protection_domain) {
|
||||||
|
unsigned int hash = compute_hash(protection_domain);
|
||||||
|
int index = hash_to_index(hash);
|
||||||
|
|
||||||
|
ProtectionDomainCacheEntry* entry = find_entry(index, protection_domain);
|
||||||
|
if (entry == NULL) {
|
||||||
|
entry = add_entry(index, hash, protection_domain);
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtectionDomainCacheEntry* ProtectionDomainCacheTable::find_entry(int index, Handle protection_domain) {
|
||||||
|
for (ProtectionDomainCacheEntry* e = bucket(index); e != NULL; e = e->next()) {
|
||||||
|
if (e->protection_domain() == protection_domain()) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtectionDomainCacheEntry* ProtectionDomainCacheTable::add_entry(int index, unsigned int hash, Handle protection_domain) {
|
||||||
|
assert_locked_or_safepoint(SystemDictionary_lock);
|
||||||
|
assert(index == index_for(protection_domain), "incorrect index?");
|
||||||
|
assert(find_entry(index, protection_domain) == NULL, "no double entry");
|
||||||
|
|
||||||
|
ProtectionDomainCacheEntry* p = new_entry(hash, protection_domain);
|
||||||
|
Hashtable<oop, mtClass>::add_entry(index, p);
|
||||||
|
return p;
|
||||||
|
}
|
118
hotspot/src/share/vm/classfile/protectionDomainCache.hpp
Normal file
118
hotspot/src/share/vm/classfile/protectionDomainCache.hpp
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SHARE_VM_CLASSFILE_PROTECTIONDOMAINCACHE_HPP
|
||||||
|
#define SHARE_VM_CLASSFILE_PROTECTIONDOMAINCACHE_HPP
|
||||||
|
|
||||||
|
#include "oops/oop.hpp"
|
||||||
|
#include "memory/iterator.hpp"
|
||||||
|
#include "utilities/hashtable.hpp"
|
||||||
|
|
||||||
|
// This class caches the approved protection domains that can access loaded classes.
|
||||||
|
// Dictionary entry pd_set point to entries in this hashtable. Please refer
|
||||||
|
// to dictionary.hpp pd_set for more information about how protection domain entries
|
||||||
|
// are used.
|
||||||
|
// This table is walked during GC, rather than the entire system dictionary
|
||||||
|
class ProtectionDomainCacheEntry : public HashtableEntry<oop, mtClass> {
|
||||||
|
friend class VMStructs;
|
||||||
|
public:
|
||||||
|
oop protection_domain() { return literal(); }
|
||||||
|
|
||||||
|
ProtectionDomainCacheEntry* next() {
|
||||||
|
return (ProtectionDomainCacheEntry*)HashtableEntry<oop, mtClass>::next();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtectionDomainCacheEntry** next_addr() {
|
||||||
|
return (ProtectionDomainCacheEntry**)HashtableEntry<oop, mtClass>::next_addr();
|
||||||
|
}
|
||||||
|
|
||||||
|
void oops_do(OopClosure* f) {
|
||||||
|
f->do_oop(literal_addr());
|
||||||
|
}
|
||||||
|
|
||||||
|
void print() PRODUCT_RETURN;
|
||||||
|
void verify();
|
||||||
|
};
|
||||||
|
|
||||||
|
// The ProtectionDomainCacheTable contains all protection domain oops. The system
|
||||||
|
// dictionary entries reference its entries instead of having references to oops
|
||||||
|
// directly.
|
||||||
|
// This is used to speed up system dictionary iteration: the oops in the
|
||||||
|
// protection domain are the only ones referring the Java heap. So when there is
|
||||||
|
// need to update these, instead of going over every entry of the system dictionary,
|
||||||
|
// we only need to iterate over this set.
|
||||||
|
// The amount of different protection domains used is typically magnitudes smaller
|
||||||
|
// than the number of system dictionary entries (loaded classes).
|
||||||
|
class ProtectionDomainCacheTable : public Hashtable<oop, mtClass> {
|
||||||
|
friend class VMStructs;
|
||||||
|
private:
|
||||||
|
ProtectionDomainCacheEntry* bucket(int i) {
|
||||||
|
return (ProtectionDomainCacheEntry*) Hashtable<oop, mtClass>::bucket(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following method is not MT-safe and must be done under lock.
|
||||||
|
ProtectionDomainCacheEntry** bucket_addr(int i) {
|
||||||
|
return (ProtectionDomainCacheEntry**) Hashtable<oop, mtClass>::bucket_addr(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtectionDomainCacheEntry* new_entry(unsigned int hash, Handle protection_domain) {
|
||||||
|
ProtectionDomainCacheEntry* entry = (ProtectionDomainCacheEntry*) Hashtable<oop, mtClass>::new_entry(hash, protection_domain());
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int compute_hash(Handle protection_domain);
|
||||||
|
|
||||||
|
int index_for(Handle protection_domain);
|
||||||
|
ProtectionDomainCacheEntry* add_entry(int index, unsigned int hash, Handle protection_domain);
|
||||||
|
ProtectionDomainCacheEntry* find_entry(int index, Handle protection_domain);
|
||||||
|
|
||||||
|
public:
|
||||||
|
ProtectionDomainCacheTable(int table_size);
|
||||||
|
ProtectionDomainCacheEntry* get(Handle protection_domain);
|
||||||
|
|
||||||
|
void unlink(BoolObjectClosure* cl);
|
||||||
|
|
||||||
|
// GC support
|
||||||
|
void oops_do(OopClosure* f);
|
||||||
|
|
||||||
|
void print() PRODUCT_RETURN;
|
||||||
|
void verify();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class ProtectionDomainEntry :public CHeapObj<mtClass> {
|
||||||
|
friend class VMStructs;
|
||||||
|
public:
|
||||||
|
ProtectionDomainEntry* _next;
|
||||||
|
ProtectionDomainCacheEntry* _pd_cache;
|
||||||
|
|
||||||
|
ProtectionDomainEntry(ProtectionDomainCacheEntry* pd_cache, ProtectionDomainEntry* next) {
|
||||||
|
_pd_cache = pd_cache;
|
||||||
|
_next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtectionDomainEntry* next() { return _next; }
|
||||||
|
oop protection_domain() { return _pd_cache->protection_domain(); }
|
||||||
|
};
|
||||||
|
#endif // SHARE_VM_CLASSFILE_PROTECTIONDOMAINCACHE_HPP
|
Loading…
Add table
Add a link
Reference in a new issue