Mercurial > hg > graal-compiler
comparison src/share/vm/classfile/symbolTable.cpp @ 14909:4ca6dc0799b6
Backout jdk9 merge
author | Gilles Duboscq <duboscq@ssw.jku.at> |
---|---|
date | Tue, 01 Apr 2014 13:57:07 +0200 |
parents | 893ce66f7473 |
children | 52b4284cb496 |
comparison
equal
deleted
inserted
replaced
14908:8db6e76cb658 | 14909:4ca6dc0799b6 |
---|---|
36 #include "runtime/mutexLocker.hpp" | 36 #include "runtime/mutexLocker.hpp" |
37 #include "utilities/hashtable.inline.hpp" | 37 #include "utilities/hashtable.inline.hpp" |
38 | 38 |
39 // -------------------------------------------------------------------------- | 39 // -------------------------------------------------------------------------- |
40 | 40 |
41 // the number of buckets a thread claims | |
42 const int ClaimChunkSize = 32; | |
43 | |
44 SymbolTable* SymbolTable::_the_table = NULL; | 41 SymbolTable* SymbolTable::_the_table = NULL; |
45 // Static arena for symbols that are not deallocated | 42 // Static arena for symbols that are not deallocated |
46 Arena* SymbolTable::_arena = NULL; | 43 Arena* SymbolTable::_arena = NULL; |
47 bool SymbolTable::_needs_rehashing = false; | 44 bool SymbolTable::_needs_rehashing = false; |
48 | 45 |
84 cl->do_symbol(p->literal_addr()); | 81 cl->do_symbol(p->literal_addr()); |
85 } | 82 } |
86 } | 83 } |
87 } | 84 } |
88 | 85 |
89 int SymbolTable::_symbols_removed = 0; | 86 int SymbolTable::symbols_removed = 0; |
90 int SymbolTable::_symbols_counted = 0; | 87 int SymbolTable::symbols_counted = 0; |
91 volatile int SymbolTable::_parallel_claimed_idx = 0; | 88 |
92 | 89 // Remove unreferenced symbols from the symbol table |
93 void SymbolTable::buckets_unlink(int start_idx, int end_idx, int* processed, int* removed, size_t* memory_total) { | 90 // This is done late during GC. |
94 for (int i = start_idx; i < end_idx; ++i) { | 91 void SymbolTable::unlink() { |
92 int removed = 0; | |
93 int total = 0; | |
94 size_t memory_total = 0; | |
95 for (int i = 0; i < the_table()->table_size(); ++i) { | |
95 HashtableEntry<Symbol*, mtSymbol>** p = the_table()->bucket_addr(i); | 96 HashtableEntry<Symbol*, mtSymbol>** p = the_table()->bucket_addr(i); |
96 HashtableEntry<Symbol*, mtSymbol>* entry = the_table()->bucket(i); | 97 HashtableEntry<Symbol*, mtSymbol>* entry = the_table()->bucket(i); |
97 while (entry != NULL) { | 98 while (entry != NULL) { |
98 // Shared entries are normally at the end of the bucket and if we run into | 99 // Shared entries are normally at the end of the bucket and if we run into |
99 // a shared entry, then there is nothing more to remove. However, if we | 100 // a shared entry, then there is nothing more to remove. However, if we |
101 // end of the bucket. | 102 // end of the bucket. |
102 if (entry->is_shared() && !use_alternate_hashcode()) { | 103 if (entry->is_shared() && !use_alternate_hashcode()) { |
103 break; | 104 break; |
104 } | 105 } |
105 Symbol* s = entry->literal(); | 106 Symbol* s = entry->literal(); |
106 (*memory_total) += s->size(); | 107 memory_total += s->size(); |
107 (*processed)++; | 108 total++; |
108 assert(s != NULL, "just checking"); | 109 assert(s != NULL, "just checking"); |
109 // If reference count is zero, remove. | 110 // If reference count is zero, remove. |
110 if (s->refcount() == 0) { | 111 if (s->refcount() == 0) { |
111 assert(!entry->is_shared(), "shared entries should be kept live"); | 112 assert(!entry->is_shared(), "shared entries should be kept live"); |
112 delete s; | 113 delete s; |
113 (*removed)++; | 114 removed++; |
114 *p = entry->next(); | 115 *p = entry->next(); |
115 the_table()->free_entry(entry); | 116 the_table()->free_entry(entry); |
116 } else { | 117 } else { |
117 p = entry->next_addr(); | 118 p = entry->next_addr(); |
118 } | 119 } |
119 // get next entry | 120 // get next entry |
120 entry = (HashtableEntry<Symbol*, mtSymbol>*)HashtableEntry<Symbol*, mtSymbol>::make_ptr(*p); | 121 entry = (HashtableEntry<Symbol*, mtSymbol>*)HashtableEntry<Symbol*, mtSymbol>::make_ptr(*p); |
121 } | 122 } |
122 } | 123 } |
123 } | 124 symbols_removed += removed; |
124 | 125 symbols_counted += total; |
125 // Remove unreferenced symbols from the symbol table | |
126 // This is done late during GC. | |
127 void SymbolTable::unlink(int* processed, int* removed) { | |
128 size_t memory_total = 0; | |
129 buckets_unlink(0, the_table()->table_size(), processed, removed, &memory_total); | |
130 _symbols_removed += *removed; | |
131 _symbols_counted += *processed; | |
132 // Exclude printing for normal PrintGCDetails because people parse | 126 // Exclude printing for normal PrintGCDetails because people parse |
133 // this output. | 127 // this output. |
134 if (PrintGCDetails && Verbose && WizardMode) { | 128 if (PrintGCDetails && Verbose && WizardMode) { |
135 gclog_or_tty->print(" [Symbols=%d size=" SIZE_FORMAT "K] ", *processed, | 129 gclog_or_tty->print(" [Symbols=%d size=" SIZE_FORMAT "K] ", total, |
136 (memory_total*HeapWordSize)/1024); | |
137 } | |
138 } | |
139 | |
140 void SymbolTable::possibly_parallel_unlink(int* processed, int* removed) { | |
141 const int limit = the_table()->table_size(); | |
142 | |
143 size_t memory_total = 0; | |
144 | |
145 for (;;) { | |
146 // Grab next set of buckets to scan | |
147 int start_idx = Atomic::add(ClaimChunkSize, &_parallel_claimed_idx) - ClaimChunkSize; | |
148 if (start_idx >= limit) { | |
149 // End of table | |
150 break; | |
151 } | |
152 | |
153 int end_idx = MIN2(limit, start_idx + ClaimChunkSize); | |
154 buckets_unlink(start_idx, end_idx, processed, removed, &memory_total); | |
155 } | |
156 Atomic::add(*processed, &_symbols_counted); | |
157 Atomic::add(*removed, &_symbols_removed); | |
158 // Exclude printing for normal PrintGCDetails because people parse | |
159 // this output. | |
160 if (PrintGCDetails && Verbose && WizardMode) { | |
161 gclog_or_tty->print(" [Symbols: scanned=%d removed=%d size=" SIZE_FORMAT "K] ", *processed, *removed, | |
162 (memory_total*HeapWordSize)/1024); | 130 (memory_total*HeapWordSize)/1024); |
163 } | 131 } |
164 } | 132 } |
165 | 133 |
166 // Create a new table and using alternate hash code, populate the new table | 134 // Create a new table and using alternate hash code, populate the new table |
524 } | 492 } |
525 tty->print_cr("Symbol Table:"); | 493 tty->print_cr("Symbol Table:"); |
526 tty->print_cr("Total number of symbols %5d", count); | 494 tty->print_cr("Total number of symbols %5d", count); |
527 tty->print_cr("Total size in memory %5dK", | 495 tty->print_cr("Total size in memory %5dK", |
528 (memory_total*HeapWordSize)/1024); | 496 (memory_total*HeapWordSize)/1024); |
529 tty->print_cr("Total counted %5d", _symbols_counted); | 497 tty->print_cr("Total counted %5d", symbols_counted); |
530 tty->print_cr("Total removed %5d", _symbols_removed); | 498 tty->print_cr("Total removed %5d", symbols_removed); |
531 if (_symbols_counted > 0) { | 499 if (symbols_counted > 0) { |
532 tty->print_cr("Percent removed %3.2f", | 500 tty->print_cr("Percent removed %3.2f", |
533 ((float)_symbols_removed/(float)_symbols_counted)* 100); | 501 ((float)symbols_removed/(float)symbols_counted)* 100); |
534 } | 502 } |
535 tty->print_cr("Reference counts %5d", Symbol::_total_count); | 503 tty->print_cr("Reference counts %5d", Symbol::_total_count); |
536 tty->print_cr("Symbol arena size %5d used %5d", | 504 tty->print_cr("Symbol arena size %5d used %5d", |
537 arena()->size_in_bytes(), arena()->used()); | 505 arena()->size_in_bytes(), arena()->used()); |
538 tty->print_cr("Histogram of symbol length:"); | 506 tty->print_cr("Histogram of symbol length:"); |
769 Handle string; | 737 Handle string; |
770 oop result = intern(string, chars, length, CHECK_NULL); | 738 oop result = intern(string, chars, length, CHECK_NULL); |
771 return result; | 739 return result; |
772 } | 740 } |
773 | 741 |
774 void StringTable::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f, int* processed, int* removed) { | 742 void StringTable::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f) { |
775 buckets_unlink_or_oops_do(is_alive, f, 0, the_table()->table_size(), processed, removed); | |
776 } | |
777 | |
778 void StringTable::possibly_parallel_unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f, int* processed, int* removed) { | |
779 // Readers of the table are unlocked, so we should only be removing | 743 // Readers of the table are unlocked, so we should only be removing |
780 // entries at a safepoint. | 744 // entries at a safepoint. |
781 assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); | 745 assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); |
782 const int limit = the_table()->table_size(); | 746 for (int i = 0; i < the_table()->table_size(); ++i) { |
783 | |
784 for (;;) { | |
785 // Grab next set of buckets to scan | |
786 int start_idx = Atomic::add(ClaimChunkSize, &_parallel_claimed_idx) - ClaimChunkSize; | |
787 if (start_idx >= limit) { | |
788 // End of table | |
789 break; | |
790 } | |
791 | |
792 int end_idx = MIN2(limit, start_idx + ClaimChunkSize); | |
793 buckets_unlink_or_oops_do(is_alive, f, start_idx, end_idx, processed, removed); | |
794 } | |
795 } | |
796 | |
797 void StringTable::buckets_oops_do(OopClosure* f, int start_idx, int end_idx) { | |
798 const int limit = the_table()->table_size(); | |
799 | |
800 assert(0 <= start_idx && start_idx <= limit, | |
801 err_msg("start_idx (" INT32_FORMAT ") is out of bounds", start_idx)); | |
802 assert(0 <= end_idx && end_idx <= limit, | |
803 err_msg("end_idx (" INT32_FORMAT ") is out of bounds", end_idx)); | |
804 assert(start_idx <= end_idx, | |
805 err_msg("Index ordering: start_idx=" INT32_FORMAT", end_idx=" INT32_FORMAT, | |
806 start_idx, end_idx)); | |
807 | |
808 for (int i = start_idx; i < end_idx; i += 1) { | |
809 HashtableEntry<oop, mtSymbol>* entry = the_table()->bucket(i); | |
810 while (entry != NULL) { | |
811 assert(!entry->is_shared(), "CDS not used for the StringTable"); | |
812 | |
813 f->do_oop((oop*)entry->literal_addr()); | |
814 | |
815 entry = entry->next(); | |
816 } | |
817 } | |
818 } | |
819 | |
820 void StringTable::buckets_unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f, int start_idx, int end_idx, int* processed, int* removed) { | |
821 const int limit = the_table()->table_size(); | |
822 | |
823 assert(0 <= start_idx && start_idx <= limit, | |
824 err_msg("start_idx (" INT32_FORMAT ") is out of bounds", start_idx)); | |
825 assert(0 <= end_idx && end_idx <= limit, | |
826 err_msg("end_idx (" INT32_FORMAT ") is out of bounds", end_idx)); | |
827 assert(start_idx <= end_idx, | |
828 err_msg("Index ordering: start_idx=" INT32_FORMAT", end_idx=" INT32_FORMAT, | |
829 start_idx, end_idx)); | |
830 | |
831 for (int i = start_idx; i < end_idx; ++i) { | |
832 HashtableEntry<oop, mtSymbol>** p = the_table()->bucket_addr(i); | 747 HashtableEntry<oop, mtSymbol>** p = the_table()->bucket_addr(i); |
833 HashtableEntry<oop, mtSymbol>* entry = the_table()->bucket(i); | 748 HashtableEntry<oop, mtSymbol>* entry = the_table()->bucket(i); |
834 while (entry != NULL) { | 749 while (entry != NULL) { |
835 assert(!entry->is_shared(), "CDS not used for the StringTable"); | 750 assert(!entry->is_shared(), "CDS not used for the StringTable"); |
836 | 751 |
840 } | 755 } |
841 p = entry->next_addr(); | 756 p = entry->next_addr(); |
842 } else { | 757 } else { |
843 *p = entry->next(); | 758 *p = entry->next(); |
844 the_table()->free_entry(entry); | 759 the_table()->free_entry(entry); |
845 (*removed)++; | 760 } |
846 } | |
847 (*processed)++; | |
848 entry = *p; | 761 entry = *p; |
849 } | 762 } |
850 } | 763 } |
851 } | 764 } |
852 | 765 |
766 void StringTable::buckets_do(OopClosure* f, int start_idx, int end_idx) { | |
767 const int limit = the_table()->table_size(); | |
768 | |
769 assert(0 <= start_idx && start_idx <= limit, | |
770 err_msg("start_idx (" INT32_FORMAT ") oob?", start_idx)); | |
771 assert(0 <= end_idx && end_idx <= limit, | |
772 err_msg("end_idx (" INT32_FORMAT ") oob?", end_idx)); | |
773 assert(start_idx <= end_idx, | |
774 err_msg("Ordering: start_idx=" INT32_FORMAT", end_idx=" INT32_FORMAT, | |
775 start_idx, end_idx)); | |
776 | |
777 for (int i = start_idx; i < end_idx; i += 1) { | |
778 HashtableEntry<oop, mtSymbol>* entry = the_table()->bucket(i); | |
779 while (entry != NULL) { | |
780 assert(!entry->is_shared(), "CDS not used for the StringTable"); | |
781 | |
782 f->do_oop((oop*)entry->literal_addr()); | |
783 | |
784 entry = entry->next(); | |
785 } | |
786 } | |
787 } | |
788 | |
853 void StringTable::oops_do(OopClosure* f) { | 789 void StringTable::oops_do(OopClosure* f) { |
854 buckets_oops_do(f, 0, the_table()->table_size()); | 790 buckets_do(f, 0, the_table()->table_size()); |
855 } | 791 } |
856 | 792 |
857 void StringTable::possibly_parallel_oops_do(OopClosure* f) { | 793 void StringTable::possibly_parallel_oops_do(OopClosure* f) { |
794 const int ClaimChunkSize = 32; | |
858 const int limit = the_table()->table_size(); | 795 const int limit = the_table()->table_size(); |
859 | 796 |
860 for (;;) { | 797 for (;;) { |
861 // Grab next set of buckets to scan | 798 // Grab next set of buckets to scan |
862 int start_idx = Atomic::add(ClaimChunkSize, &_parallel_claimed_idx) - ClaimChunkSize; | 799 int start_idx = Atomic::add(ClaimChunkSize, &_parallel_claimed_idx) - ClaimChunkSize; |
864 // End of table | 801 // End of table |
865 break; | 802 break; |
866 } | 803 } |
867 | 804 |
868 int end_idx = MIN2(limit, start_idx + ClaimChunkSize); | 805 int end_idx = MIN2(limit, start_idx + ClaimChunkSize); |
869 buckets_oops_do(f, start_idx, end_idx); | 806 buckets_do(f, start_idx, end_idx); |
870 } | 807 } |
871 } | 808 } |
872 | 809 |
873 // This verification is part of Universe::verify() and needs to be quick. | 810 // This verification is part of Universe::verify() and needs to be quick. |
874 // See StringTable::verify_and_compare() below for exhaustive verification. | 811 // See StringTable::verify_and_compare() below for exhaustive verification. |