8210875: Refactor CompactHashtable
authoriklam
Tue, 18 Sep 2018 21:47:14 -0700
changeset 51823 2a51125b2794
parent 51822 f3c1945fa8aa
child 51824 9777d724ace8
8210875: Refactor CompactHashtable Reviewed-by: ccheung, jiangli
src/hotspot/share/classfile/compactHashtable.cpp
src/hotspot/share/classfile/compactHashtable.hpp
src/hotspot/share/classfile/compactHashtable.inline.hpp
src/hotspot/share/classfile/javaClasses.cpp
src/hotspot/share/classfile/javaClasses.hpp
src/hotspot/share/classfile/stringTable.cpp
src/hotspot/share/classfile/stringTable.hpp
src/hotspot/share/classfile/symbolTable.cpp
src/hotspot/share/classfile/symbolTable.hpp
src/hotspot/share/classfile/systemDictionaryShared.cpp
src/hotspot/share/memory/filemap.cpp
src/hotspot/share/services/diagnosticCommand.cpp
src/hotspot/share/utilities/utf8.cpp
src/hotspot/share/utilities/utf8.hpp
--- a/src/hotspot/share/classfile/compactHashtable.cpp	Thu Sep 20 18:39:53 2018 +0200
+++ b/src/hotspot/share/classfile/compactHashtable.cpp	Tue Sep 18 21:47:14 2018 -0700
@@ -24,7 +24,7 @@
 
 #include "precompiled.hpp"
 #include "jvm.h"
-#include "classfile/compactHashtable.inline.hpp"
+#include "classfile/compactHashtable.hpp"
 #include "classfile/javaClasses.hpp"
 #include "logging/logMessage.hpp"
 #include "memory/heapShared.inline.hpp"
@@ -35,6 +35,7 @@
 #include "utilities/numberSeq.hpp"
 #include <sys/stat.h>
 
+#if INCLUDE_CDS
 /////////////////////////////////////////////////////
 //
 // The compact hash table writer implementations
@@ -170,33 +171,6 @@
 
 /////////////////////////////////////////////////////////////
 //
-// Customization for dumping Symbol and String tables
-
-void CompactSymbolTableWriter::add(unsigned int hash, Symbol *symbol) {
-  uintx deltax = MetaspaceShared::object_delta(symbol);
-  // When the symbols are stored into the archive, we already check that
-  // they won't be more than MAX_SHARED_DELTA from the base address, or
-  // else the dumping would have been aborted.
-  assert(deltax <= MAX_SHARED_DELTA, "must not be");
-  u4 delta = u4(deltax);
-
-  CompactHashtableWriter::add(hash, delta);
-}
-
-void CompactStringTableWriter::add(unsigned int hash, oop string) {
-  CompactHashtableWriter::add(hash, CompressedOops::encode(string));
-}
-
-void CompactSymbolTableWriter::dump(CompactHashtable<Symbol*, char> *cht) {
-  CompactHashtableWriter::dump(cht, "symbol");
-}
-
-void CompactStringTableWriter::dump(CompactHashtable<oop, char> *cht) {
-  CompactHashtableWriter::dump(cht, "string");
-}
-
-/////////////////////////////////////////////////////////////
-//
 // The CompactHashtable implementation
 //
 
@@ -207,95 +181,7 @@
   soc->do_ptr((void**)&_buckets);
   soc->do_ptr((void**)&_entries);
 }
