# HG changeset patch # User jmasa # Date 1277307331 25200 # Node ID fdde661c8e066c0ef9ac8baa9f98bf16bb03229a # Parent b9bc732be7c06a8677746ce5841719ef9a8fb9a3 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 diff -r b9bc732be7c0 -r fdde661c8e06 src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Thu Jun 10 08:27:35 2010 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Wed Jun 23 08:35:31 2010 -0700 @@ -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 @@ #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 @@ 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 @@ "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 -r b9bc732be7c0 -r fdde661c8e06 src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.hpp Thu Jun 10 08:27:35 2010 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.hpp Wed Jun 23 08:35:31 2010 -0700 @@ -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 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 -r b9bc732be7c0 -r fdde661c8e06 src/share/vm/memory/cardTableModRefBS.cpp --- a/src/share/vm/memory/cardTableModRefBS.cpp Thu Jun 10 08:27:35 2010 -0700 +++ b/src/share/vm/memory/cardTableModRefBS.cpp Wed Jun 23 08:35:31 2010 -0700 @@ -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 @@ 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 @@ // 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 @@ 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();) }