// Write the compact table's entries
juint* CompactHashtableWriter::dump_buckets(juint* compact_table, juint* p,
                                            NumberSeq* summary) {
  uintx base_address = 0;
  uintx max_delta = 0;
  int num_compact_buckets = 0;
  if (_type == CompactHashtable<Symbol*, char>::_symbol_table) {
    base_address = uintx(MetaspaceShared::shared_rs()->base());
    max_delta    = uintx(MetaspaceShared::shared_rs()->size());
    assert(max_delta <= 0x7fffffff, "range check");
  } else {
    assert((_type == CompactHashtable<oop, char>::_string_table), "unknown table");
    assert(UseCompressedOops, "UseCompressedOops is required");
  }

  assert(p != NULL, "sanity");
  for (int index = 0; index < _num_buckets; index++) {
    juint count = 0;
    int bucket_size = _bucket_sizes[index];
    int bucket_type = BUCKET_TYPE(compact_table[index]);

    if (bucket_size == 1) {
      assert(bucket_type == COMPACT_BUCKET_TYPE, "Bad bucket type");
      num_compact_buckets ++;
    }
    for (Entry* tent = _buckets[index]; tent;
         tent = tent->next()) {
      if (bucket_type == REGULAR_BUCKET_TYPE) {
        *p++ = juint(tent->hash()); // write entry hash
      }
      if (_type == CompactHashtable<Symbol*, char>::_symbol_table) {
        uintx deltax = uintx(tent->value()) - base_address;
        assert(deltax < max_delta, "range check");
        juint delta = juint(deltax);
        *p++ = delta; // write entry offset
      } else {
        *p++ = oopDesc::encode_heap_oop(tent->string());
      }
      count ++;
    }
    assert(count == _bucket_sizes[index], "sanity");
  }

  // Adjust the hashentry_bytes in CompactHashtableStats. Each compact
  // bucket saves 4-byte.
  _stats->hashentry_bytes -= num_compact_buckets * 4;

  return p;
}
// Write the compact table
void CompactHashtableWriter::dump(char** top, char* end) {
  NumberSeq summary;
  char* old_top = *top;
  juint* p = (juint*)(*top);

  uintx base_address = uintx(MetaspaceShared::shared_rs()->base());

  *p++ = high(base_address);
  *p++ = low (base_address); // base address
  *p++ = _num_entries;  // number of entries in the table
  *p++ = _num_buckets;  // number of buckets in the table

  juint* first_bucket = NULL;
  juint* compact_table = dump_table(p, &first_bucket, &summary);
  juint* bucket_end = dump_buckets(compact_table, first_bucket, &summary);

  assert(bucket_end <= (juint*)end, "cannot write past end");
  *top = (char*)bucket_end;

  if (PrintSharedSpaces) {
    double avg_cost = 0.0;
    if (_num_entries > 0) {
      avg_cost = double(_required_bytes)/double(_num_entries);
    }
    tty->print_cr("Shared %s table stats -------- base: " PTR_FORMAT, _table_name, (intptr_t)base_address);
    tty->print_cr("Number of entries       : %9d", _num_entries);
    tty->print_cr("Total bytes used        : %9d", (int)((*top) - old_top));
    tty->print_cr("Average bytes per entry : %9.3f", avg_cost);
    tty->print_cr("Average bucket size     : %9.3f", summary.avg());
    tty->print_cr("Variance of bucket size : %9.3f", summary.variance());
    tty->print_cr("Std. dev. of bucket size: %9.3f", summary.sd());
    tty->print_cr("Maximum bucket size     : %9d", (int)summary.maximum());
  }
}
/////////////////////////////////////////////////////////////
//
// The CompactHashtable implementation
//
template <class T, class N> const char* CompactHashtable<T, N>::init(const char* buffer) {
  assert(!DumpSharedSpaces, "run-time only");
  juint*p = (juint*)buffer;
  juint upper = *p++;
  juint lower = *p++;
  _base_address = uintx(jlong_from(upper, lower));
  _entry_count = *p++;
  _bucket_count = *p++;
  _buckets = p;
  _table_end_offset = BUCKET_OFFSET(p[_bucket_count]); // located at the end of the bucket_info table

  juint *end = _buckets + _table_end_offset;
  return (const char*)end;
}
// Write the compact table's entries
juint* CompactHashtableWriter::dump_buckets(juint* compact_table, juint* p,
                                            NumberSeq* summary) {
  uintx base_address = uintx(MetaspaceShared::shared_rs()->base());
  uintx max_delta    = uintx(MetaspaceShared::shared_rs()->size());
  assert(max_delta <= 0x7fffffff, "range check");
  int num_compact_buckets = 0;

  assert(p != NULL, "sanity");
  for (int index = 0; index < _num_buckets; index++) {
    juint count = 0;
    int bucket_size = _bucket_sizes[index];
    int bucket_type = BUCKET_TYPE(compact_table[index]);

    if (bucket_size == 1) {
      assert(bucket_type == COMPACT_BUCKET_TYPE, "Bad bucket type");
      num_compact_buckets ++;
    }
    for (Entry* tent = _buckets[index]; tent;
         tent = tent->next()) {
      if (bucket_type == REGULAR_BUCKET_TYPE) {
        *p++ = juint(tent->hash()); // write symbol hash
      }
      uintx deltax = uintx(tent->value()) - base_address;
      assert(deltax < max_delta, "range check");
      juint delta = juint(deltax);
      *p++ = delta; // write symbol offset
      count ++;
    }
    assert(count == _bucket_sizes[index], "sanity");
  }

  // Adjust the hashentry_bytes in CompactHashtableStats. Each compact
  // bucket saves 4-byte.
  _stats->hashentry_bytes -= num_compact_buckets * 4;

  return p;
}