-
-bool SimpleCompactHashtable::exists(u4 value) {
-  assert(!DumpSharedSpaces, "run-time only");
-
-  if (_entry_count == 0) {
-    return false;
-  }
-
-  unsigned int hash = (unsigned int)value;
-  int index = hash % _bucket_count;
-  u4 bucket_info = _buckets[index];
-  u4 bucket_offset = BUCKET_OFFSET(bucket_info);
-  int bucket_type = BUCKET_TYPE(bucket_info);
-  u4* entry = _entries + bucket_offset;
-
-  if (bucket_type == VALUE_ONLY_BUCKET_TYPE) {
-    return (entry[0] == value);
-  } else {
-    u4*entry_max = _entries + BUCKET_OFFSET(_buckets[index + 1]);
-    while (entry <entry_max) {
-      if (entry[1] == value) {
-        return true;
-      }
-      entry += 2;
-    }
-    return false;
-  }
-}
-
-template <class I>
-inline void SimpleCompactHashtable::iterate(const I& iterator) {
-  for (u4 i = 0; i < _bucket_count; i++) {
-    u4 bucket_info = _buckets[i];
-    u4 bucket_offset = BUCKET_OFFSET(bucket_info);
-    int bucket_type = BUCKET_TYPE(bucket_info);
-    u4* entry = _entries + bucket_offset;
-
-    if (bucket_type == VALUE_ONLY_BUCKET_TYPE) {
-      iterator.do_value(_base_address, entry[0]);
-    } else {
-      u4*entry_max = _entries + BUCKET_OFFSET(_buckets[i + 1]);
-      while (entry < entry_max) {
-        iterator.do_value(_base_address, entry[1]);
-        entry += 2;
-      }
-    }
-  }
-}
-
-template <class T, class N> void CompactHashtable<T, N>::serialize(SerializeClosure* soc) {
-  SimpleCompactHashtable::serialize(soc);
-  soc->do_u4(&_type);
-}
-
-class CompactHashtable_SymbolIterator {
-  SymbolClosure* const _closure;
-public:
-  CompactHashtable_SymbolIterator(SymbolClosure *cl) : _closure(cl) {}
-  inline void do_value(address base_address, u4 offset) const {
-    Symbol* sym = (Symbol*)((void*)(base_address + offset));
-    _closure->do_symbol(&sym);
-  }
-};
-
-template <class T, class N> void CompactHashtable<T, N>::symbols_do(SymbolClosure *cl) {
-  CompactHashtable_SymbolIterator iterator(cl);
-  iterate(iterator);
-}
-
-class CompactHashtable_OopIterator {
-  OopClosure* const _closure;
-public:
-  CompactHashtable_OopIterator(OopClosure *cl) : _closure(cl) {}
-  inline void do_value(address base_address, u4 offset) const {
-    narrowOop v = (narrowOop)offset;
-    oop obj = HeapShared::decode_from_archive(v);
-    _closure->do_oop(&obj);
-  }
-};
-
-template <class T, class N> void CompactHashtable<T, N>::oops_do(OopClosure* cl) {
-  assert(_type == _string_table || _bucket_count == 0, "sanity");
-  CompactHashtable_OopIterator iterator(cl);
-  iterate(iterator);
-}
-
-// Explicitly instantiate these types
-template class CompactHashtable<Symbol*, char>;
-template class CompactHashtable<oop, char>;
+#endif // INCLUDE_CDS
 
 #ifndef O_BINARY       // if defined (Win32) use binary files.
 #define O_BINARY 0     // otherwise do nothing.
--- a/src/hotspot/share/classfile/compactHashtable.hpp	Thu Sep 20 18:39:53 2018 +0200
+++ b/src/hotspot/share/classfile/compactHashtable.hpp	Tue Sep 18 21:47:14 2018 -0700
@@ -29,7 +29,14 @@
 #include "oops/symbol.hpp"
 #include "utilities/hashtable.hpp"
 
-template <class T, class N> class CompactHashtable;
+
+template <
+  typename K,
+  typename V,
+  V (*DECODE)(address base_address, u4 offset),
+  bool (*EQUALS)(V value, K key, int len)
+  >
+class CompactHashtable;
 class NumberSeq;
 class SimpleCompactHashtable;
 class SerializeClosure;
@@ -43,6 +50,7 @@
   int bucket_bytes;
 };
 
+#if INCLUDE_CDS
 /////////////////////////////////////////////////////////////////////////
 //
 // The compact hash table writer. Used at dump time for writing out
@@ -108,9 +116,6 @@
   ~CompactHashtableWriter();
 
   void add(unsigned int hash, u4 value);
-  void add(u4 value) {
-    add((unsigned int)value, value);
-  }
 
 private:
   void allocate_table();
@@ -118,24 +123,8 @@
 
 public:
   void dump(SimpleCompactHashtable *cht, const char* table_name);
-  const char* table_name();
 };
-
-class CompactSymbolTableWriter: public CompactHashtableWriter {
-public:
-  CompactSymbolTableWriter(int num_buckets, CompactHashtableStats* stats) :
-    CompactHashtableWriter(num_buckets, stats) {}
-  void add(unsigned int hash, Symbol *symbol);
-  void dump(CompactHashtable<Symbol*, char> *cht);
-};
-
-class CompactStringTableWriter: public CompactHashtableWriter {
-public:
-  CompactStringTableWriter(int num_entries, CompactHashtableStats* stats) :
-    CompactHashtableWriter(num_entries, stats) {}
-  void add(unsigned int hash, oop string);
-  void dump(CompactHashtable<oop, char> *cht);
-};
+#endif // INCLUDE_CDS
 
 #define REGULAR_BUCKET_TYPE       0
 #define VALUE_ONLY_BUCKET_TYPE    1
@@ -148,8 +137,7 @@
 
 /////////////////////////////////////////////////////////////////////////////
 //
-// CompactHashtable is used to stored the CDS archive's symbol/string table. Used
-// at runtime only to access the compact table from the archive.
+// CompactHashtable is used to store the CDS archive's symbol/string tables.
 //
 // Because these tables are read-only (no entries can be added/deleted) at run-time
 // and tend to have large number of entries, we try to minimize the footprint
@@ -225,56 +213,82 @@
     _entries = entries;
   }
 
-  template <class I> inline void iterate(const I& iterator);
-
-  bool exists(u4 value);
-
   // For reading from/writing to the CDS archive
-  void serialize(SerializeClosure* soc);
+  void serialize(SerializeClosure* soc) NOT_CDS_RETURN;
 
   inline bool empty() {
     return (_entry_count == 0);
   }
 };
 
