From 57e0ee46b5c01a0f10838e8ecb28607e43757e96 Mon Sep 17 00:00:00 2001 From: jmasa Date: Wed, 23 Jun 2010 08:35:31 -0700 Subject: [PATCH] 6952853: SIGSEGV with UseAdaptiveGCBoundary on 64b linux running jvm2008 Summary: Shrinking of a generation and the corresponding card table was causing part of the card table to be uncommitted. Reviewed-by: jcoomes --- .../parallelScavenge/cardTableExtension.cpp | 28 ++++++++++---- .../parallelScavenge/cardTableExtension.hpp | 6 ++- src/share/vm/memory/cardTableModRefBS.cpp | 37 +++++++++++++++---- 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp b/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp index b2e0a6adb..c87190d0c 100644 --- a/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp +++ b/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -566,14 +566,14 @@ void CardTableExtension::resize_covered_region_by_end(int changed_region, #endif // Commit new or uncommit old pages, if necessary. - resize_commit_uncommit(changed_region, new_region); + if (resize_commit_uncommit(changed_region, new_region)) { + // Set the new start of the committed region + resize_update_committed_table(changed_region, new_region); + } // Update card table entries resize_update_card_table_entries(changed_region, new_region); - // Set the new start of the committed region - resize_update_committed_table(changed_region, new_region); - // Update the covered region resize_update_covered_table(changed_region, new_region); @@ -604,8 +604,9 @@ void CardTableExtension::resize_covered_region_by_end(int changed_region, debug_only(verify_guard();) } -void CardTableExtension::resize_commit_uncommit(int changed_region, +bool CardTableExtension::resize_commit_uncommit(int changed_region, MemRegion new_region) { + bool result = false; // Commit new or uncommit old pages, if necessary. MemRegion cur_committed = _committed[changed_region]; assert(_covered[changed_region].end() == new_region.end(), @@ -675,20 +676,31 @@ void CardTableExtension::resize_commit_uncommit(int changed_region, "card table expansion"); } } + result = true; } else if (new_start_aligned > cur_committed.start()) { // Shrink the committed region +#if 0 // uncommitting space is currently unsafe because of the interactions + // of growing and shrinking regions. One region A can uncommit space + // that it owns but which is being used by another region B (maybe). + // Region B has not committed the space because it was already + // committed by region A. MemRegion uncommit_region = committed_unique_to_self(changed_region, MemRegion(cur_committed.start(), new_start_aligned)); if (!uncommit_region.is_empty()) { if (!os::uncommit_memory((char*)uncommit_region.start(), uncommit_region.byte_size())) { - vm_exit_out_of_memory(uncommit_region.byte_size(), - "card table contraction"); + // If the uncommit fails, ignore it. Let the + // committed table resizing go even though the committed + // table will over state the committed space. } } +#else + assert(!result, "Should be false with current workaround"); +#endif } assert(_committed[changed_region].end() == cur_committed.end(), "end should not change"); + return result; } void CardTableExtension::resize_update_committed_table(int changed_region, diff --git a/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.hpp b/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.hpp index 6654a37ae..90243a721 100644 --- a/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.hpp +++ b/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,9 @@ class GCTaskQueue; class CardTableExtension : public CardTableModRefBS { private: // Support methods for resizing the card table. - void resize_commit_uncommit(int changed_region, MemRegion new_region); + // resize_commit_uncommit() returns true if the pages were committed or + // uncommitted + bool resize_commit_uncommit(int changed_region, MemRegion new_region); void resize_update_card_table_entries(int changed_region, MemRegion new_region); void resize_update_committed_table(int changed_region, MemRegion new_region); diff --git a/src/share/vm/memory/cardTableModRefBS.cpp b/src/share/vm/memory/cardTableModRefBS.cpp index e9a7efc24..979678e25 100644 --- a/src/share/vm/memory/cardTableModRefBS.cpp +++ b/src/share/vm/memory/cardTableModRefBS.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -284,12 +284,19 @@ void CardTableModRefBS::resize_covered_region(MemRegion new_region) { committed_unique_to_self(ind, MemRegion(new_end_aligned, cur_committed.end())); if (!uncommit_region.is_empty()) { - if (!os::uncommit_memory((char*)uncommit_region.start(), - uncommit_region.byte_size())) { - assert(false, "Card table contraction failed"); - // The call failed so don't change the end of the - // committed region. This is better than taking the - // VM down. + // It is not safe to uncommit cards if the boundary between + // the generations is moving. A shrink can uncommit cards + // owned by generation A but being used by generation B. + if (!UseAdaptiveGCBoundary) { + if (!os::uncommit_memory((char*)uncommit_region.start(), + uncommit_region.byte_size())) { + assert(false, "Card table contraction failed"); + // The call failed so don't change the end of the + // committed region. This is better than taking the + // VM down. + new_end_aligned = _committed[ind].end(); + } + } else { new_end_aligned = _committed[ind].end(); } } @@ -297,6 +304,19 @@ void CardTableModRefBS::resize_covered_region(MemRegion new_region) { // In any case, we can reset the end of the current committed entry. _committed[ind].set_end(new_end_aligned); +#ifdef ASSERT + // Check that the last card in the new region is committed according + // to the tables. + bool covered = false; + for (int cr = 0; cr < _cur_covered_regions; cr++) { + if (_committed[cr].contains(new_end - 1)) { + covered = true; + break; + } + } + assert(covered, "Card for end of new region not committed"); +#endif + // The default of 0 is not necessarily clean cards. jbyte* entry; if (old_region.last() < _whole_heap.start()) { @@ -354,6 +374,9 @@ void CardTableModRefBS::resize_covered_region(MemRegion new_region) { addr_for((jbyte*) _committed[ind].start()), addr_for((jbyte*) _committed[ind].last())); } + // Touch the last card of the covered region to show that it + // is committed (or SEGV). + debug_only(*byte_for(_covered[ind].last());) debug_only(verify_guard();) } -- GitLab