Skip to content

Commit 86b9fce

Browse files
calvinccheungrobehn
andcommitted
8301992: Embed SymbolTable CHT node
Co-authored-by: Robbin Ehn <rehn@openjdk.org> Reviewed-by: coleenp, iklam
1 parent 03d613b commit 86b9fce

File tree

4 files changed

+114
-132
lines changed

4 files changed

+114
-132
lines changed

src/hotspot/share/classfile/symbolTable.cpp

+102-91
Original file line numberDiff line numberDiff line change
@@ -126,39 +126,84 @@ static uintx hash_shared_symbol(const char* s, int len) {
126126
#endif
127127

128128
class SymbolTableConfig : public AllStatic {
129-
private:
129+
130130
public:
131-
typedef Symbol* Value; // value of the Node in the hashtable
131+
typedef Symbol Value; // value of the Node in the hashtable
132132

133133
static uintx get_hash(Value const& value, bool* is_dead) {
134-
*is_dead = (value->refcount() == 0);
134+
*is_dead = (value.refcount() == 0);
135135
if (*is_dead) {
136136
return 0;
137137
} else {
138-
return hash_symbol((const char*)value->bytes(), value->utf8_length(), _alt_hash);
138+
return hash_symbol((const char*)value.bytes(), value.utf8_length(), _alt_hash);
139139
}
140140
}
141141
// We use default allocation/deallocation but counted
142142
static void* allocate_node(void* context, size_t size, Value const& value) {
143143
SymbolTable::item_added();
144-
return AllocateHeap(size, mtSymbol);
144+
return allocate_node_impl(size, value);
145145
}
146-
static void free_node(void* context, void* memory, Value const& value) {
146+
static void free_node(void* context, void* memory, Value & value) {
147147
// We get here because #1 some threads lost a race to insert a newly created Symbol
148148
// or #2 we're cleaning up unused symbol.
149149
// If #1, then the symbol can be either permanent,
150150
// or regular newly created one (refcount==1)
151151
// If #2, then the symbol is dead (refcount==0)
152-
assert(value->is_permanent() || (value->refcount() == 1) || (value->refcount() == 0),
153-
"refcount %d", value->refcount());
154-
if (value->refcount() == 1) {
155-
value->decrement_refcount();
156-
assert(value->refcount() == 0, "expected dead symbol");
152+
assert(value.is_permanent() || (value.refcount() == 1) || (value.refcount() == 0),
153+
"refcount %d", value.refcount());
154+
#if INCLUDE_CDS
155+
if (DumpSharedSpaces) {
156+
// no deallocation is needed
157+
return;
158+
}
159+
#endif
160+
if (value.refcount() == 1) {
161+
value.decrement_refcount();
162+
assert(value.refcount() == 0, "expected dead symbol");
163+
}
164+
if (value.refcount() != PERM_REFCOUNT) {
165+
FreeHeap(memory);
166+
} else {
167+
MutexLocker ml(SymbolArena_lock, Mutex::_no_safepoint_check_flag); // Protect arena
168+
// Deleting permanent symbol should not occur very often (insert race condition),
169+
// so log it.
170+
log_trace_symboltable_helper(&value, "Freeing permanent symbol");
171+
size_t alloc_size = _local_table->get_node_size() + value.byte_size() + value.effective_length();
172+
if (!SymbolTable::arena()->Afree(memory, alloc_size)) {
173+
log_trace_symboltable_helper(&value, "Leaked permanent symbol");
174+
}
157175
}
158-
SymbolTable::delete_symbol(value);
159-
FreeHeap(memory);
160176
SymbolTable::item_removed();
161177
}
178+
179+
private:
180+
static void* allocate_node_impl(size_t size, Value const& value) {
181+
size_t alloc_size = size + value.byte_size() + value.effective_length();
182+
#if INCLUDE_CDS
183+
if (DumpSharedSpaces) {
184+
MutexLocker ml(DumpRegion_lock, Mutex::_no_safepoint_check_flag);
185+
// To get deterministic output from -Xshare:dump, we ensure that Symbols are allocated in
186+
// increasing addresses. When the symbols are copied into the archive, we preserve their
187+
// relative address order (sorted, see ArchiveBuilder::gather_klasses_and_symbols).
188+
//
189+
// We cannot use arena because arena chunks are allocated by the OS. As a result, for example,
190+
// the archived symbol of "java/lang/Object" may sometimes be lower than "java/lang/String", and
191+
// sometimes be higher. This would cause non-deterministic contents in the archive.
192+
DEBUG_ONLY(static void* last = 0);
193+
void* p = (void*)MetaspaceShared::symbol_space_alloc(alloc_size);
194+
assert(p > last, "must increase monotonically");
195+
DEBUG_ONLY(last = p);
196+
return p;
197+
}
198+
#endif
199+
if (value.refcount() != PERM_REFCOUNT) {
200+
return AllocateHeap(alloc_size, mtSymbol);
201+
} else {
202+
// Allocate to global arena
203+
MutexLocker ml(SymbolArena_lock, Mutex::_no_safepoint_check_flag); // Protect arena
204+
return SymbolTable::arena()->Amalloc(alloc_size);
205+
}
206+
}
162207
};
163208

164209
void SymbolTable::create_table () {
@@ -176,20 +221,6 @@ void SymbolTable::create_table () {
176221
}
177222
}
178223

179-
void SymbolTable::delete_symbol(Symbol* sym) {
180-
if (sym->is_permanent()) {
181-
MutexLocker ml(SymbolArena_lock, Mutex::_no_safepoint_check_flag); // Protect arena
182-
// Deleting permanent symbol should not occur very often (insert race condition),
183-
// so log it.
184-
log_trace_symboltable_helper(sym, "Freeing permanent symbol");
185-
if (!arena()->Afree(sym, sym->size())) {
186-
log_trace_symboltable_helper(sym, "Leaked permanent symbol");
187-
}
188-
} else {
189-
delete sym;
190-
}
191-
}
192-
193224
void SymbolTable::reset_has_items_to_clean() { Atomic::store(&_has_items_to_clean, false); }
194225
void SymbolTable::mark_has_items_to_clean() { Atomic::store(&_has_items_to_clean, true); }
195226
bool SymbolTable::has_items_to_clean() { return Atomic::load(&_has_items_to_clean); }
@@ -217,39 +248,13 @@ void SymbolTable::trigger_cleanup() {
217248
Service_lock->notify_all();
218249
}
219250

220-
Symbol* SymbolTable::allocate_symbol(const char* name, int len, bool c_heap) {
221-
assert (len <= Symbol::max_length(), "should be checked by caller");
222-
223-
Symbol* sym;
224-
if (DumpSharedSpaces) {
225-
// TODO: Special handling of Symbol allocation for DumpSharedSpaces will be removed
226-
// in JDK-8250989
227-
c_heap = false;
228-
}
229-
if (c_heap) {
230-
// refcount starts as 1
231-
sym = new (len) Symbol((const u1*)name, len, 1);
232-
assert(sym != nullptr, "new should call vm_exit_out_of_memory if C_HEAP is exhausted");
233-
} else if (DumpSharedSpaces) {
234-
// See comments inside Symbol::operator new(size_t, int)
235-
sym = new (len) Symbol((const u1*)name, len, PERM_REFCOUNT);
236-
assert(sym != nullptr, "new should call vm_exit_out_of_memory if failed to allocate symbol during DumpSharedSpaces");
237-
} else {
238-
// Allocate to global arena
239-
MutexLocker ml(SymbolArena_lock, Mutex::_no_safepoint_check_flag); // Protect arena
240-
sym = new (len, arena()) Symbol((const u1*)name, len, PERM_REFCOUNT);
241-
}
242-
return sym;
243-
}
244-
245251
class SymbolsDo : StackObj {
246252
SymbolClosure *_cl;
247253
public:
248254
SymbolsDo(SymbolClosure *cl) : _cl(cl) {}
249-
bool operator()(Symbol** value) {
255+
bool operator()(Symbol* value) {
250256
assert(value != nullptr, "expected valid value");
251-
assert(*value != nullptr, "value should point to a symbol");
252-
_cl->do_symbol(value);
257+
_cl->do_symbol(&value);
253258
return true;
254259
};
255260
};
@@ -334,7 +339,7 @@ Symbol* SymbolTable::new_symbol(const char* name, int len) {
334339
unsigned int hash = hash_symbol(name, len, _alt_hash);
335340
Symbol* sym = lookup_common(name, len, hash);
336341
if (sym == nullptr) {
337-
sym = do_add_if_needed(name, len, hash, true);
342+
sym = do_add_if_needed(name, len, hash, /* is_permanent */ false);
338343
}
339344
assert(sym->refcount() != 0, "lookup should have incremented the count");
340345
assert(sym->equals(name, len), "symbol must be properly initialized");
@@ -349,7 +354,7 @@ Symbol* SymbolTable::new_symbol(const Symbol* sym, int begin, int end) {
349354
unsigned int hash = hash_symbol(name, len, _alt_hash);
350355
Symbol* found = lookup_common(name, len, hash);
351356
if (found == nullptr) {
352-
found = do_add_if_needed(name, len, hash, true);
357+
found = do_add_if_needed(name, len, hash, /* is_permanent */ false);
353358
}
354359
return found;
355360
}
@@ -365,10 +370,9 @@ class SymbolTableLookup : StackObj {
365370
uintx get_hash() const {
366371
return _hash;
367372
}
368-
bool equals(Symbol** value, bool* is_dead) {
373+
bool equals(Symbol* value, bool* is_dead) {
369374
assert(value != nullptr, "expected valid value");
370-
assert(*value != nullptr, "value should point to a symbol");
371-
Symbol *sym = *value;
375+
Symbol *sym = value;
372376
if (sym->equals(_str, _len)) {
373377
if (sym->try_increment_refcount()) {
374378
// something is referencing this symbol now.
@@ -389,10 +393,9 @@ class SymbolTableGet : public StackObj {
389393
Symbol* _return;
390394
public:
391395
SymbolTableGet() : _return(nullptr) {}
392-
void operator()(Symbol** value) {
396+
void operator()(Symbol* value) {
393397
assert(value != nullptr, "expected valid value");
394-
assert(*value != nullptr, "value should point to a symbol");
395-
_return = *value;
398+
_return = value;
396399
}
397400
Symbol* get_res_sym() const {
398401
return _return;
@@ -453,37 +456,51 @@ Symbol* SymbolTable::lookup_only_unicode(const jchar* name, int utf16_length,
453456
void SymbolTable::new_symbols(ClassLoaderData* loader_data, const constantPoolHandle& cp,
454457
int names_count, const char** names, int* lengths,
455458
int* cp_indices, unsigned int* hashValues) {
456-
// Note that c_heap will be true for non-strong hidden classes.
459+
// Note that is_permanent will be false for non-strong hidden classes.
457460
// even if their loader is the boot loader because they will have a different cld.
458-
bool c_heap = !loader_data->is_the_null_class_loader_data();
461+
bool is_permanent = loader_data->is_the_null_class_loader_data();
459462
for (int i = 0; i < names_count; i++) {
460463
const char *name = names[i];
461464
int len = lengths[i];
462465
unsigned int hash = hashValues[i];
463466
assert(lookup_shared(name, len, hash) == nullptr, "must have checked already");
464-
Symbol* sym = do_add_if_needed(name, len, hash, c_heap);
467+
Symbol* sym = do_add_if_needed(name, len, hash, is_permanent);
465468
assert(sym->refcount() != 0, "lookup should have incremented the count");
466469
cp->symbol_at_put(cp_indices[i], sym);
467470
}
468471
}
469472

470-
Symbol* SymbolTable::do_add_if_needed(const char* name, int len, uintx hash, bool heap) {
473+
Symbol* SymbolTable::do_add_if_needed(const char* name, int len, uintx hash, bool is_permanent) {
471474
SymbolTableLookup lookup(name, len, hash);
472475
SymbolTableGet stg;
473476
bool clean_hint = false;
474477
bool rehash_warning = false;
475-
Symbol* sym = nullptr;
476478
Thread* current = Thread::current();
479+
Symbol* sym;
480+
481+
ResourceMark rm(current);
482+
const int alloc_size = Symbol::byte_size(len);
483+
u1* u1_buf = NEW_RESOURCE_ARRAY_IN_THREAD(current, u1, alloc_size);
484+
Symbol* tmp = ::new ((void*)u1_buf) Symbol((const u1*)name, len,
485+
(is_permanent || DumpSharedSpaces) ? PERM_REFCOUNT : 1);
477486

478487
do {
479-
// Callers have looked up the symbol once, insert the symbol.
480-
sym = allocate_symbol(name, len, heap);
481-
if (_local_table->insert(current, lookup, sym, &rehash_warning, &clean_hint)) {
482-
break;
488+
if (_local_table->insert(current, lookup, *tmp, &rehash_warning, &clean_hint)) {
489+
if (_local_table->get(current, lookup, stg, &rehash_warning)) {
490+
sym = stg.get_res_sym();
491+
// The get adds one to ref count, but we inserted with our ref already included.
492+
// Therefore decrement with one.
493+
if (sym->refcount() != PERM_REFCOUNT) {
494+
sym->decrement_refcount();
495+
}
496+
break;
497+
}
483498
}
499+
484500
// In case another thread did a concurrent add, return value already in the table.
485501
// This could fail if the symbol got deleted concurrently, so loop back until success.
486502
if (_local_table->get(current, lookup, stg, &rehash_warning)) {
503+
// The lookup added a refcount, which is ours.
487504
sym = stg.get_res_sym();
488505
break;
489506
}
@@ -505,7 +522,7 @@ Symbol* SymbolTable::new_permanent_symbol(const char* name) {
505522
int len = (int)strlen(name);
506523
Symbol* sym = SymbolTable::lookup_only(name, len, hash);
507524
if (sym == nullptr) {
508-
sym = do_add_if_needed(name, len, hash, false);
525+
sym = do_add_if_needed(name, len, hash, /* is_permanent */ true);
509526
}
510527
if (!sym->is_permanent()) {
511528
sym->make_permanent();
@@ -515,10 +532,9 @@ Symbol* SymbolTable::new_permanent_symbol(const char* name) {
515532
}
516533

517534
struct SizeFunc : StackObj {
518-
size_t operator()(Symbol** value) {
535+
size_t operator()(Symbol* value) {
519536
assert(value != nullptr, "expected valid value");
520-
assert(*value != nullptr, "value should point to a symbol");
521-
return (*value)->size() * HeapWordSize;
537+
return (value)->size() * HeapWordSize;
522538
};
523539
};
524540

@@ -545,10 +561,9 @@ void SymbolTable::print_table_statistics(outputStream* st) {
545561
// Verification
546562
class VerifySymbols : StackObj {
547563
public:
548-
bool operator()(Symbol** value) {
564+
bool operator()(Symbol* value) {
549565
guarantee(value != nullptr, "expected valid value");
550-
guarantee(*value != nullptr, "value should point to a symbol");
551-
Symbol* sym = *value;
566+
Symbol* sym = value;
552567
guarantee(sym->equals((const char*)sym->bytes(), sym->utf8_length()),
553568
"symbol must be internally consistent");
554569
return true;
@@ -577,10 +592,9 @@ class DumpSymbol : StackObj {
577592
outputStream* _st;
578593
public:
579594
DumpSymbol(Thread* thr, outputStream* st) : _thr(thr), _st(st) {}
580-
bool operator()(Symbol** value) {
595+
bool operator()(Symbol* value) {
581596
assert(value != nullptr, "expected valid value");
582-
assert(*value != nullptr, "value should point to a symbol");
583-
print_symbol(_st, *value);
597+
print_symbol(_st, value);
584598
return true;
585599
};
586600
};
@@ -695,10 +709,9 @@ void SymbolTable::grow(JavaThread* jt) {
695709
struct SymbolTableDoDelete : StackObj {
696710
size_t _deleted;
697711
SymbolTableDoDelete() : _deleted(0) {}
698-
void operator()(Symbol** value) {
712+
void operator()(Symbol* value) {
699713
assert(value != nullptr, "expected valid value");
700-
assert(*value != nullptr, "value should point to a symbol");
701-
Symbol *sym = *value;
714+
Symbol *sym = value;
702715
assert(sym->refcount() == 0, "refcount");
703716
_deleted++;
704717
}
@@ -707,11 +720,10 @@ struct SymbolTableDoDelete : StackObj {
707720
struct SymbolTableDeleteCheck : StackObj {
708721
size_t _processed;
709722
SymbolTableDeleteCheck() : _processed(0) {}
710-
bool operator()(Symbol** value) {
723+
bool operator()(Symbol* value) {
711724
assert(value != nullptr, "expected valid value");
712-
assert(*value != nullptr, "value should point to a symbol");
713725
_processed++;
714-
Symbol *sym = *value;
726+
Symbol *sym = value;
715727
return (sym->refcount() == 0);
716728
}
717729
};
@@ -849,10 +861,9 @@ class HistogramIterator : StackObj {
849861
sizes[i] = 0;
850862
}
851863
}
852-
bool operator()(Symbol** value) {
864+
bool operator()(Symbol* value) {
853865
assert(value != nullptr, "expected valid value");
854-
assert(*value != nullptr, "value should point to a symbol");
855-
Symbol* sym = *value;
866+
Symbol* sym = value;
856867
size_t size = sym->size();
857868
size_t len = sym->utf8_length();
858869
if (len < results_length) {

src/hotspot/share/classfile/symbolTable.hpp

+1-3
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ class SymbolTable : public AllStatic {
5959
// Set if one bucket is out of balance due to hash algorithm deficiency
6060
static volatile bool _needs_rehashing;
6161

62-
static void delete_symbol(Symbol* sym);
6362
static void grow(JavaThread* jt);
6463
static void clean_dead_entries(JavaThread* jt);
6564

@@ -75,9 +74,8 @@ class SymbolTable : public AllStatic {
7574
static void mark_has_items_to_clean();
7675
static bool has_items_to_clean();
7776

78-
static Symbol* allocate_symbol(const char* name, int len, bool c_heap); // Assumes no characters larger than 0x7F
7977
static Symbol* do_lookup(const char* name, int len, uintx hash);
80-
static Symbol* do_add_if_needed(const char* name, int len, uintx hash, bool heap);
78+
static Symbol* do_add_if_needed(const char* name, int len, uintx hash, bool is_permanent);
8179

8280
// lookup only, won't add. Also calculate hash. Used by the ClassfileParser.
8381
static Symbol* lookup_only(const char* name, int len, unsigned int& hash);

0 commit comments

Comments
 (0)