1 /*
   2  * Copyright (c) 1997, 2018, 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 #ifndef SHARE_VM_CLASSFILE_COMPACTHASHTABLE_HPP
  26 #define SHARE_VM_CLASSFILE_COMPACTHASHTABLE_HPP
  27 
  28 #include "oops/array.hpp"
  29 #include "oops/symbol.hpp"
  30 #include "utilities/hashtable.hpp"
  31 
  32 
  33 template <
  34   typename K,
  35   typename V,
  36   V (*DECODE)(address base_address, u4 offset),
  37   bool (*EQUALS)(V value, K key, int len)
  38   >
  39 class CompactHashtable;
  40 class NumberSeq;
  41 class SimpleCompactHashtable;
  42 class SerializeClosure;
  43 
  44 // Stats for symbol tables in the CDS archive
  45 class CompactHashtableStats {
  46 public:
  47   int hashentry_count;
  48   int hashentry_bytes;
  49   int bucket_count;
  50   int bucket_bytes;
  51 };
  52 
  53 #if INCLUDE_CDS
  54 /////////////////////////////////////////////////////////////////////////
  55 //
  56 // The compact hash table writer. Used at dump time for writing out
  57 // the compact table to the shared archive.
  58 //
  59 // At dump time, the CompactHashtableWriter obtains all entries from the
  60 // symbol/string table and adds them to a new temporary hash table. The hash
  61 // table size (number of buckets) is calculated using
  62 // '(num_entries + bucket_size - 1) / bucket_size'. The default bucket
  63 // size is 4 and can be changed by -XX:SharedSymbolTableBucketSize option.
  64 // 4 is chosen because it produces smaller sized bucket on average for
  65 // faster lookup. It also has relatively small number of empty buckets and
  66 // good distribution of the entries.
  67 //
  68 // We use a simple hash function (hash % num_bucket) for the table.
  69 // The new table is compacted when written out. Please see comments
  70 // above the CompactHashtable class for the table layout detail. The bucket
  71 // offsets are written to the archive as part of the compact table. The
  72 // bucket offset is encoded in the low 30-bit (0-29) and the bucket type
  73 // (regular or compact) are encoded in bit[31, 30]. For buckets with more
  74 // than one entry, both hash and entry offset are written to the
  75 // table. For buckets with only one entry, only the entry offset is written
  76 // to the table and the buckets are tagged as compact in their type bits.
  77 // Buckets without entry are skipped from the table. Their offsets are
  78 // still written out for faster lookup.
  79 //
  80 class CompactHashtableWriter: public StackObj {
  81 public:
  82   class Entry {
  83     unsigned int _hash;
  84     u4 _value;
  85 
  86   public:
  87     Entry() {}
  88     Entry(unsigned int hash, u4 val) : _hash(hash), _value(val) {}
  89 
  90     u4 value() {
  91       return _value;
  92     }
  93     unsigned int hash() {
  94       return _hash;
  95     }
  96 
  97     bool operator==(const CompactHashtableWriter::Entry& other) {
  98       return (_value == other._value && _hash == other._hash);
  99     }
 100   }; // class CompactHashtableWriter::Entry
 101 
 102 private:
 103   int _num_entries;
 104   int _num_buckets;
 105   int _num_empty_buckets;
 106   int _num_value_only_buckets;
 107   int _num_other_buckets;
 108   GrowableArray<Entry>** _buckets;
 109   CompactHashtableStats* _stats;
 110   Array<u4>* _compact_buckets;
 111   Array<u4>* _compact_entries;
 112 
 113 public:
 114   // This is called at dump-time only
 115   CompactHashtableWriter(int num_buckets, CompactHashtableStats* stats);
 116   ~CompactHashtableWriter();
 117 
 118   void add(unsigned int hash, u4 value);
 119 
 120 private:
 121   void allocate_table();
 122   void dump_table(NumberSeq* summary);
 123 
 124 public:
 125   void dump(SimpleCompactHashtable *cht, const char* table_name);
 126 };
 127 #endif // INCLUDE_CDS
 128 
 129 #define REGULAR_BUCKET_TYPE       0
 130 #define VALUE_ONLY_BUCKET_TYPE    1
 131 #define TABLEEND_BUCKET_TYPE      3
 132 #define BUCKET_OFFSET_MASK        0x3FFFFFFF
 133 #define BUCKET_OFFSET(info)       ((info) & BUCKET_OFFSET_MASK)
 134 #define BUCKET_TYPE_SHIFT         30
 135 #define BUCKET_TYPE(info)         (((info) & ~BUCKET_OFFSET_MASK) >> BUCKET_TYPE_SHIFT)
 136 #define BUCKET_INFO(offset, type) (((type) << BUCKET_TYPE_SHIFT) | ((offset) & BUCKET_OFFSET_MASK))
 137 
 138 /////////////////////////////////////////////////////////////////////////////
 139 //
 140 // CompactHashtable is used to store the CDS archive's symbol/string tables.
 141 //
 142 // Because these tables are read-only (no entries can be added/deleted) at run-time
 143 // and tend to have large number of entries, we try to minimize the footprint
 144 // cost per entry.
 145 //
 146 // The CompactHashtable is split into two arrays
 147 //
 148 //   u4 buckets[num_buckets+1]; // bit[31,30]: type; bit[29-0]: offset
 149 //   u4 entries[<variable size>]
 150 //
 151 // The size of buckets[] is 'num_buckets + 1'. Each entry of
 152 // buckets[] is a 32-bit encoding of the bucket type and bucket offset,
 153 // with the type in the left-most 2-bit and offset in the remaining 30-bit.
 154 // The last entry is a special type. It contains the end of the last
 155 // bucket.
 156 //
 157 // There are two types of buckets, regular buckets and value_only buckets. The
 158 // value_only buckets have '01' in their highest 2-bit, and regular buckets have
 159 // '00' in their highest 2-bit.
 160 //
 161 // For normal buckets, each entry is 8 bytes in the entries[]:
 162 //   u4 hash;    /* symbol/string hash */
 163 //   union {
 164 //     u4 offset;  /* Symbol* sym = (Symbol*)(base_address + offset) */
 165 //     narrowOop str; /* String narrowOop encoding */
 166 //   }
 167 //
 168 //
 169 // For value_only buckets, each entry has only the 4-byte 'offset' in the entries[].
 170 //
 171 // Example -- note that the second bucket is a VALUE_ONLY_BUCKET_TYPE so the hash code
 172 //            is skipped.
 173 // buckets[0, 4, 5, ....]
 174 //         |  |  |
 175 //         |  |  +---+
 176 //         |  |      |
 177 //         |  +----+ |
 178 //         v       v v
 179 // entries[H,O,H,O,O,H,O,H,O.....]
 180 //
 181 // See CompactHashtable::lookup() for how the table is searched at runtime.
 182 // See CompactHashtableWriter::dump() for how the table is written at CDS
 183 // dump time.
 184 //
 185 class SimpleCompactHashtable {
 186 protected:
 187   address  _base_address;
 188   u4  _bucket_count;
 189   u4  _entry_count;
 190   u4* _buckets;
 191   u4* _entries;
 192 
 193 public:
 194   SimpleCompactHashtable() {
 195     _entry_count = 0;
 196     _bucket_count = 0;
 197     _buckets = 0;
 198     _entries = 0;
 199   }
 200 
 201   void reset() {
 202     _bucket_count = 0;
 203     _entry_count = 0;
 204     _buckets = 0;
 205     _entries = 0;
 206   }
 207 
 208   void init(address base_address, u4 entry_count, u4 bucket_count, u4* buckets, u4* entries) {
 209     _base_address = base_address;
 210     _bucket_count = bucket_count;
 211     _entry_count = entry_count;
 212     _buckets = buckets;
 213     _entries = entries;
 214   }
 215 
 216   // For reading from/writing to the CDS archive
 217   void serialize(SerializeClosure* soc) NOT_CDS_RETURN;
 218 
 219   inline bool empty() {
 220     return (_entry_count == 0);
 221   }
 222 };
 223 
 224 template <
 225   typename K,
 226   typename V,
 227   V (*DECODE)(address base_address, u4 offset),
 228   bool (*EQUALS)(V value, K key, int len)
 229   >
 230 class CompactHashtable : public SimpleCompactHashtable {
 231   friend class VMStructs;
 232 
 233   V decode(u4 offset) const {
 234     return DECODE(_base_address, offset);
 235   }
 236 
 237 public:
 238   CompactHashtable() : SimpleCompactHashtable() {}
 239 
 240   // Lookup a value V from the compact table using key K
 241   inline V lookup(K key, unsigned int hash, int len) const {
 242     if (_entry_count > 0) {
 243       int index = hash % _bucket_count;
 244       u4 bucket_info = _buckets[index];
 245       u4 bucket_offset = BUCKET_OFFSET(bucket_info);
 246       int bucket_type = BUCKET_TYPE(bucket_info);
 247       u4* entry = _entries + bucket_offset;
 248 
 249       if (bucket_type == VALUE_ONLY_BUCKET_TYPE) {
 250         V value = decode(entry[0]);
 251         if (EQUALS(value, key, len)) {
 252           return value;
 253         }
 254       } else {
 255         // This is a regular bucket, which has more than one
 256         // entries. Each entry is a pair of entry (hash, offset).
 257         // Seek until the end of the bucket.
 258         u4* entry_max = _entries + BUCKET_OFFSET(_buckets[index + 1]);
 259         while (entry < entry_max) {
 260           unsigned int h = (unsigned int)(entry[0]);
 261           if (h == hash) {
 262             V value = decode(entry[1]);
 263             if (EQUALS(value, key, len)) {
 264               return value;
 265             }
 266           }
 267           entry += 2;
 268         }
 269       }
 270     }
 271     return NULL;
 272   }
 273 
 274   template <class ITER>
 275   inline void iterate(ITER* iter) const {
 276     for (u4 i = 0; i < _bucket_count; i++) {
 277       u4 bucket_info = _buckets[i];
 278       u4 bucket_offset = BUCKET_OFFSET(bucket_info);
 279       int bucket_type = BUCKET_TYPE(bucket_info);
 280       u4* entry = _entries + bucket_offset;
 281 
 282       if (bucket_type == VALUE_ONLY_BUCKET_TYPE) {
 283         iter->do_value(decode(entry[0]));
 284       } else {
 285         u4*entry_max = _entries + BUCKET_OFFSET(_buckets[i + 1]);
 286         while (entry < entry_max) {
 287           iter->do_value(decode(entry[1]));
 288           entry += 2;
 289         }
 290       }
 291     }
 292   }
 293 };
 294 
 295 ////////////////////////////////////////////////////////////////////////
 296 //
 297 // Read/Write the contents of a hashtable textual dump (created by
 298 // SymbolTable::dump and StringTable::dump).
 299 // Because the dump file may be big (hundred of MB in extreme cases),
 300 // we use mmap for fast access when reading it.
 301 //
 302 class HashtableTextDump {
 303   int _fd;
 304   const char* _base;
 305   const char* _p;
 306   const char* _end;
 307   const char* _filename;
 308   size_t      _size;
 309   int         _prefix_type;
 310   int         _line_no;
 311 public:
 312   HashtableTextDump(const char* filename);
 313   ~HashtableTextDump();
 314 
 315   enum {
 316     SymbolPrefix = 1 << 0,
 317     StringPrefix = 1 << 1,
 318     Unknown = 1 << 2
 319   };
 320 
 321   void quit(const char* err, const char* msg);
 322 
 323   inline int remain() {
 324     return (int)(_end - _p);
 325   }
 326 
 327   void corrupted(const char *p, const char *msg);
 328 
 329   inline void corrupted_if(bool cond, const char *msg) {
 330     if (cond) {
 331       corrupted(_p, msg);
 332     }
 333   }
 334 
 335   bool skip_newline();
 336   int skip(char must_be_char);
 337   void skip_past(char c);
 338   void check_version(const char* ver);
 339 
 340   inline void get_num(char delim, int *num) {
 341     const char* p   = _p;
 342     const char* end = _end;
 343     u8 n = 0;
 344 
 345     while (p < end) {
 346       char c = *p++;
 347       if ('0' <= c && c <= '9') {
 348         n = n * 10 + (c - '0');
 349         if (n > (u8)INT_MAX) {
 350           corrupted(_p, "Num overflow");
 351         }
 352       } else if (c == delim) {
 353         _p = p;
 354         *num = (int)n;
 355         return;
 356       } else {
 357         // Not [0-9], not 'delim'
 358         corrupted(_p, "Unrecognized format");;
 359       }
 360     }
 361 
 362     corrupted(_end, "Incorrect format");
 363     ShouldNotReachHere();
 364   }
 365 
 366   void scan_prefix_type();
 367   int scan_prefix(int* utf8_length);
 368   int scan_string_prefix();
 369   int scan_symbol_prefix();
 370 
 371   jchar unescape(const char* from, const char* end, int count);
 372   void get_utf8(char* utf8_buffer, int utf8_length);
 373   static void put_utf8(outputStream* st, const char* utf8_string, int utf8_length);
 374 };
 375 
 376 #endif // SHARE_VM_CLASSFILE_COMPACTHASHTABLE_HPP