7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 #include "precompiled.hpp"
26 #include "classfile/altHashing.hpp"
27 #include "classfile/compactHashtable.inline.hpp"
28 #include "classfile/javaClasses.inline.hpp"
29 #include "classfile/stringTable.hpp"
30 #include "classfile/systemDictionary.hpp"
31 #include "gc/shared/collectedHeap.hpp"
32 #include "gc/shared/oopStorage.inline.hpp"
33 #include "gc/shared/oopStorageParState.inline.hpp"
34 #include "logging/log.hpp"
35 #include "logging/logStream.hpp"
36 #include "memory/allocation.inline.hpp"
37 #include "memory/filemap.hpp"
38 #include "memory/metaspaceShared.inline.hpp"
39 #include "memory/resourceArea.hpp"
40 #include "memory/universe.hpp"
41 #include "oops/access.inline.hpp"
42 #include "oops/oop.inline.hpp"
43 #include "oops/typeArrayOop.inline.hpp"
44 #include "oops/weakHandle.inline.hpp"
45 #include "runtime/atomic.hpp"
46 #include "runtime/handles.inline.hpp"
47 #include "runtime/mutexLocker.hpp"
48 #include "runtime/safepointVerifiers.hpp"
49 #include "runtime/timerTrace.hpp"
50 #include "runtime/interfaceSupport.inline.hpp"
51 #include "services/diagnosticCommand.hpp"
52 #include "utilities/concurrentHashTable.inline.hpp"
53 #include "utilities/concurrentHashTableTasks.inline.hpp"
54 #include "utilities/macros.hpp"
55
56 // We prefer short chains of avg 2
57 #define PREF_AVG_LIST_LEN 2
58 // 2^24 is max size
59 #define END_SIZE 24
60 // If a chain gets to 32 something might be wrong
61 #define REHASH_LEN 32
62 // If we have as many dead items as 50% of the number of bucket
63 #define CLEAN_DEAD_HIGH_WATER_MARK 0.5
64
65 // --------------------------------------------------------------------------
66 StringTable* StringTable::_the_table = NULL;
67 CompactHashtable<oop, char> StringTable::_shared_table;
68 volatile bool StringTable::_shared_string_mapped = false;
69 volatile bool StringTable::_alt_hash = false;
70
71 static juint murmur_seed = 0;
72
73 uintx hash_string(const jchar* s, int len, bool useAlt) {
74 return useAlt ?
75 AltHashing::murmur3_32(murmur_seed, s, len) :
76 java_lang_String::hash_code(s, len);
77 }
78
79 class StringTableConfig : public StringTableHash::BaseConfig {
80 private:
81 public:
82 static uintx get_hash(WeakHandle<vm_string_table_data> const& value,
83 bool* is_dead) {
84 EXCEPTION_MARK;
85 oop val_oop = value.peek();
86 if (val_oop == NULL) {
87 *is_dead = true;
117 Thread* _thread;
118 uintx _hash;
119 int _len;
120 const jchar* _str;
121 Handle _found;
122
123 public:
124 StringTableLookupJchar(Thread* thread, uintx hash, const jchar* key, int len)
125 : _thread(thread), _hash(hash), _len(len), _str(key) {
126 }
127 uintx get_hash() const {
128 return _hash;
129 }
130 bool equals(WeakHandle<vm_string_table_data>* value, bool* is_dead) {
131 oop val_oop = value->peek();
132 if (val_oop == NULL) {
133 // dead oop, mark this hash dead for cleaning
134 *is_dead = true;
135 return false;
136 }
137 bool equals = java_lang_String::equals(val_oop, (jchar*)_str, _len);
138 if (!equals) {
139 return false;
140 }
141 // Need to resolve weak handle and Handleize through possible safepoint.
142 _found = Handle(_thread, value->resolve());
143 return true;
144 }
145 };
146
147 class StringTableLookupOop : public StackObj {
148 private:
149 Thread* _thread;
150 uintx _hash;
151 Handle _find;
152 Handle _found; // Might be a different oop with the same value that's already
153 // in the table, which is the point.
154 public:
155 StringTableLookupOop(Thread* thread, uintx hash, Handle handle)
156 : _thread(thread), _hash(hash), _find(handle) { }
157
219 }
220
221 size_t StringTable::table_size() {
222 return ((size_t)1) << _local_table->get_size_log2(Thread::current());
223 }
224
225 void StringTable::trigger_concurrent_work() {
226 MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
227 the_table()->_has_work = true;
228 Service_lock->notify_all();
229 }
230
231 // Probing
232 oop StringTable::lookup(Symbol* symbol) {
233 ResourceMark rm;
234 int length;
235 jchar* chars = symbol->as_unicode(length);
236 return lookup(chars, length);
237 }
238
239 oop StringTable::lookup(jchar* name, int len) {
240 unsigned int hash = java_lang_String::hash_code(name, len);
241 oop string = StringTable::the_table()->lookup_shared(name, len, hash);
242 if (string != NULL) {
243 return string;
244 }
245 if (StringTable::_alt_hash) {
246 hash = hash_string(name, len, true);
247 }
248 return StringTable::the_table()->do_lookup(name, len, hash);
249 }
250
251 class StringTableGet : public StackObj {
252 Thread* _thread;
253 Handle _return;
254 public:
255 StringTableGet(Thread* thread) : _thread(thread) {}
256 void operator()(WeakHandle<vm_string_table_data>* val) {
257 oop result = val->resolve();
258 assert(result != NULL, "Result should be reachable");
259 _return = Handle(_thread, result);
260 }
261 oop get_res_oop() {
262 return _return();
263 }
264 };
265
266 oop StringTable::do_lookup(jchar* name, int len, uintx hash) {
267 Thread* thread = Thread::current();
268 StringTableLookupJchar lookup(thread, hash, name, len);
269 StringTableGet stg(thread);
270 bool rehash_warning;
271 _local_table->get(thread, lookup, stg, &rehash_warning);
272 if (rehash_warning) {
273 _needs_rehashing = true;
274 }
275 return stg.get_res_oop();
276 }
277
278 // Interning
279 oop StringTable::intern(Symbol* symbol, TRAPS) {
280 if (symbol == NULL) return NULL;
281 ResourceMark rm(THREAD);
282 int length;
283 jchar* chars = symbol->as_unicode(length);
284 Handle string;
285 oop result = intern(string, chars, length, CHECK_NULL);
286 return result;
291 ResourceMark rm(THREAD);
292 int length;
293 Handle h_string (THREAD, string);
294 jchar* chars = java_lang_String::as_unicode_string(string, length,
295 CHECK_NULL);
296 oop result = intern(h_string, chars, length, CHECK_NULL);
297 return result;
298 }
299
300 oop StringTable::intern(const char* utf8_string, TRAPS) {
301 if (utf8_string == NULL) return NULL;
302 ResourceMark rm(THREAD);
303 int length = UTF8::unicode_length(utf8_string);
304 jchar* chars = NEW_RESOURCE_ARRAY(jchar, length);
305 UTF8::convert_to_unicode(utf8_string, chars, length);
306 Handle string;
307 oop result = intern(string, chars, length, CHECK_NULL);
308 return result;
309 }
310
311 oop StringTable::intern(Handle string_or_null_h, jchar* name, int len, TRAPS) {
312 // shared table always uses java_lang_String::hash_code
313 unsigned int hash = java_lang_String::hash_code(name, len);
314 oop found_string = StringTable::the_table()->lookup_shared(name, len, hash);
315 if (found_string != NULL) {
316 return found_string;
317 }
318 if (StringTable::_alt_hash) {
319 hash = hash_string(name, len, true);
320 }
321 return StringTable::the_table()->do_intern(string_or_null_h, name, len,
322 hash, CHECK_NULL);
323 }
324
325 class StringTableCreateEntry : public StackObj {
326 private:
327 Thread* _thread;
328 Handle _return;
329 Handle _store;
330 public:
331 StringTableCreateEntry(Thread* thread, Handle store)
332 : _thread(thread), _store(store) {}
333
334 WeakHandle<vm_string_table_data> operator()() { // No dups found
335 WeakHandle<vm_string_table_data> wh =
336 WeakHandle<vm_string_table_data>::create(_store);
337 return wh;
338 }
339 void operator()(bool inserted, WeakHandle<vm_string_table_data>* val) {
340 oop result = val->resolve();
341 assert(result != NULL, "Result should be reachable");
342 _return = Handle(_thread, result);
343 }
344 oop get_return() const {
345 return _return();
346 }
347 };
348
349 oop StringTable::do_intern(Handle string_or_null_h, jchar* name,
350 int len, uintx hash, TRAPS) {
351 HandleMark hm(THREAD); // cleanup strings created
352 Handle string_h;
353
354 if (!string_or_null_h.is_null()) {
355 string_h = string_or_null_h;
356 } else {
357 string_h = java_lang_String::create_from_unicode(name, len, CHECK_NULL);
358 }
359
360 // Deduplicate the string before it is interned. Note that we should never
361 // deduplicate a string after it has been interned. Doing so will counteract
362 // compiler optimizations done on e.g. interned string literals.
363 Universe::heap()->deduplicate_string(string_h());
364
365 assert(java_lang_String::equals(string_h(), name, len),
366 "string must be properly initialized");
367 assert(len == java_lang_String::length(string_h()), "Must be same length");
368 StringTableLookupOop lookup(THREAD, hash, string_h);
369 StringTableCreateEntry stc(THREAD, string_h);
758
759 void StringtableDCmd::execute(DCmdSource source, TRAPS) {
760 VM_DumpHashtable dumper(output(), VM_DumpHashtable::DumpStrings,
761 _verbose.value());
762 VMThread::execute(&dumper);
763 }
764
765 int StringtableDCmd::num_arguments() {
766 ResourceMark rm;
767 StringtableDCmd* dcmd = new StringtableDCmd(NULL, false);
768 if (dcmd != NULL) {
769 DCmdMark mark(dcmd);
770 return dcmd->_dcmdparser.num_arguments();
771 } else {
772 return 0;
773 }
774 }
775
776 // Sharing
777 #if INCLUDE_CDS_JAVA_HEAP
778 oop StringTable::lookup_shared(jchar* name, int len, unsigned int hash) {
779 assert(hash == java_lang_String::hash_code(name, len),
780 "hash must be computed using java_lang_String::hash_code");
781 return _shared_table.lookup((const char*)name, hash, len);
782 }
783
784 oop StringTable::create_archived_string(oop s, Thread* THREAD) {
785 assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
786
787 if (MetaspaceShared::is_archive_object(s)) {
788 return s;
789 }
790
791 oop new_s = NULL;
792 typeArrayOop v = java_lang_String::value_no_keepalive(s);
793 typeArrayOop new_v =
794 (typeArrayOop)MetaspaceShared::archive_heap_object(v, THREAD);
795 if (new_v == NULL) {
796 return NULL;
797 }
798 new_s = MetaspaceShared::archive_heap_object(s, THREAD);
799 if (new_s == NULL) {
800 return NULL;
801 }
802
803 // adjust the pointer to the 'value' field in the new String oop
804 java_lang_String::set_value_raw(new_s, new_v);
805 return new_s;
806 }
807
808 struct CopyToArchive : StackObj {
809 CompactStringTableWriter* _writer;
810 CopyToArchive(CompactStringTableWriter* writer) : _writer(writer) {}
811 bool operator()(WeakHandle<vm_string_table_data>* val) {
812 oop s = val->peek();
813 if (s == NULL) {
814 return true;
815 }
816 unsigned int hash = java_lang_String::hash_code(s);
817 if (hash == 0) {
818 return true;
819 }
820
821 java_lang_String::set_hash(s, hash);
822 oop new_s = StringTable::create_archived_string(s, Thread::current());
823 if (new_s == NULL) {
824 return true;
825 }
826
827 val->replace(new_s);
832 };
833
834 void StringTable::copy_shared_string_table(CompactStringTableWriter* writer) {
835 assert(MetaspaceShared::is_heap_object_archiving_allowed(), "must be");
836
837 CopyToArchive copy(writer);
838 StringTable::the_table()->_local_table->do_scan(Thread::current(), copy);
839 }
840
841 void StringTable::write_to_archive() {
842 assert(MetaspaceShared::is_heap_object_archiving_allowed(), "must be");
843
844 _shared_table.reset();
845 int num_buckets = the_table()->_items_count / SharedSymbolTableBucketSize;
846 // calculation of num_buckets can result in zero buckets, we need at least one
847 CompactStringTableWriter writer(num_buckets > 1 ? num_buckets : 1,
848 &MetaspaceShared::stats()->string);
849
850 // Copy the interned strings into the "string space" within the java heap
851 copy_shared_string_table(&writer);
852 writer.dump(&_shared_table);
853 }
854
855 void StringTable::serialize(SerializeClosure* soc) {
856 _shared_table.set_type(CompactHashtable<oop, char>::_string_table);
857 _shared_table.serialize(soc);
858
859 if (soc->writing()) {
860 // Sanity. Make sure we don't use the shared table at dump time
861 _shared_table.reset();
862 } else if (!_shared_string_mapped) {
863 _shared_table.reset();
864 }
865 }
866
867 void StringTable::shared_oops_do(OopClosure* f) {
868 _shared_table.oops_do(f);
869 }
870 #endif //INCLUDE_CDS_JAVA_HEAP
|
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 #include "precompiled.hpp"
26 #include "classfile/altHashing.hpp"
27 #include "classfile/compactHashtable.hpp"
28 #include "classfile/javaClasses.inline.hpp"
29 #include "classfile/stringTable.hpp"
30 #include "classfile/systemDictionary.hpp"
31 #include "gc/shared/collectedHeap.hpp"
32 #include "gc/shared/oopStorage.inline.hpp"
33 #include "gc/shared/oopStorageParState.inline.hpp"
34 #include "logging/log.hpp"
35 #include "logging/logStream.hpp"
36 #include "memory/allocation.inline.hpp"
37 #include "memory/filemap.hpp"
38 #include "memory/heapShared.inline.hpp"
39 #include "memory/metaspaceShared.inline.hpp"
40 #include "memory/resourceArea.hpp"
41 #include "memory/universe.hpp"
42 #include "oops/access.inline.hpp"
43 #include "oops/oop.inline.hpp"
44 #include "oops/typeArrayOop.inline.hpp"
45 #include "oops/weakHandle.inline.hpp"
46 #include "runtime/atomic.hpp"
47 #include "runtime/handles.inline.hpp"
48 #include "runtime/mutexLocker.hpp"
49 #include "runtime/safepointVerifiers.hpp"
50 #include "runtime/timerTrace.hpp"
51 #include "runtime/interfaceSupport.inline.hpp"
52 #include "services/diagnosticCommand.hpp"
53 #include "utilities/concurrentHashTable.inline.hpp"
54 #include "utilities/concurrentHashTableTasks.inline.hpp"
55 #include "utilities/macros.hpp"
56
57 // We prefer short chains of avg 2
58 #define PREF_AVG_LIST_LEN 2
59 // 2^24 is max size
60 #define END_SIZE 24
61 // If a chain gets to 32 something might be wrong
62 #define REHASH_LEN 32
63 // If we have as many dead items as 50% of the number of bucket
64 #define CLEAN_DEAD_HIGH_WATER_MARK 0.5
65
66 #if INCLUDE_CDS_JAVA_HEAP
67 inline oop read_string_from_compact_hashtable(address base_address, u4 offset) {
68 assert(sizeof(narrowOop) == sizeof(offset), "must be");
69 narrowOop v = (narrowOop)offset;
70 return HeapShared::decode_from_archive(v);
71 }
72
73 static CompactHashtable<
74 const jchar*, oop,
75 read_string_from_compact_hashtable,
76 java_lang_String::equals
77 > _shared_table;
78 #endif
79
80 // --------------------------------------------------------------------------
81 StringTable* StringTable::_the_table = NULL;
82 volatile bool StringTable::_shared_string_mapped = false;
83 volatile bool StringTable::_alt_hash = false;
84
85 static juint murmur_seed = 0;
86
87 uintx hash_string(const jchar* s, int len, bool useAlt) {
88 return useAlt ?
89 AltHashing::murmur3_32(murmur_seed, s, len) :
90 java_lang_String::hash_code(s, len);
91 }
92
93 class StringTableConfig : public StringTableHash::BaseConfig {
94 private:
95 public:
96 static uintx get_hash(WeakHandle<vm_string_table_data> const& value,
97 bool* is_dead) {
98 EXCEPTION_MARK;
99 oop val_oop = value.peek();
100 if (val_oop == NULL) {
101 *is_dead = true;
131 Thread* _thread;
132 uintx _hash;
133 int _len;
134 const jchar* _str;
135 Handle _found;
136
137 public:
138 StringTableLookupJchar(Thread* thread, uintx hash, const jchar* key, int len)
139 : _thread(thread), _hash(hash), _len(len), _str(key) {
140 }
141 uintx get_hash() const {
142 return _hash;
143 }
144 bool equals(WeakHandle<vm_string_table_data>* value, bool* is_dead) {
145 oop val_oop = value->peek();
146 if (val_oop == NULL) {
147 // dead oop, mark this hash dead for cleaning
148 *is_dead = true;
149 return false;
150 }
151 bool equals = java_lang_String::equals(val_oop, _str, _len);
152 if (!equals) {
153 return false;
154 }
155 // Need to resolve weak handle and Handleize through possible safepoint.
156 _found = Handle(_thread, value->resolve());
157 return true;
158 }
159 };
160
161 class StringTableLookupOop : public StackObj {
162 private:
163 Thread* _thread;
164 uintx _hash;
165 Handle _find;
166 Handle _found; // Might be a different oop with the same value that's already
167 // in the table, which is the point.
168 public:
169 StringTableLookupOop(Thread* thread, uintx hash, Handle handle)
170 : _thread(thread), _hash(hash), _find(handle) { }
171
233 }
234
235 size_t StringTable::table_size() {
236 return ((size_t)1) << _local_table->get_size_log2(Thread::current());
237 }
238
239 void StringTable::trigger_concurrent_work() {
240 MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
241 the_table()->_has_work = true;
242 Service_lock->notify_all();
243 }
244
245 // Probing
246 oop StringTable::lookup(Symbol* symbol) {
247 ResourceMark rm;
248 int length;
249 jchar* chars = symbol->as_unicode(length);
250 return lookup(chars, length);
251 }
252
253 oop StringTable::lookup(const jchar* name, int len) {
254 unsigned int hash = java_lang_String::hash_code(name, len);
255 oop string = StringTable::the_table()->lookup_shared(name, len, hash);
256 if (string != NULL) {
257 return string;
258 }
259 if (StringTable::_alt_hash) {
260 hash = hash_string(name, len, true);
261 }
262 return StringTable::the_table()->do_lookup(name, len, hash);
263 }
264
265 class StringTableGet : public StackObj {
266 Thread* _thread;
267 Handle _return;
268 public:
269 StringTableGet(Thread* thread) : _thread(thread) {}
270 void operator()(WeakHandle<vm_string_table_data>* val) {
271 oop result = val->resolve();
272 assert(result != NULL, "Result should be reachable");
273 _return = Handle(_thread, result);
274 }
275 oop get_res_oop() {
276 return _return();
277 }
278 };
279
280 oop StringTable::do_lookup(const jchar* name, int len, uintx hash) {
281 Thread* thread = Thread::current();
282 StringTableLookupJchar lookup(thread, hash, name, len);
283 StringTableGet stg(thread);
284 bool rehash_warning;
285 _local_table->get(thread, lookup, stg, &rehash_warning);
286 if (rehash_warning) {
287 _needs_rehashing = true;
288 }
289 return stg.get_res_oop();
290 }
291
292 // Interning
293 oop StringTable::intern(Symbol* symbol, TRAPS) {
294 if (symbol == NULL) return NULL;
295 ResourceMark rm(THREAD);
296 int length;
297 jchar* chars = symbol->as_unicode(length);
298 Handle string;
299 oop result = intern(string, chars, length, CHECK_NULL);
300 return result;
305 ResourceMark rm(THREAD);
306 int length;
307 Handle h_string (THREAD, string);
308 jchar* chars = java_lang_String::as_unicode_string(string, length,
309 CHECK_NULL);
310 oop result = intern(h_string, chars, length, CHECK_NULL);
311 return result;
312 }
313
314 oop StringTable::intern(const char* utf8_string, TRAPS) {
315 if (utf8_string == NULL) return NULL;
316 ResourceMark rm(THREAD);
317 int length = UTF8::unicode_length(utf8_string);
318 jchar* chars = NEW_RESOURCE_ARRAY(jchar, length);
319 UTF8::convert_to_unicode(utf8_string, chars, length);
320 Handle string;
321 oop result = intern(string, chars, length, CHECK_NULL);
322 return result;
323 }
324
325 oop StringTable::intern(Handle string_or_null_h, const jchar* name, int len, TRAPS) {
326 // shared table always uses java_lang_String::hash_code
327 unsigned int hash = java_lang_String::hash_code(name, len);
328 oop found_string = StringTable::the_table()->lookup_shared(name, len, hash);
329 if (found_string != NULL) {
330 return found_string;
331 }
332 if (StringTable::_alt_hash) {
333 hash = hash_string(name, len, true);
334 }
335 return StringTable::the_table()->do_intern(string_or_null_h, name, len,
336 hash, CHECK_NULL);
337 }
338
339 class StringTableCreateEntry : public StackObj {
340 private:
341 Thread* _thread;
342 Handle _return;
343 Handle _store;
344 public:
345 StringTableCreateEntry(Thread* thread, Handle store)
346 : _thread(thread), _store(store) {}
347
348 WeakHandle<vm_string_table_data> operator()() { // No dups found
349 WeakHandle<vm_string_table_data> wh =
350 WeakHandle<vm_string_table_data>::create(_store);
351 return wh;
352 }
353 void operator()(bool inserted, WeakHandle<vm_string_table_data>* val) {
354 oop result = val->resolve();
355 assert(result != NULL, "Result should be reachable");
356 _return = Handle(_thread, result);
357 }
358 oop get_return() const {
359 return _return();
360 }
361 };
362
363 oop StringTable::do_intern(Handle string_or_null_h, const jchar* name,
364 int len, uintx hash, TRAPS) {
365 HandleMark hm(THREAD); // cleanup strings created
366 Handle string_h;
367
368 if (!string_or_null_h.is_null()) {
369 string_h = string_or_null_h;
370 } else {
371 string_h = java_lang_String::create_from_unicode(name, len, CHECK_NULL);
372 }
373
374 // Deduplicate the string before it is interned. Note that we should never
375 // deduplicate a string after it has been interned. Doing so will counteract
376 // compiler optimizations done on e.g. interned string literals.
377 Universe::heap()->deduplicate_string(string_h());
378
379 assert(java_lang_String::equals(string_h(), name, len),
380 "string must be properly initialized");
381 assert(len == java_lang_String::length(string_h()), "Must be same length");
382 StringTableLookupOop lookup(THREAD, hash, string_h);
383 StringTableCreateEntry stc(THREAD, string_h);
772
773 void StringtableDCmd::execute(DCmdSource source, TRAPS) {
774 VM_DumpHashtable dumper(output(), VM_DumpHashtable::DumpStrings,
775 _verbose.value());
776 VMThread::execute(&dumper);
777 }
778
779 int StringtableDCmd::num_arguments() {
780 ResourceMark rm;
781 StringtableDCmd* dcmd = new StringtableDCmd(NULL, false);
782 if (dcmd != NULL) {
783 DCmdMark mark(dcmd);
784 return dcmd->_dcmdparser.num_arguments();
785 } else {
786 return 0;
787 }
788 }
789
790 // Sharing
791 #if INCLUDE_CDS_JAVA_HEAP
792 oop StringTable::lookup_shared(const jchar* name, int len, unsigned int hash) {
793 assert(hash == java_lang_String::hash_code(name, len),
794 "hash must be computed using java_lang_String::hash_code");
795 return _shared_table.lookup(name, hash, len);
796 }
797
798 oop StringTable::create_archived_string(oop s, Thread* THREAD) {
799 assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
800
801 if (MetaspaceShared::is_archive_object(s)) {
802 return s;
803 }
804
805 oop new_s = NULL;
806 typeArrayOop v = java_lang_String::value_no_keepalive(s);
807 typeArrayOop new_v =
808 (typeArrayOop)MetaspaceShared::archive_heap_object(v, THREAD);
809 if (new_v == NULL) {
810 return NULL;
811 }
812 new_s = MetaspaceShared::archive_heap_object(s, THREAD);
813 if (new_s == NULL) {
814 return NULL;
815 }
816
817 // adjust the pointer to the 'value' field in the new String oop
818 java_lang_String::set_value_raw(new_s, new_v);
819 return new_s;
820 }
821
822 class CompactStringTableWriter: public CompactHashtableWriter {
823 public:
824 CompactStringTableWriter(int num_entries, CompactHashtableStats* stats) :
825 CompactHashtableWriter(num_entries, stats) {}
826 void add(unsigned int hash, oop string) {
827 CompactHashtableWriter::add(hash, CompressedOops::encode(string));
828 }
829 };
830
831 struct CopyToArchive : StackObj {
832 CompactStringTableWriter* _writer;
833 CopyToArchive(CompactStringTableWriter* writer) : _writer(writer) {}
834 bool operator()(WeakHandle<vm_string_table_data>* val) {
835 oop s = val->peek();
836 if (s == NULL) {
837 return true;
838 }
839 unsigned int hash = java_lang_String::hash_code(s);
840 if (hash == 0) {
841 return true;
842 }
843
844 java_lang_String::set_hash(s, hash);
845 oop new_s = StringTable::create_archived_string(s, Thread::current());
846 if (new_s == NULL) {
847 return true;
848 }
849
850 val->replace(new_s);
855 };
856
857 void StringTable::copy_shared_string_table(CompactStringTableWriter* writer) {
858 assert(MetaspaceShared::is_heap_object_archiving_allowed(), "must be");
859
860 CopyToArchive copy(writer);
861 StringTable::the_table()->_local_table->do_scan(Thread::current(), copy);
862 }
863
864 void StringTable::write_to_archive() {
865 assert(MetaspaceShared::is_heap_object_archiving_allowed(), "must be");
866
867 _shared_table.reset();
868 int num_buckets = the_table()->_items_count / SharedSymbolTableBucketSize;
869 // calculation of num_buckets can result in zero buckets, we need at least one
870 CompactStringTableWriter writer(num_buckets > 1 ? num_buckets : 1,
871 &MetaspaceShared::stats()->string);
872
873 // Copy the interned strings into the "string space" within the java heap
874 copy_shared_string_table(&writer);
875 writer.dump(&_shared_table, "string");
876 }
877
878 void StringTable::serialize(SerializeClosure* soc) {
879 _shared_table.serialize(soc);
880
881 if (soc->writing()) {
882 // Sanity. Make sure we don't use the shared table at dump time
883 _shared_table.reset();
884 } else if (!_shared_string_mapped) {
885 _shared_table.reset();
886 }
887 }
888
889 class SharedStringIterator {
890 OopClosure* _oop_closure;
891 public:
892 SharedStringIterator(OopClosure* f) : _oop_closure(f) {}
893 void do_value(oop string) {
894 _oop_closure->do_oop(&string);
895 }
896 };
897
898 void StringTable::shared_oops_do(OopClosure* f) {
899 SharedStringIterator iter(f);
900 _shared_table.iterate(&iter);
901 }
902 #endif //INCLUDE_CDS_JAVA_HEAP
|