RFR (M) 8207359: Make SymbolTable increment_refcount disallow zero

Ioi Lam ioi.lam at oracle.com
Wed Jul 18 21:14:53 UTC 2018


Hi Coleen,

The changes look good! The new operations on _length_and_refcount are 
much cleaner than my old ATOMIC_SHORT_PAIR hack.

symbolTable.cpp:

  SymbolTable::lookup_dynamic() {
  ...
  214       Symbol* sym = e->literal();
  215       if (sym->equals(name, len) && sym->try_increment_refcount()) {
  216         // something is referencing this symbol now.
  217         return sym;
  218       }


symbol.cpp:

  221 void Symbol::increment_refcount() {
  222   if (refcount() != PERM_REFCOUNT) { // not a permanent symbol
  223     if (!try_increment_refcount()) {
  224 #ifdef ASSERT
  225       print();
  226 #endif
  227       fatal("refcount has gone to zero");
  228     }
  229     NOT_PRODUCT(Atomic::inc(&_total_count);)
  230   }
  231 }

  246 // Atomically increment while checking for zero, zero is bad.
  247 bool Symbol::try_increment_refcount() {
  248   uint32_t old_value = _length_and_refcount;  // fetch once
  249   int refc = extract_refcount(old_value);
  250
  251   if (refc == PERM_REFCOUNT) {
  252     return true;
  253   } else if (refc == 0) {
  254     return false; // effectively dead, can't revive
  255   }
  256
  257   uint32_t now;
  258   while ((now = Atomic::cmpxchg(old_value + 1, 
&_length_and_refcount, old_value)) != old_value) {
  259     // failed to increment, check refcount again.
  260     refc = extract_refcount(now);
  261     if (refc == 0) {
  262       return false; // just died
  263     } else if (refc == PERM_REFCOUNT) {
  264       return true; // just became permanent
  265     }
  266     old_value = now; // refcount changed, try again
  267   }
  268   return true;
  269 }


So is it valid for Symbol::try_increment_refcount() to return false? 
SymbolTable::lookup_dynamic() seems to suggest YES, but 
Symbol::increment_refcount() seems to suggest NO.

If it's always an invalid condition, I think the fatal() should be moved 
inside try_increment_refcount.

Otherwise, I think you need to add comments in all 3 places, to say when 
it's possible to get a 0 refcount, and when it's not. And, it might be 
worth expanding on why "zero is bad" :-)

My guess is:
+ if you're doing a lookup, you might be seeing Symbols that have 
already been marked for deletion, which is indicated by a 0 refcount. 
You want to skip such Symbols.

+ if you're incrementing the refcount, that means you're holding a valid 
Symbol, which means this Symbol should have never been marked for deletion.

Is this correct?

Thanks
- Ioi


On 7/17/18 2:08 PM, coleen.phillimore at oracle.com wrote:
>
> Gerard, thank you for the code review.
>
> On 7/17/18 4:13 PM, Gerard Ziemski wrote:
>> Thank you Coleen (and Kim)!
>>
>> #1 Need copyright year updates:
>>
>> src/hotspot/share/oops/symbol.cpp
>> src/hotspot/share/classfile/symbolTable.cpp
>> src/hotspot/share/classfile/compactHashtable.inline.hpp
>
> Yes, I'll update with my commit.
>>
>> #2 What’s the purpose of this code in src/hotspot/share/oops/symbol.cpp
>>
>>    38   STATIC_ASSERT(max_symbol_length == ((1 << 16) - 1));
>>
>> when we have:
>>
>>   117   enum {
>>   118     // max_symbol_length is constrained by type of _length
>>   119     max_symbol_length = (1 << 16) -1
>>   120   };
>>
>> Wouldn’t that always be true?  Is it to make sure that nobody changes 
>> max_symbol_length, because the implementation needs it to be that? If 
>> so, should we add comment to:
>>
>>   119     max_symbol_length = (1 << 16) -1
>>
>> with a big warning of some sorts?
>
> Yes, it's so that we can store the length of the symbol into 16 bits.
>
> How I change the comment above max_symbol_length from:
>
>     // max_symbol_length is constrained by type of _length
>
> to
>
>     // max_symbol_length must fit into the top 16 bits of 
> _length_and_refcount
>
>>
>> #3 If we have:
>>
>>    39   STATIC_ASSERT(PERM_REFCOUNT == ((1 << 16) - 1));
>>
>> then why not
>>
>>   101 #define PERM_REFCOUNT ((1 << 16) - 1)) // 0xffff
>>
>> or
>>    39   STATIC_ASSERT(PERM_REFCOUNT == 0xffff;
>>   101 #define PERM_REFCOUNT 0xffff
>>
> I can change PERM_REFCOUNT to ((1 << 16)) -1) to be consistent.
>
>> #4 We have:
>>
>>   221 void Symbol::increment_refcount() {
>>   222   if (refcount() != PERM_REFCOUNT) { // not a permanent symbol
>>   223     if (!try_increment_refcount()) {
>>   224 #ifdef ASSERT
>>   225       print();
>>   226 #endif
>>   227       fatal("refcount has gone to zero");
>>
>> but
>>
>>   233 void Symbol::decrement_refcount() {
>>   234   if (refcount() != PERM_REFCOUNT) { // not a permanent symbol
>>   235     int new_value = Atomic::sub((uint32_t)1, 
>> &_length_and_refcount);
>>   236 #ifdef ASSERT
>>   237     // Check if we have transitioned to 0xffff
>>   238     if (extract_refcount(new_value) == PERM_REFCOUNT) {
>>   239       print();
>>   240       fatal("refcount underflow");
>>   241     }
>>   242 #endif
>>
>> Where the line:
>>
>>   240       fatal("refcount underflow”);
>>
>> is inside #ifdef ASSERT, but:
>>
>> 227       fatal("refcount has gone to zero”);
>>
>> is outside. Shouldn't “fatal" be consistent in both?
>>
>
> I was thought that looked strange too.  I'll move the #endif from 226 
> to after 227.
>
> Thank you for reviewing the code!
> Coleen
>
>> cheers
>>
>>
>>> On Jul 17, 2018, at 10:51 AM, coleen.phillimore at oracle.com wrote:
>>>
>>> Summary: Use cmpxchg for non permanent symbol refcounting, and pack 
>>> refcount and length into an int.
>>>
>>> This is a precurser change to the concurrent SymbolTable change. 
>>> Zeroed refcounted entries can be deleted at anytime so they cannot 
>>> be allowed to be zero in runtime code.  Thanks to Kim for writing 
>>> the packing function and helping me avoid undefined behavior.
>>>
>>> open webrev at http://cr.openjdk.java.net/~coleenp/8207359.01/webrev
>>> bug link https://bugs.openjdk.java.net/browse/JDK-8207359
>>>
>>> Tested with solaris ptrace helper, mach5 tier1-5 including solaris. 
>>> Added multithreaded gtest which exercises the code.
>>>
>>> Thanks,
>>> Coleen
>



More information about the hotspot-runtime-dev mailing list