-template <class T, class N> class CompactHashtable : public SimpleCompactHashtable {
+template <
+  typename K,
+  typename V,
+  V (*DECODE)(address base_address, u4 offset),
+  bool (*EQUALS)(V value, K key, int len)
+  >
+class CompactHashtable : public SimpleCompactHashtable {
   friend class VMStructs;
 
-public:
-  enum CompactHashtableType {
-    _symbol_table = 0,
-    _string_table = 1
-  };
+  V decode(u4 offset) const {
+    return DECODE(_base_address, offset);
+  }
 
-private:
-  u4 _type;
-
-  inline Symbol* decode_entry(CompactHashtable<Symbol*, char>* const t,
-                              u4 offset, const char* name, int len);
-
-  inline oop decode_entry(CompactHashtable<oop, char>* const t,
-                          u4 offset, const char* name, int len);
 public:
   CompactHashtable() : SimpleCompactHashtable() {}
 
-  void set_type(CompactHashtableType type) {
-    _type = (u4)type;
+  // Lookup a value V from the compact table using key K
+  inline V lookup(K key, unsigned int hash, int len) const {
+    if (_entry_count > 0) {
+      int index = hash % _bucket_count;
+      u4 bucket_info = _buckets[index];
+      u4 bucket_offset = BUCKET_OFFSET(bucket_info);
+      int bucket_type = BUCKET_TYPE(bucket_info);
+      u4* entry = _entries + bucket_offset;
+
+      if (bucket_type == VALUE_ONLY_BUCKET_TYPE) {
+        V value = decode(entry[0]);
+        if (EQUALS(value, key, len)) {
+          return value;
+        }
+      } else {
+        // This is a regular bucket, which has more than one
+        // entries. Each entry is a pair of entry (hash, offset).
+        // Seek until the end of the bucket.
+        u4* entry_max = _entries + BUCKET_OFFSET(_buckets[index + 1]);
+        while (entry < entry_max) {
+          unsigned int h = (unsigned int)(entry[0]);
+          if (h == hash) {
+            V value = decode(entry[1]);
+            if (EQUALS(value, key, len)) {
+              return value;
+            }
+          }
+          entry += 2;
+        }
+      }
+    }
+    return NULL;
   }
 
-  // Lookup an entry from the compact table
-  inline T lookup(const N* name, unsigned int hash, int len);
-
-  // iterate over symbols
-  void symbols_do(SymbolClosure *cl);
+  template <class ITER>
+  inline void iterate(ITER* iter) const {
+    for (u4 i = 0; i < _bucket_count; i++) {
+      u4 bucket_info = _buckets[i];
+      u4 bucket_offset = BUCKET_OFFSET(bucket_info);
+      int bucket_type = BUCKET_TYPE(bucket_info);
+      u4* entry = _entries + bucket_offset;
 
-  // iterate over strings
-  void oops_do(OopClosure* f);
-
-  // For reading from/writing to the CDS archive
-  void serialize(SerializeClosure* soc);
-
-  uintx base_address() {
-    return (uintx) _base_address;
+      if (bucket_type == VALUE_ONLY_BUCKET_TYPE) {
+        iter->do_value(decode(entry[0]));
+      } else {
+        u4*entry_max = _entries + BUCKET_OFFSET(_buckets[i + 1]);
+        while (entry < entry_max) {
+          iter->do_value(decode(entry[1]));
+          entry += 2;
+        }
+      }
+    }
   }
 };
 
--- a/src/hotspot/share/classfile/compactHashtable.inline.hpp	Thu Sep 20 18:39:53 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef SHARE_VM_CLASSFILE_COMPACTHASHTABLE_INLINE_HPP
-#define SHARE_VM_CLASSFILE_COMPACTHASHTABLE_INLINE_HPP
-
-#include "classfile/compactHashtable.hpp"
-#include "classfile/javaClasses.hpp"
-#include "memory/allocation.inline.hpp"
-#include "memory/filemap.hpp"
-#include "memory/heapShared.inline.hpp"
-#include "oops/oop.hpp"
-
-template <class T, class N>
-inline Symbol* CompactHashtable<T, N>::decode_entry(CompactHashtable<Symbol*, char>* const t,
-                                                    u4 offset, const char* name, int len) {
-  Symbol* sym = (Symbol*)(_base_address + offset);
-  if (sym->equals(name, len)) {
-    assert(sym->refcount() == PERM_REFCOUNT, "must be shared");
-    return sym;
-  }
-
-  return NULL;
-}
-
-template <class T, class N>
-inline oop CompactHashtable<T, N>::decode_entry(CompactHashtable<oop, char>* const t,
-                                                u4 offset, const char* name, int len) {
-  narrowOop v = (narrowOop)offset;
-  oop string = HeapShared::decode_from_archive(v);
-  if (java_lang_String::equals(string, (jchar*)name, len)) {
-    return string;
-  }
-
-  return NULL;
-}
-
-template <class T, class N>
-inline T CompactHashtable<T,N>::lookup(const N* name, unsigned int hash, int len) {
-  if (_entry_count > 0) {
-    int index = hash % _bucket_count;
-    u4 bucket_info = _buckets[index];
-    u4 bucket_offset = BUCKET_OFFSET(bucket_info);
-    int bucket_type = BUCKET_TYPE(bucket_info);
-    u4* entry = _entries + bucket_offset;
-
-    if (bucket_type == VALUE_ONLY_BUCKET_TYPE) {
-      T res = decode_entry(this, entry[0], name, len);
-      if (res != NULL) {
-        return res;
-      }
-    } else {
-      // This is a regular bucket, which has more than one
-      // entries. Each entry is a pair of entry (hash, offset).
-      // Seek until the end of the bucket.
-      u4* entry_max = _entries + BUCKET_OFFSET(_buckets[index + 1]);
-      while (entry < entry_max) {
-        unsigned int h = (unsigned int)(entry[0]);
-        if (h == hash) {
-          T res = decode_entry(this, entry[1], name, len);
-          if (res != NULL) {
-            return res;
-          }
-        }
-        entry += 2;
-      }
-    }
-  }
-  return NULL;
-}
-
-#endif // SHARE_VM_CLASSFILE_COMPACTHASHTABLE_INLINE_HPP
--- a/src/hotspot/share/classfile/javaClasses.cpp	Thu Sep 20 18:39:53 2018 +0200
+++ b/src/hotspot/share/classfile/javaClasses.cpp	Tue Sep 18 21:47:14 2018 -0700
@@ -241,7 +241,7 @@
   return h_obj;
 }
 
-Handle java_lang_String::create_from_unicode(jchar* unicode, int length, TRAPS) {
+Handle java_lang_String::create_from_unicode(const jchar* unicode, int length, TRAPS) {
   bool is_latin1 = CompactStrings && UNICODE::is_latin1(unicode, length);
   Handle h_obj = basic_create(length, is_latin1, CHECK_NH);
   typeArrayOop buffer = value(h_obj());
@@ -271,7 +271,7 @@
   return h_obj;
 }
 
-oop java_lang_String::create_oop_from_unicode(jchar* unicode, int length, TRAPS) {
+oop java_lang_String::create_oop_from_unicode(const jchar* unicode, int length, TRAPS) {
   Handle h_obj = create_from_unicode(unicode, length, CHECK_0);
   return h_obj();
 }
@@ -643,7 +643,7 @@
   }
 }
 
-bool java_lang_String::equals(oop java_string, jchar* chars, int len) {
+bool java_lang_String::equals(oop java_string, const jchar* chars, int len) {
   assert(java_string->klass() == SystemDictionary::String_klass(),
          "must be java_string");
   typeArrayOop value = java_lang_String::value_no_keepalive(java_string);
@@ -2569,7 +2569,7 @@
   // Fill in class name
   ResourceMark rm(THREAD);
   const char* str = holder->external_name();
-  oop classname = StringTable::intern((char*) str, CHECK);
+  oop classname = StringTable::intern(str, CHECK);
   java_lang_StackTraceElement::set_declaringClass(element(), classname);
   java_lang_StackTraceElement::set_declaringClassObject(element(), holder->java_mirror());
 
--- a/src/hotspot/share/classfile/javaClasses.hpp	Thu Sep 20 18:39:53 2018 +0200
+++ b/src/hotspot/share/classfile/javaClasses.hpp	Tue Sep 18 21:47:14 2018 -0700
@@ -114,8 +114,8 @@
   static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
 
   // Instance creation
-  static Handle create_from_unicode(jchar* unicode, int len, TRAPS);
-  static oop    create_oop_from_unicode(jchar* unicode, int len, TRAPS);
+  static Handle create_from_unicode(const jchar* unicode, int len, TRAPS);
+  static oop    create_oop_from_unicode(const jchar* unicode, int len, TRAPS);
   static Handle create_from_str(const char* utf8_str, TRAPS);
   static oop    create_oop_from_str(const char* utf8_str, TRAPS);
   static Handle create_from_symbol(Symbol* symbol, TRAPS);
@@ -189,7 +189,7 @@
 
   static unsigned int hash_code(oop java_string);
 
-  static bool equals(oop java_string, jchar* chars, int len);
+  static bool equals(oop java_string, const jchar* chars, int len);
   static bool equals(oop str1, oop str2);
 
   // Conversion between '.' and '/' formats
--- a/src/hotspot/share/classfile/stringTable.cpp	Thu Sep 20 18:39:53 2018 +0200
+++ b/src/hotspot/share/classfile/stringTable.cpp	Tue Sep 18 21:47:14 2018 -0700
@@ -24,7 +24,7 @@
 
 #include "precompiled.hpp"
 #include "classfile/altHashing.hpp"
-#include "classfile/compactHashtable.inline.hpp"
+#include "classfile/compactHashtable.hpp"
 #include "classfile/javaClasses.inline.hpp"
 #include "classfile/stringTable.hpp"
 #include "classfile/systemDictionary.hpp"
@@ -35,6 +35,7 @@
 #include "logging/logStream.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/filemap.hpp"
+#include "memory/heapShared.inline.hpp"
 #include "memory/metaspaceShared.inline.hpp"
 #include "memory/resourceArea.hpp"
 #include "memory/universe.hpp"
@@ -62,9 +63,22 @@
 // If we have as many dead items as 50% of the number of bucket
 #define CLEAN_DEAD_HIGH_WATER_MARK 0.5
 
+#if INCLUDE_CDS_JAVA_HEAP
+inline oop read_string_from_compact_hashtable(address base_address, u4 offset) {
+  assert(sizeof(narrowOop) == sizeof(offset), "must be");
+  narrowOop v = (narrowOop)offset;
+  return HeapShared::decode_from_archive(v);
+}
+
+static CompactHashtable<
+  const jchar*, oop,
+  read_string_from_compact_hashtable,
+  java_lang_String::equals
+> _shared_table;
+#endif
+
 // --------------------------------------------------------------------------
 StringTable* StringTable::_the_table = NULL;
-CompactHashtable<oop, char> StringTable::_shared_table;
 volatile bool StringTable::_shared_string_mapped = false;
 volatile bool StringTable::_alt_hash = false;
 
@@ -134,7 +148,7 @@
       *is_dead = true;
       return false;
     }
-    bool equals = java_lang_String::equals(val_oop, (jchar*)_str, _len);
+    bool equals = java_lang_String::equals(val_oop, _str, _len);
     if (!equals) {
       return false;
     }
@@ -236,7 +250,7 @@
   return lookup(chars, length);
 }
 
-oop StringTable::lookup(jchar* name, int len) {
+oop StringTable::lookup(const jchar* name, int len) {
   unsigned int hash = java_lang_String::hash_code(name, len);
   oop string = StringTable::the_table()->lookup_shared(name, len, hash);
   if (string != NULL) {
@@ -263,7 +277,7 @@
   }
 };
 
-oop StringTable::do_lookup(jchar* name, int len, uintx hash) {
+oop StringTable::do_lookup(const jchar* name, int len, uintx hash) {
   Thread* thread = Thread::current();
   StringTableLookupJchar lookup(thread, hash, name, len);
   StringTableGet stg(thread);
@@ -308,7 +322,7 @@
   return result;
 }
 
-oop StringTable::intern(Handle string_or_null_h, jchar* name, int len, TRAPS) {
+oop StringTable::intern(Handle string_or_null_h, const jchar* name, int len, TRAPS) {
   // shared table always uses java_lang_String::hash_code
   unsigned int hash = java_lang_String::hash_code(name, len);
   oop found_string = StringTable::the_table()->lookup_shared(name, len, hash);
@@ -346,7 +360,7 @@
   }
 };
 
-oop StringTable::do_intern(Handle string_or_null_h, jchar* name,
+oop StringTable::do_intern(Handle string_or_null_h, const jchar* name,
                            int len, uintx hash, TRAPS) {
   HandleMark hm(THREAD);  // cleanup strings created
   Handle string_h;
@@ -775,10 +789,10 @@
 
 // Sharing
 #if INCLUDE_CDS_JAVA_HEAP
-oop StringTable::lookup_shared(jchar* name, int len, unsigned int hash) {
+oop StringTable::lookup_shared(const jchar* name, int len, unsigned int hash) {
   assert(hash == java_lang_String::hash_code(name, len),
          "hash must be computed using java_lang_String::hash_code");
-  return _shared_table.lookup((const char*)name, hash, len);
+  return _shared_table.lookup(name, hash, len);
 }
 
 oop StringTable::create_archived_string(oop s, Thread* THREAD) {
@@ -805,6 +819,15 @@
   return new_s;
 }
 
+class CompactStringTableWriter: public CompactHashtableWriter {
+public:
+  CompactStringTableWriter(int num_entries, CompactHashtableStats* stats) :
+    CompactHashtableWriter(num_entries, stats) {}
+  void add(unsigned int hash, oop string) {
+    CompactHashtableWriter::add(hash, CompressedOops::encode(string));
+  }
+};
+
 struct CopyToArchive : StackObj {
   CompactStringTableWriter* _writer;
   CopyToArchive(CompactStringTableWriter* writer) : _writer(writer) {}
@@ -849,11 +872,10 @@
 
   // Copy the interned strings into the "string space" within the java heap
   copy_shared_string_table(&writer);
-  writer.dump(&_shared_table);
+  writer.dump(&_shared_table, "string");
 }
 
 void StringTable::serialize(SerializeClosure* soc) {
-  _shared_table.set_type(CompactHashtable<oop, char>::_string_table);
   _shared_table.serialize(soc);
 
   if (soc->writing()) {
@@ -864,7 +886,17 @@
   }
 }
 
+class SharedStringIterator {
+  OopClosure* _oop_closure;
+public:
+  SharedStringIterator(OopClosure* f) : _oop_closure(f) {}
+  void do_value(oop string) {
+    _oop_closure->do_oop(&string);
+  }
+};
+
 void StringTable::shared_oops_do(OopClosure* f) {
-  _shared_table.oops_do(f);
+  SharedStringIterator iter(f);
+  _shared_table.iterate(&iter);
 }
 #endif //INCLUDE_CDS_JAVA_HEAP
--- a/src/hotspot/share/classfile/stringTable.hpp	Thu Sep 20 18:39:53 2018 +0200
+++ b/src/hotspot/share/classfile/stringTable.hpp	Tue Sep 18 21:47:14 2018 -0700
@@ -33,7 +33,6 @@
 #include "oops/weakHandle.hpp"
 #include "utilities/concurrentHashTable.hpp"
 
-template <class T, class N> class CompactHashtable;
 class CompactStringTableWriter;
 class SerializeClosure;
 
@@ -56,8 +55,6 @@
 
   // The string table
   static StringTable* _the_table;
-  // Shared string table
-  static CompactHashtable<oop, char> _shared_table;
   static volatile bool _shared_string_mapped;
   static volatile bool _alt_hash;
 
@@ -88,9 +85,9 @@
 
   StringTable();
 
-  static oop intern(Handle string_or_null_h, jchar* name, int len, TRAPS);
-  oop do_intern(Handle string_or_null, jchar* name, int len, uintx hash, TRAPS);
-  oop do_lookup(jchar* name, int len, uintx hash);
+  static oop intern(Handle string_or_null_h, const jchar* name, int len, TRAPS);
+  oop do_intern(Handle string_or_null, const jchar* name, int len, uintx hash, TRAPS);
+  oop do_lookup(const jchar* name, int len, uintx hash);
 
   void concurrent_work(JavaThread* jt);
   void print_table_statistics(outputStream* st, const char* table_name);
@@ -151,7 +148,7 @@
 
   // Probing
   static oop lookup(Symbol* symbol);
-  static oop lookup(jchar* chars, int length);
+  static oop lookup(const jchar* chars, int length);
 
   // Interning
   static oop intern(Symbol* symbol, TRAPS);
@@ -165,7 +162,7 @@
 
   // Sharing
  private:
-  oop lookup_shared(jchar* name, int len, unsigned int hash) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
+  oop lookup_shared(const jchar* name, int len, unsigned int hash) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
   static void copy_shared_string_table(CompactStringTableWriter* ch_table) NOT_CDS_JAVA_HEAP_RETURN;
  public:
   static oop create_archived_string(oop s, Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
--- a/src/hotspot/share/classfile/symbolTable.cpp	Thu Sep 20 18:39:53 2018 +0200
+++ b/src/hotspot/share/classfile/symbolTable.cpp	Tue Sep 18 21:47:14 2018 -0700
@@ -24,11 +24,12 @@
 
 #include "precompiled.hpp"
 #include "classfile/altHashing.hpp"
-#include "classfile/compactHashtable.inline.hpp"
+#include "classfile/compactHashtable.hpp"
 #include "classfile/javaClasses.hpp"
 #include "classfile/symbolTable.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/metaspaceClosure.hpp"
+#include "memory/metaspaceShared.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/oop.inline.hpp"
 #include "runtime/atomic.hpp"
@@ -56,8 +57,27 @@
 #define ON_STACK_BUFFER_LENGTH 128
 
 // --------------------------------------------------------------------------
+inline Symbol* read_symbol_from_compact_hashtable(address base_address, u4 offset) {
+  return (Symbol*)(base_address + offset);
+}
+
+inline bool symbol_equals_compact_hashtable_entry(Symbol* value, const char* key, int len) {
+  if (value->equals(key, len)) {
+    assert(value->refcount() == PERM_REFCOUNT, "must be shared");
+    return true;
+  } else {
+    return false;
+  }
+}
+
+static CompactHashtable<
+  const char*, Symbol*,
+  read_symbol_from_compact_hashtable,
+  symbol_equals_compact_hashtable_entry
+> _shared_table;
+
+// --------------------------------------------------------------------------
 SymbolTable* SymbolTable::_the_table = NULL;
-CompactHashtable<Symbol*, char> SymbolTable::_shared_table;
 volatile bool SymbolTable::_alt_hash = false;
 volatile bool SymbolTable::_lookup_shared_first = false;
 // Static arena for symbols that are not deallocated
@@ -224,10 +244,20 @@
   };
 };
 
+class SharedSymbolIterator {
+  SymbolClosure* _symbol_closure;
+public:
+  SharedSymbolIterator(SymbolClosure* f) : _symbol_closure(f) {}
+  void do_value(Symbol* symbol) {
+    _symbol_closure->do_symbol(&symbol);
+  }
+};
+
 // Call function for all symbols in the symbol table.
 void SymbolTable::symbols_do(SymbolClosure *cl) {
   // all symbols from shared table
-  _shared_table.symbols_do(cl);
+  SharedSymbolIterator iter(cl);
+  _shared_table.iterate(&iter);
 
   // all symbols from the dynamic table
   SymbolsDo sd(cl);
@@ -597,6 +627,22 @@
 }
 
 #if INCLUDE_CDS
+class CompactSymbolTableWriter: public CompactHashtableWriter {
+public:
+  CompactSymbolTableWriter(int num_buckets, CompactHashtableStats* stats) :
+    CompactHashtableWriter(num_buckets, stats) {}
+  void add(unsigned int hash, Symbol *symbol) {
+    uintx deltax = MetaspaceShared::object_delta(symbol);
+    // When the symbols are stored into the archive, we already check that
+    // they won't be more than MAX_SHARED_DELTA from the base address, or
+    // else the dumping would have been aborted.
+    assert(deltax <= MAX_SHARED_DELTA, "must not be");
+    u4 delta = u4(deltax);
+
+    CompactHashtableWriter::add(hash, delta);
+  }
+};
+
 struct CopyToArchive : StackObj {
   CompactSymbolTableWriter* _writer;
   CopyToArchive(CompactSymbolTableWriter* writer) : _writer(writer) {}
@@ -613,7 +659,6 @@
 
     // add to the compact table
     _writer->add(fixed_hash, sym);
-
     return true;
   }
 };
@@ -631,7 +676,7 @@
   CompactSymbolTableWriter writer(num_buckets > 1 ? num_buckets : 1,
                                   &MetaspaceShared::stats()->symbol);
   copy_shared_symbol_table(&writer);
-  writer.dump(&_shared_table);
+  writer.dump(&_shared_table, "symbol");
 
   // Verify table is correct
   Symbol* sym = vmSymbols::java_lang_Object();
@@ -642,7 +687,6 @@
 }
 
 void SymbolTable::serialize(SerializeClosure* soc) {
-  _shared_table.set_type(CompactHashtable<Symbol*, char>::_symbol_table);
   _shared_table.serialize(soc);
 
   if (soc->writing()) {
--- a/src/hotspot/share/classfile/symbolTable.hpp	Thu Sep 20 18:39:53 2018 +0200
+++ b/src/hotspot/share/classfile/symbolTable.hpp	Tue Sep 18 21:47:14 2018 -0700
@@ -84,7 +84,6 @@
   operator Symbol*()                             { return _temp; }
 };
 
-template <class T, class N> class CompactHashtable;
 class CompactSymbolTableWriter;
 class SerializeClosure;
 
@@ -108,8 +107,6 @@
 
   // The symbol table
   static SymbolTable* _the_table;
-  // Shared symbol table.
-  static CompactHashtable<Symbol*, char> _shared_table;
   static volatile bool _lookup_shared_first;
   static volatile bool _alt_hash;
 
--- a/src/hotspot/share/classfile/systemDictionaryShared.cpp	Thu Sep 20 18:39:53 2018 +0200
+++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp	Tue Sep 18 21:47:14 2018 -0700
@@ -28,7 +28,6 @@
 #include "classfile/classLoader.hpp"
 #include "classfile/classLoaderData.inline.hpp"
 #include "classfile/classLoaderExt.hpp"
-#include "classfile/compactHashtable.inline.hpp"
 #include "classfile/dictionary.hpp"
 #include "classfile/javaClasses.hpp"
 #include "classfile/symbolTable.hpp"
--- a/src/hotspot/share/memory/filemap.cpp	Thu Sep 20 18:39:53 2018 +0200
+++ b/src/hotspot/share/memory/filemap.cpp	Tue Sep 18 21:47:14 2018 -0700
@@ -26,7 +26,6 @@
 #include "jvm.h"
 #include "classfile/classLoader.inline.hpp"
 #include "classfile/classLoaderExt.hpp"
-#include "classfile/compactHashtable.inline.hpp"
 #include "classfile/stringTable.hpp"
 #include "classfile/symbolTable.hpp"
 #include "classfile/systemDictionaryShared.hpp"
--- a/src/hotspot/share/services/diagnosticCommand.cpp	Thu Sep 20 18:39:53 2018 +0200
+++ b/src/hotspot/share/services/diagnosticCommand.cpp	Tue Sep 18 21:47:14 2018 -0700
@@ -26,7 +26,6 @@
 #include "jvm.h"
 #include "classfile/classLoaderHierarchyDCmd.hpp"
 #include "classfile/classLoaderStats.hpp"
-#include "classfile/compactHashtable.hpp"
 #include "compiler/compileBroker.hpp"
 #include "compiler/directivesParser.hpp"
 #include "gc/shared/vmGCOperations.hpp"
--- a/src/hotspot/share/utilities/utf8.cpp	Thu Sep 20 18:39:53 2018 +0200
+++ b/src/hotspot/share/utilities/utf8.cpp	Tue Sep 18 21:47:14 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -401,7 +401,7 @@
   return (c <= 0x00FF);
 }
 
-bool UNICODE::is_latin1(jchar* base, int length) {
+bool UNICODE::is_latin1(const jchar* base, int length) {
   for (int index = 0; index < length; index++) {
     if (base[index] > 0x00FF) {
       return false;
@@ -434,7 +434,7 @@
 }
 
 template<typename T>
-int UNICODE::utf8_length(T* base, int length) {
+int UNICODE::utf8_length(const T* base, int length) {
   int result = 0;
   for (int index = 0; index < length; index++) {
     T c = base[index];
@@ -444,7 +444,7 @@
 }
 
 template<typename T>
-char* UNICODE::as_utf8(T* base, int& length) {
+char* UNICODE::as_utf8(const T* base, int& length) {
   int utf8_len = utf8_length(base, length);
   u_char* buf = NEW_RESOURCE_ARRAY(u_char, utf8_len + 1);
   char* result = as_utf8(base, length, (char*) buf, utf8_len + 1);
@@ -454,7 +454,7 @@
   return (char*) result;
 }
 
-char* UNICODE::as_utf8(jchar* base, int length, char* buf, int buflen) {
+char* UNICODE::as_utf8(const jchar* base, int length, char* buf, int buflen) {
   u_char* p = (u_char*)buf;
   for (int index = 0; index < length; index++) {
     jchar c = base[index];
@@ -466,7 +466,7 @@
   return buf;
 }
 
-char* UNICODE::as_utf8(jbyte* base, int length, char* buf, int buflen) {
+char* UNICODE::as_utf8(const jbyte* base, int length, char* buf, int buflen) {
   u_char* p = (u_char*)buf;
   u_char* end = (u_char*)buf + buflen;
   for (int index = 0; index < length; index++) {
@@ -496,7 +496,7 @@
 
 // returns the quoted ascii length of a unicode string
 template<typename T>
-int UNICODE::quoted_ascii_length(T* base, int length) {
+int UNICODE::quoted_ascii_length(const T* base, int length) {
   int result = 0;
   for (int i = 0; i < length; i++) {
     T c = base[i];
@@ -529,11 +529,11 @@
 }
 
 // Explicit instantiation for all supported types.
-template int UNICODE::utf8_length(jbyte* base, int length);
-template int UNICODE::utf8_length(jchar* base, int length);
-template char* UNICODE::as_utf8(jbyte* base, int& length);
-template char* UNICODE::as_utf8(jchar* base, int& length);
-template int UNICODE::quoted_ascii_length<jbyte>(jbyte* base, int length);
-template int UNICODE::quoted_ascii_length<jchar>(jchar* base, int length);
+template int UNICODE::utf8_length(const jbyte* base, int length);
+template int UNICODE::utf8_length(const jchar* base, int length);
+template char* UNICODE::as_utf8(const jbyte* base, int& length);
+template char* UNICODE::as_utf8(const jchar* base, int& length);
+template int UNICODE::quoted_ascii_length<jbyte>(const jbyte* base, int length);
+template int UNICODE::quoted_ascii_length<jchar>(const jchar* base, int length);
 template void UNICODE::as_quoted_ascii<jbyte>(const jbyte* base, int length, char* buf, int buflen);
 template void UNICODE::as_quoted_ascii<jchar>(const jchar* base, int length, char* buf, int buflen);
--- a/src/hotspot/share/utilities/utf8.hpp	Thu Sep 20 18:39:53 2018 +0200
+++ b/src/hotspot/share/utilities/utf8.hpp	Tue Sep 18 21:47:14 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -90,14 +90,14 @@
   static bool is_latin1(jchar c);
 
   // checks if the given string can be encoded as latin1
-  static bool is_latin1(jchar* base, int length);
+  static bool is_latin1(const jchar* base, int length);
 
   // returns the utf8 size of a unicode character
   static int utf8_size(jchar c);
   static int utf8_size(jbyte c);
 
   // returns the utf8 length of a unicode string
-  template<typename T> static int utf8_length(T* base, int length);
+  template<typename T> static int utf8_length(const T* base, int length);
 
   // converts a unicode string to utf8 string
   static void convert_to_utf8(const jchar* base, int length, char* utf8_buffer);
@@ -105,12 +105,12 @@
   // converts a unicode string to a utf8 string; result is allocated
   // in resource area unless a buffer is provided. The unicode 'length'
   // parameter is set to the length of the result utf8 string.
-  template<typename T> static char* as_utf8(T* base, int& length);
-  static char* as_utf8(jchar* base, int length, char* buf, int buflen);
-  static char* as_utf8(jbyte* base, int length, char* buf, int buflen);
+  template<typename T> static char* as_utf8(const T* base, int& length);
+  static char* as_utf8(const jchar* base, int length, char* buf, int buflen);
+  static char* as_utf8(const jbyte* base, int length, char* buf, int buflen);
 
   // returns the quoted ascii length of a unicode string
-  template<typename T> static int quoted_ascii_length(T* base, int length);
+  template<typename T> static int quoted_ascii_length(const T* base, int length);
 
   // converts a unicode string to quoted ascii
   template<typename T> static void as_quoted_ascii(const T* base, int length, char* buf, int buflen);