annotate src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp @ 20211:82693fb204a5

8038930: G1CodeRootSet::test fails with assert(_num_chunks_handed_out == 0) failed: No elements must have been handed out yet Summary: The test incorrectly assumed that it had been started with no other previous compilation activity. Fix this by allowing multiple code root free chunk lists, and use one separate from the global one to perform the test. Reviewed-by: brutisso
author tschatzl
date Wed, 16 Apr 2014 10:14:50 +0200
parents 595c0f60d50d
children 04a62a3d51d7
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
17764
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
1 /*
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
4 *
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
5 * This code is free software; you can redistribute it and/or modify it
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
6 * under the terms of the GNU General Public License version 2 only, as
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
7 * published by the Free Software Foundation.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
8 *
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
9 * This code is distributed in the hope that it will be useful, but WITHOUT
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
12 * version 2 for more details (a copy is included in the LICENSE file that
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
13 * accompanied this code).
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
14 *
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
15 * You should have received a copy of the GNU General Public License version
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
16 * 2 along with this work; if not, write to the Free Software Foundation,
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
18 *
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
20 * or visit www.oracle.com if you need additional information or have any
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
21 * questions.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
22 *
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
23 */
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
24
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
25 #include "precompiled.hpp"
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
26 #include "classfile/altHashing.hpp"
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
27 #include "classfile/javaClasses.hpp"
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
28 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
29 #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
30 #include "gc_implementation/g1/g1StringDedupTable.hpp"
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
31 #include "memory/gcLocker.hpp"
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
32 #include "memory/padded.inline.hpp"
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
33 #include "oops/typeArrayOop.hpp"
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
34 #include "runtime/mutexLocker.hpp"
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
35
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
36 //
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
37 // Freelist in the deduplication table entry cache. Links table
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
38 // entries together using their _next fields.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
39 //
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
40 class G1StringDedupEntryFreeList : public CHeapObj<mtGC> {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
41 private:
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
42 G1StringDedupEntry* _list;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
43 size_t _length;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
44
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
45 public:
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
46 G1StringDedupEntryFreeList() :
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
47 _list(NULL),
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
48 _length(0) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
49 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
50
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
51 void add(G1StringDedupEntry* entry) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
52 entry->set_next(_list);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
53 _list = entry;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
54 _length++;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
55 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
56
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
57 G1StringDedupEntry* remove() {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
58 G1StringDedupEntry* entry = _list;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
59 if (entry != NULL) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
60 _list = entry->next();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
61 _length--;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
62 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
63 return entry;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
64 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
65
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
66 size_t length() {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
67 return _length;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
68 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
69 };
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
70
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
71 //
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
72 // Cache of deduplication table entries. This cache provides fast allocation and
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
73 // reuse of table entries to lower the pressure on the underlying allocator.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
74 // But more importantly, it provides fast/deferred freeing of table entries. This
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
75 // is important because freeing of table entries is done during stop-the-world
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
76 // phases and it is not uncommon for large number of entries to be freed at once.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
77 // Tables entries that are freed during these phases are placed onto a freelist in
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
78 // the cache. The deduplication thread, which executes in a concurrent phase, will
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
79 // later reuse or free the underlying memory for these entries.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
80 //
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
81 // The cache allows for single-threaded allocations and multi-threaded frees.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
82 // Allocations are synchronized by StringDedupTable_lock as part of a table
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
83 // modification.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
84 //
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
85 class G1StringDedupEntryCache : public CHeapObj<mtGC> {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
86 private:
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
87 // One freelist per GC worker to allow lock less freeing of
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
88 // entries while doing a parallel scan of the table. Using
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
89 // PaddedEnd to avoid false sharing.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
90 PaddedEnd<G1StringDedupEntryFreeList>* _lists;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
91 size_t _nlists;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
92
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
93 public:
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
94 G1StringDedupEntryCache();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
95 ~G1StringDedupEntryCache();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
96
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
97 // Get a table entry from the cache freelist, or allocate a new
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
98 // entry if the cache is empty.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
99 G1StringDedupEntry* alloc();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
100
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
101 // Insert a table entry into the cache freelist.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
102 void free(G1StringDedupEntry* entry, uint worker_id);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
103
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
104 // Returns current number of entries in the cache.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
105 size_t size();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
106
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
107 // If the cache has grown above the given max size, trim it down
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
108 // and deallocate the memory occupied by trimmed of entries.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
109 void trim(size_t max_size);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
110 };
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
111
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
112 G1StringDedupEntryCache::G1StringDedupEntryCache() {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
113 _nlists = MAX2(ParallelGCThreads, (size_t)1);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
114 _lists = PaddedArray<G1StringDedupEntryFreeList, mtGC>::create_unfreeable((uint)_nlists);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
115 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
116
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
117 G1StringDedupEntryCache::~G1StringDedupEntryCache() {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
118 ShouldNotReachHere();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
119 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
120
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
121 G1StringDedupEntry* G1StringDedupEntryCache::alloc() {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
122 for (size_t i = 0; i < _nlists; i++) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
123 G1StringDedupEntry* entry = _lists[i].remove();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
124 if (entry != NULL) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
125 return entry;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
126 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
127 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
128 return new G1StringDedupEntry();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
129 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
130
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
131 void G1StringDedupEntryCache::free(G1StringDedupEntry* entry, uint worker_id) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
132 assert(entry->obj() != NULL, "Double free");
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
133 assert(worker_id < _nlists, "Invalid worker id");
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
134 entry->set_obj(NULL);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
135 entry->set_hash(0);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
136 _lists[worker_id].add(entry);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
137 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
138
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
139 size_t G1StringDedupEntryCache::size() {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
140 size_t size = 0;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
141 for (size_t i = 0; i < _nlists; i++) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
142 size += _lists[i].length();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
143 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
144 return size;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
145 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
146
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
147 void G1StringDedupEntryCache::trim(size_t max_size) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
148 size_t cache_size = 0;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
149 for (size_t i = 0; i < _nlists; i++) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
150 G1StringDedupEntryFreeList* list = &_lists[i];
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
151 cache_size += list->length();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
152 while (cache_size > max_size) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
153 G1StringDedupEntry* entry = list->remove();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
154 assert(entry != NULL, "Should not be null");
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
155 cache_size--;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
156 delete entry;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
157 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
158 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
159 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
160
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
161 G1StringDedupTable* G1StringDedupTable::_table = NULL;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
162 G1StringDedupEntryCache* G1StringDedupTable::_entry_cache = NULL;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
163
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
164 const size_t G1StringDedupTable::_min_size = (1 << 10); // 1024
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
165 const size_t G1StringDedupTable::_max_size = (1 << 24); // 16777216
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
166 const double G1StringDedupTable::_grow_load_factor = 2.0; // Grow table at 200% load
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
167 const double G1StringDedupTable::_shrink_load_factor = _grow_load_factor / 3.0; // Shrink table at 67% load
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
168 const double G1StringDedupTable::_max_cache_factor = 0.1; // Cache a maximum of 10% of the table size
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
169 const uintx G1StringDedupTable::_rehash_multiple = 60; // Hash bucket has 60 times more collisions than expected
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
170 const uintx G1StringDedupTable::_rehash_threshold = (uintx)(_rehash_multiple * _grow_load_factor);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
171
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
172 uintx G1StringDedupTable::_entries_added = 0;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
173 uintx G1StringDedupTable::_entries_removed = 0;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
174 uintx G1StringDedupTable::_resize_count = 0;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
175 uintx G1StringDedupTable::_rehash_count = 0;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
176
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
177 G1StringDedupTable::G1StringDedupTable(size_t size, jint hash_seed) :
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
178 _size(size),
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
179 _entries(0),
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
180 _grow_threshold((uintx)(size * _grow_load_factor)),
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
181 _shrink_threshold((uintx)(size * _shrink_load_factor)),
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
182 _rehash_needed(false),
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
183 _hash_seed(hash_seed) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
184 assert(is_power_of_2(size), "Table size must be a power of 2");
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
185 _buckets = NEW_C_HEAP_ARRAY(G1StringDedupEntry*, _size, mtGC);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
186 memset(_buckets, 0, _size * sizeof(G1StringDedupEntry*));
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
187 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
188
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
189 G1StringDedupTable::~G1StringDedupTable() {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
190 FREE_C_HEAP_ARRAY(G1StringDedupEntry*, _buckets, mtGC);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
191 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
192
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
193 void G1StringDedupTable::create() {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
194 assert(_table == NULL, "One string deduplication table allowed");
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
195 _entry_cache = new G1StringDedupEntryCache();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
196 _table = new G1StringDedupTable(_min_size);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
197 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
198
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
199 void G1StringDedupTable::add(typeArrayOop value, unsigned int hash, G1StringDedupEntry** list) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
200 G1StringDedupEntry* entry = _entry_cache->alloc();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
201 entry->set_obj(value);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
202 entry->set_hash(hash);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
203 entry->set_next(*list);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
204 *list = entry;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
205 _entries++;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
206 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
207
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
208 void G1StringDedupTable::remove(G1StringDedupEntry** pentry, uint worker_id) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
209 G1StringDedupEntry* entry = *pentry;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
210 *pentry = entry->next();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
211 _entry_cache->free(entry, worker_id);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
212 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
213
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
214 void G1StringDedupTable::transfer(G1StringDedupEntry** pentry, G1StringDedupTable* dest) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
215 G1StringDedupEntry* entry = *pentry;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
216 *pentry = entry->next();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
217 unsigned int hash = entry->hash();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
218 size_t index = dest->hash_to_index(hash);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
219 G1StringDedupEntry** list = dest->bucket(index);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
220 entry->set_next(*list);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
221 *list = entry;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
222 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
223
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
224 bool G1StringDedupTable::equals(typeArrayOop value1, typeArrayOop value2) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
225 return (value1 == value2 ||
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
226 (value1->length() == value2->length() &&
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
227 (!memcmp(value1->base(T_CHAR),
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
228 value2->base(T_CHAR),
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
229 value1->length() * sizeof(jchar)))));
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
230 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
231
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
232 typeArrayOop G1StringDedupTable::lookup(typeArrayOop value, unsigned int hash,
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
233 G1StringDedupEntry** list, uintx &count) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
234 for (G1StringDedupEntry* entry = *list; entry != NULL; entry = entry->next()) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
235 if (entry->hash() == hash) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
236 typeArrayOop existing_value = entry->obj();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
237 if (equals(value, existing_value)) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
238 // Match found
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
239 return existing_value;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
240 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
241 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
242 count++;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
243 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
244
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
245 // Not found
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
246 return NULL;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
247 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
248
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
249 typeArrayOop G1StringDedupTable::lookup_or_add_inner(typeArrayOop value, unsigned int hash) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
250 size_t index = hash_to_index(hash);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
251 G1StringDedupEntry** list = bucket(index);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
252 uintx count = 0;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
253
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
254 // Lookup in list
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
255 typeArrayOop existing_value = lookup(value, hash, list, count);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
256
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
257 // Check if rehash is needed
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
258 if (count > _rehash_threshold) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
259 _rehash_needed = true;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
260 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
261
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
262 if (existing_value == NULL) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
263 // Not found, add new entry
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
264 add(value, hash, list);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
265
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
266 // Update statistics
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
267 _entries_added++;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
268 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
269
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
270 return existing_value;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
271 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
272
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
273 unsigned int G1StringDedupTable::hash_code(typeArrayOop value) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
274 unsigned int hash;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
275 int length = value->length();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
276 const jchar* data = (jchar*)value->base(T_CHAR);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
277
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
278 if (use_java_hash()) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
279 hash = java_lang_String::hash_code(data, length);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
280 } else {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
281 hash = AltHashing::murmur3_32(_table->_hash_seed, data, length);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
282 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
283
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
284 return hash;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
285 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
286
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
287 void G1StringDedupTable::deduplicate(oop java_string, G1StringDedupStat& stat) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
288 assert(java_lang_String::is_instance(java_string), "Must be a string");
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
289 No_Safepoint_Verifier nsv;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
290
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
291 stat.inc_inspected();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
292
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
293 typeArrayOop value = java_lang_String::value(java_string);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
294 if (value == NULL) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
295 // String has no value
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
296 stat.inc_skipped();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
297 return;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
298 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
299
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
300 unsigned int hash = 0;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
301
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
302 if (use_java_hash()) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
303 // Get hash code from cache
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
304 hash = java_lang_String::hash(java_string);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
305 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
306
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
307 if (hash == 0) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
308 // Compute hash
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
309 hash = hash_code(value);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
310 stat.inc_hashed();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
311 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
312
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
313 if (use_java_hash() && hash != 0) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
314 // Store hash code in cache
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
315 java_lang_String::set_hash(java_string, hash);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
316 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
317
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
318 typeArrayOop existing_value = lookup_or_add(value, hash);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
319 if (existing_value == value) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
320 // Same value, already known
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
321 stat.inc_known();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
322 return;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
323 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
324
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
325 // Get size of value array
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
326 uintx size_in_bytes = value->size() * HeapWordSize;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
327 stat.inc_new(size_in_bytes);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
328
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
329 if (existing_value != NULL) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
330 // Enqueue the reference to make sure it is kept alive. Concurrent mark might
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
331 // otherwise declare it dead if there are no other strong references to this object.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
332 G1SATBCardTableModRefBS::enqueue(existing_value);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
333
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
334 // Existing value found, deduplicate string
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
335 java_lang_String::set_value(java_string, existing_value);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
336
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
337 if (G1CollectedHeap::heap()->is_in_young(value)) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
338 stat.inc_deduped_young(size_in_bytes);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
339 } else {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
340 stat.inc_deduped_old(size_in_bytes);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
341 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
342 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
343 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
344
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
345 G1StringDedupTable* G1StringDedupTable::prepare_resize() {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
346 size_t size = _table->_size;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
347
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
348 // Check if the hashtable needs to be resized
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
349 if (_table->_entries > _table->_grow_threshold) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
350 // Grow table, double the size
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
351 size *= 2;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
352 if (size > _max_size) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
353 // Too big, don't resize
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
354 return NULL;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
355 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
356 } else if (_table->_entries < _table->_shrink_threshold) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
357 // Shrink table, half the size
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
358 size /= 2;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
359 if (size < _min_size) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
360 // Too small, don't resize
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
361 return NULL;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
362 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
363 } else if (StringDeduplicationResizeALot) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
364 // Force grow
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
365 size *= 2;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
366 if (size > _max_size) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
367 // Too big, force shrink instead
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
368 size /= 4;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
369 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
370 } else {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
371 // Resize not needed
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
372 return NULL;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
373 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
374
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
375 // Update statistics
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
376 _resize_count++;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
377
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
378 // Allocate the new table. The new table will be populated by workers
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
379 // calling unlink_or_oops_do() and finally installed by finish_resize().
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
380 return new G1StringDedupTable(size, _table->_hash_seed);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
381 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
382
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
383 void G1StringDedupTable::finish_resize(G1StringDedupTable* resized_table) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
384 assert(resized_table != NULL, "Invalid table");
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
385
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
386 resized_table->_entries = _table->_entries;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
387
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
388 // Free old table
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
389 delete _table;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
390
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
391 // Install new table
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
392 _table = resized_table;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
393 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
394
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
395 void G1StringDedupTable::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, uint worker_id) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
396 // The table is divided into partitions to allow lock-less parallel processing by
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
397 // multiple worker threads. A worker thread first claims a partition, which ensures
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
398 // exclusive access to that part of the table, then continues to process it. To allow
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
399 // shrinking of the table in parallel we also need to make sure that the same worker
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
400 // thread processes all partitions where entries will hash to the same destination
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
401 // partition. Since the table size is always a power of two and we always shrink by
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
402 // dividing the table in half, we know that for a given partition there is only one
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
403 // other partition whoes entries will hash to the same destination partition. That
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
404 // other partition is always the sibling partition in the second half of the table.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
405 // For example, if the table is divided into 8 partitions, the sibling of partition 0
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
406 // is partition 4, the sibling of partition 1 is partition 5, etc.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
407 size_t table_half = _table->_size / 2;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
408
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
409 // Let each partition be one page worth of buckets
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
410 size_t partition_size = MIN2(table_half, os::vm_page_size() / sizeof(G1StringDedupEntry*));
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
411 assert(table_half % partition_size == 0, "Invalid partition size");
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
412
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
413 // Number of entries removed during the scan
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
414 uintx removed = 0;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
415
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
416 for (;;) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
417 // Grab next partition to scan
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
418 size_t partition_begin = cl->claim_table_partition(partition_size);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
419 size_t partition_end = partition_begin + partition_size;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
420 if (partition_begin >= table_half) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
421 // End of table
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
422 break;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
423 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
424
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
425 // Scan the partition followed by the sibling partition in the second half of the table
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
426 removed += unlink_or_oops_do(cl, partition_begin, partition_end, worker_id);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
427 removed += unlink_or_oops_do(cl, table_half + partition_begin, table_half + partition_end, worker_id);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
428 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
429
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
430 // Delayed update avoid contention on the table lock
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
431 if (removed > 0) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
432 MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
433 _table->_entries -= removed;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
434 _entries_removed += removed;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
435 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
436 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
437
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
438 uintx G1StringDedupTable::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl,
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
439 size_t partition_begin,
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
440 size_t partition_end,
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
441 uint worker_id) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
442 uintx removed = 0;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
443 for (size_t bucket = partition_begin; bucket < partition_end; bucket++) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
444 G1StringDedupEntry** entry = _table->bucket(bucket);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
445 while (*entry != NULL) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
446 oop* p = (oop*)(*entry)->obj_addr();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
447 if (cl->is_alive(*p)) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
448 cl->keep_alive(p);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
449 if (cl->is_resizing()) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
450 // We are resizing the table, transfer entry to the new table
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
451 _table->transfer(entry, cl->resized_table());
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
452 } else {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
453 if (cl->is_rehashing()) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
454 // We are rehashing the table, rehash the entry but keep it
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
455 // in the table. We can't transfer entries into the new table
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
456 // at this point since we don't have exclusive access to all
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
457 // destination partitions. finish_rehash() will do a single
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
458 // threaded transfer of all entries.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
459 typeArrayOop value = (typeArrayOop)*p;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
460 unsigned int hash = hash_code(value);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
461 (*entry)->set_hash(hash);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
462 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
463
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
464 // Move to next entry
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
465 entry = (*entry)->next_addr();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
466 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
467 } else {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
468 // Not alive, remove entry from table
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
469 _table->remove(entry, worker_id);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
470 removed++;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
471 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
472 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
473 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
474
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
475 return removed;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
476 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
477
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
478 G1StringDedupTable* G1StringDedupTable::prepare_rehash() {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
479 if (!_table->_rehash_needed && !StringDeduplicationRehashALot) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
480 // Rehash not needed
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
481 return NULL;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
482 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
483
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
484 // Update statistics
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
485 _rehash_count++;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
486
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
487 // Compute new hash seed
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
488 _table->_hash_seed = AltHashing::compute_seed();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
489
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
490 // Allocate the new table, same size and hash seed
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
491 return new G1StringDedupTable(_table->_size, _table->_hash_seed);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
492 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
493
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
494 void G1StringDedupTable::finish_rehash(G1StringDedupTable* rehashed_table) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
495 assert(rehashed_table != NULL, "Invalid table");
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
496
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
497 // Move all newly rehashed entries into the correct buckets in the new table
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
498 for (size_t bucket = 0; bucket < _table->_size; bucket++) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
499 G1StringDedupEntry** entry = _table->bucket(bucket);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
500 while (*entry != NULL) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
501 _table->transfer(entry, rehashed_table);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
502 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
503 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
504
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
505 rehashed_table->_entries = _table->_entries;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
506
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
507 // Free old table
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
508 delete _table;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
509
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
510 // Install new table
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
511 _table = rehashed_table;
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
512 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
513
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
514 void G1StringDedupTable::verify() {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
515 for (size_t bucket = 0; bucket < _table->_size; bucket++) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
516 // Verify entries
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
517 G1StringDedupEntry** entry = _table->bucket(bucket);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
518 while (*entry != NULL) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
519 typeArrayOop value = (*entry)->obj();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
520 guarantee(value != NULL, "Object must not be NULL");
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
521 guarantee(Universe::heap()->is_in_reserved(value), "Object must be on the heap");
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
522 guarantee(!value->is_forwarded(), "Object must not be forwarded");
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
523 guarantee(value->is_typeArray(), "Object must be a typeArrayOop");
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
524 unsigned int hash = hash_code(value);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
525 guarantee((*entry)->hash() == hash, "Table entry has inorrect hash");
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
526 guarantee(_table->hash_to_index(hash) == bucket, "Table entry has incorrect index");
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
527 entry = (*entry)->next_addr();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
528 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
529
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
530 // Verify that we do not have entries with identical oops or identical arrays.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
531 // We only need to compare entries in the same bucket. If the same oop or an
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
532 // identical array has been inserted more than once into different/incorrect
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
533 // buckets the verification step above will catch that.
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
534 G1StringDedupEntry** entry1 = _table->bucket(bucket);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
535 while (*entry1 != NULL) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
536 typeArrayOop value1 = (*entry1)->obj();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
537 G1StringDedupEntry** entry2 = (*entry1)->next_addr();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
538 while (*entry2 != NULL) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
539 typeArrayOop value2 = (*entry2)->obj();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
540 guarantee(!equals(value1, value2), "Table entries must not have identical arrays");
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
541 entry2 = (*entry2)->next_addr();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
542 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
543 entry1 = (*entry1)->next_addr();
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
544 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
545 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
546 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
547
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
548 void G1StringDedupTable::trim_entry_cache() {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
549 MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
550 size_t max_cache_size = (size_t)(_table->_size * _max_cache_factor);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
551 _entry_cache->trim(max_cache_size);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
552 }
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
553
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
554 void G1StringDedupTable::print_statistics(outputStream* st) {
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
555 st->print_cr(
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
556 " [Table]\n"
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
557 " [Memory Usage: "G1_STRDEDUP_BYTES_FORMAT_NS"]\n"
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
558 " [Size: "SIZE_FORMAT", Min: "SIZE_FORMAT", Max: "SIZE_FORMAT"]\n"
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
559 " [Entries: "UINTX_FORMAT", Load: "G1_STRDEDUP_PERCENT_FORMAT_NS", Cached: " UINTX_FORMAT ", Added: "UINTX_FORMAT", Removed: "UINTX_FORMAT"]\n"
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
560 " [Resize Count: "UINTX_FORMAT", Shrink Threshold: "UINTX_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT_NS"), Grow Threshold: "UINTX_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT_NS")]\n"
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
561 " [Rehash Count: "UINTX_FORMAT", Rehash Threshold: "UINTX_FORMAT", Hash Seed: 0x%x]\n"
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
562 " [Age Threshold: "UINTX_FORMAT"]",
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
563 G1_STRDEDUP_BYTES_PARAM(_table->_size * sizeof(G1StringDedupEntry*) + (_table->_entries + _entry_cache->size()) * sizeof(G1StringDedupEntry)),
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
564 _table->_size, _min_size, _max_size,
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
565 _table->_entries, (double)_table->_entries / (double)_table->_size * 100.0, _entry_cache->size(), _entries_added, _entries_removed,
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
566 _resize_count, _table->_shrink_threshold, _shrink_load_factor * 100.0, _table->_grow_threshold, _grow_load_factor * 100.0,
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
567 _rehash_count, _rehash_threshold, _table->_hash_seed,
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
568 StringDeduplicationAgeThreshold);
595c0f60d50d 8029075: String deduplication in G1
pliden
parents:
diff changeset
569 }