1 /*
  2  * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  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/oopStorageSet.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/resourceArea.hpp"
 40 #include "memory/universe.hpp"
 41 #include "oops/access.inline.hpp"
 42 #include "oops/compressedOops.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 #include "utilities/utf8.hpp"
 57 
 58 // We prefer short chains of avg 2
 59 const double PREF_AVG_LIST_LEN = 2.0;
 60 // 2^24 is max size
 61 const size_t END_SIZE = 24;
 62 // If a chain gets to 100 something might be wrong
 63 const size_t REHASH_LEN = 100;
 64 // If we have as many dead items as 50% of the number of bucket
 65 const double CLEAN_DEAD_HIGH_WATER_MARK = 0.5;
 66 
 67 #if INCLUDE_CDS_JAVA_HEAP
 68 inline oop read_string_from_compact_hashtable(address base_address, u4 offset) {
 69   assert(sizeof(narrowOop) == sizeof(offset), "must be");
 70   narrowOop v = (narrowOop)offset;
 71   return HeapShared::decode_from_archive(v);
 72 }
 73 
 74 static CompactHashtable<
 75   const jchar*, oop,
 76   read_string_from_compact_hashtable,
 77   java_lang_String::equals
 78 > _shared_table;
 79 #endif
 80 
 81 // --------------------------------------------------------------------------
 82 
 83 typedef ConcurrentHashTable<StringTableConfig, mtSymbol> StringTableHash;
 84 static StringTableHash* _local_table = NULL;
 85 
 86 volatile bool StringTable::_has_work = false;
 87 volatile bool StringTable::_needs_rehashing = false;
 88 
 89 volatile size_t StringTable::_uncleaned_items_count = 0;
 90 
 91 static size_t _current_size = 0;
 92 static volatile size_t _items_count = 0;
 93 
 94 volatile bool _alt_hash = false;
 95 static juint murmur_seed = 0;
 96 
 97 uintx hash_string(const jchar* s, int len, bool useAlt) {
 98   return  useAlt ?
 99     AltHashing::murmur3_32(murmur_seed, s, len) :
100     java_lang_String::hash_code(s, len);
101 }
102 
103 class StringTableConfig : public StackObj {
104  private:
105  public:
106   typedef WeakHandle Value;
107 
108   static uintx get_hash(Value const& value, bool* is_dead) {
109     EXCEPTION_MARK;
110     oop val_oop = value.peek();
111     if (val_oop == NULL) {
112       *is_dead = true;
113       return 0;
114     }
115     *is_dead = false;
116     ResourceMark rm(THREAD);
117     // All String oops are hashed as unicode
118     int length;
119     jchar* chars = java_lang_String::as_unicode_string(val_oop, length, THREAD);
120     if (chars != NULL) {
121       return hash_string(chars, length, _alt_hash);
122     }
123     vm_exit_out_of_memory(length, OOM_MALLOC_ERROR, "get hash from oop");
124     return 0;
125   }
126   // We use default allocation/deallocation but counted
127   static void* allocate_node(size_t size, Value const& value) {
128     StringTable::item_added();
129     return AllocateHeap(size, mtSymbol);
130   }
131   static void free_node(void* memory, Value const& value) {
132     value.release(OopStorageSet::string_table_weak());
133     FreeHeap(memory);
134     StringTable::item_removed();
135   }
136 };
137 
138 class StringTableLookupJchar : StackObj {
139  private:
140   Thread* _thread;
141   uintx _hash;
142   int _len;
143   const jchar* _str;
144   Handle _found;
145 
146  public:
147   StringTableLookupJchar(Thread* thread, uintx hash, const jchar* key, int len)
148     : _thread(thread), _hash(hash), _len(len), _str(key) {
149   }
150   uintx get_hash() const {
151     return _hash;
152   }
153   bool equals(WeakHandle* value, bool* is_dead) {
154     oop val_oop = value->peek();
155     if (val_oop == NULL) {
156       // dead oop, mark this hash dead for cleaning
157       *is_dead = true;
158       return false;
159     }
160     bool equals = java_lang_String::equals(val_oop, _str, _len);
161     if (!equals) {
162       return false;
163     }
164     // Need to resolve weak handle and Handleize through possible safepoint.
165      _found = Handle(_thread, value->resolve());
166     return true;
167   }
168 };
169 
170 class StringTableLookupOop : public StackObj {
171  private:
172   Thread* _thread;
173   uintx _hash;
174   Handle _find;
175   Handle _found;  // Might be a different oop with the same value that's already
176                   // in the table, which is the point.
177  public:
178   StringTableLookupOop(Thread* thread, uintx hash, Handle handle)
179     : _thread(thread), _hash(hash), _find(handle) { }
180 
181   uintx get_hash() const {
182     return _hash;
183   }
184 
185   bool equals(WeakHandle* value, bool* is_dead) {
186     oop val_oop = value->peek();
187     if (val_oop == NULL) {
188       // dead oop, mark this hash dead for cleaning
189       *is_dead = true;
190       return false;
191     }
192     bool equals = java_lang_String::equals(_find(), val_oop);
193     if (!equals) {
194       return false;
195     }
196     // Need to resolve weak handle and Handleize through possible safepoint.
197     _found = Handle(_thread, value->resolve());
198     return true;
199   }
200 };
201 
202 static size_t ceil_log2(size_t val) {
203   size_t ret;
204   for (ret = 1; ((size_t)1 << ret) < val; ++ret);
205   return ret;
206 }
207 
208 void StringTable::create_table() {
209   size_t start_size_log_2 = ceil_log2(StringTableSize);
210   _current_size = ((size_t)1) << start_size_log_2;
211   log_trace(stringtable)("Start size: " SIZE_FORMAT " (" SIZE_FORMAT ")",
212                          _current_size, start_size_log_2);
213   _local_table = new StringTableHash(start_size_log_2, END_SIZE, REHASH_LEN);
214 }
215 
216 size_t StringTable::item_added() {
217   return Atomic::add(&_items_count, (size_t)1);
218 }
219 
220 void StringTable::item_removed() {
221   Atomic::add(&_items_count, (size_t)-1);
222 }
223 
224 double StringTable::get_load_factor() {
225   return double(_items_count)/double(_current_size);
226 }
227 
228 double StringTable::get_dead_factor() {
229   return double(_uncleaned_items_count)/double(_current_size);
230 }
231 
232 size_t StringTable::table_size() {
233   return ((size_t)1) << _local_table->get_size_log2(Thread::current());
234 }
235 
236 void StringTable::trigger_concurrent_work() {
237   MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
238   _has_work = true;
239   Service_lock->notify_all();
240 }
241 
242 // Probing
243 oop StringTable::lookup(Symbol* symbol) {
244   ResourceMark rm;
245   int length;
246   jchar* chars = symbol->as_unicode(length);
247   return lookup(chars, length);
248 }
249 
250 oop StringTable::lookup(const jchar* name, int len) {
251   unsigned int hash = java_lang_String::hash_code(name, len);
252   oop string = lookup_shared(name, len, hash);
253   if (string != NULL) {
254     return string;
255   }
256   if (_alt_hash) {
257     hash = hash_string(name, len, true);
258   }
259   return do_lookup(name, len, hash);
260 }
261 
262 class StringTableGet : public StackObj {
263   Thread* _thread;
264   Handle  _return;
265  public:
266   StringTableGet(Thread* thread) : _thread(thread) {}
267   void operator()(WeakHandle* val) {
268     oop result = val->resolve();
269     assert(result != NULL, "Result should be reachable");
270     _return = Handle(_thread, result);
271   }
272   oop get_res_oop() {
273     return _return();
274   }
275 };
276 
277 oop StringTable::do_lookup(const jchar* name, int len, uintx hash) {
278   Thread* thread = Thread::current();
279   StringTableLookupJchar lookup(thread, hash, name, len);
280   StringTableGet stg(thread);
281   bool rehash_warning;
282   _local_table->get(thread, lookup, stg, &rehash_warning);
283   update_needs_rehash(rehash_warning);
284   return stg.get_res_oop();
285 }
286 
287 // Interning
288 oop StringTable::intern(Symbol* symbol, TRAPS) {
289   if (symbol == NULL) return NULL;
290   ResourceMark rm(THREAD);
291   int length;
292   jchar* chars = symbol->as_unicode(length);
293   Handle string;
294   oop result = intern(string, chars, length, CHECK_NULL);
295   return result;
296 }
297 
298 oop StringTable::intern(oop string, TRAPS) {
299   if (string == NULL) return NULL;
300   ResourceMark rm(THREAD);
301   int length;
302   Handle h_string (THREAD, string);
303   jchar* chars = java_lang_String::as_unicode_string(string, length,
304                                                      CHECK_NULL);
305   oop result = intern(h_string, chars, length, CHECK_NULL);
306   return result;
307 }
308 
309 oop StringTable::intern(const char* utf8_string, TRAPS) {
310   if (utf8_string == NULL) return NULL;
311   ResourceMark rm(THREAD);
312   int length = UTF8::unicode_length(utf8_string);
313   jchar* chars = NEW_RESOURCE_ARRAY(jchar, length);
314   UTF8::convert_to_unicode(utf8_string, chars, length);
315   Handle string;
316   oop result = intern(string, chars, length, CHECK_NULL);
317   return result;
318 }
319 
320 oop StringTable::intern(Handle string_or_null_h, const jchar* name, int len, TRAPS) {
321   // shared table always uses java_lang_String::hash_code
322   unsigned int hash = java_lang_String::hash_code(name, len);
323   oop found_string = lookup_shared(name, len, hash);
324   if (found_string != NULL) {
325     return found_string;
326   }
327   if (_alt_hash) {
328     hash = hash_string(name, len, true);
329   }
330   found_string = do_lookup(name, len, hash);
331   if (found_string != NULL) {
332     return found_string;
333   }
334   return do_intern(string_or_null_h, name, len, hash, THREAD);
335 }
336 
337 oop StringTable::do_intern(Handle string_or_null_h, const jchar* name,
338                            int len, uintx hash, TRAPS) {
339   HandleMark hm(THREAD);  // cleanup strings created
340   Handle string_h;
341 
342   if (!string_or_null_h.is_null()) {
343     string_h = string_or_null_h;
344   } else {
345     string_h = java_lang_String::create_from_unicode(name, len, CHECK_NULL);
346   }
347 
348   // Deduplicate the string before it is interned. Note that we should never
349   // deduplicate a string after it has been interned. Doing so will counteract
350   // compiler optimizations done on e.g. interned string literals.
351   Universe::heap()->deduplicate_string(string_h());
352 
353   assert(java_lang_String::equals(string_h(), name, len),
354          "string must be properly initialized");
355   assert(len == java_lang_String::length(string_h()), "Must be same length");
356 
357   StringTableLookupOop lookup(THREAD, hash, string_h);
358   StringTableGet stg(THREAD);
359 
360   bool rehash_warning;
361   do {
362     // Callers have already looked up the String using the jchar* name, so just go to add.
363     WeakHandle wh(OopStorageSet::string_table_weak(), string_h);
364     // The hash table takes ownership of the WeakHandle, even if it's not inserted.
365     if (_local_table->insert(THREAD, lookup, wh, &rehash_warning)) {
366       update_needs_rehash(rehash_warning);
367       return wh.resolve();
368     }
369     // In case another thread did a concurrent add, return value already in the table.
370     // This could fail if the String got gc'ed concurrently, so loop back until success.
371     if (_local_table->get(THREAD, lookup, stg, &rehash_warning)) {
372       update_needs_rehash(rehash_warning);
373       return stg.get_res_oop();
374     }
375   } while(true);
376 }
377 
378 // Concurrent work
379 void StringTable::grow(JavaThread* jt) {
380   StringTableHash::GrowTask gt(_local_table);
381   if (!gt.prepare(jt)) {
382     return;
383   }
384   log_trace(stringtable)("Started to grow");
385   {
386     TraceTime timer("Grow", TRACETIME_LOG(Debug, stringtable, perf));
387     while (gt.do_task(jt)) {
388       gt.pause(jt);
389       {
390         ThreadBlockInVM tbivm(jt);
391       }
392       gt.cont(jt);
393     }
394   }
395   gt.done(jt);
396   _current_size = table_size();
397   log_debug(stringtable)("Grown to size:" SIZE_FORMAT, _current_size);
398 }
399 
400 struct StringTableDoDelete : StackObj {
401   void operator()(WeakHandle* val) {
402     /* do nothing */
403   }
404 };
405 
406 struct StringTableDeleteCheck : StackObj {
407   long _count;
408   long _item;
409   StringTableDeleteCheck() : _count(0), _item(0) {}
410   bool operator()(WeakHandle* val) {
411     ++_item;
412     oop tmp = val->peek();
413     if (tmp == NULL) {
414       ++_count;
415       return true;
416     } else {
417       return false;
418     }
419   }
420 };
421 
422 void StringTable::clean_dead_entries(JavaThread* jt) {
423   StringTableHash::BulkDeleteTask bdt(_local_table);
424   if (!bdt.prepare(jt)) {
425     return;
426   }
427 
428   StringTableDeleteCheck stdc;
429   StringTableDoDelete stdd;
430   {
431     TraceTime timer("Clean", TRACETIME_LOG(Debug, stringtable, perf));
432     while(bdt.do_task(jt, stdc, stdd)) {
433       bdt.pause(jt);
434       {
435         ThreadBlockInVM tbivm(jt);
436       }
437       bdt.cont(jt);
438     }
439     bdt.done(jt);
440   }
441   log_debug(stringtable)("Cleaned %ld of %ld", stdc._count, stdc._item);
442 }
443 
444 void StringTable::gc_notification(size_t dead_count) {
445   _uncleaned_items_count += dead_count;
446 
447   if (_has_work) {
448     return;
449   }
450 
451   double load_factor = StringTable::get_load_factor();
452   double dead_factor = StringTable::get_dead_factor();
453   // We should clean/resize if we have more dead than alive,
454   // more items than preferred load factor or
455   // more dead items than water mark.
456   if ((dead_factor > load_factor) ||
457       (load_factor > PREF_AVG_LIST_LEN) ||
458       (dead_factor > CLEAN_DEAD_HIGH_WATER_MARK)) {
459     log_debug(stringtable)("Concurrent work triggered, live factor: %g dead factor: %g",
460                            load_factor, dead_factor);
461     _uncleaned_items_count = 0;
462     trigger_concurrent_work();
463   }
464 }
465 
466 void StringTable::do_concurrent_work(JavaThread* jt) {
467   _has_work = false;
468   double load_factor = get_load_factor();
469   log_debug(stringtable, perf)("Concurrent work, live factor: %g", load_factor);
470   // We prefer growing, since that also removes dead items
471   if (load_factor > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached()) {
472     grow(jt);
473   } else {
474     clean_dead_entries(jt);
475   }
476 }
477 
478 // Rehash
479 bool StringTable::do_rehash() {
480   if (!_local_table->is_safepoint_safe()) {
481     return false;
482   }
483 
484   // We use current size, not max size.
485   size_t new_size = _local_table->get_size_log2(Thread::current());
486   StringTableHash* new_table = new StringTableHash(new_size, END_SIZE, REHASH_LEN);
487   // Use alt hash from now on
488   _alt_hash = true;
489   if (!_local_table->try_move_nodes_to(Thread::current(), new_table)) {
490     _alt_hash = false;
491     delete new_table;
492     return false;
493   }
494 
495   // free old table
496   delete _local_table;
497   _local_table = new_table;
498 
499   return true;
500 }
501 
502 void StringTable::rehash_table() {
503   static bool rehashed = false;
504   log_debug(stringtable)("Table imbalanced, rehashing called.");
505 
506   // Grow instead of rehash.
507   if (get_load_factor() > PREF_AVG_LIST_LEN &&
508       !_local_table->is_max_size_reached()) {
509     log_debug(stringtable)("Choosing growing over rehashing.");
510     trigger_concurrent_work();
511     _needs_rehashing = false;
512     return;
513   }
514   // Already rehashed.
515   if (rehashed) {
516     log_warning(stringtable)("Rehashing already done, still long lists.");
517     trigger_concurrent_work();
518     _needs_rehashing = false;
519     return;
520   }
521 
522   murmur_seed = AltHashing::compute_seed();
523   {
524     if (do_rehash()) {
525       rehashed = true;
526     } else {
527       log_info(stringtable)("Resizes in progress rehashing skipped.");
528     }
529   }
530   _needs_rehashing = false;
531 }
532 
533 // Statistics
534 static int literal_size(oop obj) {
535   // NOTE: this would over-count if (pre-JDK8)
536   // java_lang_Class::has_offset_field() is true and the String.value array is
537   // shared by several Strings. However, starting from JDK8, the String.value
538   // array is not shared anymore.
539   if (obj == NULL) {
540     return 0;
541   } else if (obj->klass() == SystemDictionary::String_klass()) {
542     return (obj->size() + java_lang_String::value(obj)->size()) * HeapWordSize;
543   } else {
544     return obj->size();
545   }
546 }
547 
548 struct SizeFunc : StackObj {
549   size_t operator()(WeakHandle* val) {
550     oop s = val->peek();
551     if (s == NULL) {
552       // Dead
553       return 0;
554     }
555     return literal_size(s);
556   };
557 };
558 
559 TableStatistics StringTable::get_table_statistics() {
560   static TableStatistics ts;
561   SizeFunc sz;
562   ts = _local_table->statistics_get(Thread::current(), sz, ts);
563   return ts;
564 }
565 
566 void StringTable::print_table_statistics(outputStream* st,
567                                          const char* table_name) {
568   SizeFunc sz;
569   _local_table->statistics_to(Thread::current(), sz, st, table_name);
570 }
571 
572 // Verification
573 class VerifyStrings : StackObj {
574  public:
575   bool operator()(WeakHandle* val) {
576     oop s = val->peek();
577     if (s != NULL) {
578       assert(java_lang_String::length(s) >= 0, "Length on string must work.");
579     }
580     return true;
581   };
582 };
583 
584 // This verification is part of Universe::verify() and needs to be quick.
585 void StringTable::verify() {
586   Thread* thr = Thread::current();
587   VerifyStrings vs;
588   if (!_local_table->try_scan(thr, vs)) {
589     log_info(stringtable)("verify unavailable at this moment");
590   }
591 }
592 
593 // Verification and comp
594 class VerifyCompStrings : StackObj {
595   GrowableArray<oop>* _oops;
596  public:
597   size_t _errors;
598   VerifyCompStrings(GrowableArray<oop>* oops) : _oops(oops), _errors(0) {}
599   bool operator()(WeakHandle* val) {
600     oop s = val->resolve();
601     if (s == NULL) {
602       return true;
603     }
604     int len = _oops->length();
605     for (int i = 0; i < len; i++) {
606       bool eq = java_lang_String::equals(s, _oops->at(i));
607       assert(!eq, "Duplicate strings");
608       if (eq) {
609         _errors++;
610       }
611     }
612     _oops->push(s);
613     return true;
614   };
615 };
616 
617 size_t StringTable::verify_and_compare_entries() {
618   Thread* thr = Thread::current();
619   GrowableArray<oop>* oops =
620     new (ResourceObj::C_HEAP, mtInternal)
621       GrowableArray<oop>((int)_current_size, mtInternal);
622 
623   VerifyCompStrings vcs(oops);
624   if (!_local_table->try_scan(thr, vcs)) {
625     log_info(stringtable)("verify unavailable at this moment");
626   }
627   delete oops;
628   return vcs._errors;
629 }
630 
631 // Dumping
632 class PrintString : StackObj {
633   Thread* _thr;
634   outputStream* _st;
635  public:
636   PrintString(Thread* thr, outputStream* st) : _thr(thr), _st(st) {}
637   bool operator()(WeakHandle* val) {
638     oop s = val->peek();
639     if (s == NULL) {
640       return true;
641     }
642     typeArrayOop value     = java_lang_String::value_no_keepalive(s);
643     int          length    = java_lang_String::length(s);
644     bool         is_latin1 = java_lang_String::is_latin1(s);
645 
646     if (length <= 0) {
647       _st->print("%d: ", length);
648     } else {
649       ResourceMark rm(_thr);
650       int utf8_length = length;
651       char* utf8_string;
652 
653       if (!is_latin1) {
654         jchar* chars = value->char_at_addr(0);
655         utf8_string = UNICODE::as_utf8(chars, utf8_length);
656       } else {
657         jbyte* bytes = value->byte_at_addr(0);
658         utf8_string = UNICODE::as_utf8(bytes, utf8_length);
659       }
660 
661       _st->print("%d: ", utf8_length);
662       HashtableTextDump::put_utf8(_st, utf8_string, utf8_length);
663     }
664     _st->cr();
665     return true;
666   };
667 };
668 
669 void StringTable::dump(outputStream* st, bool verbose) {
670   if (!verbose) {
671     print_table_statistics(st, "StringTable");
672   } else {
673     Thread* thr = Thread::current();
674     ResourceMark rm(thr);
675     st->print_cr("VERSION: 1.1");
676     PrintString ps(thr, st);
677     if (!_local_table->try_scan(thr, ps)) {
678       st->print_cr("dump unavailable at this moment");
679     }
680   }
681 }
682 
683 // Utility for dumping strings
684 StringtableDCmd::StringtableDCmd(outputStream* output, bool heap) :
685                                  DCmdWithParser(output, heap),
686   _verbose("-verbose", "Dump the content of each string in the table",
687            "BOOLEAN", false, "false") {
688   _dcmdparser.add_dcmd_option(&_verbose);
689 }
690 
691 void StringtableDCmd::execute(DCmdSource source, TRAPS) {
692   VM_DumpHashtable dumper(output(), VM_DumpHashtable::DumpStrings,
693                          _verbose.value());
694   VMThread::execute(&dumper);
695 }
696 
697 int StringtableDCmd::num_arguments() {
698   ResourceMark rm;
699   StringtableDCmd* dcmd = new StringtableDCmd(NULL, false);
700   if (dcmd != NULL) {
701     DCmdMark mark(dcmd);
702     return dcmd->_dcmdparser.num_arguments();
703   } else {
704     return 0;
705   }
706 }
707 
708 // Sharing
709 #if INCLUDE_CDS_JAVA_HEAP
710 oop StringTable::lookup_shared(const jchar* name, int len, unsigned int hash) {
711   assert(hash == java_lang_String::hash_code(name, len),
712          "hash must be computed using java_lang_String::hash_code");
713   return _shared_table.lookup(name, hash, len);
714 }
715 
716 oop StringTable::create_archived_string(oop s, Thread* THREAD) {
717   assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
718 
719   if (HeapShared::is_archived_object(s)) {
720     return s;
721   }
722 
723   oop new_s = NULL;
724   typeArrayOop v = java_lang_String::value_no_keepalive(s);
725   typeArrayOop new_v = (typeArrayOop)HeapShared::archive_heap_object(v, THREAD);
726   if (new_v == NULL) {
727     return NULL;
728   }
729   new_s = HeapShared::archive_heap_object(s, THREAD);
730   if (new_s == NULL) {
731     return NULL;
732   }
733 
734   // adjust the pointer to the 'value' field in the new String oop
735   java_lang_String::set_value_raw(new_s, new_v);
736   return new_s;
737 }
738 
739 struct CopyToArchive : StackObj {
740   CompactHashtableWriter* _writer;
741   CopyToArchive(CompactHashtableWriter* writer) : _writer(writer) {}
742   bool operator()(WeakHandle* val) {
743     oop s = val->peek();
744     if (s == NULL) {
745       return true;
746     }
747     unsigned int hash = java_lang_String::hash_code(s);
748     oop new_s = StringTable::create_archived_string(s, Thread::current());
749     if (new_s == NULL) {
750       return true;
751     }
752 
753     val->replace(new_s);
754     // add to the compact table
755     _writer->add(hash, CompressedOops::encode(new_s));
756     return true;
757   }
758 };
759 
760 void StringTable::copy_shared_string_table(CompactHashtableWriter* writer) {
761   assert(HeapShared::is_heap_object_archiving_allowed(), "must be");
762 
763   CopyToArchive copy(writer);
764   _local_table->do_safepoint_scan(copy);
765 }
766 
767 void StringTable::write_to_archive() {
768   assert(HeapShared::is_heap_object_archiving_allowed(), "must be");
769 
770   _shared_table.reset();
771   CompactHashtableWriter writer(_items_count, &MetaspaceShared::stats()->string);
772 
773   // Copy the interned strings into the "string space" within the java heap
774   copy_shared_string_table(&writer);
775   writer.dump(&_shared_table, "string");
776 }
777 
778 void StringTable::serialize_shared_table_header(SerializeClosure* soc) {
779   _shared_table.serialize_header(soc);
780 
781   if (soc->writing()) {
782     // Sanity. Make sure we don't use the shared table at dump time
783     _shared_table.reset();
784   } else if (!HeapShared::closed_archive_heap_region_mapped()) {
785     _shared_table.reset();
786   }
787 }
788 
789 class SharedStringIterator {
790   OopClosure* _oop_closure;
791 public:
792   SharedStringIterator(OopClosure* f) : _oop_closure(f) {}
793   void do_value(oop string) {
794     _oop_closure->do_oop(&string);
795   }
796 };
797 
798 void StringTable::shared_oops_do(OopClosure* f) {
799   SharedStringIterator iter(f);
800   _shared_table.iterate(&iter);
801 }
802 #endif //INCLUDE_CDS_JAVA_HEAP