8289164: Convert ResolutionErrorTable to use ResourceHashtable

Reviewed-by: iklam, coleenp
This commit is contained in:
Justin Gu 2022-07-07 14:57:24 +00:00 committed by Coleen Phillimore
parent 013a5eeeb9
commit 86f63f9703
7 changed files with 192 additions and 178 deletions

View File

@ -25,162 +25,141 @@
#include "precompiled.hpp"
#include "classfile/resolutionErrors.hpp"
#include "memory/allocation.hpp"
#include "memory/resourceArea.hpp"
#include "oops/constantPool.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/klass.inline.hpp"
#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/safepoint.hpp"
#include "utilities/hashtable.inline.hpp"
#include "runtime/mutexLocker.hpp"
#include "utilities/resourceHash.hpp"
ResourceHashtable<uintptr_t, ResolutionErrorEntry*, 107, ResourceObj::C_HEAP, mtClass> _resolution_error_table;
// create new error entry
void ResolutionErrorTable::add_entry(int index, unsigned int hash,
const constantPoolHandle& pool, int cp_index,
void ResolutionErrorTable::add_entry(const constantPoolHandle& pool, int cp_index,
Symbol* error, Symbol* message,
Symbol* cause, Symbol* cause_msg)
{
assert_locked_or_safepoint(SystemDictionary_lock);
assert(!pool.is_null() && error != NULL, "adding NULL obj");
ResolutionErrorEntry* entry = (ResolutionErrorEntry*)Hashtable<ConstantPool*, mtClass>::new_entry(hash, pool());
entry->set_cp_index(cp_index);
entry->set_error(error);
entry->set_message(message);
entry->set_nest_host_error(NULL);
entry->set_cause(cause);
entry->set_cause_msg(cause_msg);
add_entry(index, entry);
ResolutionErrorEntry* entry = new ResolutionErrorEntry(pool(), cp_index, error, message, cause, cause_msg);
_resolution_error_table.put(convert_key(pool, cp_index), entry);
}
// create new nest host error entry
void ResolutionErrorTable::add_entry(int index, unsigned int hash,
const constantPoolHandle& pool, int cp_index,
void ResolutionErrorTable::add_entry(const constantPoolHandle& pool, int cp_index,
const char* message)
{
assert_locked_or_safepoint(SystemDictionary_lock);
assert(!pool.is_null() && message != NULL, "adding NULL obj");
ResolutionErrorEntry* entry = (ResolutionErrorEntry*)Hashtable<ConstantPool*, mtClass>::new_entry(hash, pool());
entry->set_cp_index(cp_index);
entry->set_nest_host_error(message);
entry->set_error(NULL);
entry->set_message(NULL);
entry->set_cause(NULL);
entry->set_cause_msg(NULL);
add_entry(index, entry);
ResolutionErrorEntry* entry = new ResolutionErrorEntry(pool(), cp_index, message);
_resolution_error_table.put(convert_key(pool, cp_index), entry);
}
// find entry in the table
ResolutionErrorEntry* ResolutionErrorTable::find_entry(int index, unsigned int hash,
const constantPoolHandle& pool, int cp_index)
{
ResolutionErrorEntry* ResolutionErrorTable::find_entry(const constantPoolHandle& pool, int cp_index) {
assert_locked_or_safepoint(SystemDictionary_lock);
for (ResolutionErrorEntry *error_probe = bucket(index);
error_probe != NULL;
error_probe = error_probe->next()) {
if (error_probe->hash() == hash && error_probe->pool() == pool()) {
return error_probe;;
}
ResolutionErrorEntry** entry = _resolution_error_table.get(convert_key(pool, cp_index));
if (entry != nullptr) {
return *entry;
} else {
return nullptr;
}
return NULL;
}
void ResolutionErrorEntry::set_error(Symbol* e) {
_error = e;
if (_error != NULL) {
ResolutionErrorEntry::ResolutionErrorEntry(ConstantPool* pool, int cp_index, Symbol* error, Symbol* message,
Symbol* cause, Symbol* cause_msg):
_cp_index(cp_index),
_error(error),
_message(message),
_cause(cause),
_cause_msg(cause_msg),
_pool(pool),
_nest_host_error(nullptr) {
if (_error != nullptr) {
_error->increment_refcount();
}
}
void ResolutionErrorEntry::set_message(Symbol* c) {
_message = c;
if (_message != NULL) {
if (_message != nullptr) {
_message->increment_refcount();
}
}
void ResolutionErrorEntry::set_cause(Symbol* c) {
_cause = c;
if (_cause != NULL) {
if (_cause != nullptr) {
_cause->increment_refcount();
}
}
void ResolutionErrorEntry::set_cause_msg(Symbol* c) {
_cause_msg = c;
if (_cause_msg != NULL) {
if (_cause_msg != nullptr) {
_cause_msg->increment_refcount();
}
}
void ResolutionErrorEntry::set_nest_host_error(const char* message) {
_nest_host_error = message;
}
void ResolutionErrorTable::free_entry(ResolutionErrorEntry *entry) {
ResolutionErrorEntry::~ResolutionErrorEntry() {
// decrement error refcount
if (entry->error() != NULL) {
entry->error()->decrement_refcount();
if (error() != NULL) {
error()->decrement_refcount();
}
if (entry->message() != NULL) {
entry->message()->decrement_refcount();
if (message() != NULL) {
message()->decrement_refcount();
}
if (entry->cause() != NULL) {
entry->cause()->decrement_refcount();
if (cause() != NULL) {
cause()->decrement_refcount();
}
if (entry->cause_msg() != NULL) {
entry->cause_msg()->decrement_refcount();
if (cause_msg() != NULL) {
cause_msg()->decrement_refcount();
}
if (entry->nest_host_error() != NULL) {
FREE_C_HEAP_ARRAY(char, entry->nest_host_error());
if (nest_host_error() != NULL) {
FREE_C_HEAP_ARRAY(char, nest_host_error());
}
BasicHashtable<mtClass>::free_entry(entry);
}
class ResolutionErrorDeleteIterate : StackObj{
private:
ConstantPool* p;
// create resolution error table
ResolutionErrorTable::ResolutionErrorTable(int table_size)
: Hashtable<ConstantPool*, mtClass>(table_size, sizeof(ResolutionErrorEntry)) {
}
public:
ResolutionErrorDeleteIterate(ConstantPool* pool):
p(pool) {};
// RedefineClasses support - remove matching entry of a
// constant pool that is going away
void ResolutionErrorTable::delete_entry(ConstantPool* c) {
assert_locked_or_safepoint(SystemDictionary_lock);
for (int i = 0; i < table_size(); i++) {
for (ResolutionErrorEntry** p = bucket_addr(i); *p != NULL; ) {
ResolutionErrorEntry* entry = *p;
assert(entry->pool() != NULL, "resolution error table is corrupt");
if (entry->pool() == c) {
*p = entry->next();
free_entry(entry);
} else {
p = entry->next_addr();
}
bool do_entry(uintptr_t key, ResolutionErrorEntry* value){
if (value -> pool() == p) {
delete value;
return true;
} else {
return false;
}
}
};
// Delete entries in the table that match with ConstantPool c
void ResolutionErrorTable::delete_entry(ConstantPool* c) {
assert_locked_or_safepoint(SystemDictionary_lock);
ResolutionErrorDeleteIterate deleteIterator(c);
_resolution_error_table.unlink(&deleteIterator);
}
class ResolutionIteratePurgeErrors : StackObj{
public:
bool do_entry(uintptr_t key, ResolutionErrorEntry* value) {
ConstantPool* pool = value -> pool();
if (!(pool->pool_holder()->is_loader_alive())) {
delete value;
return true;
} else {
return false;
}
}
};
// Remove unloaded entries from the table
void ResolutionErrorTable::purge_resolution_errors() {
assert_locked_or_safepoint(SystemDictionary_lock);
for (int i = 0; i < table_size(); i++) {
for (ResolutionErrorEntry** p = bucket_addr(i); *p != NULL; ) {
ResolutionErrorEntry* entry = *p;
assert(entry->pool() != (ConstantPool*)NULL, "resolution error table is corrupt");
ConstantPool* pool = entry->pool();
assert(pool->pool_holder() != NULL, "Constant pool without a class?");
if (pool->pool_holder()->is_loader_alive()) {
p = entry->next_addr();
} else {
*p = entry->next();
free_entry(entry);
}
}
}
ResolutionIteratePurgeErrors purgeErrorsIterator;
_resolution_error_table.unlink(&purgeErrorsIterator);
}

View File

@ -26,7 +26,6 @@
#define SHARE_CLASSFILE_RESOLUTIONERRORS_HPP
#include "oops/constantPool.hpp"
#include "utilities/hashtable.hpp"
class ResolutionErrorEntry;
@ -39,48 +38,23 @@ class ResolutionErrorEntry;
// index of another entry in the table.
const int CPCACHE_INDEX_MANGLE_VALUE = 1000000;
class ResolutionErrorTable : public Hashtable<ConstantPool*, mtClass> {
private:
void free_entry(ResolutionErrorEntry *entry);
class ResolutionErrorTable : AllStatic {
public:
ResolutionErrorTable(int table_size);
ResolutionErrorEntry* bucket(int i) {
return (ResolutionErrorEntry*)Hashtable<ConstantPool*, mtClass>::bucket(i);
}
ResolutionErrorEntry** bucket_addr(int i) {
return (ResolutionErrorEntry**)Hashtable<ConstantPool*, mtClass>::bucket_addr(i);
}
void add_entry(int index, ResolutionErrorEntry* new_entry) {
Hashtable<ConstantPool*, mtClass>::add_entry(index,
(HashtableEntry<ConstantPool*, mtClass>*)new_entry);
}
void add_entry(int index, unsigned int hash,
const constantPoolHandle& pool, int which, Symbol* error, Symbol* message,
static void add_entry(const constantPoolHandle& pool, int which, Symbol* error, Symbol* message,
Symbol* cause, Symbol* cause_msg);
void add_entry(int index, unsigned int hash,
const constantPoolHandle& pool, int which, const char* message);
static void add_entry(const constantPoolHandle& pool, int which, const char* message);
// find error given the constant pool and constant pool index
ResolutionErrorEntry* find_entry(int index, unsigned int hash,
const constantPoolHandle& pool, int cp_index);
unsigned int compute_hash(const constantPoolHandle& pool, int cp_index) {
return (unsigned int) pool->identity_hash() + cp_index;
}
static ResolutionErrorEntry* find_entry(const constantPoolHandle& pool, int cp_index);
// purges unloaded entries from the table
void purge_resolution_errors();
static void purge_resolution_errors();
// RedefineClasses support - remove obsolete constant pool entry
void delete_entry(ConstantPool* c);
static void delete_entry(ConstantPool* c);
// This function is used to encode an index to differentiate it from a
// constant pool index. It assumes it is being called with a cpCache index
@ -89,46 +63,52 @@ public:
assert(index < 0, "Unexpected non-negative cpCache index");
return index + CPCACHE_INDEX_MANGLE_VALUE;
}
static uintptr_t convert_key(const constantPoolHandle& pool, int cp_index) {
return (uintptr_t) (pool() + cp_index);
}
};
class ResolutionErrorEntry : public HashtableEntry<ConstantPool*, mtClass> {
class ResolutionErrorEntry : public CHeapObj<mtClass> {
private:
int _cp_index;
Symbol* _error;
Symbol* _message;
Symbol* _cause;
Symbol* _cause_msg;
ConstantPool* _pool;
const char* _nest_host_error;
public:
ConstantPool* pool() const { return literal(); }
ResolutionErrorEntry(ConstantPool* pool, int cp_index, Symbol* error, Symbol* message,
Symbol* cause, Symbol* cause_msg);
ResolutionErrorEntry(ConstantPool* pool, int cp_index, const char* message):
_cp_index(cp_index),
_error(nullptr),
_message(nullptr),
_cause(nullptr),
_cause_msg(nullptr),
_pool(pool),
_nest_host_error(message) {}
~ResolutionErrorEntry();
void set_nest_host_error(const char* message) {
_nest_host_error = message;
}
ConstantPool* pool() const { return _pool; }
int cp_index() const { return _cp_index; }
void set_cp_index(int cp_index) { _cp_index = cp_index; }
Symbol* error() const { return _error; }
void set_error(Symbol* e);
Symbol* message() const { return _message; }
void set_message(Symbol* c);
Symbol* cause() const { return _cause; }
void set_cause(Symbol* c);
Symbol* cause_msg() const { return _cause_msg; }
void set_cause_msg(Symbol* c);
const char* nest_host_error() const { return _nest_host_error; }
void set_nest_host_error(const char* message);
ResolutionErrorEntry* next() const {
return (ResolutionErrorEntry*)HashtableEntry<ConstantPool*, mtClass>::next();
}
ResolutionErrorEntry** next_addr() {
return (ResolutionErrorEntry**)HashtableEntry<ConstantPool*, mtClass>::next_addr();
}
};
#endif // SHARE_CLASSFILE_RESOLUTIONERRORS_HPP

View File

@ -87,7 +87,6 @@
#include "jfr/jfr.hpp"
#endif
ResolutionErrorTable* SystemDictionary::_resolution_errors = NULL;
SymbolPropertyTable* SystemDictionary::_invoke_method_table = NULL;
ProtectionDomainCacheTable* SystemDictionary::_pd_cache_table = NULL;
@ -1605,7 +1604,7 @@ bool SystemDictionary::do_unloading(GCTimer* gc_timer) {
MutexLocker ml1(is_concurrent ? SystemDictionary_lock : NULL);
ClassLoaderDataGraph::clean_module_and_package_info();
constraints()->purge_loader_constraints();
resolution_errors()->purge_resolution_errors();
ResolutionErrorTable::purge_resolution_errors();
}
}
@ -1647,7 +1646,6 @@ void SystemDictionary::initialize(TRAPS) {
// Allocate arrays
_placeholders = new PlaceholderTable(_placeholder_table_size);
_loader_constraints = new LoaderConstraintTable(_loader_constraint_size);
_resolution_errors = new ResolutionErrorTable(_resolution_error_size);
_invoke_method_table = new SymbolPropertyTable(_invoke_method_size);
_pd_cache_table = new ProtectionDomainCacheTable(defaultProtectionDomainCacheSize);
@ -1848,30 +1846,27 @@ bool SystemDictionary::add_loader_constraint(Symbol* class_name,
void SystemDictionary::add_resolution_error(const constantPoolHandle& pool, int which,
Symbol* error, Symbol* message,
Symbol* cause, Symbol* cause_msg) {
unsigned int hash = resolution_errors()->compute_hash(pool, which);
int index = resolution_errors()->hash_to_index(hash);
{
MutexLocker ml(Thread::current(), SystemDictionary_lock);
ResolutionErrorEntry* entry = resolution_errors()->find_entry(index, hash, pool, which);
ResolutionErrorEntry* entry = ResolutionErrorTable::find_entry(pool, which);
if (entry == NULL) {
resolution_errors()->add_entry(index, hash, pool, which, error, message, cause, cause_msg);
ResolutionErrorTable::add_entry(pool, which, error, message, cause, cause_msg);
}
}
}
// Delete a resolution error for RedefineClasses for a constant pool is going away
void SystemDictionary::delete_resolution_error(ConstantPool* pool) {
resolution_errors()->delete_entry(pool);
ResolutionErrorTable::delete_entry(pool);
}
// Lookup resolution error table. Returns error if found, otherwise NULL.
Symbol* SystemDictionary::find_resolution_error(const constantPoolHandle& pool, int which,
Symbol** message, Symbol** cause, Symbol** cause_msg) {
unsigned int hash = resolution_errors()->compute_hash(pool, which);
int index = resolution_errors()->hash_to_index(hash);
{
MutexLocker ml(Thread::current(), SystemDictionary_lock);
ResolutionErrorEntry* entry = resolution_errors()->find_entry(index, hash, pool, which);
ResolutionErrorEntry* entry = ResolutionErrorTable::find_entry(pool, which);
if (entry != NULL) {
*message = entry->message();
*cause = entry->cause();
@ -1887,14 +1882,13 @@ Symbol* SystemDictionary::find_resolution_error(const constantPoolHandle& pool,
// validating a nest host. This is used to construct informative error
// messages when IllegalAccessError's occur. If an entry already exists it will
// be updated with the nest host error message.
void SystemDictionary::add_nest_host_error(const constantPoolHandle& pool,
int which,
const char* message) {
unsigned int hash = resolution_errors()->compute_hash(pool, which);
int index = resolution_errors()->hash_to_index(hash);
{
MutexLocker ml(Thread::current(), SystemDictionary_lock);
ResolutionErrorEntry* entry = resolution_errors()->find_entry(index, hash, pool, which);
ResolutionErrorEntry* entry = ResolutionErrorTable::find_entry(pool, which);
if (entry != NULL && entry->nest_host_error() == NULL) {
// An existing entry means we had a true resolution failure (LinkageError) with our nest host, but we
// still want to add the error message for the higher-level access checks to report. We should
@ -1902,18 +1896,16 @@ void SystemDictionary::add_nest_host_error(const constantPoolHandle& pool,
// the message. If we see it is already set then we can ignore it.
entry->set_nest_host_error(message);
} else {
resolution_errors()->add_entry(index, hash, pool, which, message);
ResolutionErrorTable::add_entry(pool, which, message);
}
}
}
// Lookup any nest host error
const char* SystemDictionary::find_nest_host_error(const constantPoolHandle& pool, int which) {
unsigned int hash = resolution_errors()->compute_hash(pool, which);
int index = resolution_errors()->hash_to_index(hash);
{
MutexLocker ml(Thread::current(), SystemDictionary_lock);
ResolutionErrorEntry* entry = resolution_errors()->find_entry(index, hash, pool, which);
ResolutionErrorEntry* entry = ResolutionErrorTable::find_entry(pool, which);
if (entry != NULL) {
return entry->nest_host_error();
} else {
@ -1922,7 +1914,6 @@ const char* SystemDictionary::find_nest_host_error(const constantPoolHandle& poo
}
}
// Signature constraints ensure that callers and callees agree about
// the meaning of type names in their signatures. This routine is the
// intake for constraints. It collects them from several places:

View File

@ -71,7 +71,6 @@ class ClassFileStream;
class ClassLoadInfo;
class Dictionary;
template <MEMFLAGS F> class HashtableBucket;
class ResolutionErrorTable;
class SymbolPropertyTable;
class PackageEntry;
class ProtectionDomainCacheTable;
@ -293,9 +292,6 @@ public:
private:
// Static tables owned by the SystemDictionary
// Resolution errors
static ResolutionErrorTable* _resolution_errors;
// Invoke methods (JSR 292)
static SymbolPropertyTable* _invoke_method_table;
@ -312,7 +308,6 @@ private:
static OopHandle _java_system_loader;
static OopHandle _java_platform_loader;
static ResolutionErrorTable* resolution_errors() { return _resolution_errors; }
static SymbolPropertyTable* invoke_method_table() { return _invoke_method_table; }
private:

View File

@ -27,7 +27,6 @@
#include "cds/archiveUtils.hpp"
#include "classfile/defaultMethods.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/resolutionErrors.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmClasses.hpp"

View File

@ -34,7 +34,6 @@
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/moduleEntry.hpp"
#include "classfile/resolutionErrors.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/systemDictionaryShared.hpp"

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2022, 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.
*/
/*
* @test 8289164
* @summary Test that tests the ResolutionErrorTable
*/
import java.io.File;
import java.io.*;
public class ErrorsDemoTest {
static int x = 0;
public static void main(String args[]) {
String classDirectory = System.getProperty("test.classes");
String filename = classDirectory + File.separator + "DeleteMe.class";
File file = new File(filename);
boolean success = file.delete();
String oldMessage = null;
for (int i = 0; i < 2; i++) {
try {
ErrorInResolution.doit();
}
catch (Throwable t) {
String s = t.getMessage();
if (oldMessage == null){
oldMessage = s;
}
else {
if(!s.equals(oldMessage)){
RuntimeException e = new RuntimeException();
throw e;
}
}
}
}
}
}
class DeleteMe {
static int x;
}
class ErrorInResolution {
static int doit() {
return DeleteMe.x;
}
}