1 /* 2 * Copyright (c) 1997, 2015, 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/javaClasses.hpp" 27 #include "memory/metaspaceShared.hpp" 28 #include "utilities/numberSeq.hpp" 29 #include <sys/stat.h> 30 31 ///////////////////////////////////////////////////// 32 // 33 // The compact hash table writer implementations 34 // 35 CompactHashtableWriter::CompactHashtableWriter(int table_type, 36 int num_entries, 37 CompactHashtableStats* stats) { 38 assert(DumpSharedSpaces, "dump-time only"); 39 _type = table_type; 40 _num_entries = num_entries; 41 _num_buckets = number_of_buckets(_num_entries); 42 _buckets = NEW_C_HEAP_ARRAY(Entry*, _num_buckets, mtSymbol); 43 memset(_buckets, 0, sizeof(Entry*) * _num_buckets); 44 45 /* bucket sizes table */ 46 _bucket_sizes = NEW_C_HEAP_ARRAY(juint, _num_buckets, mtSymbol); 47 memset(_bucket_sizes, 0, sizeof(juint) * _num_buckets); 48 49 stats->hashentry_count = _num_entries; 50 // Compact buckets' entries will have only the 4-byte offset, but 51 // we don't know how many there will be at this point. So use a 52 // conservative estimate here. The size is adjusted later when we 53 // write out the buckets. 54 stats->hashentry_bytes = _num_entries * 8; 55 stats->bucket_count = _num_buckets; 56 stats->bucket_bytes = (_num_buckets + 1) * (sizeof(juint)); 57 _stats = stats; 58 59 // See compactHashtable.hpp for table layout 60 _required_bytes = sizeof(juint) * 2; // _base_address, written as 2 juints 61 _required_bytes+= sizeof(juint) + // num_entries 62 sizeof(juint) + // num_buckets 63 stats->hashentry_bytes + 64 stats->bucket_bytes; 65 } 66 67 CompactHashtableWriter::~CompactHashtableWriter() { 68 for (int index = 0; index < _num_buckets; index++) { 69 Entry* next = NULL; 70 for (Entry* tent = _buckets[index]; tent; tent = next) { 71 next = tent->next(); 72 delete tent; 73 } 74 } 75 76 FREE_C_HEAP_ARRAY(juint, _bucket_sizes); 77 FREE_C_HEAP_ARRAY(Entry*, _buckets); 78 } 79 80 // Calculate the number of buckets in the temporary hash table 81 int CompactHashtableWriter::number_of_buckets(int num_entries) { 82 const int buksize = (int)SharedSymbolTableBucketSize; 83 int num_buckets = (num_entries + buksize - 1) / buksize; 84 num_buckets = (num_buckets + 1) & (~0x01); 85 86 return num_buckets; 87 } 88 89 // Add a symbol entry to the temporary hash table 90 void CompactHashtableWriter::add(unsigned int hash, Entry* entry) { 91 int index = hash % _num_buckets; 92 entry->set_next(_buckets[index]); 93 _buckets[index] = entry; 94 _bucket_sizes[index] ++; 95 } 96 97 // Write the compact table's bucket infos 98 juint* CompactHashtableWriter::dump_table(juint* p, juint** first_bucket, 99 NumberSeq* summary) { 100 int index; 101 juint* compact_table = p; 102 // Compute the start of the buckets, include the compact_bucket_infos table 103 // and the table end offset. 104 juint offset = _num_buckets + 1; 105 *first_bucket = compact_table + offset; 106 107 for (index = 0; index < _num_buckets; index++) { 108 int bucket_size = _bucket_sizes[index]; 109 if (bucket_size == 1) { 110 // bucket with one entry is compacted and only has the symbol offset 111 compact_table[index] = BUCKET_INFO(offset, COMPACT_BUCKET_TYPE); 112 offset += bucket_size; // each entry contains symbol offset only 113 } else { 114 // regular bucket, each entry is a symbol (hash, offset) pair 115 compact_table[index] = BUCKET_INFO(offset, REGULAR_BUCKET_TYPE); 116 offset += bucket_size * 2; // each hash entry is 2 juints 117 } 118 if (offset & ~BUCKET_OFFSET_MASK) { 119 vm_exit_during_initialization("CompactHashtableWriter::dump_table: Overflow! " 120 "Too many symbols."); 121 } 122 summary->add(bucket_size); 123 } 124 // Mark the end of the table 125 compact_table[_num_buckets] = BUCKET_INFO(offset, TABLEEND_BUCKET_TYPE); 126 127 return compact_table; 128 } 129 130 // Write the compact table's entries 131 juint* CompactHashtableWriter::dump_buckets(juint* compact_table, juint* p, 132 NumberSeq* summary) { 133 uintx base_address = 0; 134 uintx max_delta = 0; 135 int num_compact_buckets = 0; 136 if (_type == CompactHashtable<Symbol*, char>::_symbol_table) { 137 base_address = uintx(MetaspaceShared::shared_rs()->base()); 138 max_delta = uintx(MetaspaceShared::shared_rs()->size()); 139 assert(max_delta <= 0x7fffffff, "range check"); 140 } else { 141 assert((_type == CompactHashtable<oop, char>::_string_table), "unknown table"); 142 assert(UseCompressedOops, "UseCompressedOops is required"); 143 } 144 145 assert(p != NULL, "sanity"); 146 for (int index = 0; index < _num_buckets; index++) { 147 juint count = 0; 148 int bucket_size = _bucket_sizes[index]; 149 int bucket_type = BUCKET_TYPE(compact_table[index]); 150 151 if (bucket_size == 1) { 152 assert(bucket_type == COMPACT_BUCKET_TYPE, "Bad bucket type"); 153 num_compact_buckets ++; 154 } 155 for (Entry* tent = _buckets[index]; tent; 156 tent = tent->next()) { 157 if (bucket_type == REGULAR_BUCKET_TYPE) { 158 *p++ = juint(tent->hash()); // write entry hash 159 } 160 if (_type == CompactHashtable<Symbol*, char>::_symbol_table) { 161 uintx deltax = uintx(tent->value()) - base_address; 162 assert(deltax < max_delta, "range check"); 163 juint delta = juint(deltax); 164 *p++ = delta; // write entry offset 165 } else { 166 *p++ = oopDesc::encode_heap_oop(tent->string()); 167 } 168 count ++; 169 } 170 assert(count == _bucket_sizes[index], "sanity"); 171 } 172 173 // Adjust the hashentry_bytes in CompactHashtableStats. Each compact 174 // bucket saves 4-byte. 175 _stats->hashentry_bytes -= num_compact_buckets * 4; 176 177 return p; 178 } 179 180 // Write the compact table 181 void CompactHashtableWriter::dump(char** top, char* end) { 182 NumberSeq summary; 183 char* old_top = *top; 184 juint* p = (juint*)(*top); 185 186 uintx base_address = uintx(MetaspaceShared::shared_rs()->base()); 187 188 // Now write the following at the beginning of the table: 189 // base_address (uintx) 190 // num_entries (juint) 191 // num_buckets (juint) 192 *p++ = high(base_address); 193 *p++ = low (base_address); // base address 194 *p++ = _num_entries; // number of entries in the table 195 *p++ = _num_buckets; // number of buckets in the table 196 197 juint* first_bucket = NULL; 198 juint* compact_table = dump_table(p, &first_bucket, &summary); 199 juint* bucket_end = dump_buckets(compact_table, first_bucket, &summary); 200 201 assert(bucket_end <= (juint*)end, "cannot write past end"); 202 *top = (char*)bucket_end; 203 204 if (PrintSharedSpaces) { 205 double avg_cost = 0.0; 206 if (_num_entries > 0) { 207 avg_cost = double(_required_bytes)/double(_num_entries); 208 } 209 tty->print_cr("Shared %s table stats -------- base: " PTR_FORMAT, 210 table_name(), (intptr_t)base_address); 211 tty->print_cr("Number of entries : %9d", _num_entries); 212 tty->print_cr("Total bytes used : %9d", (int)((*top) - old_top)); 213 tty->print_cr("Average bytes per entry : %9.3f", avg_cost); 214 tty->print_cr("Average bucket size : %9.3f", summary.avg()); 215 tty->print_cr("Variance of bucket size : %9.3f", summary.variance()); 216 tty->print_cr("Std. dev. of bucket size: %9.3f", summary.sd()); 217 tty->print_cr("Maximum bucket size : %9d", (int)summary.maximum()); 218 } 219 } 220 221 const char* CompactHashtableWriter::table_name() { 222 switch (_type) { 223 case CompactHashtable<Symbol*, char>::_symbol_table: return "symbol"; 224 case CompactHashtable<oop, char>::_string_table: return "string"; 225 default: 226 ; 227 } 228 return "unknown"; 229 } 230 231 ///////////////////////////////////////////////////////////// 232 // 233 // The CompactHashtable implementation 234 // 235 template <class T, class N> const char* CompactHashtable<T, N>::init( 236 CompactHashtableType type, const char* buffer) { 237 assert(!DumpSharedSpaces, "run-time only"); 238 _type = type; 239 juint*p = (juint*)buffer; 240 juint upper = *p++; 241 juint lower = *p++; 242 _base_address = uintx(jlong_from(upper, lower)); 243 _entry_count = *p++; 244 _bucket_count = *p++; 245 _buckets = p; 246 _table_end_offset = BUCKET_OFFSET(p[_bucket_count]); // located at the end of the bucket_info table 247 248 juint *end = _buckets + _table_end_offset; 249 return (const char*)end; 250 } 251 252 template <class T, class N> void CompactHashtable<T, N>::symbols_do(SymbolClosure *cl) { 253 assert(!DumpSharedSpaces, "run-time only"); 254 for (juint i = 0; i < _bucket_count; i ++) { 255 juint bucket_info = _buckets[i]; 256 juint bucket_offset = BUCKET_OFFSET(bucket_info); 257 int bucket_type = BUCKET_TYPE(bucket_info); 258 juint* bucket = _buckets + bucket_offset; 259 juint* bucket_end = _buckets; 260 261 Symbol* sym; 262 if (bucket_type == COMPACT_BUCKET_TYPE) { 263 sym = (Symbol*)((void*)(_base_address + bucket[0])); 264 cl->do_symbol(&sym); 265 } else { 266 bucket_end += BUCKET_OFFSET(_buckets[i + 1]); 267 while (bucket < bucket_end) { 268 sym = (Symbol*)((void*)(_base_address + bucket[1])); 269 cl->do_symbol(&sym); 270 bucket += 2; 271 } 272 } 273 } 274 } 275 276 template <class T, class N> void CompactHashtable<T, N>::oops_do(OopClosure* f) { 277 assert(!DumpSharedSpaces, "run-time only"); 278 assert(_type == _string_table, "sanity"); 279 for (juint i = 0; i < _bucket_count; i ++) { 280 juint bucket_info = _buckets[i]; 281 juint bucket_offset = BUCKET_OFFSET(bucket_info); 282 int bucket_type = BUCKET_TYPE(bucket_info); 283 juint* bucket = _buckets + bucket_offset; 284 juint* bucket_end = _buckets; 285 286 narrowOop o; 287 if (bucket_type == COMPACT_BUCKET_TYPE) { 288 o = (narrowOop)bucket[0]; 289 f->do_oop(&o); 290 } else { 291 bucket_end += BUCKET_OFFSET(_buckets[i + 1]); 292 while (bucket < bucket_end) { 293 o = (narrowOop)bucket[1]; 294 f->do_oop(&o); 295 bucket += 2; 296 } 297 } 298 } 299 } 300 301 // Explicitly instantiate these types 302 template class CompactHashtable<Symbol*, char>; 303 template class CompactHashtable<oop, char>; 304 305 #ifndef O_BINARY // if defined (Win32) use binary files. 306 #define O_BINARY 0 // otherwise do nothing. 307 #endif 308 309 //////////////////////////////////////////////////////// 310 // 311 // HashtableTextDump 312 // 313 HashtableTextDump::HashtableTextDump(const char* filename) : _fd(-1) { 314 struct stat st; 315 if (os::stat(filename, &st) != 0) { 316 quit("Unable to get hashtable dump file size", filename); 317 } 318 _size = st.st_size; 319 _fd = open(filename, O_RDONLY | O_BINARY, 0); 320 if (_fd < 0) { 321 quit("Unable to open hashtable dump file", filename); 322 } 323 _base = os::map_memory(_fd, filename, 0, NULL, _size, true, false); 324 if (_base == NULL) { 325 quit("Unable to map hashtable dump file", filename); 326 } 327 _p = _base; 328 _end = _base + st.st_size; 329 _filename = filename; 330 _prefix_type = Unknown; 331 _line_no = 1; 332 } 333 334 HashtableTextDump::~HashtableTextDump() { 335 os::unmap_memory((char*)_base, _size); 336 if (_fd >= 0) { 337 close(_fd); 338 } 339 } 340 341 void HashtableTextDump::quit(const char* err, const char* msg) { 342 vm_exit_during_initialization(err, msg); 343 } 344 345 void HashtableTextDump::corrupted(const char *p, const char* msg) { 346 char info[60]; 347 sprintf(info, "%s. Corrupted at line %d (file pos %d)", msg, _line_no, (int)(p - _base)); 348 quit(info, _filename); 349 } 350 351 bool HashtableTextDump::skip_newline() { 352 if (_p[0] == '\r' && _p[1] == '\n') { 353 _p += 2; 354 } else if (_p[0] == '\n') { 355 _p += 1; 356 } else { 357 corrupted(_p, "Unexpected character"); 358 } 359 _line_no ++; 360 return true; 361 } 362 363 int HashtableTextDump::skip(char must_be_char) { 364 corrupted_if(remain() < 1); 365 corrupted_if(*_p++ != must_be_char); 366 return 0; 367 } 368 369 void HashtableTextDump::skip_past(char c) { 370 for (;;) { 371 corrupted_if(remain() < 1); 372 if (*_p++ == c) { 373 return; 374 } 375 } 376 } 377 378 void HashtableTextDump::check_version(const char* ver) { 379 int len = (int)strlen(ver); 380 corrupted_if(remain() < len); 381 if (strncmp(_p, ver, len) != 0) { 382 quit("wrong version of hashtable dump file", _filename); 383 } 384 _p += len; 385 skip_newline(); 386 } 387 388 void HashtableTextDump::scan_prefix_type() { 389 _p ++; 390 if (strncmp(_p, "SECTION: String", 15) == 0) { 391 _p += 15; 392 _prefix_type = StringPrefix; 393 } else if (strncmp(_p, "SECTION: Symbol", 15) == 0) { 394 _p += 15; 395 _prefix_type = SymbolPrefix; 396 } else { 397 _prefix_type = Unknown; 398 } 399 skip_newline(); 400 } 401 402 int HashtableTextDump::scan_prefix(int* utf8_length) { 403 if (*_p == '@') { 404 scan_prefix_type(); 405 } 406 407 switch (_prefix_type) { 408 case SymbolPrefix: 409 *utf8_length = scan_symbol_prefix(); break; 410 case StringPrefix: 411 *utf8_length = scan_string_prefix(); break; 412 default: 413 tty->print_cr("Shared input data type: Unknown."); 414 corrupted(_p, "Unknown data type"); 415 } 416 417 return _prefix_type; 418 } 419 420 int HashtableTextDump::scan_string_prefix() { 421 // Expect /[0-9]+: / 422 int utf8_length; 423 get_num(':', &utf8_length); 424 if (*_p != ' ') { 425 corrupted(_p, "Wrong prefix format for string"); 426 } 427 _p++; 428 return utf8_length; 429 } 430 431 int HashtableTextDump::scan_symbol_prefix() { 432 // Expect /[0-9]+ (-|)[0-9]+: / 433 int utf8_length; 434 get_num(' ', &utf8_length); 435 if (*_p == '-') { 436 _p++; 437 } 438 int ref_num; 439 (void)get_num(':', &ref_num); 440 if (*_p != ' ') { 441 corrupted(_p, "Wrong prefix format for symbol"); 442 } 443 _p++; 444 return utf8_length; 445 } 446 447 jchar HashtableTextDump::unescape(const char* from, const char* end, int count) { 448 jchar value = 0; 449 450 corrupted_if(from + count > end); 451 452 for (int i=0; i<count; i++) { 453 char c = *from++; 454 switch (c) { 455 case '0': case '1': case '2': case '3': case '4': 456 case '5': case '6': case '7': case '8': case '9': 457 value = (value << 4) + c - '0'; 458 break; 459 case 'a': case 'b': case 'c': 460 case 'd': case 'e': case 'f': 461 value = (value << 4) + 10 + c - 'a'; 462 break; 463 case 'A': case 'B': case 'C': 464 case 'D': case 'E': case 'F': 465 value = (value << 4) + 10 + c - 'A'; 466 break; 467 default: 468 ShouldNotReachHere(); 469 } 470 } 471 return value; 472 } 473 474 void HashtableTextDump::get_utf8(char* utf8_buffer, int utf8_length) { 475 // cache in local vars 476 const char* from = _p; 477 const char* end = _end; 478 char* to = utf8_buffer; 479 int n = utf8_length; 480 481 for (; n > 0 && from < end; n--) { 482 if (*from != '\\') { 483 *to++ = *from++; 484 } else { 485 corrupted_if(from + 2 > end); 486 char c = from[1]; 487 from += 2; 488 switch (c) { 489 case 'x': 490 { 491 jchar value = unescape(from, end, 2); 492 from += 2; 493 assert(value <= 0xff, "sanity"); 494 *to++ = (char)(value & 0xff); 495 } 496 break; 497 case 't': *to++ = '\t'; break; 498 case 'n': *to++ = '\n'; break; 499 case 'r': *to++ = '\r'; break; 500 case '\\': *to++ = '\\'; break; 501 default: 502 corrupted(_p, "Unsupported character"); 503 } 504 } 505 } 506 corrupted_if(n > 0); // expected more chars but file has ended 507 _p = from; 508 skip_newline(); 509 } 510 511 // NOTE: the content is NOT the same as 512 // UTF8::as_quoted_ascii(const char* utf8_str, int utf8_length, char* buf, int buflen). 513 // We want to escape \r\n\t so that output [1] is more readable; [2] can be more easily 514 // parsed by scripts; [3] quickly processed by HashtableTextDump::get_utf8() 515 void HashtableTextDump::put_utf8(outputStream* st, const char* utf8_string, int utf8_length) { 516 const char *c = utf8_string; 517 const char *end = c + utf8_length; 518 for (; c < end; c++) { 519 switch (*c) { 520 case '\t': st->print("\\t"); break; 521 case '\r': st->print("\\r"); break; 522 case '\n': st->print("\\n"); break; 523 case '\\': st->print("\\\\"); break; 524 default: 525 if (isprint(*c)) { 526 st->print("%c", *c); 527 } else { 528 st->print("\\x%02x", ((unsigned int)*c) & 0xff); 529 } 530 } 531 } 532 }