Mon, 08 Sep 2014 17:47:43 +0200
8057722: G1: Code root hashtable updated incorrectly when evacuation failed
Reviewed-by: brutisso, jwilhelm
src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp | file | annotate | diff | comparison | revisions |
1.1 --- a/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp Fri Aug 29 13:12:21 2014 +0200 1.2 +++ b/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp Mon Sep 08 17:47:43 2014 +0200 1.3 @@ -48,6 +48,7 @@ 1.4 return hash ^ (hash >> 7); // code heap blocks are 128byte aligned 1.5 } 1.6 1.7 + void remove_entry(Entry* e, Entry* previous); 1.8 Entry* new_entry(nmethod* nm); 1.9 1.10 public: 1.11 @@ -67,7 +68,7 @@ 1.12 void nmethods_do(CodeBlobClosure* blk); 1.13 1.14 template<typename CB> 1.15 - void remove_if(CB& should_remove); 1.16 + int remove_if(CB& should_remove); 1.17 1.18 static void purge_list_append(CodeRootSetTable* tbl); 1.19 static void purge(); 1.20 @@ -91,6 +92,18 @@ 1.21 return entry; 1.22 } 1.23 1.24 +void CodeRootSetTable::remove_entry(Entry* e, Entry* previous) { 1.25 + int index = hash_to_index(e->hash()); 1.26 + assert((e == bucket(index)) == (previous == NULL), "if e is the first entry then previous should be null"); 1.27 + 1.28 + if (previous == NULL) { 1.29 + set_entry(index, e->next()); 1.30 + } else { 1.31 + previous->set_next(e->next()); 1.32 + } 1.33 + free_entry(e); 1.34 +} 1.35 + 1.36 CodeRootSetTable::~CodeRootSetTable() { 1.37 for (int index = 0; index < table_size(); ++index) { 1.38 for (Entry* e = bucket(index); e != NULL; ) { 1.39 @@ -133,12 +146,7 @@ 1.40 Entry* previous = NULL; 1.41 for (Entry* e = bucket(index); e != NULL; previous = e, e = e->next()) { 1.42 if (e->literal() == nm) { 1.43 - if (previous != NULL) { 1.44 - previous->set_next(e->next()); 1.45 - } else { 1.46 - set_entry(index, e->next()); 1.47 - } 1.48 - free_entry(e); 1.49 + remove_entry(e, previous); 1.50 return true; 1.51 } 1.52 } 1.53 @@ -163,25 +171,23 @@ 1.54 } 1.55 1.56 template<typename CB> 1.57 -void CodeRootSetTable::remove_if(CB& should_remove) { 1.58 +int CodeRootSetTable::remove_if(CB& should_remove) { 1.59 + int num_removed = 0; 1.60 for (int index = 0; index < table_size(); ++index) { 1.61 Entry* previous = NULL; 1.62 Entry* e = bucket(index); 1.63 while (e != NULL) { 1.64 Entry* next = e->next(); 1.65 if (should_remove(e->literal())) { 1.66 - if (previous != NULL) { 1.67 - previous->set_next(next); 1.68 - } else { 1.69 - set_entry(index, next); 1.70 - } 1.71 - free_entry(e); 1.72 + remove_entry(e, previous); 1.73 + ++num_removed; 1.74 } else { 1.75 previous = e; 1.76 } 1.77 e = next; 1.78 } 1.79 } 1.80 + return num_removed; 1.81 } 1.82 1.83 G1CodeRootSet::~G1CodeRootSet() { 1.84 @@ -320,14 +326,19 @@ 1.85 bool operator() (nmethod* nm) { 1.86 _detector._points_into = false; 1.87 _blobs.do_code_blob(nm); 1.88 - return _detector._points_into; 1.89 + return !_detector._points_into; 1.90 } 1.91 }; 1.92 1.93 void G1CodeRootSet::clean(HeapRegion* owner) { 1.94 CleanCallback should_clean(owner); 1.95 if (_table != NULL) { 1.96 - _table->remove_if(should_clean); 1.97 + int removed = _table->remove_if(should_clean); 1.98 + assert((size_t)removed <= _length, "impossible"); 1.99 + _length -= removed; 1.100 + } 1.101 + if (_length == 0) { 1.102 + clear(); 1.103 } 1.104 } 1.105