/* * Copyright (c) 1997, 2022, 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. *
*/
// In worst case, we have no VALUE_ONLY_BUCKET_TYPE, so each entry takes 2 slots int entries_space = 2 * num_entries;
size_t entry_bytes = ArchiveBuilder::ro_array_bytesize<u4>(entries_space);
// Add a symbol entry to the temporary hash table void CompactHashtableWriter::add(unsignedint hash, u4 value) { int index = hash % _num_buckets;
_buckets[index]->append_if_missing(Entry(hash, value));
_num_entries_written++;
}
void CompactHashtableWriter::allocate_table() { int entries_space = 0; for (int index = 0; index < _num_buckets; index++) {
GrowableArray<Entry>* bucket = _buckets[index]; int bucket_size = bucket->length(); if (bucket_size == 1) {
entries_space++;
} elseif (bucket_size > 1) {
entries_space += 2 * bucket_size;
}
}
if (entries_space & ~BUCKET_OFFSET_MASK) {
vm_exit_during_initialization("CompactHashtableWriter::allocate_table: Overflow! " "Too many entries.");
}
// Write the compact table's buckets void CompactHashtableWriter::dump_table(NumberSeq* summary) {
u4 offset = 0; for (int index = 0; index < _num_buckets; index++) {
GrowableArray<Entry>* bucket = _buckets[index]; int bucket_size = bucket->length(); if (bucket_size == 1) { // bucket with one entry is compacted and only has the symbol offset
_compact_buckets->at_put(index, BUCKET_INFO(offset, VALUE_ONLY_BUCKET_TYPE));
Entry ent = bucket->at(0);
_compact_entries->at_put(offset++, ent.value());
_num_value_only_buckets++;
} else { // regular bucket, each entry is a symbol (hash, offset) pair
_compact_buckets->at_put(index, BUCKET_INFO(offset, REGULAR_BUCKET_TYPE));
// Mark the end of the buckets
_compact_buckets->at_put(_num_buckets, BUCKET_INFO(offset, TABLEEND_BUCKET_TYPE));
assert(offset == (u4)_compact_entries->length(), "sanity");
}
size_t SimpleCompactHashtable::calculate_header_size() { // We have 5 fields. Each takes up sizeof(intptr_t). See WriteClosure::do_u4
size_t bytes = sizeof(intptr_t) * 5; return bytes;
}
void SimpleCompactHashtable::serialize_header(SerializeClosure* soc) { // NOTE: if you change this function, you MUST change the number 5 in // calculate_header_size() accordingly.
soc->do_u4(&_entry_count);
soc->do_u4(&_bucket_count);
soc->do_ptr((void**)&_buckets);
soc->do_ptr((void**)&_entries); if (soc->reading()) {
_base_address = (address)SharedBaseAddress;
}
} #endif// INCLUDE_CDS
#ifndef O_BINARY // if defined (Win32) use binary files. #define O_BINARY 0 // otherwise do nothing. #endif
int HashtableTextDump::scan_prefix(int* utf8_length) { if (*_p == '@') {
scan_prefix_type();
}
switch (_prefix_type) { case SymbolPrefix:
*utf8_length = scan_symbol_prefix(); break; case StringPrefix:
*utf8_length = scan_string_prefix(); break; default:
tty->print_cr("Shared input data type: Unknown.");
corrupted(_p, "Unknown data type");
}
return _prefix_type;
}
int HashtableTextDump::scan_string_prefix() { // Expect /[0-9]+: / int utf8_length = 0;
get_num(':', &utf8_length); if (*_p != ' ') {
corrupted(_p, "Wrong prefix format for string");
}
_p++; return utf8_length;
}
int HashtableTextDump::scan_symbol_prefix() { // Expect /[0-9]+ (-|)[0-9]+: / int utf8_length = 0;
get_num(' ', &utf8_length); if (*_p == '-') {
_p++;
} int ref_num;
get_num(':', &ref_num); if (*_p != ' ') {
corrupted(_p, "Wrong prefix format for symbol");
}
_p++; return utf8_length;
}
jchar HashtableTextDump::unescape(constchar* from, constchar* end, int count) {
jchar value = 0;
corrupted_if(from + count > end, "Truncated");
for (int i=0; i<count; i++) { char c = *from++; switch (c) { case'0': case'1': case'2': case'3': case'4': case'5': case'6': case'7': case'8': case'9':
value = (value << 4) + c - '0'; break; case'a': case'b': case'c': case'd': case'e': case'f':
value = (value << 4) + 10 + c - 'a'; break; case'A': case'B': case'C': case'D': case'E': case'F':
value = (value << 4) + 10 + c - 'A'; break; default:
ShouldNotReachHere();
}
} return value;
}
void HashtableTextDump::get_utf8(char* utf8_buffer, int utf8_length) { // cache in local vars constchar* from = _p; constchar* end = _end; char* to = utf8_buffer; int n = utf8_length;
for (; n > 0 && from < end; n--) { if (*from != '\\') {
*to++ = *from++;
} else {
corrupted_if(from + 2 > end, "Truncated"); char c = from[1];
from += 2; switch (c) { case'x':
{
jchar value = unescape(from, end, 2);
from += 2;
assert(value <= 0xff, "sanity");
*to++ = (char)(value & 0xff);
} break; case't': *to++ = '\t'; break; case'n': *to++ = '\n'; break; case'r': *to++ = '\r'; break; case'\\': *to++ = '\\'; break; default:
corrupted(_p, "Unsupported character");
}
}
}
corrupted_if(n > 0, "Truncated"); // expected more chars but file has ended
_p = from;
skip_newline();
}
// NOTE: the content is NOT the same as // UTF8::as_quoted_ascii(const char* utf8_str, int utf8_length, char* buf, int buflen). // We want to escape \r\n\t so that output [1] is more readable; [2] can be more easily // parsed by scripts; [3] quickly processed by HashtableTextDump::get_utf8() void HashtableTextDump::put_utf8(outputStream* st, constchar* utf8_string, int utf8_length) { constchar *c = utf8_string; constchar *end = c + utf8_length; for (; c < end; c++) { switch (*c) { case'\t': st->print("\\t"); break; case'\r': st->print("\\r"); break; case'\n': st->print("\\n"); break; case'\\': st->print("\\\\"); break; default: if (isprint(*c)) {
st->print("%c", *c);
} else {
st->print("\\x%02x", ((unsignedint)*c) & 0xff);
}
}
}
}
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.