--- old/src/share/vm/classfile/dictionary.cpp 2013-09-25 14:44:52.396642861 +0200 +++ new/src/share/vm/classfile/dictionary.cpp 2013-09-25 14:44:52.324642862 +0200 @@ -38,7 +38,7 @@ : TwoOopHashtable(table_size, sizeof(DictionaryEntry)) { _current_class_index = 0; _current_class_entry = NULL; - _pd_cache_table = new ProtectionDomainCacheTable(137); + _pd_cache_table = new ProtectionDomainCacheTable(ProtectionDomainCacheSize); }; @@ -47,7 +47,7 @@ : TwoOopHashtable(table_size, sizeof(DictionaryEntry), t, number_of_entries) { _current_class_index = 0; _current_class_entry = NULL; - _pd_cache_table = new ProtectionDomainCacheTable(137); + _pd_cache_table = new ProtectionDomainCacheTable(ProtectionDomainCacheSize); }; ProtectionDomainCacheEntry* Dictionary::cache_get(oop protection_domain) { @@ -202,17 +202,10 @@ void Dictionary::always_strong_oops_do(OopClosure* blk) { - // This code is not multi-thread safe, but it should be called only - // by GC thread. - static int scan_generation = 0; - scan_generation++; - if (scan_generation == 0) { - // Wrapped around 32-bit. Never use 0 -- it's the initial value of - // ProtectionDomainCacheEntry::_scan_generation. - scan_generation = 1; - } - - // Follow all system classes and temporary placeholders in dictionary + // Follow all system classes and temporary placeholders in dictionary; only + // protection domain oops contain references into the heap. In a first + // pass over the system dictionary determine which need to be treated as + // strongly reachable and mark them as such. for (int index = 0; index < table_size(); index++) { for (DictionaryEntry *probe = bucket(index); probe != NULL; @@ -220,12 +213,13 @@ Klass* e = probe->klass(); ClassLoaderData* loader_data = probe->loader_data(); if (is_strongly_reachable(loader_data, e)) { - probe->set_strongly_reachable(scan_generation); + probe->set_strongly_reachable(); } } } - - _pd_cache_table->always_strong_oops_do(blk, scan_generation); + // then iterate over the protection domain cache to apply the closure on the + // previously marked ones. + _pd_cache_table->always_strong_oops_do(blk); } @@ -288,6 +282,8 @@ } void Dictionary::oops_do(OopClosure* f) { + // only the protection domain oops contain references into the heap. Iterate + // over all of them. _pd_cache_table->oops_do(f); } @@ -472,13 +468,58 @@ } } +uint ProtectionDomainCacheTable::bucket_size() { + return sizeof(ProtectionDomainCacheEntry); +} -void ProtectionDomainCacheTable::always_strong_oops_do(OopClosure* f, int gen) { +#ifndef PRODUCT +void ProtectionDomainCacheTable::print() { + tty->print_cr("Protection domain cache table (table_size=%d, classes=%d)", + table_size(), number_of_entries()); for (int index = 0; index < table_size(); index++) { for (ProtectionDomainCacheEntry* probe = bucket(index); probe != NULL; probe = probe->next()) { - if (probe->is_strongly_reachable(gen)) { + probe->print(); + } + } +} + +void ProtectionDomainCacheEntry::print() { + tty->print_cr("entry "PTR_FORMAT" value "PTR_FORMAT" refcount %d strongly_reachable %d next "PTR_FORMAT, + this, literal(), refcount(), _strongly_reachable, next()); +} +#endif + +void ProtectionDomainCacheTable::verify() { + int element_count = 0; + for (int index = 0; index < table_size(); index++) { + for (ProtectionDomainCacheEntry* probe = bucket(index); + probe != NULL; + probe = probe->next()) { + probe->verify(); + element_count++; + } + } + guarantee(number_of_entries() == element_count, + "Verify of protection domain cache table failed"); + debug_only(verify_lookup_length((double)number_of_entries() / table_size())); +} + +void ProtectionDomainCacheEntry::verify() { + guarantee(literal()->is_oop(), "must be an oop"); + guarantee(_refcount >= 0, "must be"); +} + +void ProtectionDomainCacheTable::always_strong_oops_do(OopClosure* f) { + // the caller marked the protection domain cache entries that we need to apply + // the closure on. Only process them. + for (int index = 0; index < table_size(); index++) { + for (ProtectionDomainCacheEntry* probe = bucket(index); + probe != NULL; + probe = probe->next()) { + if (probe->is_strongly_reachable()) { + probe->reset_strongly_reachable(); probe->oops_do(f); } } @@ -622,11 +663,12 @@ tty->cr(); } } + tty->cr(); + _pd_cache_table->print(); } #endif - void Dictionary::verify() { guarantee(number_of_entries() >= 0, "Verify of system dictionary failed"); @@ -653,5 +695,7 @@ guarantee(number_of_entries() == element_count, "Verify of system dictionary failed"); debug_only(verify_lookup_length((double)number_of_entries() / table_size())); + + _pd_cache_table->verify(); } --- old/src/share/vm/classfile/dictionary.hpp 2013-09-25 14:44:52.800642855 +0200 +++ new/src/share/vm/classfile/dictionary.hpp 2013-09-25 14:44:52.724642856 +0200 @@ -135,8 +135,12 @@ class ProtectionDomainCacheEntry : public HashtableEntry { friend class VMStructs; private: + // the number of system dictionary entries referring to this entry int _refcount; - int _scan_generation; + // flag indicating whether this protection domain entry is strongly reachable. + // Used during iterating over the system dictionary to remember oops that need + // to be updated. + bool _strongly_reachable; public: oop protection_domain() { return literal(); } @@ -154,7 +158,7 @@ void init() { _refcount = 0; - _scan_generation = 0; + _strongly_reachable = false; } ProtectionDomainCacheEntry* next() { @@ -169,11 +173,25 @@ f->do_oop(literal_addr()); } - void set_strongly_reachable(int gen) { _scan_generation = gen; } + void set_strongly_reachable() { _strongly_reachable = true; } - bool is_strongly_reachable(int gen) { return _scan_generation == gen; } + bool is_strongly_reachable() { return _strongly_reachable; } + + void reset_strongly_reachable() { _strongly_reachable = false; } + + void print() PRODUCT_RETURN; + void verify(); }; +// the ProtectionDomainCacheTable contains all protection domain oops. The system +// dictionary entries reference its entries instead of having references to oops +// directly. +// This is used to speed up system dictionary iteration: the oops in the +// protection domain are the only ones referring the Java heap. So when there is +// need to update these, instead of going over every entry of the system dictionary, +// we only need to iterate over this set. +// The amount of different protection domains used is typically magnitudes smaller +// than the number of system dictionary entries (loaded classes). class ProtectionDomainCacheTable : public Hashtable { friend class VMStructs; private: @@ -192,7 +210,7 @@ return entry; } - unsigned int compute_hash(oop protection_domain) { + static unsigned int compute_hash(oop protection_domain) { return (unsigned int)(protection_domain->identity_hash()); } @@ -212,11 +230,11 @@ // GC support void oops_do(OopClosure* f); - void always_strong_oops_do(OopClosure* f, int gen); + void always_strong_oops_do(OopClosure* f); -#ifndef PRODUCT - void print(); -#endif + static uint bucket_size(); + + void print() PRODUCT_RETURN; void verify(); }; @@ -235,6 +253,7 @@ ProtectionDomainEntry* next() { return _next; } oop protection_domain() { return _pd_cache->protection_domain(); } + ProtectionDomainCacheEntry * release_pd_cache() { if (_pd_cache->decrement_refcount() == 0) { return _pd_cache; @@ -290,11 +309,11 @@ : contains_protection_domain(protection_domain()); } - void set_strongly_reachable(int gen) { + void set_strongly_reachable() { for (ProtectionDomainEntry* current = _pd_set; current != NULL; current = current->_next) { - current->_pd_cache->set_strongly_reachable(gen); + current->_pd_cache->set_strongly_reachable(); } } --- old/src/share/vm/runtime/arguments.cpp 2013-09-25 14:44:53.232642848 +0200 +++ new/src/share/vm/runtime/arguments.cpp 2013-09-25 14:44:53.156642849 +0200 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/dictionary.hpp" #include "classfile/javaAssertions.hpp" #include "classfile/symbolTable.hpp" #include "compiler/compilerOracle.hpp" @@ -2038,6 +2039,9 @@ status = status && verify_interval(StringTableSize, minimumStringTableSize, (max_uintx / StringTable::bucket_size()), "StringTable size"); + status = status && verify_interval(ProtectionDomainCacheSize, minimumProtectionDomainCacheSize, + (max_uintx / ProtectionDomainCacheTable::bucket_size()), "ProtectionDomainCache size"); + if (MinHeapFreeRatio > MaxHeapFreeRatio) { jio_fprintf(defaultStream::error_stream(), "MinHeapFreeRatio (" UINTX_FORMAT ") must be less than or " --- old/src/share/vm/runtime/globals.hpp 2013-09-25 14:44:53.684642841 +0200 +++ new/src/share/vm/runtime/globals.hpp 2013-09-25 14:44:53.604642842 +0200 @@ -3685,6 +3685,9 @@ diagnostic(bool, PrintDTraceDOF, false, \ "Print the DTrace DOF passed to the system for JSDT probes") \ \ + product(uintx, ProtectionDomainCacheSize, defaultProtectionDomainCacheSize,\ + "Number of buckets in the protection domain cache table") \ + \ product(uintx, StringTableSize, defaultStringTableSize, \ "Number of buckets in the interned String table") \ \ --- old/src/share/vm/utilities/globalDefinitions.hpp 2013-09-25 14:44:54.092642835 +0200 +++ new/src/share/vm/utilities/globalDefinitions.hpp 2013-09-25 14:44:54.020642836 +0200 @@ -326,12 +326,16 @@ const int max_method_code_size = 64*K - 1; // JVM spec, 2nd ed. section 4.8.1 (p.134) +// Default ProtectionDomainCacheSize values + +const int defaultProtectionDomainCacheSize = NOT_LP64(137) LP64_ONLY(2017); +const int minimumProtectionDomainCacheSize = 137; //---------------------------------------------------------------------------------------------------- // Default and minimum StringTableSize values const int defaultStringTableSize = NOT_LP64(1009) LP64_ONLY(60013); -const int minimumStringTableSize=1009; +const int minimumStringTableSize = 1009; //----------------------------------------------------------------------------------------------------