8213346: Re-implement shared dictionary using CompactHashtable
Reviewed-by: jiangli
--- a/src/hotspot/share/classfile/classListParser.cpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/classfile/classListParser.cpp Wed Nov 07 19:40:27 2018 -0800
@@ -287,7 +287,7 @@
if (!is_id_specified()) {
error("If source location is specified, id must be also specified");
}
- InstanceKlass* k = ClassLoaderExt::load_class(class_name, _source, THREAD);
+ InstanceKlass* k = ClassLoaderExt::load_class(class_name, _source, CHECK_NULL);
if (strncmp(_class_name, "java/", 5) == 0) {
log_info(cds)("Prohibited package for non-bootstrap classes: %s.class from %s",
@@ -303,8 +303,9 @@
_interfaces->length(), k->local_interfaces()->length());
}
- if (!SystemDictionaryShared::add_non_builtin_klass(class_name, ClassLoaderData::the_null_class_loader_data(),
- k, THREAD)) {
+ bool added = SystemDictionaryShared::add_unregistered_class(k, CHECK_NULL);
+ if (!added) {
+ // We allow only a single unregistered class for each unique name.
error("Duplicated class %s", _class_name);
}
@@ -353,7 +354,7 @@
vmSymbols::loadClass_name(),
vmSymbols::string_class_signature(),
ext_class_name,
- THREAD);
+ THREAD); // <-- failure is handled below
} else {
// array classes are not supported in class list.
THROW_NULL(vmSymbols::java_lang_ClassNotFoundException());
--- a/src/hotspot/share/classfile/classLoaderExt.cpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/classfile/classLoaderExt.cpp Wed Nov 07 19:40:27 2018 -0800
@@ -350,7 +350,3 @@
cached_path_entries->insert_before(0, ccpe);
return new_entry;
}
-
-Klass* ClassLoaderExt::load_one_class(ClassListParser* parser, TRAPS) {
- return parser->load_current_class(THREAD);
-}
--- a/src/hotspot/share/classfile/classLoaderExt.hpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/classfile/classLoaderExt.hpp Wed Nov 07 19:40:27 2018 -0800
@@ -115,7 +115,6 @@
static void record_result(const s2 classpath_index,
InstanceKlass* result, TRAPS);
static InstanceKlass* load_class(Symbol* h_name, const char* path, TRAPS);
- static Klass* load_one_class(ClassListParser* parser, TRAPS);
static void set_has_app_classes() {
_has_app_classes = true;
}
--- a/src/hotspot/share/classfile/compactHashtable.cpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/classfile/compactHashtable.cpp Wed Nov 07 19:40:27 2018 -0800
@@ -163,6 +163,7 @@
msg.info("Average bucket size : %9.3f", summary.avg());
msg.info("Variance of bucket size : %9.3f", summary.variance());
msg.info("Std. dev. of bucket size: %9.3f", summary.sd());
+ msg.info("Maximum bucket size : %9d", (int)summary.maximum());
msg.info("Empty buckets : %9d", _num_empty_buckets);
msg.info("Value_Only buckets : %9d", _num_value_only_buckets);
msg.info("Other buckets : %9d", _num_other_buckets);
--- a/src/hotspot/share/classfile/compactHashtable.hpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/classfile/compactHashtable.hpp Wed Nov 07 19:40:27 2018 -0800
@@ -244,8 +244,6 @@
}
public:
- CompactHashtable() : SimpleCompactHashtable() {}
-
// Lookup a value V from the compact table using key K
inline V lookup(K key, unsigned int hash, int len) const {
if (_entry_count > 0) {
@@ -299,10 +297,55 @@
}
}
}
+
+ void print_table_statistics(outputStream* st, const char* name) {
+ st->print_cr("%s statistics:", name);
+ int total_entries = 0;
+ int max_bucket = 0;
+ for (u4 i = 0; i < _bucket_count; i++) {
+ u4 bucket_info = _buckets[i];
+ int bucket_type = BUCKET_TYPE(bucket_info);
+ int bucket_size;
+
+ if (bucket_type == VALUE_ONLY_BUCKET_TYPE) {
+ bucket_size = 1;
+ } else {
+ bucket_size = (BUCKET_OFFSET(_buckets[i + 1]) - BUCKET_OFFSET(bucket_info)) / 2;
+ }
+ total_entries += bucket_size;
+ if (max_bucket < bucket_size) {
+ max_bucket = bucket_size;
+ }
+ }
+ st->print_cr("Number of buckets : %9d", _bucket_count);
+ st->print_cr("Number of entries : %9d", total_entries);
+ st->print_cr("Maximum bucket size : %9d", max_bucket);
+ }
};
////////////////////////////////////////////////////////////////////////
//
+// OffsetCompactHashtable -- This is used to store many types of objects
+// in the CDS archive. On 64-bit platforms, we save space by using a 32-bit
+// offset from the CDS base address.
+
+template <typename V>
+V read_value_from_compact_hashtable(address base_address, u4 offset) {
+ return (V)(base_address + offset);
+}
+
+template <
+ typename K,
+ typename V,
+ bool (*EQUALS)(V value, K key, int len)
+ >
+class OffsetCompactHashtable : public CompactHashtable<
+ K, V, read_value_from_compact_hashtable<V>, EQUALS> {
+};
+
+
+////////////////////////////////////////////////////////////////////////
+//
// Read/Write the contents of a hashtable textual dump (created by
// SymbolTable::dump and StringTable::dump).
// Because the dump file may be big (hundred of MB in extreme cases),
--- a/src/hotspot/share/classfile/dictionary.cpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/classfile/dictionary.cpp Wed Nov 07 19:40:27 2018 -0800
@@ -27,7 +27,6 @@
#include "classfile/dictionary.inline.hpp"
#include "classfile/protectionDomainCache.hpp"
#include "classfile/systemDictionary.hpp"
-#include "classfile/systemDictionaryShared.hpp"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/iterator.hpp"
@@ -44,16 +43,8 @@
// needs resizing, which is costly to do at Safepoint.
bool Dictionary::_some_dictionary_needs_resizing = false;
-size_t Dictionary::entry_size() {
- if (DumpSharedSpaces) {
- return SystemDictionaryShared::dictionary_entry_size();
- } else {
- return sizeof(DictionaryEntry);
- }
-}
-
Dictionary::Dictionary(ClassLoaderData* loader_data, int table_size, bool resizable)
- : Hashtable<InstanceKlass*, mtClass>(table_size, (int)entry_size()),
+ : Hashtable<InstanceKlass*, mtClass>(table_size, (int)sizeof(DictionaryEntry)),
_resizable(resizable), _needs_resizing(false), _loader_data(loader_data) {
};
@@ -61,7 +52,7 @@
Dictionary::Dictionary(ClassLoaderData* loader_data,
int table_size, HashtableBucket<mtClass>* t,
int number_of_entries, bool resizable)
- : Hashtable<InstanceKlass*, mtClass>(table_size, (int)entry_size(), t, number_of_entries),
+ : Hashtable<InstanceKlass*, mtClass>(table_size, (int)sizeof(DictionaryEntry), t, number_of_entries),
_resizable(resizable), _needs_resizing(false), _loader_data(loader_data) {
};
@@ -83,9 +74,6 @@
DictionaryEntry* entry = (DictionaryEntry*)Hashtable<InstanceKlass*, mtClass>::allocate_new_entry(hash, klass);
entry->set_pd_set(NULL);
assert(klass->is_instance_klass(), "Must be");
- if (DumpSharedSpaces) {
- SystemDictionaryShared::init_shared_dictionary_entry(klass, entry);
- }
return entry;
}
@@ -280,26 +268,6 @@
}
}
-void Dictionary::remove_classes_in_error_state() {
- assert(DumpSharedSpaces, "supported only when dumping");
- DictionaryEntry* probe = NULL;
- for (int index = 0; index < table_size(); index++) {
- for (DictionaryEntry** p = bucket_addr(index); *p != NULL; ) {
- probe = *p;
- InstanceKlass* ik = probe->instance_klass();
- if (ik->is_in_error_state()) { // purge this entry
- *p = probe->next();
- free_entry(probe);
- ResourceMark rm;
- tty->print_cr("Preload Warning: Removed error class: %s", ik->external_name());
- continue;
- }
-
- p = probe->next_addr();
- }
- }
-}
-
// Just the classes from defining class loaders
void Dictionary::classes_do(void f(InstanceKlass*)) {
for (int index = 0; index < table_size(); index++) {
@@ -349,7 +317,6 @@
probe != NULL;
probe = probe->next()) {
it->push(probe->klass_addr());
- ((SharedDictionaryEntry*)probe)->metaspace_pointers_do(it);
}
}
}
@@ -390,9 +357,7 @@
entry != NULL;
entry = entry->next()) {
if (entry->hash() == hash && entry->equals(class_name)) {
- if (!DumpSharedSpaces || SystemDictionaryShared::is_builtin(entry)) {
- return entry;
- }
+ return entry;
}
}
return NULL;
@@ -423,18 +388,6 @@
}
-// Variant of find_class for shared classes. No locking required, as
-// that table is static.
-
-InstanceKlass* Dictionary::find_shared_class(int index, unsigned int hash,
- Symbol* name) {
- assert (index == index_for(name), "incorrect index?");
-
- DictionaryEntry* entry = get_entry(index, hash, name);
- return (entry != NULL) ? entry->instance_klass() : NULL;
-}
-
-
void Dictionary::add_protection_domain(int index, unsigned int hash,
InstanceKlass* klass,
Handle protection_domain,
@@ -465,70 +418,6 @@
return entry->is_valid_protection_domain(protection_domain);
}
-#if INCLUDE_CDS
-static bool is_jfr_event_class(Klass *k) {
- while (k) {
- if (k->name()->equals("jdk/internal/event/Event")) {
- return true;
- }
- k = k->super();
- }
- return false;
-}
-
-void Dictionary::reorder_dictionary_for_sharing() {
-
- // Copy all the dictionary entries into a single master list.
- assert(DumpSharedSpaces, "Should only be used at dump time");
-
- DictionaryEntry* master_list = NULL;
- for (int i = 0; i < table_size(); ++i) {
- DictionaryEntry* p = bucket(i);
- while (p != NULL) {
- DictionaryEntry* next = p->next();
- InstanceKlass*ik = p->instance_klass();
- if (ik->has_signer_and_not_archived()) {
- // We cannot include signed classes in the archive because the certificates
- // used during dump time may be different than those used during
- // runtime (due to expiration, etc).
- ResourceMark rm;
- tty->print_cr("Preload Warning: Skipping %s from signed JAR",
- ik->name()->as_C_string());
- free_entry(p);
- } else if (is_jfr_event_class(ik)) {
- // We cannot include JFR event classes because they need runtime-specific
- // instrumentation in order to work with -XX:FlightRecorderOptions=retransform=false.
- // There are only a small number of these classes, so it's not worthwhile to
- // support them and make CDS more complicated.
- ResourceMark rm;
- tty->print_cr("Skipping JFR event class %s", ik->name()->as_C_string());
- free_entry(p);
- } else {
- p->set_next(master_list);
- master_list = p;
- }
- p = next;
- }
- set_entry(i, NULL);
- }
-
- // Add the dictionary entries back to the list in the correct buckets.
- while (master_list != NULL) {
- DictionaryEntry* p = master_list;
- master_list = master_list->next();
- p->set_next(NULL);
- Symbol* class_name = p->instance_klass()->name();
- // Since the null class loader data isn't copied to the CDS archive,
- // compute the hash with NULL for loader data.
- unsigned int hash = compute_hash(class_name);
- int index = hash_to_index(hash);
- p->set_hash(hash);
- p->set_next(bucket(index));
- set_entry(index, p);
- }
-}
-#endif
-
SymbolPropertyTable::SymbolPropertyTable(int table_size)
: Hashtable<Symbol*, mtSymbol>(table_size, sizeof(SymbolPropertyEntry))
{
@@ -605,10 +494,7 @@
(loader_data() == e->class_loader_data());
st->print("%4d: %s%s", index, is_defining_class ? " " : "^", e->external_name());
ClassLoaderData* cld = e->class_loader_data();
- if (cld == NULL) {
- // Shared class not restored yet in shared dictionary
- st->print(", loader data <shared, not restored>");
- } else if (!loader_data()->is_the_null_class_loader_data()) {
+ if (!loader_data()->is_the_null_class_loader_data()) {
// Class loader output for the dictionary for the null class loader data is
// redundant and obvious.
st->print(", ");
@@ -634,7 +520,7 @@
ClassLoaderData* cld = loader_data();
// class loader must be present; a null class loader is the
// boostrap loader
- guarantee(cld != NULL || DumpSharedSpaces ||
+ guarantee(cld != NULL ||
cld->class_loader() == NULL ||
cld->class_loader()->is_instance(),
"checking type of class_loader");
--- a/src/hotspot/share/classfile/dictionary.hpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/classfile/dictionary.hpp Wed Nov 07 19:40:27 2018 -0800
@@ -36,8 +36,7 @@
class BoolObjectClosure;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// The data structure for the class loader data dictionaries (and the shared system
-// dictionary).
+// The data structure for the class loader data dictionaries.
class Dictionary : public Hashtable<InstanceKlass*, mtClass> {
friend class VMStructs;
@@ -54,8 +53,6 @@
void clean_cached_protection_domains(DictionaryEntry* probe);
-protected:
- static size_t entry_size();
public:
Dictionary(ClassLoaderData* loader_data, int table_size, bool resizable = false);
Dictionary(ClassLoaderData* loader_data, int table_size, HashtableBucket<mtClass>* t, int number_of_entries, bool resizable = false);
@@ -70,15 +67,12 @@
InstanceKlass* find_class(int index, unsigned int hash, Symbol* name);
- InstanceKlass* find_shared_class(int index, unsigned int hash, Symbol* name);
-
void classes_do(void f(InstanceKlass*));
void classes_do(void f(InstanceKlass*, TRAPS), TRAPS);
void all_entries_do(KlassClosure* closure);
void classes_do(MetaspaceClosure* it);
void unlink();
- void remove_classes_in_error_state();
// Unload classes whose defining loaders are unloaded
void do_unloading();
@@ -92,9 +86,6 @@
InstanceKlass* klass,
Handle protection_domain, TRAPS);
- // Sharing support
- void reorder_dictionary_for_sharing() NOT_CDS_RETURN;
-
void print_on(outputStream* st) const;
void verify();
DictionaryEntry* bucket(int i) const {
--- a/src/hotspot/share/classfile/javaClasses.cpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/classfile/javaClasses.cpp Wed Nov 07 19:40:27 2018 -0800
@@ -1090,8 +1090,7 @@
if (k->is_instance_klass()) {
InstanceKlass *ik = InstanceKlass::cast(k);
- assert(ik->signers() == NULL && !k->has_signer_and_not_archived(),
- "class with signer cannot be supported");
+ assert(ik->signers() == NULL, "class with signer should have been excluded");
if (!(ik->is_shared_boot_class() || ik->is_shared_platform_class() ||
ik->is_shared_app_class())) {
--- a/src/hotspot/share/classfile/symbolTable.cpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/classfile/symbolTable.cpp Wed Nov 07 19:40:27 2018 -0800
@@ -57,9 +57,6 @@
#define ON_STACK_BUFFER_LENGTH 128
// --------------------------------------------------------------------------
-inline Symbol* read_symbol_from_compact_hashtable(address base_address, u4 offset) {
- return (Symbol*)(base_address + offset);
-}
inline bool symbol_equals_compact_hashtable_entry(Symbol* value, const char* key, int len) {
if (value->equals(key, len)) {
@@ -70,9 +67,8 @@
}
}
-static CompactHashtable<
+static OffsetCompactHashtable<
const char*, Symbol*,
- read_symbol_from_compact_hashtable,
symbol_equals_compact_hashtable_entry
> _shared_table;
@@ -637,16 +633,7 @@
unsigned int fixed_hash = hash_shared_symbol((const char*)sym->bytes(), sym->utf8_length());
assert(fixed_hash == hash_symbol((const char*)sym->bytes(), sym->utf8_length(), false),
"must not rehash during dumping");
-
- uintx deltax = MetaspaceShared::object_delta(sym);
- // When the symbols are stored into the archive, we already check that
- // they won't be more than MAX_SHARED_DELTA from the base address, or
- // else the dumping would have been aborted.
- assert(deltax <= MAX_SHARED_DELTA, "must not be");
- u4 delta = u4(deltax);
-
- // add to the compact table
- _writer->add(fixed_hash, delta);
+ _writer->add(fixed_hash, MetaspaceShared::object_delta_u4(sym));
return true;
}
};
--- a/src/hotspot/share/classfile/systemDictionary.cpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/classfile/systemDictionary.cpp Wed Nov 07 19:40:27 2018 -0800
@@ -96,7 +96,6 @@
#endif
PlaceholderTable* SystemDictionary::_placeholders = NULL;
-Dictionary* SystemDictionary::_shared_dictionary = NULL;
LoaderConstraintTable* SystemDictionary::_loader_constraints = NULL;
ResolutionErrorTable* SystemDictionary::_resolution_errors = NULL;
SymbolPropertyTable* SystemDictionary::_invoke_method_table = NULL;
@@ -355,7 +354,7 @@
assert(!FieldType::is_array(super_name), "invalid super class name");
#if INCLUDE_CDS
if (DumpSharedSpaces) {
- // Special processing for CDS dump time.
+ // Special processing for handling UNREGISTERED shared classes.
InstanceKlass* k = SystemDictionaryShared::dump_time_resolve_super_or_fail(child_name,
super_name, class_loader, protection_domain, is_superclass, CHECK_NULL);
if (k) {
@@ -1163,39 +1162,11 @@
}
#if INCLUDE_CDS
-void SystemDictionary::set_shared_dictionary(HashtableBucket<mtClass>* t, int length,
- int number_of_entries) {
- assert(!DumpSharedSpaces, "Should not be called with DumpSharedSpaces");
- assert(length == _shared_dictionary_size * sizeof(HashtableBucket<mtClass>),
- "bad shared dictionary size.");
- _shared_dictionary = new Dictionary(ClassLoaderData::the_null_class_loader_data(),
- _shared_dictionary_size, t, number_of_entries,
- false /* explicitly set _resizable to false */);
-}
-
-
-// If there is a shared dictionary, then find the entry for the
-// given shared system class, if any.
-
-InstanceKlass* SystemDictionary::find_shared_class(Symbol* class_name) {
- if (shared_dictionary() != NULL) {
- unsigned int d_hash = shared_dictionary()->compute_hash(class_name);
- int d_index = shared_dictionary()->hash_to_index(d_hash);
-
- return shared_dictionary()->find_shared_class(d_index, d_hash, class_name);
- } else {
- return NULL;
- }
-}
-
-
-// Load a class for boot loader from the shared spaces (found through
-// the shared system dictionary). Force the super class and all interfaces
-// to be loaded.
+// Load a class for boot loader from the shared spaces. This also
+// forces the super class and all interfaces to be loaded.
InstanceKlass* SystemDictionary::load_shared_boot_class(Symbol* class_name,
TRAPS) {
- InstanceKlass* ik = find_shared_class(class_name);
- // Make sure we only return the boot class.
+ InstanceKlass* ik = SystemDictionaryShared::find_builtin_class(class_name);
if (ik != NULL && ik->is_shared_boot_class()) {
return load_shared_class(ik, Handle(), Handle(), THREAD);
}
@@ -1410,18 +1381,6 @@
}
return ik;
}
-
-void SystemDictionary::clear_invoke_method_table() {
- SymbolPropertyEntry* spe = NULL;
- for (int index = 0; index < _invoke_method_table->table_size(); index++) {
- SymbolPropertyEntry* p = _invoke_method_table->bucket(index);
- while (p != NULL) {
- spe = p;
- p = p->next();
- _invoke_method_table->free_entry(spe);
- }
- }
-}
#endif // INCLUDE_CDS
InstanceKlass* SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) {
@@ -1900,11 +1859,6 @@
invoke_method_table()->oops_do(f);
}
-// CDS: scan and relocate all classes in the system dictionary.
-void SystemDictionary::classes_do(MetaspaceClosure* it) {
- ClassLoaderData::the_null_class_loader_data()->dictionary()->classes_do(it);
-}
-
// CDS: scan and relocate all classes referenced by _well_known_klasses[].
void SystemDictionary::well_known_klasses_do(MetaspaceClosure* it) {
for (int id = FIRST_WKID; id < WKID_LIMIT; id++) {
@@ -1920,22 +1874,6 @@
invoke_method_table()->methods_do(f);
}
-class RemoveClassesClosure : public CLDClosure {
- public:
- void do_cld(ClassLoaderData* cld) {
- if (cld->is_system_class_loader_data() || cld->is_platform_class_loader_data()) {
- cld->dictionary()->remove_classes_in_error_state();
- }
- }
-};
-
-void SystemDictionary::remove_classes_in_error_state() {
- ClassLoaderData::the_null_class_loader_data()->dictionary()->remove_classes_in_error_state();
- RemoveClassesClosure rcc;
- MutexLocker ml(ClassLoaderDataGraph_lock);
- ClassLoaderDataGraph::cld_do(&rcc);
-}
-
// ----------------------------------------------------------------------------
// Initialization
@@ -2038,6 +1976,7 @@
HeapShared::fixup_mapped_heap_regions();
// Initialize the constant pool for the Object_class
+ assert(Object_klass()->is_shared(), "must be");
Object_klass()->constants()->restore_unshareable_info(CHECK);
resolve_wk_klasses_through(WK_KLASS_ENUM_NAME(Class_klass), scan, CHECK);
} else
@@ -2921,40 +2860,10 @@
return _pd_cache_table->get(protection_domain);
}
-#if INCLUDE_CDS
-void SystemDictionary::reorder_dictionary_for_sharing() {
- ClassLoaderData::the_null_class_loader_data()->dictionary()->reorder_dictionary_for_sharing();
-}
-#endif
-
-size_t SystemDictionary::count_bytes_for_buckets() {
- return ClassLoaderData::the_null_class_loader_data()->dictionary()->count_bytes_for_buckets();
-}
-
-size_t SystemDictionary::count_bytes_for_table() {
- return ClassLoaderData::the_null_class_loader_data()->dictionary()->count_bytes_for_table();
-}
-
-void SystemDictionary::copy_buckets(char* top, char* end) {
- ClassLoaderData::the_null_class_loader_data()->dictionary()->copy_buckets(top, end);
-}
-
-void SystemDictionary::copy_table(char* top, char* end) {
- ClassLoaderData::the_null_class_loader_data()->dictionary()->copy_table(top, end);
-}
-
// ----------------------------------------------------------------------------
-void SystemDictionary::print_shared(outputStream *st) {
- shared_dictionary()->print_on(st);
-}
void SystemDictionary::print_on(outputStream *st) {
- if (shared_dictionary() != NULL) {
- st->print_cr("Shared Dictionary");
- shared_dictionary()->print_on(st);
- st->cr();
- }
-
+ CDS_ONLY(SystemDictionaryShared::print_on(st));
GCMutexLocker mu(SystemDictionary_lock);
ClassLoaderDataGraph::print_dictionary(st);
@@ -2996,9 +2905,7 @@
if (verbose) {
print_on(st);
} else {
- if (shared_dictionary() != NULL) {
- shared_dictionary()->print_table_statistics(st, "Shared Dictionary");
- }
+ CDS_ONLY(SystemDictionaryShared::print_table_statistics(st));
ClassLoaderDataGraph::print_dictionary_statistics(st);
placeholders()->print_table_statistics(st, "Placeholder Table");
constraints()->print_table_statistics(st, "LoaderConstraints Table");
@@ -3031,60 +2938,6 @@
}
}
-class CombineDictionariesClosure : public CLDClosure {
- private:
- Dictionary* _master_dictionary;
- public:
- CombineDictionariesClosure(Dictionary* master_dictionary) :
- _master_dictionary(master_dictionary) {}
- void do_cld(ClassLoaderData* cld) {
- ResourceMark rm;
- if (cld->is_unsafe_anonymous()) {
- return;
- }
- if (cld->is_system_class_loader_data() || cld->is_platform_class_loader_data()) {
- for (int i = 0; i < cld->dictionary()->table_size(); ++i) {
- Dictionary* curr_dictionary = cld->dictionary();
- DictionaryEntry* p = curr_dictionary->bucket(i);
- while (p != NULL) {
- Symbol* name = p->instance_klass()->name();
- unsigned int d_hash = _master_dictionary->compute_hash(name);
- int d_index = _master_dictionary->hash_to_index(d_hash);
- DictionaryEntry* next = p->next();
- if (p->literal()->class_loader_data() != cld) {
- // This is an initiating class loader entry; don't use it
- log_trace(cds)("Skipping initiating cl entry: %s", name->as_C_string());
- curr_dictionary->free_entry(p);
- } else {
- log_trace(cds)("Moved to boot dictionary: %s", name->as_C_string());
- curr_dictionary->unlink_entry(p);
- p->set_pd_set(NULL); // pd_set is runtime only information and will be reconstructed.
- _master_dictionary->add_entry(d_index, p);
- }
- p = next;
- }
- *curr_dictionary->bucket_addr(i) = NULL;
- }
- }
- }
-};
-
-// Combining platform and system loader dictionaries into boot loader dictionary.
-// During run time, we only have one shared dictionary.
-void SystemDictionary::combine_shared_dictionaries() {
- assert(DumpSharedSpaces, "dump time only");
- Dictionary* master_dictionary = ClassLoaderData::the_null_class_loader_data()->dictionary();
- CombineDictionariesClosure cdc(master_dictionary);
- ClassLoaderDataGraph::cld_do(&cdc);
-
- // These tables are no longer valid or necessary. Keeping them around will
- // cause SystemDictionary::verify() to fail. Let's empty them.
- _placeholders = new PlaceholderTable(_placeholder_table_size);
- _loader_constraints = new LoaderConstraintTable(_loader_constraint_size);
-
- NOT_PRODUCT(SystemDictionary::verify());
-}
-
void SystemDictionary::initialize_oop_storage() {
_vm_weak_oop_storage =
new OopStorage("VM Weak Oop Handles",
--- a/src/hotspot/share/classfile/systemDictionary.hpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/classfile/systemDictionary.hpp Wed Nov 07 19:40:27 2018 -0800
@@ -349,11 +349,6 @@
// loaders. Returns "true" iff something was unloaded.
static bool do_unloading(GCTimer* gc_timer);
- // Used by DumpSharedSpaces only to remove classes that failed verification
- static void remove_classes_in_error_state();
-
- static int calculate_systemdictionary_size(int loadedclasses);
-
// Applies "f->do_oop" to all root oops in the system dictionary.
static void oops_do(OopClosure* f);
@@ -364,19 +359,9 @@
static ProtectionDomainCacheTable* pd_cache_table() { return _pd_cache_table; }
public:
- // Sharing support.
- static void reorder_dictionary_for_sharing() NOT_CDS_RETURN;
- static void combine_shared_dictionaries();
- static size_t count_bytes_for_buckets();
- static size_t count_bytes_for_table();
- static void copy_buckets(char* top, char* end);
- static void copy_table(char* top, char* end);
- static void set_shared_dictionary(HashtableBucket<mtClass>* t, int length,
- int number_of_entries);
// Printing
static void print() { return print_on(tty); }
static void print_on(outputStream* st);
- static void print_shared(outputStream* st);
static void dump(outputStream* st, bool verbose);
// Monotonically increasing counter which grows as classes are
@@ -579,7 +564,6 @@
_loader_constraint_size = 107, // number of entries in constraint table
_resolution_error_size = 107, // number of entries in resolution error table
_invoke_method_size = 139, // number of entries in invoke method table
- _shared_dictionary_size = 1009, // number of entries in shared dictionary
_placeholder_table_size = 1009 // number of entries in hash table for placeholders
};
@@ -589,9 +573,6 @@
// Hashtable holding placeholders for classes being loaded.
static PlaceholderTable* _placeholders;
- // Hashtable holding classes from the shared archive.
- static Dictionary* _shared_dictionary;
-
// Monotonically increasing counter which grows with
// loading classes as well as hot-swapping and breakpoint setting
// and removal.
@@ -622,7 +603,6 @@
friend class VM_PopulateDumpSharedSpace;
friend class TraversePlaceholdersClosure;
- static Dictionary* shared_dictionary() { return _shared_dictionary; }
static PlaceholderTable* placeholders() { return _placeholders; }
static LoaderConstraintTable* constraints() { return _loader_constraints; }
static ResolutionErrorTable* resolution_errors() { return _resolution_errors; }
@@ -662,7 +642,6 @@
public:
static bool is_system_class_loader(oop class_loader);
static bool is_platform_class_loader(oop class_loader);
- static void clear_invoke_method_table();
// Returns TRUE if the method is a non-public member of class java.lang.Object.
static bool is_nonpublic_Object_method(Method* m) {
@@ -674,8 +653,6 @@
static OopStorage* vm_weak_oop_storage();
protected:
- static InstanceKlass* find_shared_class(Symbol* class_name);
-
// Setup link to hierarchy
static void add_to_hierarchy(InstanceKlass* k, TRAPS);
--- a/src/hotspot/share/classfile/systemDictionaryShared.cpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp Wed Nov 07 19:40:27 2018 -0800
@@ -53,12 +53,277 @@
#include "runtime/javaCalls.hpp"
#include "runtime/mutexLocker.hpp"
#include "utilities/hashtable.inline.hpp"
+#include "utilities/resourceHash.hpp"
#include "utilities/stringUtils.hpp"
objArrayOop SystemDictionaryShared::_shared_protection_domains = NULL;
objArrayOop SystemDictionaryShared::_shared_jar_urls = NULL;
objArrayOop SystemDictionaryShared::_shared_jar_manifests = NULL;
+DEBUG_ONLY(bool SystemDictionaryShared::_checked_excluded_classes = false;)
+
+class DumpTimeSharedClassInfo: public CHeapObj<mtClass> {
+public:
+ struct DTConstraint {
+ Symbol* _name;
+ Symbol* _from_name;
+ DTConstraint() : _name(NULL), _from_name(NULL) {}
+ DTConstraint(Symbol* n, Symbol* fn) : _name(n), _from_name(fn) {}
+ };
+
+ InstanceKlass* _klass;
+ int _id;
+ int _clsfile_size;
+ int _clsfile_crc32;
+ bool _excluded;
+ GrowableArray<DTConstraint>* _verifier_constraints;
+ GrowableArray<char>* _verifier_constraint_flags;
+
+ DumpTimeSharedClassInfo() {
+ _klass = NULL;
+ _id = -1;
+ _clsfile_size = -1;
+ _clsfile_crc32 = -1;
+ _excluded = false;
+ _verifier_constraints = NULL;
+ _verifier_constraint_flags = NULL;
+ }
+
+ void add_verification_constraint(InstanceKlass* k, Symbol* name,
+ Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object);
+
+ bool is_builtin() {
+ return SystemDictionaryShared::is_builtin(_klass);
+ }
+
+ int num_constraints() {
+ if (_verifier_constraint_flags != NULL) {
+ return _verifier_constraint_flags->length();
+ } else {
+ return 0;
+ }
+ }
+
+ void metaspace_pointers_do(MetaspaceClosure* it) {
+ it->push(&_klass);
+ if (_verifier_constraints != NULL) {
+ for (int i = 0; i < _verifier_constraints->length(); i++) {
+ DTConstraint* cons = _verifier_constraints->adr_at(i);
+ it->push(&cons->_name);
+ it->push(&cons->_from_name);
+ }
+ }
+ }
+};
+
+class DumpTimeSharedClassTable: public ResourceHashtable<
+ InstanceKlass*,
+ DumpTimeSharedClassInfo,
+ primitive_hash<InstanceKlass*>,
+ primitive_equals<InstanceKlass*>,
+ 15889, // prime number
+ ResourceObj::C_HEAP>
+{
+ int _builtin_count;
+ int _unregistered_count;
+public:
+ DumpTimeSharedClassInfo* find_or_allocate_info_for(InstanceKlass* k) {
+ DumpTimeSharedClassInfo* p = get(k);
+ if (p == NULL) {
+ assert(!SystemDictionaryShared::checked_excluded_classes(),
+ "no new classes can be added after check_excluded_classes");
+ put(k, DumpTimeSharedClassInfo());
+ p = get(k);
+ assert(p != NULL, "sanity");
+ p->_klass = k;
+ }
+ return p;
+ }
+
+ class CountClassByCategory : StackObj {
+ DumpTimeSharedClassTable* _table;
+ public:
+ CountClassByCategory(DumpTimeSharedClassTable* table) : _table(table) {}
+ bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
+ if (SystemDictionaryShared::is_builtin(k)) {
+ ++ _table->_builtin_count;
+ } else {
+ ++ _table->_unregistered_count;
+ }
+ return true; // keep on iterating
+ }
+ };
+
+ void update_counts() {
+ CountClassByCategory counter(this);
+ iterate(&counter);
+ }
+
+ int count_of(bool is_builtin) const {
+ if (is_builtin) {
+ return _builtin_count;
+ } else {
+ return _unregistered_count;
+ }
+ }
+};
+
+class RunTimeSharedClassInfo {
+public:
+ struct CrcInfo {
+ int _clsfile_size;
+ int _clsfile_crc32;
+ };
+
+ // This is different than DumpTimeSharedClassInfo::DTConstraint. We use
+ // u4 instead of Symbol* to save space on 64-bit CPU.
+ struct RTConstraint {
+ u4 _name;
+ u4 _from_name;
+ };
+
+ InstanceKlass* _klass;
+ int _num_constraints;
+
+ // optional CrcInfo _crc; (only for UNREGISTERED classes)
+ // optional RTConstraint _verifier_constraints[_num_constraints]
+ // optional char _verifier_constraint_flags[_num_constraints]
+
+private:
+ static size_t header_size_size() {
+ return sizeof(RunTimeSharedClassInfo);
+ }
+ static size_t crc_size(InstanceKlass* klass) {
+ if (!SystemDictionaryShared::is_builtin(klass)) {
+ return sizeof(CrcInfo);
+ } else {
+ return 0;
+ }
+ }
+ static size_t verifier_constraints_size(int num_constraints) {
+ return sizeof(RTConstraint) * num_constraints;
+ }
+ static size_t verifier_constraint_flags_size(int num_constraints) {
+ return sizeof(char) * num_constraints;
+ }
+
+public:
+ static size_t byte_size(InstanceKlass* klass, int num_constraints) {
+ return header_size_size() +
+ crc_size(klass) +
+ verifier_constraints_size(num_constraints) +
+ verifier_constraint_flags_size(num_constraints);
+ }
+
+private:
+ size_t crc_offset() const {
+ return header_size_size();
+ }
+ size_t verifier_constraints_offset() const {
+ return crc_offset() + crc_size(_klass);
+ }
+ size_t verifier_constraint_flags_offset() const {
+ return verifier_constraints_offset() + verifier_constraints_size(_num_constraints);
+ }
+
+ void check_constraint_offset(int i) const {
+ assert(0 <= i && i < _num_constraints, "sanity");
+ }
+
+public:
+ CrcInfo* crc() const {
+ assert(crc_size(_klass) > 0, "must be");
+ return (CrcInfo*)(address(this) + crc_offset());
+ }
+ RTConstraint* verifier_constraints() {
+ assert(_num_constraints > 0, "sanity");
+ return (RTConstraint*)(address(this) + verifier_constraints_offset());
+ }
+ RTConstraint* verifier_constraint_at(int i) {
+ check_constraint_offset(i);
+ return verifier_constraints() + i;
+ }
+
+ char* verifier_constraint_flags() {
+ assert(_num_constraints > 0, "sanity");
+ return (char*)(address(this) + verifier_constraint_flags_offset());
+ }
+
+ void init(DumpTimeSharedClassInfo& info) {
+ _klass = info._klass;
+ _num_constraints = info.num_constraints();
+ if (!SystemDictionaryShared::is_builtin(_klass)) {
+ CrcInfo* c = crc();
+ c->_clsfile_size = info._clsfile_size;
+ c->_clsfile_crc32 = info._clsfile_crc32;
+ }
+ if (_num_constraints > 0) {
+ RTConstraint* constraints = verifier_constraints();
+ char* flags = verifier_constraint_flags();
+ int i;
+ for (i = 0; i < _num_constraints; i++) {
+ constraints[i]._name = MetaspaceShared::object_delta_u4(info._verifier_constraints->at(i)._name);
+ constraints[i]._from_name = MetaspaceShared::object_delta_u4(info._verifier_constraints->at(i)._from_name);
+ }
+ for (i = 0; i < _num_constraints; i++) {
+ flags[i] = info._verifier_constraint_flags->at(i);
+ }
+ }
+ }
+
+ bool matches(int clsfile_size, int clsfile_crc32) const {
+ return crc()->_clsfile_size == clsfile_size &&
+ crc()->_clsfile_crc32 == clsfile_crc32;
+ }
+
+ Symbol* get_constraint_name(int i) {
+ return (Symbol*)(SharedBaseAddress + verifier_constraint_at(i)->_name);
+ }
+ Symbol* get_constraint_from_name(int i) {
+ return (Symbol*)(SharedBaseAddress + verifier_constraint_at(i)->_from_name);
+ }
+
+ char get_constraint_flag(int i) {
+ check_constraint_offset(i);
+ return verifier_constraint_flags()[i];
+ }
+
+private:
+ // ArchiveCompactor::allocate() has reserved a pointer immediately before
+ // archived InstanceKlasses. We can use this slot to do a quick
+ // lookup of InstanceKlass* -> RunTimeSharedClassInfo* without
+ // building a new hashtable.
+ //
+ // info_pointer_addr(klass) --> 0x0100 RunTimeSharedClassInfo*
+ // InstanceKlass* klass --> 0x0108 <C++ vtbl>
+ // 0x0110 fields from Klass ...
+ static RunTimeSharedClassInfo** info_pointer_addr(InstanceKlass* klass) {
+ return &((RunTimeSharedClassInfo**)klass)[-1];
+ }
+
+public:
+ static RunTimeSharedClassInfo* get_for(InstanceKlass* klass) {
+ return *info_pointer_addr(klass);
+ }
+ static void set_for(InstanceKlass* klass, RunTimeSharedClassInfo* record) {
+ *info_pointer_addr(klass) = record;
+ }
+
+ // Used by RunTimeSharedDictionary to implement OffsetCompactHashtable::EQUALS
+ static inline bool EQUALS(
+ const RunTimeSharedClassInfo* value, Symbol* key, int len_unused) {
+ return (value->_klass->name() == key);
+ }
+};
+
+class RunTimeSharedDictionary : public OffsetCompactHashtable<
+ Symbol*,
+ const RunTimeSharedClassInfo*,
+ RunTimeSharedClassInfo::EQUALS> {};
+
+static DumpTimeSharedClassTable* _dumptime_table = NULL;
+static RunTimeSharedDictionary _builtin_dictionary;
+static RunTimeSharedDictionary _unregistered_dictionary;
oop SystemDictionaryShared::shared_protection_domain(int index) {
return _shared_protection_domains->obj_at(index);
@@ -478,9 +743,8 @@
return NULL;
}
- if (shared_dictionary() != NULL &&
- (SystemDictionary::is_system_class_loader(class_loader()) ||
- SystemDictionary::is_platform_class_loader(class_loader()))) {
+ if (SystemDictionary::is_system_class_loader(class_loader()) ||
+ SystemDictionary::is_platform_class_loader(class_loader())) {
// Fix for 4474172; see evaluation for more details
class_loader = Handle(
THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
@@ -523,8 +787,7 @@
InstanceKlass* SystemDictionaryShared::load_shared_class_for_builtin_loader(
Symbol* class_name, Handle class_loader, TRAPS) {
assert(UseSharedSpaces, "must be");
- assert(shared_dictionary() != NULL, "already checked");
- InstanceKlass* ik = shared_dictionary()->find_class_for_builtin_loader(class_name);
+ InstanceKlass* ik = find_builtin_class(class_name);
if (ik != NULL) {
if ((ik->is_shared_app_class() &&
@@ -536,7 +799,6 @@
return load_shared_class(ik, class_loader, protection_domain, THREAD);
}
}
-
return NULL;
}
@@ -574,12 +836,12 @@
}
// This function is called for loading only UNREGISTERED classes
-InstanceKlass* SystemDictionaryShared::lookup_from_stream(const Symbol* class_name,
+InstanceKlass* SystemDictionaryShared::lookup_from_stream(Symbol* class_name,
Handle class_loader,
Handle protection_domain,
const ClassFileStream* cfs,
TRAPS) {
- if (shared_dictionary() == NULL) {
+ if (!UseSharedSpaces) {
return NULL;
}
if (class_name == NULL) { // don't do this for anonymous classes
@@ -592,27 +854,18 @@
return NULL;
}
- ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(class_loader());
- InstanceKlass* k;
-
- { // UNREGISTERED loader
- if (!shared_dictionary()->class_exists_for_unregistered_loader(class_name)) {
- // No classes of this name for unregistered loaders.
- return NULL;
- }
-
- int clsfile_size = cfs->length();
- int clsfile_crc32 = ClassLoader::crc32(0, (const char*)cfs->buffer(), cfs->length());
-
- k = shared_dictionary()->find_class_for_unregistered_loader(class_name,
- clsfile_size, clsfile_crc32);
- }
-
- if (k == NULL) { // not archived
+ const RunTimeSharedClassInfo* record = find_record(&_unregistered_dictionary, class_name);
+ if (record == NULL) {
return NULL;
}
- return acquire_class_for_current_thread(k, class_loader,
+ int clsfile_size = cfs->length();
+ int clsfile_crc32 = ClassLoader::crc32(0, (const char*)cfs->buffer(), cfs->length());
+ if (!record->matches(clsfile_size, clsfile_crc32)) {
+ return NULL;
+ }
+
+ return acquire_class_for_current_thread(record->_klass, class_loader,
protection_domain, THREAD);
}
@@ -649,19 +902,27 @@
return shared_klass;
}
-bool SystemDictionaryShared::add_non_builtin_klass(Symbol* name,
- ClassLoaderData* loader_data,
- InstanceKlass* k,
- TRAPS) {
+static ResourceHashtable<
+ Symbol*, bool,
+ primitive_hash<Symbol*>,
+ primitive_equals<Symbol*>,
+ 6661, // prime number
+ ResourceObj::C_HEAP> _loaded_unregistered_classes;
+
+bool SystemDictionaryShared::add_unregistered_class(InstanceKlass* k, TRAPS) {
assert(DumpSharedSpaces, "only when dumping");
- assert(boot_loader_dictionary() != NULL, "must be");
- if (boot_loader_dictionary()->add_non_builtin_klass(name, loader_data, k)) {
- MutexLocker mu_r(Compile_lock, THREAD); // not really necessary, but add_to_hierarchy asserts this.
- add_to_hierarchy(k, CHECK_0);
+ Symbol* name = k->name();
+ if (_loaded_unregistered_classes.get(name) != NULL) {
+ // We don't allow duplicated unregistered classes of the same name.
+ return false;
+ } else {
+ bool isnew = _loaded_unregistered_classes.put(name, true);
+ assert(isnew, "sanity");
+ MutexLocker mu_r(Compile_lock, THREAD); // add_to_hierarchy asserts this.
+ SystemDictionary::add_to_hierarchy(k, CHECK_0);
return true;
}
- return false;
}
// This function is called to resolve the super/interfaces of shared classes for
@@ -698,81 +959,138 @@
}
}
-struct SharedMiscInfo {
- InstanceKlass* _klass;
- int _clsfile_size;
- int _clsfile_crc32;
-};
-
-static GrowableArray<SharedMiscInfo>* misc_info_array = NULL;
+DumpTimeSharedClassInfo* SystemDictionaryShared::find_or_allocate_info_for(InstanceKlass* k) {
+ if (_dumptime_table == NULL) {
+ _dumptime_table = new (ResourceObj::C_HEAP, mtClass)DumpTimeSharedClassTable();
+ }
+ return _dumptime_table->find_or_allocate_info_for(k);
+}
void SystemDictionaryShared::set_shared_class_misc_info(InstanceKlass* k, ClassFileStream* cfs) {
assert(DumpSharedSpaces, "only when dumping");
- int clsfile_size = cfs->length();
- int clsfile_crc32 = ClassLoader::crc32(0, (const char*)cfs->buffer(), cfs->length());
+ assert(!is_builtin(k), "must be unregistered class");
+ DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k);
+ info->_clsfile_size = cfs->length();
+ info->_clsfile_crc32 = ClassLoader::crc32(0, (const char*)cfs->buffer(), cfs->length());
+}
- if (misc_info_array == NULL) {
- misc_info_array = new (ResourceObj::C_HEAP, mtClass) GrowableArray<SharedMiscInfo>(20, /*c heap*/ true);
- }
+void SystemDictionaryShared::init_dumptime_info(InstanceKlass* k) {
+ (void)find_or_allocate_info_for(k);
+}
+
+void SystemDictionaryShared::remove_dumptime_info(InstanceKlass* k) {
+ _dumptime_table->remove(k);
+}
- SharedMiscInfo misc_info;
- DEBUG_ONLY({
- for (int i=0; i<misc_info_array->length(); i++) {
- misc_info = misc_info_array->at(i);
- assert(misc_info._klass != k, "cannot call set_shared_class_misc_info twice for the same class");
- }
- });
+bool SystemDictionaryShared::is_jfr_event_class(InstanceKlass *k) {
+ while (k) {
+ if (k->name()->equals("jdk/internal/event/Event")) {
+ return true;
+ }
+ k = k->java_super();
+ }
+ return false;
+}
- misc_info._klass = k;
- misc_info._clsfile_size = clsfile_size;
- misc_info._clsfile_crc32 = clsfile_crc32;
-
- misc_info_array->append(misc_info);
+void SystemDictionaryShared::warn_excluded(InstanceKlass* k, const char* reason) {
+ ResourceMark rm;
+ log_warning(cds)("Skipping %s: %s", k->name()->as_C_string(), reason);
}
-void SystemDictionaryShared::init_shared_dictionary_entry(InstanceKlass* k, DictionaryEntry* ent) {
- SharedDictionaryEntry* entry = (SharedDictionaryEntry*)ent;
- entry->_id = -1;
- entry->_clsfile_size = -1;
- entry->_clsfile_crc32 = -1;
- entry->_verifier_constraints = NULL;
- entry->_verifier_constraint_flags = NULL;
+bool SystemDictionaryShared::should_be_excluded(InstanceKlass* k) {
+ if (k->class_loader_data()->is_unsafe_anonymous()) {
+ return true; // unsafe anonymous classes are not archived, skip
+ }
+ if (k->is_in_error_state()) {
+ return true;
+ }
+ if (k->shared_classpath_index() < 0 && is_builtin(k)) {
+ // These are classes loaded from unsupported locations (such as those loaded by JVMTI native
+ // agent during dump time).
+ warn_excluded(k, "Unsupported location");
+ return true;
+ }
+ if (k->signers() != NULL) {
+ // We cannot include signed classes in the archive because the certificates
+ // used during dump time may be different than those used during
+ // runtime (due to expiration, etc).
+ warn_excluded(k, "Signed JAR");
+ return true;
+ }
+ if (is_jfr_event_class(k)) {
+ // We cannot include JFR event classes because they need runtime-specific
+ // instrumentation in order to work with -XX:FlightRecorderOptions=retransform=false.
+ // There are only a small number of these classes, so it's not worthwhile to
+ // support them and make CDS more complicated.
+ warn_excluded(k, "JFR event class");
+ return true;
+ }
+ return false;
+}
- if (misc_info_array != NULL) {
- for (int i=0; i<misc_info_array->length(); i++) {
- SharedMiscInfo misc_info = misc_info_array->at(i);
- if (misc_info._klass == k) {
- entry->_clsfile_size = misc_info._clsfile_size;
- entry->_clsfile_crc32 = misc_info._clsfile_crc32;
- misc_info_array->remove_at(i);
- return;
- }
+// k is a class before relocating by ArchiveCompactor
+void SystemDictionaryShared::validate_before_archiving(InstanceKlass* k) {
+ ResourceMark rm;
+ const char* name = k->name()->as_C_string();
+ DumpTimeSharedClassInfo* info = _dumptime_table->get(k);
+ guarantee(info != NULL, "Class %s must be entered into _dumptime_table", name);
+ guarantee(!info->_excluded, "Should not attempt to archive excluded class %s", name);
+ if (is_builtin(k)) {
+ guarantee(k->loader_type() != 0,
+ "Class loader type must be set for BUILTIN class %s", name);
+ } else {
+ guarantee(k->loader_type() == 0,
+ "Class loader type must not be set for UNREGISTERED class %s", name);
+ }
+}
+
+class ExcludeDumpTimeSharedClasses : StackObj {
+public:
+ bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
+ if (SystemDictionaryShared::should_be_excluded(k)) {
+ info._excluded = true;
}
+ return true; // keep on iterating
}
+};
+
+void SystemDictionaryShared::check_excluded_classes() {
+ ExcludeDumpTimeSharedClasses excl;
+ _dumptime_table->iterate(&excl);
+ DEBUG_ONLY(_checked_excluded_classes = true;)
+}
+
+bool SystemDictionaryShared::is_excluded_class(InstanceKlass* k) {
+ assert(_checked_excluded_classes, "sanity");
+ assert(DumpSharedSpaces, "only when dumping");
+ return find_or_allocate_info_for(k)->_excluded;
+}
+
+class IterateDumpTimeSharedClassTable : StackObj {
+ MetaspaceClosure *_it;
+public:
+ IterateDumpTimeSharedClassTable(MetaspaceClosure* it) : _it(it) {}
+
+ bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
+ if (!info._excluded) {
+ info.metaspace_pointers_do(_it);
+ }
+ return true; // keep on iterating
+ }
+};
+
+void SystemDictionaryShared::dumptime_classes_do(class MetaspaceClosure* it) {
+ IterateDumpTimeSharedClassTable iter(it);
+ _dumptime_table->iterate(&iter);
}
bool SystemDictionaryShared::add_verification_constraint(InstanceKlass* k, Symbol* name,
Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object) {
assert(DumpSharedSpaces, "called at dump time only");
-
- // Skip unsafe anonymous classes, which are not archived as they are not in
- // dictionary (see assert_no_unsafe_anonymous_classes_in_dictionaries() in
- // VM_PopulateDumpSharedSpace::doit()).
- if (k->class_loader_data()->is_unsafe_anonymous()) {
- return true; // unsafe anonymous classes are not archived, skip
- }
-
- SharedDictionaryEntry* entry = ((SharedDictionary*)(k->class_loader_data()->dictionary()))->find_entry_for(k);
- ResourceMark rm;
- // Lambda classes are not archived and will be regenerated at runtime.
- if (entry == NULL) {
- guarantee(strstr(k->name()->as_C_string(), "Lambda$") != NULL,
- "class should be in dictionary before being verified");
- return true;
- }
- entry->add_verification_constraint(name, from_name, from_field_is_protected,
- from_is_array, from_is_object);
- if (entry->is_builtin()) {
+ DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k);
+ info->add_verification_constraint(k, name, from_name, from_field_is_protected,
+ from_is_array, from_is_object);
+ if (is_builtin(k)) {
// For builtin class loaders, we can try to complete the verification check at dump time,
// because we can resolve all the constraint classes.
return false;
@@ -783,135 +1101,54 @@
}
}
-void SystemDictionaryShared::finalize_verification_constraints_for(InstanceKlass* k) {
- if (!k->is_unsafe_anonymous()) {
- SharedDictionaryEntry* entry = ((SharedDictionary*)(k->class_loader_data()->dictionary()))->find_entry_for(k);
- entry->finalize_verification_constraints();
- }
-}
-
-void SystemDictionaryShared::finalize_verification_constraints() {
- MutexLocker mcld(ClassLoaderDataGraph_lock);
- ClassLoaderDataGraph::dictionary_classes_do(finalize_verification_constraints_for);
-}
-
-void SystemDictionaryShared::check_verification_constraints(InstanceKlass* klass,
- TRAPS) {
- assert(!DumpSharedSpaces && UseSharedSpaces, "called at run time with CDS enabled only");
- SharedDictionaryEntry* entry = shared_dictionary()->find_entry_for(klass);
- assert(entry != NULL, "call this only for shared classes");
- entry->check_verification_constraints(klass, THREAD);
-}
-
-SharedDictionaryEntry* SharedDictionary::find_entry_for(InstanceKlass* klass) {
- Symbol* class_name = klass->name();
- unsigned int hash = compute_hash(class_name);
- int index = hash_to_index(hash);
-
- for (SharedDictionaryEntry* entry = bucket(index);
- entry != NULL;
- entry = entry->next()) {
- if (entry->hash() == hash && entry->literal() == klass) {
- return entry;
- }
- }
-
- return NULL;
-}
-
-void SharedDictionaryEntry::add_verification_constraint(Symbol* name,
+void DumpTimeSharedClassInfo::add_verification_constraint(InstanceKlass* k, Symbol* name,
Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object) {
if (_verifier_constraints == NULL) {
- _verifier_constraints = new(ResourceObj::C_HEAP, mtClass) GrowableArray<Symbol*>(8, true, mtClass);
+ _verifier_constraints = new(ResourceObj::C_HEAP, mtClass) GrowableArray<DTConstraint>(4, true, mtClass);
}
if (_verifier_constraint_flags == NULL) {
_verifier_constraint_flags = new(ResourceObj::C_HEAP, mtClass) GrowableArray<char>(4, true, mtClass);
}
- GrowableArray<Symbol*>* vc_array = (GrowableArray<Symbol*>*)_verifier_constraints;
- for (int i=0; i<vc_array->length(); i+= 2) {
- if (name == vc_array->at(i) &&
- from_name == vc_array->at(i+1)) {
+ GrowableArray<DTConstraint>* vc_array = _verifier_constraints;
+ for (int i = 0; i < vc_array->length(); i++) {
+ DTConstraint* p = vc_array->adr_at(i);
+ if (name == p->_name && from_name == p->_from_name) {
return;
}
}
- vc_array->append(name);
- vc_array->append(from_name);
+ DTConstraint cons(name, from_name);
+ vc_array->append(cons);
- GrowableArray<char>* vcflags_array = (GrowableArray<char>*)_verifier_constraint_flags;
+ GrowableArray<char>* vcflags_array = _verifier_constraint_flags;
char c = 0;
- c |= from_field_is_protected ? FROM_FIELD_IS_PROTECTED : 0;
- c |= from_is_array ? FROM_IS_ARRAY : 0;
- c |= from_is_object ? FROM_IS_OBJECT : 0;
+ c |= from_field_is_protected ? SystemDictionaryShared::FROM_FIELD_IS_PROTECTED : 0;
+ c |= from_is_array ? SystemDictionaryShared::FROM_IS_ARRAY : 0;
+ c |= from_is_object ? SystemDictionaryShared::FROM_IS_OBJECT : 0;
vcflags_array->append(c);
if (log_is_enabled(Trace, cds, verification)) {
ResourceMark rm;
log_trace(cds, verification)("add_verification_constraint: %s: %s must be subclass of %s",
- instance_klass()->external_name(), from_name->as_klass_external_name(),
+ k->external_name(), from_name->as_klass_external_name(),
name->as_klass_external_name());
}
}
-int SharedDictionaryEntry::finalize_verification_constraints() {
- assert(DumpSharedSpaces, "called at dump time only");
- Thread* THREAD = Thread::current();
- ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
- GrowableArray<Symbol*>* vc_array = (GrowableArray<Symbol*>*)_verifier_constraints;
- GrowableArray<char>* vcflags_array = (GrowableArray<char>*)_verifier_constraint_flags;
-
- if (vc_array != NULL) {
- if (log_is_enabled(Trace, cds, verification)) {
- ResourceMark rm;
- log_trace(cds, verification)("finalize_verification_constraint: %s",
- literal()->external_name());
- }
+void SystemDictionaryShared::check_verification_constraints(InstanceKlass* klass,
+ TRAPS) {
+ assert(!DumpSharedSpaces && UseSharedSpaces, "called at run time with CDS enabled only");
+ RunTimeSharedClassInfo* record = RunTimeSharedClassInfo::get_for(klass);
- // Copy the constraints from C_HEAP-alloced GrowableArrays to Metaspace-alloced
- // Arrays
- int size = 0;
- {
- // FIXME: change this to be done after relocation, so we can use symbol offset??
- int length = vc_array->length();
- Array<Symbol*>* out = MetadataFactory::new_array<Symbol*>(loader_data, length, 0, THREAD);
- assert(out != NULL, "Dump time allocation failure would have aborted VM");
- for (int i=0; i<length; i++) {
- out->at_put(i, vc_array->at(i));
- }
- _verifier_constraints = out;
- size += out->size() * BytesPerWord;
- delete vc_array;
- }
- {
- int length = vcflags_array->length();
- Array<char>* out = MetadataFactory::new_array<char>(loader_data, length, 0, THREAD);
- assert(out != NULL, "Dump time allocation failure would have aborted VM");
- for (int i=0; i<length; i++) {
- out->at_put(i, vcflags_array->at(i));
- }
- _verifier_constraint_flags = out;
- size += out->size() * BytesPerWord;
- delete vcflags_array;
- }
+ int length = record->_num_constraints;
+ if (length > 0) {
+ for (int i = 0; i < length; i++) {
+ Symbol* name = record->get_constraint_name(i);
+ Symbol* from_name = record->get_constraint_from_name(i);
+ char c = record->get_constraint_flag(i);
- return size;
- }
- return 0;
-}
-
-void SharedDictionaryEntry::check_verification_constraints(InstanceKlass* klass, TRAPS) {
- Array<Symbol*>* vc_array = (Array<Symbol*>*)_verifier_constraints;
- Array<char>* vcflags_array = (Array<char>*)_verifier_constraint_flags;
-
- if (vc_array != NULL) {
- int length = vc_array->length();
- for (int i=0; i<length; i+=2) {
- Symbol* name = vc_array->at(i);
- Symbol* from_name = vc_array->at(i+1);
- char c = vcflags_array->at(i/2);
-
- bool from_field_is_protected = (c & FROM_FIELD_IS_PROTECTED) ? true : false;
- bool from_is_array = (c & FROM_IS_ARRAY) ? true : false;
- bool from_is_object = (c & FROM_IS_OBJECT) ? true : false;
+ bool from_field_is_protected = (c & SystemDictionaryShared::FROM_FIELD_IS_PROTECTED) ? true : false;
+ bool from_is_array = (c & SystemDictionaryShared::FROM_IS_ARRAY) ? true : false;
+ bool from_is_object = (c & SystemDictionaryShared::FROM_IS_OBJECT) ? true : false;
bool ok = VerificationType::resolve_and_check_assignability(klass, name,
from_name, from_field_is_protected, from_is_array, from_is_object, CHECK);
@@ -930,132 +1167,100 @@
}
}
-void SharedDictionaryEntry::metaspace_pointers_do(MetaspaceClosure* it) {
- it->push((Array<Symbol*>**)&_verifier_constraints);
- it->push((Array<char>**)&_verifier_constraint_flags);
+class CopySharedClassInfoToArchive : StackObj {
+ CompactHashtableWriter* _writer;
+ bool _is_builtin;
+public:
+ CopySharedClassInfoToArchive(CompactHashtableWriter* writer, bool is_builtin)
+ : _writer(writer), _is_builtin(is_builtin) {}
+
+ bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
+ if (!info._excluded && info.is_builtin() == _is_builtin) {
+ size_t byte_size = RunTimeSharedClassInfo::byte_size(info._klass, info.num_constraints());
+ RunTimeSharedClassInfo* record =
+ (RunTimeSharedClassInfo*)MetaspaceShared::read_only_space_alloc(byte_size);
+ record->init(info);
+
+ unsigned int hash = primitive_hash<Symbol*>(info._klass->name());
+ _writer->add(hash, MetaspaceShared::object_delta_u4(record));
+
+ // Save this for quick runtime lookup of InstanceKlass* -> RunTimeSharedClassInfo*
+ RunTimeSharedClassInfo::set_for(info._klass, record);
+ }
+ return true; // keep on iterating
+ }
+};
+
+void SystemDictionaryShared::write_dictionary(RunTimeSharedDictionary* dictionary, bool is_builtin) {
+ CompactHashtableStats stats;
+ dictionary->reset();
+ int num_buckets = CompactHashtableWriter::default_num_buckets(_dumptime_table->count_of(is_builtin));
+ CompactHashtableWriter writer(num_buckets, &stats);
+ CopySharedClassInfoToArchive copy(&writer, is_builtin);
+ _dumptime_table->iterate(©);
+ writer.dump(dictionary, is_builtin ? "builtin dictionary" : "unregistered dictionary");
}
-bool SharedDictionary::add_non_builtin_klass(const Symbol* class_name,
- ClassLoaderData* loader_data,
- InstanceKlass* klass) {
-
- assert(DumpSharedSpaces, "supported only when dumping");
- assert(klass != NULL, "adding NULL klass");
- assert(klass->name() == class_name, "sanity check on name");
- assert(klass->shared_classpath_index() < 0,
- "the shared classpath index should not be set for shared class loaded by the custom loaders");
-
- // Add an entry for a non-builtin class.
- // For a shared class for custom class loaders, SystemDictionary::resolve_or_null will
- // not find this class, because is_builtin() is false.
- unsigned int hash = compute_hash(class_name);
- int index = hash_to_index(hash);
-
- for (SharedDictionaryEntry* entry = bucket(index);
- entry != NULL;
- entry = entry->next()) {
- if (entry->hash() == hash) {
- InstanceKlass* klass = entry->instance_klass();
- if (klass->name() == class_name && klass->class_loader_data() == loader_data) {
- // There is already a class defined with the same name
- return false;
- }
- }
- }
-
- assert(Dictionary::entry_size() >= sizeof(SharedDictionaryEntry), "must be big enough");
- SharedDictionaryEntry* entry = (SharedDictionaryEntry*)new_entry(hash, klass);
- add_entry(index, entry);
-
- assert(entry->is_unregistered(), "sanity");
- assert(!entry->is_builtin(), "sanity");
- return true;
+void SystemDictionaryShared::write_to_archive() {
+ _dumptime_table->update_counts();
+ write_dictionary(&_builtin_dictionary, true);
+ write_dictionary(&_unregistered_dictionary, false);
}
-
-//-----------------
-// SharedDictionary
-//-----------------
-
-
-InstanceKlass* SharedDictionary::find_class_for_builtin_loader(const Symbol* name) const {
- SharedDictionaryEntry* entry = get_entry_for_builtin_loader(name);
- return entry != NULL ? entry->instance_klass() : (InstanceKlass*)NULL;
-}
-
-InstanceKlass* SharedDictionary::find_class_for_unregistered_loader(const Symbol* name,
- int clsfile_size,
- int clsfile_crc32) const {
-
- const SharedDictionaryEntry* entry = get_entry_for_unregistered_loader(name,
- clsfile_size,
- clsfile_crc32);
- return entry != NULL ? entry->instance_klass() : NULL;
+void SystemDictionaryShared::serialize_dictionary_headers(SerializeClosure* soc) {
+ _builtin_dictionary.serialize_header(soc);
+ _unregistered_dictionary.serialize_header(soc);
}
-void SharedDictionary::update_entry(InstanceKlass* klass, int id) {
- assert(DumpSharedSpaces, "supported only when dumping");
- Symbol* class_name = klass->name();
- unsigned int hash = compute_hash(class_name);
- int index = hash_to_index(hash);
+const RunTimeSharedClassInfo*
+SystemDictionaryShared::find_record(RunTimeSharedDictionary* dict, Symbol* name) {
+ if (UseSharedSpaces) {
+ unsigned int hash = primitive_hash<Symbol*>(name);
+ return dict->lookup(name, hash, 0);
+ } else {
+ return NULL;
+ }
+}
- for (SharedDictionaryEntry* entry = bucket(index);
- entry != NULL;
- entry = entry->next()) {
- if (entry->hash() == hash && entry->literal() == klass) {
- entry->_id = id;
- return;
- }
+InstanceKlass* SystemDictionaryShared::find_builtin_class(Symbol* name) {
+ const RunTimeSharedClassInfo* record = find_record(&_builtin_dictionary, name);
+ if (record) {
+ return record->_klass;
+ } else {
+ return NULL;
}
+}
- ShouldNotReachHere();
+void SystemDictionaryShared::update_shared_entry(InstanceKlass* k, int id) {
+ assert(DumpSharedSpaces, "supported only when dumping");
+ DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k);
+ info->_id = id;
}
-SharedDictionaryEntry* SharedDictionary::get_entry_for_builtin_loader(const Symbol* class_name) const {
- assert(!DumpSharedSpaces, "supported only when at runtime");
- unsigned int hash = compute_hash(class_name);
- const int index = hash_to_index(hash);
+class SharedDictionaryPrinter : StackObj {
+ outputStream* _st;
+ int _index;
+public:
+ SharedDictionaryPrinter(outputStream* st) : _st(st), _index(0) {}
- for (SharedDictionaryEntry* entry = bucket(index);
- entry != NULL;
- entry = entry->next()) {
- if (entry->hash() == hash && entry->equals(class_name)) {
- if (entry->is_builtin()) {
- return entry;
- }
- }
+ void do_value(const RunTimeSharedClassInfo* record) {
+ ResourceMark rm;
+ _st->print_cr("%4d: %s", (_index++), record->_klass->external_name());
}
- return NULL;
+};
+
+void SystemDictionaryShared::print_on(outputStream* st) {
+ if (UseSharedSpaces) {
+ st->print_cr("Shared Dictionary");
+ SharedDictionaryPrinter p(st);
+ _builtin_dictionary.iterate(&p);
+ _unregistered_dictionary.iterate(&p);
+ }
}
-SharedDictionaryEntry* SharedDictionary::get_entry_for_unregistered_loader(const Symbol* class_name,
- int clsfile_size,
- int clsfile_crc32) const {
- assert(!DumpSharedSpaces, "supported only when at runtime");
- unsigned int hash = compute_hash(class_name);
- int index = hash_to_index(hash);
-
- for (SharedDictionaryEntry* entry = bucket(index);
- entry != NULL;
- entry = entry->next()) {
- if (entry->hash() == hash && entry->equals(class_name)) {
- if (entry->is_unregistered()) {
- if (clsfile_size == -1) {
- // We're called from class_exists_for_unregistered_loader. At run time, we want to
- // compute the CRC of a ClassFileStream only if there is an UNREGISTERED class
- // with the matching name.
- return entry;
- } else {
- // We're called from find_class_for_unregistered_loader
- if (entry->_clsfile_size && clsfile_crc32 == entry->_clsfile_crc32) {
- return entry;
- }
- }
-
- // There can be only 1 class with this name for unregistered loaders.
- return NULL;
- }
- }
+void SystemDictionaryShared::print_table_statistics(outputStream* st) {
+ if (UseSharedSpaces) {
+ _builtin_dictionary.print_table_statistics(st, "Builtin Shared Dictionary");
+ _unregistered_dictionary.print_table_statistics(st, "Unregistered Shared Dictionary");
}
- return NULL;
}
--- a/src/hotspot/share/classfile/systemDictionaryShared.hpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp Wed Nov 07 19:40:27 2018 -0800
@@ -36,13 +36,12 @@
Handling of the classes in the AppCDS archive
To ensure safety and to simplify the implementation, archived classes are
- "segregated" into several types. The following rules describe how they
+ "segregated" into 2 types. The following rules describe how they
are stored and looked up.
[1] Category of archived classes
- There are 3 disjoint groups of classes stored in the AppCDS archive. They are
- categorized as by their SharedDictionaryEntry::loader_type()
+ There are 2 disjoint groups of classes stored in the AppCDS archive:
BUILTIN: These classes may be defined ONLY by the BOOT/PLATFORM/APP
loaders.
@@ -83,112 +82,39 @@
Bar id: 3 super: 0 interfaces: 1 source: /foo.jar
-[3] Identifying the loader_type of archived classes in the shared dictionary
-
- Each archived Klass* C is associated with a SharedDictionaryEntry* E
+[3] Identifying the category of archived classes
BUILTIN: (C->shared_classpath_index() >= 0)
- UNREGISTERED: (C->shared_classpath_index() < 0)
+ UNREGISTERED: (C->shared_classpath_index() == UNREGISTERED_INDEX (-9999))
[4] Lookup of archived classes at run time:
(a) BUILTIN loaders:
- Search the shared directory for a BUILTIN class with a matching name.
+ search _builtin_dictionary
(b) UNREGISTERED loaders:
- The search originates with SystemDictionaryShared::lookup_from_stream().
-
- Search the shared directory for a UNREGISTERED class with a matching
- (name, clsfile_len, clsfile_crc32) tuple.
+ search _unregistered_dictionary for an entry that matches the
+ (name, clsfile_len, clsfile_crc32).
===============================================================================*/
#define UNREGISTERED_INDEX -9999
class ClassFileStream;
+class DumpTimeSharedClassInfo;
+class DumpTimeSharedClassTable;
+class RunTimeSharedClassInfo;
+class RunTimeSharedDictionary;
-// Archived classes need extra information not needed by traditionally loaded classes.
-// To keep footprint small, we add these in the dictionary entry instead of the InstanceKlass.
-class SharedDictionaryEntry : public DictionaryEntry {
-
+class SystemDictionaryShared: public SystemDictionary {
public:
- enum LoaderType {
- LT_BUILTIN,
- LT_UNREGISTERED
- };
-
enum {
FROM_FIELD_IS_PROTECTED = 1 << 0,
FROM_IS_ARRAY = 1 << 1,
FROM_IS_OBJECT = 1 << 2
};
- int _id;
- int _clsfile_size;
- int _clsfile_crc32;
- void* _verifier_constraints; // FIXME - use a union here to avoid type casting??
- void* _verifier_constraint_flags;
-
- // See "Identifying the loader_type of archived classes" comments above.
- LoaderType loader_type() const {
- InstanceKlass* k = instance_klass();
-
- if ((k->shared_classpath_index() != UNREGISTERED_INDEX)) {
- return LT_BUILTIN;
- } else {
- return LT_UNREGISTERED;
- }
- }
-
- SharedDictionaryEntry* next() {
- return (SharedDictionaryEntry*)(DictionaryEntry::next());
- }
-
- bool is_builtin() const {
- return loader_type() == LT_BUILTIN;
- }
- bool is_unregistered() const {
- return loader_type() == LT_UNREGISTERED;
- }
-
- void add_verification_constraint(Symbol* name,
- Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object);
- int finalize_verification_constraints();
- void check_verification_constraints(InstanceKlass* klass, TRAPS);
- void metaspace_pointers_do(MetaspaceClosure* it) NOT_CDS_RETURN;
-};
-
-class SharedDictionary : public Dictionary {
- SharedDictionaryEntry* get_entry_for_builtin_loader(const Symbol* name) const;
- SharedDictionaryEntry* get_entry_for_unregistered_loader(const Symbol* name,
- int clsfile_size,
- int clsfile_crc32) const;
-
- // Convenience functions
- SharedDictionaryEntry* bucket(int index) const {
- return (SharedDictionaryEntry*)(Dictionary::bucket(index));
- }
-
-public:
- SharedDictionaryEntry* find_entry_for(InstanceKlass* klass);
-
- bool add_non_builtin_klass(const Symbol* class_name,
- ClassLoaderData* loader_data,
- InstanceKlass* obj);
-
- void update_entry(InstanceKlass* klass, int id);
-
- InstanceKlass* find_class_for_builtin_loader(const Symbol* name) const;
- InstanceKlass* find_class_for_unregistered_loader(const Symbol* name,
- int clsfile_size,
- int clsfile_crc32) const;
- bool class_exists_for_unregistered_loader(const Symbol* name) {
- return (get_entry_for_unregistered_loader(name, -1, -1) != NULL);
- }
-};
-
-class SystemDictionaryShared: public SystemDictionary {
private:
// These _shared_xxxs arrays are used to initialize the java.lang.Package and
// java.security.ProtectionDomain objects associated with each shared class.
@@ -282,8 +208,17 @@
Handle class_loader,
Handle protection_domain,
TRAPS);
- static void finalize_verification_constraints_for(InstanceKlass* k);
+ static DumpTimeSharedClassInfo* find_or_allocate_info_for(InstanceKlass* k);
+ static void write_dictionary(RunTimeSharedDictionary* dictionary, bool is_builtin);
+ static bool is_jfr_event_class(InstanceKlass *k);
+ static void warn_excluded(InstanceKlass* k, const char* reason);
+
+ DEBUG_ONLY(static bool _checked_excluded_classes;)
public:
+ static InstanceKlass* find_builtin_class(Symbol* class_name);
+
+ static const RunTimeSharedClassInfo* find_record(RunTimeSharedDictionary* dict, Symbol* name);
+
// Called by PLATFORM/APP loader only
static InstanceKlass* find_or_load_shared_class(Symbol* class_name,
Handle class_loader,
@@ -311,8 +246,7 @@
return NULL;
}
- static bool add_non_builtin_klass(Symbol* class_name, ClassLoaderData* loader_data,
- InstanceKlass* k, TRAPS);
+ static bool add_unregistered_class(InstanceKlass* k, TRAPS);
static InstanceKlass* dump_time_resolve_super_or_fail(Symbol* child_name,
Symbol* class_name,
Handle class_loader,
@@ -320,36 +254,17 @@
bool is_superclass,
TRAPS);
- static size_t dictionary_entry_size() {
- return (DumpSharedSpaces) ? sizeof(SharedDictionaryEntry) : sizeof(DictionaryEntry);
- }
- static void init_shared_dictionary_entry(InstanceKlass* k, DictionaryEntry* entry) NOT_CDS_RETURN;
- static bool is_builtin(DictionaryEntry* ent) {
- // Can't use virtual function is_builtin because DictionaryEntry doesn't initialize
- // vtable because it's not constructed properly.
- SharedDictionaryEntry* entry = (SharedDictionaryEntry*)ent;
- return entry->is_builtin();
+ static void init_dumptime_info(InstanceKlass* k) NOT_CDS_RETURN;
+ static void remove_dumptime_info(InstanceKlass* k) NOT_CDS_RETURN;
+
+ static Dictionary* boot_loader_dictionary() {
+ return ClassLoaderData::the_null_class_loader_data()->dictionary();
}
- // For convenient access to the SharedDictionaryEntry's of the archived classes.
- static SharedDictionary* shared_dictionary() {
- assert(!DumpSharedSpaces, "not for dumping");
- return (SharedDictionary*)SystemDictionary::shared_dictionary();
- }
-
- static SharedDictionary* boot_loader_dictionary() {
- return (SharedDictionary*)ClassLoaderData::the_null_class_loader_data()->dictionary();
- }
-
- static void update_shared_entry(InstanceKlass* klass, int id) {
- assert(DumpSharedSpaces, "sanity");
- assert((SharedDictionary*)(klass->class_loader_data()->dictionary()) != NULL, "sanity");
- ((SharedDictionary*)(klass->class_loader_data()->dictionary()))->update_entry(klass, id);
- }
-
+ static void update_shared_entry(InstanceKlass* klass, int id);
static void set_shared_class_misc_info(InstanceKlass* k, ClassFileStream* cfs);
- static InstanceKlass* lookup_from_stream(const Symbol* class_name,
+ static InstanceKlass* lookup_from_stream(Symbol* class_name,
Handle class_loader,
Handle protection_domain,
const ClassFileStream* st,
@@ -366,9 +281,23 @@
static bool add_verification_constraint(InstanceKlass* k, Symbol* name,
Symbol* from_name, bool from_field_is_protected,
bool from_is_array, bool from_is_object) NOT_CDS_RETURN_(false);
- static void finalize_verification_constraints() NOT_CDS_RETURN;
static void check_verification_constraints(InstanceKlass* klass,
- TRAPS) NOT_CDS_RETURN;
+ TRAPS) NOT_CDS_RETURN;
+ static bool is_builtin(InstanceKlass* k) {
+ return (k->shared_classpath_index() != UNREGISTERED_INDEX);
+ }
+ static bool should_be_excluded(InstanceKlass* k);
+ static void check_excluded_classes();
+ static void validate_before_archiving(InstanceKlass* k);
+ static bool is_excluded_class(InstanceKlass* k);
+ static void dumptime_classes_do(class MetaspaceClosure* it);
+ static void write_to_archive();
+ static void serialize_dictionary_headers(class SerializeClosure* soc);
+ static void print() { return print_on(tty); }
+ static void print_on(outputStream* st) NOT_CDS_RETURN;
+ static void print_table_statistics(outputStream* st) NOT_CDS_RETURN;
+
+ DEBUG_ONLY(static bool checked_excluded_classes() {return _checked_excluded_classes;})
};
#endif // SHARE_VM_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP
--- a/src/hotspot/share/memory/allocation.hpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/memory/allocation.hpp Wed Nov 07 19:40:27 2018 -0800
@@ -244,6 +244,7 @@
class MetaspaceClosure;
class MetaspaceObj {
+ friend class VMStructs;
// When CDS is enabled, all shared metaspace objects are mapped
// into a single contiguous memory block, so we can use these
// two pointers to quickly determine if something is in the
--- a/src/hotspot/share/memory/filemap.cpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/memory/filemap.cpp Wed Nov 07 19:40:27 2018 -0800
@@ -209,6 +209,7 @@
_verify_local = BytecodeVerificationLocal;
_verify_remote = BytecodeVerificationRemote;
_has_platform_or_app_classes = ClassLoaderExt::has_platform_or_app_classes();
+ _shared_base_address = SharedBaseAddress;
}
void SharedClassPathEntry::init(const char* name, bool is_modules_image, TRAPS) {
@@ -533,6 +534,7 @@
}
_file_offset += (long)n;
+ SharedBaseAddress = _header->_shared_base_address;
return true;
}
@@ -666,7 +668,8 @@
// +-- gap
size_t FileMapInfo::write_archive_heap_regions(GrowableArray<MemRegion> *heap_mem,
GrowableArray<ArchiveHeapOopmapInfo> *oopmaps,
- int first_region_id, int max_num_regions) {
+ int first_region_id, int max_num_regions,
+ bool print_log) {
assert(max_num_regions <= 2, "Only support maximum 2 memory regions");
int arr_len = heap_mem == NULL ? 0 : heap_mem->length();
@@ -687,8 +690,10 @@
total_size += size;
}
- log_info(cds)("Archive heap region %d " INTPTR_FORMAT " - " INTPTR_FORMAT " = " SIZE_FORMAT_W(8) " bytes",
- i, p2i(start), p2i(start + size), size);
+ if (print_log) {
+ log_info(cds)("Archive heap region %d " INTPTR_FORMAT " - " INTPTR_FORMAT " = " SIZE_FORMAT_W(8) " bytes",
+ i, p2i(start), p2i(start + size), size);
+ }
write_region(i, start, size, false, false);
if (size > 0) {
space_at(i)->_oopmap = oopmaps->at(arr_idx)._oopmap;
--- a/src/hotspot/share/memory/filemap.hpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/memory/filemap.hpp Wed Nov 07 19:40:27 2018 -0800
@@ -150,6 +150,7 @@
bool _verify_local; // BytecodeVerificationLocal setting
bool _verify_remote; // BytecodeVerificationRemote setting
bool _has_platform_or_app_classes; // Archive contains app classes
+ size_t _shared_base_address; // SharedBaseAddress used at dump time
void set_has_platform_or_app_classes(bool v) {
_has_platform_or_app_classes = v;
@@ -263,7 +264,8 @@
bool read_only, bool allow_exec);
size_t write_archive_heap_regions(GrowableArray<MemRegion> *heap_mem,
GrowableArray<ArchiveHeapOopmapInfo> *oopmaps,
- int first_region_id, int max_num_regions);
+ int first_region_id, int max_num_regions,
+ bool print_log);
void write_bytes(const void* buffer, size_t count);
void write_bytes_aligned(const void* buffer, size_t count);
char* map_region(int i, char** top_ret);
--- a/src/hotspot/share/memory/heapShared.cpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/memory/heapShared.cpp Wed Nov 07 19:40:27 2018 -0800
@@ -391,9 +391,7 @@
record->init(&info);
unsigned int hash = primitive_hash<Klass*>(klass);
- uintx deltax = MetaspaceShared::object_delta(record);
- guarantee(deltax <= MAX_SHARED_DELTA, "must not be");
- u4 delta = u4(deltax);
+ u4 delta = MetaspaceShared::object_delta_u4(record);
_writer->add(hash, delta);
}
return true; // keep on iterating
@@ -417,7 +415,7 @@
int num_buckets = CompactHashtableWriter::default_num_buckets(d_table->_count);
CompactHashtableWriter writer(num_buckets, &stats);
CopyKlassSubGraphInfoToArchive copy(&writer);
- _dump_time_subgraph_info_table->iterate(©);
+ d_table->iterate(©);
writer.dump(&_run_time_subgraph_info_table, "subgraphs");
}
@@ -433,7 +431,7 @@
assert(!DumpSharedSpaces, "Should not be called with DumpSharedSpaces");
unsigned int hash = primitive_hash<Klass*>(k);
- ArchivedKlassSubGraphInfoRecord* record = _run_time_subgraph_info_table.lookup(k, hash, 0);
+ const ArchivedKlassSubGraphInfoRecord* record = _run_time_subgraph_info_table.lookup(k, hash, 0);
// Initialize from archived data. Currently this is done only
// during VM initialization time. No lock is needed.
--- a/src/hotspot/share/memory/heapShared.hpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/memory/heapShared.hpp Wed Nov 07 19:40:27 2018 -0800
@@ -109,9 +109,9 @@
ArchivedKlassSubGraphInfoRecord() :
_k(NULL), _entry_field_records(NULL), _subgraph_object_klasses(NULL) {}
void init(KlassSubGraphInfo* info);
- Klass* klass() { return _k; }
- Array<juint>* entry_field_records() { return _entry_field_records; }
- Array<Klass*>* subgraph_object_klasses() { return _subgraph_object_klasses; }
+ Klass* klass() const { return _k; }
+ Array<juint>* entry_field_records() const { return _entry_field_records; }
+ Array<Klass*>* subgraph_object_klasses() const { return _subgraph_object_klasses; }
};
#endif // INCLUDE_CDS_JAVA_HEAP
@@ -154,18 +154,16 @@
int _count;
};
- inline static ArchivedKlassSubGraphInfoRecord* read_record_from_compact_hashtable(address base_address, u4 offset) {
- return (ArchivedKlassSubGraphInfoRecord*)(base_address + offset);
- }
-
- inline static bool record_equals_compact_hashtable_entry(ArchivedKlassSubGraphInfoRecord* value, const Klass* key, int len_unused) {
+public: // solaris compiler wants this for RunTimeKlassSubGraphInfoTable
+ inline static bool record_equals_compact_hashtable_entry(
+ const ArchivedKlassSubGraphInfoRecord* value, const Klass* key, int len_unused) {
return (value->klass() == key);
}
- typedef CompactHashtable<
+private:
+ typedef OffsetCompactHashtable<
const Klass*,
- ArchivedKlassSubGraphInfoRecord*,
- read_record_from_compact_hashtable,
+ const ArchivedKlassSubGraphInfoRecord*,
record_equals_compact_hashtable_entry
> RunTimeKlassSubGraphInfoTable;
--- a/src/hotspot/share/memory/metaspaceShared.cpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/memory/metaspaceShared.cpp Wed Nov 07 19:40:27 2018 -0800
@@ -64,7 +64,6 @@
#include "utilities/align.hpp"
#include "utilities/bitMap.hpp"
#include "utilities/defaultStream.hpp"
-#include "utilities/hashtable.inline.hpp"
#if INCLUDE_G1GC
#include "gc/g1/g1CollectedHeap.hpp"
#endif
@@ -124,6 +123,15 @@
MetaspaceShared::report_out_of_space(_name, newtop - _top);
ShouldNotReachHere();
}
+ uintx delta = MetaspaceShared::object_delta_uintx(newtop);
+ if (delta > MAX_SHARED_DELTA) {
+ // This is just a sanity check and should not appear in any real world usage. This
+ // happens only if you allocate more than 2GB of shared objects and would require
+ // millions of shared classes.
+ vm_exit_during_initialization("Out of memory in the CDS archive",
+ "Please reduce the number of shared classes.");
+ }
+
MetaspaceShared::commit_shared_space_to(newtop);
_top = newtop;
return _top;
@@ -323,6 +331,7 @@
}
_mc_region.init(&_shared_rs);
+ SharedBaseAddress = (size_t)_shared_rs.base();
tty->print_cr("Allocated shared space: " SIZE_FORMAT " bytes at " PTR_FORMAT,
_shared_rs.size(), p2i(_shared_rs.base()));
}
@@ -416,6 +425,7 @@
SymbolTable::serialize_shared_table_header(soc);
StringTable::serialize_shared_table_header(soc);
HeapShared::serialize_subgraph_info_table_header(soc);
+ SystemDictionaryShared::serialize_dictionary_headers(soc);
JavaClasses::serialize_offsets(soc);
InstanceMirrorKlass::serialize_offsets(soc);
@@ -464,13 +474,11 @@
class CollectClassesClosure : public KlassClosure {
void do_klass(Klass* k) {
- if (!(k->is_instance_klass() && InstanceKlass::cast(k)->is_in_error_state())) {
- if (k->is_instance_klass() && InstanceKlass::cast(k)->signers() != NULL) {
- // Mark any class with signers and don't add to the _global_klass_objects
- k->set_has_signer_and_not_archived();
- } else {
- _global_klass_objects->append_if_missing(k);
- }
+ if (k->is_instance_klass() &&
+ SystemDictionaryShared::is_excluded_class(InstanceKlass::cast(k))) {
+ // Don't add to the _global_klass_objects
+ } else {
+ _global_klass_objects->append_if_missing(k);
}
if (k->is_array_klass()) {
// Add in the array classes too
@@ -577,16 +585,6 @@
}
}
-NOT_PRODUCT(
-static void assert_not_unsafe_anonymous_class(InstanceKlass* k) {
- assert(!(k->is_unsafe_anonymous()), "cannot archive unsafe anonymous classes");
-}
-
-// Unsafe anonymous classes are not stored inside any dictionaries.
-static void assert_no_unsafe_anonymous_classes_in_dictionaries() {
- ClassLoaderDataGraph::dictionary_classes_do(assert_not_unsafe_anonymous_class);
-})
-
// Objects of the Metadata types (such as Klass and ConstantPool) have C++ vtables.
// (In GCC this is the field <Type>::_vptr, i.e., first word in the object.)
//
@@ -1123,6 +1121,17 @@
newtop = _ro_region.top();
} else {
oldtop = _rw_region.top();
+ if (ref->msotype() == MetaspaceObj::ClassType) {
+ // Save a pointer immediate in front of an InstanceKlass, so
+ // we can do a quick lookup from InstanceKlass* -> RunTimeSharedClassInfo*
+ // without building another hashtable. See RunTimeSharedClassInfo::get_for()
+ // in systemDictionaryShared.cpp.
+ Klass* klass = (Klass*)obj;
+ if (klass->is_instance_klass()) {
+ SystemDictionaryShared::validate_before_archiving(InstanceKlass::cast(klass));
+ _rw_region.allocate(sizeof(address), BytesPerWord);
+ }
+ }
p = _rw_region.allocate(bytes, alignment);
newtop = _rw_region.top();
}
@@ -1132,16 +1141,6 @@
assert(isnew, "must be");
_alloc_stats->record(ref->msotype(), int(newtop - oldtop), read_only);
- if (ref->msotype() == MetaspaceObj::SymbolType) {
- uintx delta = MetaspaceShared::object_delta(p);
- if (delta > MAX_SHARED_DELTA) {
- // This is just a sanity check and should not appear in any real world usage. This
- // happens only if you allocate more than 2GB of Symbols and would require
- // millions of shared classes.
- vm_exit_during_initialization("Too many Symbols in the CDS archive",
- "Please reduce the number of shared classes.");
- }
- }
}
static address get_new_loc(MetaspaceClosure::Ref* ref) {
@@ -1281,7 +1280,7 @@
}
}
FileMapInfo::metaspace_pointers_do(it);
- SystemDictionary::classes_do(it);
+ SystemDictionaryShared::dumptime_classes_do(it);
Universe::metaspace_pointers_do(it);
SymbolTable::metaspace_pointers_do(it);
vmSymbols::metaspace_pointers_do(it);
@@ -1315,9 +1314,6 @@
char* VM_PopulateDumpSharedSpace::dump_read_only_tables() {
ArchiveCompactor::OtherROAllocMark mark;
- // Reorder the system dictionary. Moving the symbols affects
- // how the hash table indices are calculated.
- SystemDictionary::reorder_dictionary_for_sharing();
tty->print("Removing java_mirror ... ");
if (!HeapShared::is_heap_object_archiving_allowed()) {
@@ -1325,15 +1321,10 @@
}
remove_java_mirror_in_classes();
tty->print_cr("done. ");
- NOT_PRODUCT(SystemDictionary::verify();)
- size_t buckets_bytes = SystemDictionary::count_bytes_for_buckets();
- char* buckets_top = _ro_region.allocate(buckets_bytes, sizeof(intptr_t));
- SystemDictionary::copy_buckets(buckets_top, _ro_region.top());
+ SystemDictionaryShared::write_to_archive();
- size_t table_bytes = SystemDictionary::count_bytes_for_table();
- char* table_top = _ro_region.allocate(table_bytes, sizeof(intptr_t));
- SystemDictionary::copy_table(table_top, _ro_region.top());
+ char* start = _ro_region.top();
// Write the other data to the output array.
WriteClosure wc(&_ro_region);
@@ -1342,7 +1333,7 @@
// Write the bitmaps for patching the archive heap regions
dump_archive_heap_oopmaps();
- return buckets_top;
+ return start;
}
void VM_PopulateDumpSharedSpace::doit() {
@@ -1367,14 +1358,11 @@
"loader constraints are not saved");
guarantee(SystemDictionary::placeholders()->number_of_entries() == 0,
"placeholders are not saved");
- // Revisit and implement this if we prelink method handle call sites:
- guarantee(SystemDictionary::invoke_method_table() == NULL ||
- SystemDictionary::invoke_method_table()->number_of_entries() == 0,
- "invoke method table is not saved");
// At this point, many classes have been loaded.
// Gather systemDictionary classes in a global array and do everything to
// that so we don't have to walk the SystemDictionary again.
+ SystemDictionaryShared::check_excluded_classes();
_global_klass_objects = new GrowableArray<Klass*>(1000);
CollectClassesClosure collect_classes;
ClassLoaderDataGraph::loaded_classes_do(&collect_classes);
@@ -1403,21 +1391,11 @@
rewrite_nofast_bytecodes_and_calculate_fingerprints();
tty->print_cr("done. ");
- // Move classes from platform/system dictionaries into the boot dictionary
- SystemDictionary::combine_shared_dictionaries();
-
- // Make sure all classes have a correct loader type.
- ClassLoaderData::the_null_class_loader_data()->dictionary()->classes_do(MetaspaceShared::check_shared_class_loader_type);
-
// Remove all references outside the metadata
tty->print("Removing unshareable information ... ");
remove_unshareable_in_classes();
tty->print_cr("done. ");
- // We don't support archiving unsafe anonymous classes. Verify that they are not stored in
- // any dictionaries.
- NOT_PRODUCT(assert_no_unsafe_anonymous_classes_in_dictionaries());
-
ArchiveCompactor::initialize();
ArchiveCompactor::copy_and_compact();
@@ -1466,6 +1444,7 @@
mapinfo->set_core_spaces_size(core_spaces_size);
for (int pass=1; pass<=2; pass++) {
+ bool print_archive_log = (pass==1);
if (pass == 1) {
// The first pass doesn't actually write the data to disk. All it
// does is to update the fields in the mapinfo->_header.
@@ -1490,12 +1469,14 @@
_closed_archive_heap_regions,
_closed_archive_heap_oopmaps,
MetaspaceShared::first_closed_archive_heap_region,
- MetaspaceShared::max_closed_archive_heap_region);
+ MetaspaceShared::max_closed_archive_heap_region,
+ print_archive_log);
_total_open_archive_region_size = mapinfo->write_archive_heap_regions(
_open_archive_heap_regions,
_open_archive_heap_oopmaps,
MetaspaceShared::first_open_archive_heap_region,
- MetaspaceShared::max_open_archive_heap_region);
+ MetaspaceShared::max_open_archive_heap_region,
+ print_archive_log);
}
mapinfo->close();
@@ -1608,17 +1589,6 @@
}
};
-void MetaspaceShared::check_shared_class_loader_type(InstanceKlass* ik) {
- ResourceMark rm;
- if (ik->shared_classpath_index() == UNREGISTERED_INDEX) {
- guarantee(ik->loader_type() == 0,
- "Class loader type must not be set for this class %s", ik->name()->as_C_string());
- } else {
- guarantee(ik->loader_type() != 0,
- "Class loader type must be set for this class %s", ik->name()->as_C_string());
- }
-}
-
void MetaspaceShared::link_and_cleanup_shared_classes(TRAPS) {
// We need to iterate because verification may cause additional classes
// to be loaded.
@@ -1639,9 +1609,6 @@
check_closure.reset();
ClassLoaderDataGraph::unlocked_loaded_classes_do(&check_closure);
} while (check_closure.made_progress());
-
- // Unverifiable classes will not be included in the CDS archive.
- SystemDictionary::remove_classes_in_error_state();
}
}
@@ -1717,10 +1684,6 @@
link_and_cleanup_shared_classes(CATCH);
tty->print_cr("Rewriting and linking classes: done");
- SystemDictionary::clear_invoke_method_table();
-
- SystemDictionaryShared::finalize_verification_constraints();
-
VM_PopulateDumpSharedSpace op;
VMThread::execute(&op);
}
@@ -1731,36 +1694,36 @@
ClassListParser parser(class_list_path);
int class_count = 0;
- while (parser.parse_one_line()) {
- Klass* klass = ClassLoaderExt::load_one_class(&parser, THREAD);
- if (HAS_PENDING_EXCEPTION) {
- if (klass == NULL &&
- (PENDING_EXCEPTION->klass()->name() == vmSymbols::java_lang_ClassNotFoundException())) {
- // print a warning only when the pending exception is class not found
- tty->print_cr("Preload Warning: Cannot find %s", parser.current_class_name());
- }
- CLEAR_PENDING_EXCEPTION;
+ while (parser.parse_one_line()) {
+ Klass* klass = parser.load_current_class(THREAD);
+ if (HAS_PENDING_EXCEPTION) {
+ if (klass == NULL &&
+ (PENDING_EXCEPTION->klass()->name() == vmSymbols::java_lang_ClassNotFoundException())) {
+ // print a warning only when the pending exception is class not found
+ tty->print_cr("Preload Warning: Cannot find %s", parser.current_class_name());
+ }
+ CLEAR_PENDING_EXCEPTION;
+ }
+ if (klass != NULL) {
+ if (log_is_enabled(Trace, cds)) {
+ ResourceMark rm;
+ log_trace(cds)("Shared spaces preloaded: %s", klass->external_name());
}
- if (klass != NULL) {
- if (log_is_enabled(Trace, cds)) {
- ResourceMark rm;
- log_trace(cds)("Shared spaces preloaded: %s", klass->external_name());
- }
- if (klass->is_instance_klass()) {
- InstanceKlass* ik = InstanceKlass::cast(klass);
+ if (klass->is_instance_klass()) {
+ InstanceKlass* ik = InstanceKlass::cast(klass);
- // Link the class to cause the bytecodes to be rewritten and the
- // cpcache to be created. The linking is done as soon as classes
- // are loaded in order that the related data structures (klass and
- // cpCache) are located together.
- try_link_class(ik, THREAD);
- guarantee(!HAS_PENDING_EXCEPTION, "exception in link_class");
- }
+ // Link the class to cause the bytecodes to be rewritten and the
+ // cpcache to be created. The linking is done as soon as classes
+ // are loaded in order that the related data structures (klass and
+ // cpCache) are located together.
+ try_link_class(ik, THREAD);
+ guarantee(!HAS_PENDING_EXCEPTION, "exception in link_class");
+ }
- class_count++;
- }
+ class_count++;
}
+ }
return class_count;
}
@@ -1994,21 +1957,6 @@
// The rest of the data is now stored in the RW region
buffer = mapinfo->read_only_tables_start();
- int sharedDictionaryLen = *(intptr_t*)buffer;
- buffer += sizeof(intptr_t);
- int number_of_entries = *(intptr_t*)buffer;
- buffer += sizeof(intptr_t);
- SystemDictionary::set_shared_dictionary((HashtableBucket<mtClass>*)buffer,
- sharedDictionaryLen,
- number_of_entries);
- buffer += sharedDictionaryLen;
-
- // The following data are the linked list elements
- // (HashtableEntry objects) for the shared dictionary table.
-
- int len = *(intptr_t*)buffer; // skip over shared dictionary entries
- buffer += sizeof(intptr_t);
- buffer += len;
// Verify various attributes of the archive, plus initialize the
// shared string/symbol tables
@@ -2027,7 +1975,7 @@
if (PrintSharedArchiveAndExit) {
if (PrintSharedDictionary) {
tty->print_cr("\nShared classes:\n");
- SystemDictionary::print_shared(tty);
+ SystemDictionaryShared::print_on(tty);
}
if (_archive_loading_failed) {
tty->print_cr("archive is invalid");
--- a/src/hotspot/share/memory/metaspaceShared.hpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/memory/metaspaceShared.hpp Wed Nov 07 19:40:27 2018 -0800
@@ -107,12 +107,19 @@
static void post_initialize(TRAPS) NOT_CDS_RETURN;
// Delta of this object from the bottom of the archive.
- static uintx object_delta(void* obj) {
+ static uintx object_delta_uintx(void* obj) {
assert(DumpSharedSpaces, "supported only for dumping");
assert(shared_rs()->contains(obj), "must be");
address base_address = address(shared_rs()->base());
- uintx delta = address(obj) - base_address;
- return delta;
+ uintx deltax = address(obj) - base_address;
+ return deltax;
+ }
+
+ static u4 object_delta_u4(void* obj) {
+ // offset is guaranteed to be less than MAX_SHARED_DELTA in DumpRegion::expand_top_to()
+ uintx deltax = object_delta_uintx(obj);
+ guarantee(deltax <= MAX_SHARED_DELTA, "must be 32-bit offset");
+ return (u4)deltax;
}
static void set_archive_loading_failed() {
--- a/src/hotspot/share/oops/instanceKlass.cpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/oops/instanceKlass.cpp Wed Nov 07 19:40:27 2018 -0800
@@ -422,17 +422,22 @@
_static_field_size(parser.static_field_size()),
_nonstatic_oop_map_size(nonstatic_oop_map_size(parser.total_oop_map_count())),
_itable_len(parser.itable_size()),
- _reference_type(parser.reference_type()) {
- set_vtable_length(parser.vtable_size());
- set_kind(kind);
- set_access_flags(parser.access_flags());
- set_is_unsafe_anonymous(parser.is_unsafe_anonymous());
- set_layout_helper(Klass::instance_layout_helper(parser.layout_size(),
+ _reference_type(parser.reference_type())
+{
+ set_vtable_length(parser.vtable_size());
+ set_kind(kind);
+ set_access_flags(parser.access_flags());
+ set_is_unsafe_anonymous(parser.is_unsafe_anonymous());
+ set_layout_helper(Klass::instance_layout_helper(parser.layout_size(),
false));
- assert(NULL == _methods, "underlying memory not zeroed?");
- assert(is_instance_klass(), "is layout incorrect?");
- assert(size_helper() == parser.layout_size(), "incorrect size_helper?");
+ assert(NULL == _methods, "underlying memory not zeroed?");
+ assert(is_instance_klass(), "is layout incorrect?");
+ assert(size_helper() == parser.layout_size(), "incorrect size_helper?");
+
+ if (DumpSharedSpaces) {
+ SystemDictionaryShared::init_dumptime_info(this);
+ }
}
void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data,
@@ -579,6 +584,10 @@
MetadataFactory::free_metadata(loader_data, annotations());
}
set_annotations(NULL);
+
+ if (DumpSharedSpaces) {
+ SystemDictionaryShared::remove_dumptime_info(this);
+ }
}
bool InstanceKlass::should_be_initialized() const {
--- a/src/hotspot/share/oops/klass.hpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/oops/klass.hpp Wed Nov 07 19:40:27 2018 -0800
@@ -176,8 +176,7 @@
// Flags of the current shared class.
u2 _shared_class_flags;
enum {
- _has_raw_archived_mirror = 1,
- _has_signer_and_not_archived = 1 << 2
+ _has_raw_archived_mirror = 1
};
#endif
// The _archived_mirror is set at CDS dump time pointing to the cached mirror
@@ -314,15 +313,6 @@
CDS_ONLY(return (_shared_class_flags & _has_raw_archived_mirror) != 0;)
NOT_CDS(return false;)
}
-#if INCLUDE_CDS
- void set_has_signer_and_not_archived() {
- _shared_class_flags |= _has_signer_and_not_archived;
- }
- bool has_signer_and_not_archived() const {
- assert(DumpSharedSpaces, "dump time only");
- return (_shared_class_flags & _has_signer_and_not_archived) != 0;
- }
-#endif // INCLUDE_CDS
// Obtain the module or package for this class
virtual ModuleEntry* module() const = 0;
--- a/src/hotspot/share/runtime/vmStructs.cpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/runtime/vmStructs.cpp Wed Nov 07 19:40:27 2018 -0800
@@ -404,6 +404,8 @@
/* Memory */ \
/**********/ \
\
+ static_field(MetaspaceObj, _shared_metaspace_base, void*) \
+ static_field(MetaspaceObj, _shared_metaspace_top, void*) \
nonstatic_field(ThreadLocalAllocBuffer, _start, HeapWord*) \
nonstatic_field(ThreadLocalAllocBuffer, _top, HeapWord*) \
nonstatic_field(ThreadLocalAllocBuffer, _end, HeapWord*) \
@@ -460,7 +462,6 @@
/* SystemDictionary */ \
/********************/ \
\
- static_field(SystemDictionary, _shared_dictionary, Dictionary*) \
static_field(SystemDictionary, _system_loader_lock_obj, oop) \
static_field(SystemDictionary, WK_KLASS(Object_klass), InstanceKlass*) \
static_field(SystemDictionary, WK_KLASS(String_klass), InstanceKlass*) \
--- a/src/hotspot/share/utilities/hashtable.cpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/utilities/hashtable.cpp Wed Nov 07 19:40:27 2018 -0800
@@ -33,7 +33,6 @@
#include "classfile/stringTable.hpp"
#include "logging/log.hpp"
#include "memory/allocation.inline.hpp"
-#include "memory/metaspaceShared.hpp"
#include "memory/resourceArea.hpp"
#include "oops/oop.inline.hpp"
#include "oops/weakHandle.inline.hpp"
@@ -99,11 +98,7 @@
template <MEMFLAGS F> void BasicHashtable<F>::free_buckets() {
if (NULL != _buckets) {
- // Don't delete the buckets in the shared space. They aren't
- // allocated by os::malloc
- if (!MetaspaceShared::is_in_shared_metaspace(_buckets)) {
- FREE_C_HEAP_ARRAY(HashtableBucket, _buckets);
- }
+ FREE_C_HEAP_ARRAY(HashtableBucket, _buckets);
_buckets = NULL;
}
}
@@ -137,47 +132,6 @@
}
Atomic::add(-context->_num_removed, &_number_of_entries);
}
-// Copy the table to the shared space.
-template <MEMFLAGS F> size_t BasicHashtable<F>::count_bytes_for_table() {
- size_t bytes = 0;
- bytes += sizeof(intptr_t); // len
-
- for (int i = 0; i < _table_size; ++i) {
- for (BasicHashtableEntry<F>** p = _buckets[i].entry_addr();
- *p != NULL;
- p = (*p)->next_addr()) {
- bytes += entry_size();
- }
- }
-
- return bytes;
-}
-
-// Dump the hash table entries (into CDS archive)
-template <MEMFLAGS F> void BasicHashtable<F>::copy_table(char* top, char* end) {
- assert(is_aligned(top, sizeof(intptr_t)), "bad alignment");
- intptr_t *plen = (intptr_t*)(top);
- top += sizeof(*plen);
-
- int i;
- for (i = 0; i < _table_size; ++i) {
- for (BasicHashtableEntry<F>** p = _buckets[i].entry_addr();
- *p != NULL;
- p = (*p)->next_addr()) {
- *p = (BasicHashtableEntry<F>*)memcpy(top, (void*)*p, entry_size());
- top += entry_size();
- }
- }
- *plen = (char*)(top) - (char*)plen - sizeof(*plen);
- assert(top == end, "count_bytes_for_table is wrong");
- // Set the shared bit.
-
- for (i = 0; i < _table_size; ++i) {
- for (BasicHashtableEntry<F>* p = bucket(i); p != NULL; p = p->next()) {
- p->set_shared();
- }
- }
-}
// For oops and Strings the size of the literal is interesting. For other types, nobody cares.
static int literal_size(ConstantPool*) { return 0; }
@@ -297,34 +251,6 @@
st->print_cr("Maximum bucket size : %9d", (int)summary.maximum());
}
-
-// Dump the hash table buckets.
-
-template <MEMFLAGS F> size_t BasicHashtable<F>::count_bytes_for_buckets() {
- size_t bytes = 0;
- bytes += sizeof(intptr_t); // len
- bytes += sizeof(intptr_t); // _number_of_entries
- bytes += _table_size * sizeof(HashtableBucket<F>); // the buckets
-
- return bytes;
-}
-
-// Dump the buckets (into CDS archive)
-template <MEMFLAGS F> void BasicHashtable<F>::copy_buckets(char* top, char* end) {
- assert(is_aligned(top, sizeof(intptr_t)), "bad alignment");
- intptr_t len = _table_size * sizeof(HashtableBucket<F>);
- *(intptr_t*)(top) = len;
- top += sizeof(intptr_t);
-
- *(intptr_t*)(top) = _number_of_entries;
- top += sizeof(intptr_t);
-
- _buckets = (HashtableBucket<F>*)memcpy(top, (void*)_buckets, len);
- top += len;
-
- assert(top == end, "count_bytes_for_buckets is wrong");
-}
-
#ifndef PRODUCT
template <class T> void print_literal(T l) {
l->print();
--- a/src/hotspot/share/utilities/hashtable.hpp Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/utilities/hashtable.hpp Wed Nov 07 19:40:27 2018 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2018, 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
@@ -147,12 +147,6 @@
BasicHashtable(int table_size, int entry_size,
HashtableBucket<F>* buckets, int number_of_entries);
- // Sharing support.
- size_t count_bytes_for_buckets();
- size_t count_bytes_for_table();
- void copy_buckets(char* top, char* end);
- void copy_table(char* top, char* end);
-
// Bucket handling
int hash_to_index(unsigned int full_hash) const {
int h = full_hash % _table_size;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/MetaspaceObj.java Wed Nov 07 19:40:27 2018 -0800
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ */
+
+package sun.jvm.hotspot.memory;
+
+import java.util.*;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.types.*;
+
+public class MetaspaceObj {
+ private static Address sharedMetaspaceBaseAddr;
+ private static Address sharedMetaspaceTopAddr;
+
+ static {
+ VM.registerVMInitializedObserver(new Observer() {
+ public void update(Observable o, Object data) {
+ initialize(VM.getVM().getTypeDataBase());
+ }
+ });
+ }
+
+ private static synchronized void initialize(TypeDataBase db) {
+ Type type = db.lookupType("MetaspaceObj");
+ sharedMetaspaceBaseAddr = type.getAddressField("_shared_metaspace_base").getStaticFieldAddress();
+ sharedMetaspaceTopAddr = type.getAddressField("_shared_metaspace_top").getStaticFieldAddress();
+ }
+
+ public static boolean isShared(Address addr) {
+ Address base = sharedMetaspaceBaseAddr.getAddressAt(0);
+ Address top = sharedMetaspaceTopAddr. getAddressAt(0);
+
+ return base.lessThanOrEqual(addr) && addr.lessThan(top);
+ }
+}
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/SystemDictionary.java Tue Nov 13 21:43:10 2018 -0500
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/SystemDictionary.java Wed Nov 07 19:40:27 2018 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2018, 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
@@ -32,7 +32,6 @@
import sun.jvm.hotspot.types.*;
public class SystemDictionary {
- private static AddressField sharedDictionaryField;
private static sun.jvm.hotspot.types.OopField javaSystemLoaderField;
private static AddressField objectKlassField;
@@ -54,7 +53,6 @@
private static synchronized void initialize(TypeDataBase db) {
Type type = db.lookupType("SystemDictionary");
- sharedDictionaryField = type.getAddressField("_shared_dictionary");
javaSystemLoaderField = type.getOopField("_java_system_loader");
objectKlassField = type.getAddressField(WK_KLASS("Object_klass"));
@@ -76,11 +74,6 @@
return (kname+"_knum");
}
- public Dictionary sharedDictionary() {
- Address tmp = sharedDictionaryField.getValue();
- return (Dictionary) VMObjectFactory.newObject(Dictionary.class, tmp);
- }
-
// few well known classes -- not all are added here.
// add more if needed.
public static InstanceKlass getThreadKlass() {
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java Tue Nov 13 21:43:10 2018 -0500
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java Wed Nov 07 19:40:27 2018 -0800
@@ -313,27 +313,6 @@
return shouldStoreFingerprint() || isShared();
}
- public boolean isShared() {
- VM vm = VM.getVM();
- if (vm.isSharingEnabled()) {
- // This is not the same implementation as the C++ function MetaspaceObj::is_shared()
- // bool MetaspaceObj::is_shared() const {
- // return MetaspaceShared::is_in_shared_space(this);
- // }
- // However, MetaspaceShared::is_in_shared_space is complicated and hard to emulate in
- // Java code, so let's do this by looking up from the shared dictionary. Of course,
- // this works for shared InstanceKlass only and does not work for other types of
- // MetaspaceObj in the CDS shared archive.
- Dictionary sharedDictionary = vm.getSystemDictionary().sharedDictionary();
- if (sharedDictionary != null) {
- if (sharedDictionary.contains(this)) {
- return true;
- }
- }
- }
- return false;
- }
-
public static long getHeaderSize() { return headerSize; }
public short getFieldAccessFlags(int index) {
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Metadata.java Tue Nov 13 21:43:10 2018 -0500
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Metadata.java Wed Nov 07 19:40:27 2018 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018, 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
@@ -26,6 +26,7 @@
import java.io.*;
import java.util.*;
+import sun.jvm.hotspot.memory.*;
import sun.jvm.hotspot.utilities.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.runtime.*;
@@ -87,4 +88,12 @@
public void dumpReplayData(PrintStream out) {
out.println("# Unknown Metadata");
}
+
+ public boolean isShared() {
+ VM vm = VM.getVM();
+ if (vm.isSharingEnabled()) {
+ return MetaspaceObj.isShared(getAddress());
+ }
+ return false;
+ }
}
--- a/test/hotspot/jtreg/runtime/appcds/CDSandJFR.java Tue Nov 13 21:43:10 2018 -0500
+++ b/test/hotspot/jtreg/runtime/appcds/CDSandJFR.java Wed Nov 07 19:40:27 2018 -0800
@@ -61,7 +61,7 @@
String appJar = ClassFileInstaller.getJarPath("CDSandJFR.jar");
OutputAnalyzer output;
output = TestCommon.testDump(appJar, TestCommon.list(classes));
- TestCommon.checkDump(output, "Skipping JFR event class jdk/jfr/");
+ TestCommon.checkDump(output, "Skipping jdk/jfr/Event: JFR event class");
output = TestCommon.exec(appJar,
"-XX:StartFlightRecording=dumponexit=true",
--- a/test/hotspot/jtreg/runtime/appcds/SignedJar.java Tue Nov 13 21:43:10 2018 -0500
+++ b/test/hotspot/jtreg/runtime/appcds/SignedJar.java Wed Nov 07 19:40:27 2018 -0800
@@ -46,7 +46,7 @@
String signedJar = TestCommon.getTestJar("signed_hello.jar");
OutputAnalyzer output;
output = TestCommon.dump(signedJar, TestCommon.list("Hello"));
- TestCommon.checkDump(output, "Preload Warning: Skipping Hello from signed JAR");
+ TestCommon.checkDump(output, "Skipping Hello: Signed JAR");
// At runtime, the Hello class should be loaded from the jar file
// instead of from the shared archive since a class from a signed
@@ -63,6 +63,6 @@
// Test class exists in both signed JAR and unsigned JAR
String jars = signedJar + System.getProperty("path.separator") + unsignedJar;
output = TestCommon.dump(jars, TestCommon.list("Hello"));
- TestCommon.checkDump(output, "Preload Warning: Skipping Hello from signed JAR");
+ TestCommon.checkDump(output, "Skipping Hello: Signed JAR");
}
}