--- old/src/share/vm/classfile/symbolTable.hpp 2016-01-13 11:26:15.505861367 -0500 +++ new/src/share/vm/classfile/symbolTable.hpp 2016-01-13 11:26:15.065208859 -0500 @@ -42,8 +42,17 @@ class BoolObjectClosure; class outputStream; -// Class to hold a newly created or referenced Symbol* temporarily in scope. -// new_symbol() and lookup() will create a Symbol* if not already in the +// TempNewSymbol acts as a handle class in a handle/body idiom and is +// responsible for proper resource management of the body (which is a Symbol*). +// The body is resource managed by a reference counting scheme. +// TempNewSymbol can therefore be used to properly hold a newly created or referenced +// Symbol* temporarily in scope. +// +// Routines in SymbolTable will initialize the reference count of a Symbol* before +// it becomes "managed" by TempNewSymbol instances. As a handle class, TempNewSymbol +// needs to maintain proper reference counting in context of copy semantics. +// +// In SymbolTable, new_symbol() and lookup() will create a Symbol* if not already in the // symbol table and add to the symbol's reference count. // probe() and lookup_only() will increment the refcount if symbol is found. class TempNewSymbol : public StackObj { @@ -51,25 +60,37 @@ public: TempNewSymbol() : _temp(NULL) {} - // Creating or looking up a symbol increments the symbol's reference count + + // Conversion from a Symbol* to a TempNewSymbol. + // Does not increment the current reference count. TempNewSymbol(Symbol *s) : _temp(s) {} - // Operator= increments reference count. - void operator=(const TempNewSymbol &s) { - //clear(); //FIXME - _temp = s._temp; - if (_temp !=NULL) _temp->increment_refcount(); + // Copy constructor increments reference count. + TempNewSymbol(const TempNewSymbol& rhs) : _temp(rhs._temp) { + if (_temp != NULL) { + _temp->increment_refcount(); + } } - // Decrement reference counter so it can go away if it's unique - void clear() { if (_temp != NULL) _temp->decrement_refcount(); _temp = NULL; } + // Assignment operator uses a c++ trick called copy and swap idiom. + // The rhs is a copied so gets the new value incremented and is given the old + // temp which gets refcount for old _temp decremented. + void operator=(TempNewSymbol rhs) { + Symbol* tmp = rhs._temp; + rhs._temp = _temp; + _temp = tmp; + } - ~TempNewSymbol() { clear(); } + // Decrement reference counter so it can go away if it's unique + ~TempNewSymbol() { + if (_temp != NULL) { + _temp->decrement_refcount(); + } + } - // Operators so they can be used like Symbols + // Symbol* conversion operators Symbol* operator -> () const { return _temp; } bool operator == (Symbol* o) const { return _temp == o; } - // Sneaky conversion function operator Symbol*() { return _temp; } }; --- old/src/share/vm/classfile/symbolTable.cpp 2016-01-13 11:26:15.505874163 -0500 +++ new/src/share/vm/classfile/symbolTable.cpp 2016-01-13 11:26:15.070317560 -0500 @@ -667,3 +667,37 @@ return 0; } } + +#ifndef PRODUCT +// Internal test of TempNewSymbol +void Test_TempNewSymbol() { + Thread* THREAD = Thread::current(); + Symbol* sym = SymbolTable::new_symbol("abc", CATCH); + TempNewSymbol ss = sym; + assert(ss->refcount() == 1, "only one abc"); + assert(ss->refcount() == sym->refcount(), "should match TempNewSymbol"); + + Symbol* sym1 = SymbolTable::new_symbol("efg", CATCH); + Symbol* sym2 = SymbolTable::new_symbol("hij", CATCH); + TempNewSymbol s1 = sym1; + TempNewSymbol s2 = sym2; + assert(s1->refcount() == 1, "one efg"); + assert(s2->refcount() == 1, "one hij"); + + // Assignment operator + s1 = s2; + assert(sym2->refcount() == 2, "should be two hij"); + assert(sym1->refcount() == 0, "should be no efg"); + + s1 = ss; // s1 is abc + assert(s1->refcount() == 2, "should be two abc (s1 and ss)"); + assert(sym2->refcount() == 1, "should only have one hij now (s2)"); + + s1 = s1; // self assignment + assert(s1->refcount() == 2, "should still be two abc (s1 and ss)"); + + TempNewSymbol s3; + s3 = SymbolTable::new_symbol("klm", CATCH); + assert(s3->refcount() == 1, "only one klm now"); +} +#endif // PRODUCT --- old/src/share/vm/prims/jni.cpp 2016-01-13 11:26:15.474955363 -0500 +++ new/src/share/vm/prims/jni.cpp 2016-01-13 11:26:15.065444832 -0500 @@ -3889,6 +3889,7 @@ void TestResourcehash_test(); void TestChunkedList_test(); void Test_log_length(); +void Test_TempNewSymbol(); #if INCLUDE_ALL_GCS void TestOldFreeSpaceCalculation_test(); void TestG1BiasedArray_test(); @@ -3932,6 +3933,7 @@ run_unit_test(JSONTest::test()); run_unit_test(Test_log_length()); run_unit_test(DirectivesParser::test()); + run_unit_test(Test_TempNewSymbol()); #if INCLUDE_VM_STRUCTS run_unit_test(VMStructs::test()); #endif