@@ -126,39 +126,84 @@ static uintx hash_shared_symbol(const char* s, int len) {
126
126
#endif
127
127
128
128
class SymbolTableConfig : public AllStatic {
129
- private:
129
+
130
130
public:
131
- typedef Symbol* Value; // value of the Node in the hashtable
131
+ typedef Symbol Value; // value of the Node in the hashtable
132
132
133
133
static uintx get_hash (Value const & value, bool * is_dead) {
134
- *is_dead = (value-> refcount () == 0 );
134
+ *is_dead = (value. refcount () == 0 );
135
135
if (*is_dead) {
136
136
return 0 ;
137
137
} 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);
139
139
}
140
140
}
141
141
// We use default allocation/deallocation but counted
142
142
static void * allocate_node (void * context, size_t size, Value const & value) {
143
143
SymbolTable::item_added ();
144
- return AllocateHeap (size, mtSymbol );
144
+ return allocate_node_impl (size, value );
145
145
}
146
- static void free_node (void * context, void * memory, Value const & value) {
146
+ static void free_node (void * context, void * memory, Value & value) {
147
147
// We get here because #1 some threads lost a race to insert a newly created Symbol
148
148
// or #2 we're cleaning up unused symbol.
149
149
// If #1, then the symbol can be either permanent,
150
150
// or regular newly created one (refcount==1)
151
151
// 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
+ }
157
175
}
158
- SymbolTable::delete_symbol (value);
159
- FreeHeap (memory);
160
176
SymbolTable::item_removed ();
161
177
}
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
+ }
162
207
};
163
208
164
209
void SymbolTable::create_table () {
@@ -176,20 +221,6 @@ void SymbolTable::create_table () {
176
221
}
177
222
}
178
223
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
-
193
224
void SymbolTable::reset_has_items_to_clean () { Atomic::store (&_has_items_to_clean, false ); }
194
225
void SymbolTable::mark_has_items_to_clean () { Atomic::store (&_has_items_to_clean, true ); }
195
226
bool SymbolTable::has_items_to_clean () { return Atomic::load (&_has_items_to_clean); }
@@ -217,39 +248,13 @@ void SymbolTable::trigger_cleanup() {
217
248
Service_lock->notify_all ();
218
249
}
219
250
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
-
245
251
class SymbolsDo : StackObj {
246
252
SymbolClosure *_cl;
247
253
public:
248
254
SymbolsDo (SymbolClosure *cl) : _cl(cl) {}
249
- bool operator ()(Symbol** value) {
255
+ bool operator ()(Symbol* value) {
250
256
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);
253
258
return true ;
254
259
};
255
260
};
@@ -334,7 +339,7 @@ Symbol* SymbolTable::new_symbol(const char* name, int len) {
334
339
unsigned int hash = hash_symbol (name, len, _alt_hash);
335
340
Symbol* sym = lookup_common (name, len, hash);
336
341
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 );
338
343
}
339
344
assert (sym->refcount () != 0 , " lookup should have incremented the count" );
340
345
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) {
349
354
unsigned int hash = hash_symbol (name, len, _alt_hash);
350
355
Symbol* found = lookup_common (name, len, hash);
351
356
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 );
353
358
}
354
359
return found;
355
360
}
@@ -365,10 +370,9 @@ class SymbolTableLookup : StackObj {
365
370
uintx get_hash () const {
366
371
return _hash;
367
372
}
368
- bool equals (Symbol** value, bool * is_dead) {
373
+ bool equals (Symbol* value, bool * is_dead) {
369
374
assert (value != nullptr , " expected valid value" );
370
- assert (*value != nullptr , " value should point to a symbol" );
371
- Symbol *sym = *value;
375
+ Symbol *sym = value;
372
376
if (sym->equals (_str, _len)) {
373
377
if (sym->try_increment_refcount ()) {
374
378
// something is referencing this symbol now.
@@ -389,10 +393,9 @@ class SymbolTableGet : public StackObj {
389
393
Symbol* _return;
390
394
public:
391
395
SymbolTableGet () : _return(nullptr ) {}
392
- void operator ()(Symbol** value) {
396
+ void operator ()(Symbol* value) {
393
397
assert (value != nullptr , " expected valid value" );
394
- assert (*value != nullptr , " value should point to a symbol" );
395
- _return = *value;
398
+ _return = value;
396
399
}
397
400
Symbol* get_res_sym () const {
398
401
return _return;
@@ -453,37 +456,51 @@ Symbol* SymbolTable::lookup_only_unicode(const jchar* name, int utf16_length,
453
456
void SymbolTable::new_symbols (ClassLoaderData* loader_data, const constantPoolHandle& cp,
454
457
int names_count, const char ** names, int * lengths,
455
458
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.
457
460
// 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 ();
459
462
for (int i = 0 ; i < names_count; i++) {
460
463
const char *name = names[i];
461
464
int len = lengths[i];
462
465
unsigned int hash = hashValues[i];
463
466
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 );
465
468
assert (sym->refcount () != 0 , " lookup should have incremented the count" );
466
469
cp->symbol_at_put (cp_indices[i], sym);
467
470
}
468
471
}
469
472
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 ) {
471
474
SymbolTableLookup lookup (name, len, hash);
472
475
SymbolTableGet stg;
473
476
bool clean_hint = false ;
474
477
bool rehash_warning = false ;
475
- Symbol* sym = nullptr ;
476
478
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 );
477
486
478
487
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
+ }
483
498
}
499
+
484
500
// In case another thread did a concurrent add, return value already in the table.
485
501
// This could fail if the symbol got deleted concurrently, so loop back until success.
486
502
if (_local_table->get (current, lookup, stg, &rehash_warning)) {
503
+ // The lookup added a refcount, which is ours.
487
504
sym = stg.get_res_sym ();
488
505
break ;
489
506
}
@@ -505,7 +522,7 @@ Symbol* SymbolTable::new_permanent_symbol(const char* name) {
505
522
int len = (int )strlen (name);
506
523
Symbol* sym = SymbolTable::lookup_only (name, len, hash);
507
524
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 );
509
526
}
510
527
if (!sym->is_permanent ()) {
511
528
sym->make_permanent ();
@@ -515,10 +532,9 @@ Symbol* SymbolTable::new_permanent_symbol(const char* name) {
515
532
}
516
533
517
534
struct SizeFunc : StackObj {
518
- size_t operator ()(Symbol** value) {
535
+ size_t operator ()(Symbol* value) {
519
536
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;
522
538
};
523
539
};
524
540
@@ -545,10 +561,9 @@ void SymbolTable::print_table_statistics(outputStream* st) {
545
561
// Verification
546
562
class VerifySymbols : StackObj {
547
563
public:
548
- bool operator ()(Symbol** value) {
564
+ bool operator ()(Symbol* value) {
549
565
guarantee (value != nullptr , " expected valid value" );
550
- guarantee (*value != nullptr , " value should point to a symbol" );
551
- Symbol* sym = *value;
566
+ Symbol* sym = value;
552
567
guarantee (sym->equals ((const char *)sym->bytes (), sym->utf8_length ()),
553
568
" symbol must be internally consistent" );
554
569
return true ;
@@ -577,10 +592,9 @@ class DumpSymbol : StackObj {
577
592
outputStream* _st;
578
593
public:
579
594
DumpSymbol (Thread* thr, outputStream* st) : _thr(thr), _st(st) {}
580
- bool operator ()(Symbol** value) {
595
+ bool operator ()(Symbol* value) {
581
596
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);
584
598
return true ;
585
599
};
586
600
};
@@ -695,10 +709,9 @@ void SymbolTable::grow(JavaThread* jt) {
695
709
struct SymbolTableDoDelete : StackObj {
696
710
size_t _deleted;
697
711
SymbolTableDoDelete () : _deleted(0 ) {}
698
- void operator ()(Symbol** value) {
712
+ void operator ()(Symbol* value) {
699
713
assert (value != nullptr , " expected valid value" );
700
- assert (*value != nullptr , " value should point to a symbol" );
701
- Symbol *sym = *value;
714
+ Symbol *sym = value;
702
715
assert (sym->refcount () == 0 , " refcount" );
703
716
_deleted++;
704
717
}
@@ -707,11 +720,10 @@ struct SymbolTableDoDelete : StackObj {
707
720
struct SymbolTableDeleteCheck : StackObj {
708
721
size_t _processed;
709
722
SymbolTableDeleteCheck () : _processed(0 ) {}
710
- bool operator ()(Symbol** value) {
723
+ bool operator ()(Symbol* value) {
711
724
assert (value != nullptr , " expected valid value" );
712
- assert (*value != nullptr , " value should point to a symbol" );
713
725
_processed++;
714
- Symbol *sym = * value;
726
+ Symbol *sym = value;
715
727
return (sym->refcount () == 0 );
716
728
}
717
729
};
@@ -849,10 +861,9 @@ class HistogramIterator : StackObj {
849
861
sizes[i] = 0 ;
850
862
}
851
863
}
852
- bool operator ()(Symbol** value) {
864
+ bool operator ()(Symbol* value) {
853
865
assert (value != nullptr , " expected valid value" );
854
- assert (*value != nullptr , " value should point to a symbol" );
855
- Symbol* sym = *value;
866
+ Symbol* sym = value;
856
867
size_t size = sym->size ();
857
868
size_t len = sym->utf8_length ();
858
869
if (len < results_length) {
0 commit comments