# HG changeset patch # User jprovino # Date 1452904108 0 # Node ID 616a5f8dbb987665963901e98f5360b174a11d8a # Parent 252674e1e51d9595943e4179b5dc6094385fa265# Parent 819d5b58955067e19cc751968cc9cbf0f8228527 Merge diff -r 252674e1e51d -r 616a5f8dbb98 hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Fri Jan 15 15:37:00 2016 -0500 +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Sat Jan 16 00:28:28 2016 +0000 @@ -3535,6 +3535,16 @@ cl.flush_rem_set_entries(); } +class VerifyRegionRemSetClosure : public HeapRegionClosure { + public: + bool doHeapRegion(HeapRegion* hr) { + if (!hr->is_archive() && !hr->is_continues_humongous()) { + hr->verify_rem_set(); + } + return false; + } +}; + #ifdef ASSERT class VerifyCSetClosure: public HeapRegionClosure { public: @@ -3724,6 +3734,12 @@ increment_total_collections(false /* full gc */); increment_gc_time_stamp(); + if (VerifyRememberedSets) { + log_info(gc, verify)("[Verifying RemSets before GC]"); + VerifyRegionRemSetClosure v_cl; + heap_region_iterate(&v_cl); + } + verify_before_gc(); check_bitmaps("GC Start"); @@ -3928,6 +3944,12 @@ // scanning cards (see CR 7039627). increment_gc_time_stamp(); + if (VerifyRememberedSets) { + log_info(gc, verify)("[Verifying RemSets after GC]"); + VerifyRegionRemSetClosure v_cl; + heap_region_iterate(&v_cl); + } + verify_after_gc(); check_bitmaps("GC End"); diff -r 252674e1e51d -r 616a5f8dbb98 hotspot/src/share/vm/gc/g1/heapRegion.cpp --- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp Fri Jan 15 15:37:00 2016 -0500 +++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp Sat Jan 16 00:28:28 2016 +0000 @@ -599,8 +599,8 @@ p2i(prev_top_at_mark_start()), p2i(next_top_at_mark_start())); } -class VerifyLiveClosure: public OopClosure { -private: +class G1VerificationClosure : public OopClosure { +protected: G1CollectedHeap* _g1h; CardTableModRefBS* _bs; oop _containing_obj; @@ -611,10 +611,10 @@ // _vo == UsePrevMarking -> use "prev" marking information, // _vo == UseNextMarking -> use "next" marking information, // _vo == UseMarkWord -> use mark word from object header. - VerifyLiveClosure(G1CollectedHeap* g1h, VerifyOption vo) : + G1VerificationClosure(G1CollectedHeap* g1h, VerifyOption vo) : _g1h(g1h), _bs(barrier_set_cast(g1h->barrier_set())), - _containing_obj(NULL), _failures(false), _n_failures(0), _vo(vo) - { } + _containing_obj(NULL), _failures(false), _n_failures(0), _vo(vo) { + } void set_containing_obj(oop obj) { _containing_obj = obj; @@ -623,9 +623,6 @@ bool failures() { return _failures; } int n_failures() { return _n_failures; } - virtual void do_oop(narrowOop* p) { do_oop_work(p); } - virtual void do_oop( oop* p) { do_oop_work(p); } - void print_object(outputStream* out, oop obj) { #ifdef PRODUCT Klass* k = obj->klass(); @@ -635,12 +632,24 @@ obj->print_on(out); #endif // PRODUCT } +}; + +class VerifyLiveClosure : public G1VerificationClosure { +public: + VerifyLiveClosure(G1CollectedHeap* g1h, VerifyOption vo) : G1VerificationClosure(g1h, vo) {} + virtual void do_oop(narrowOop* p) { do_oop_work(p); } + virtual void do_oop(oop* p) { do_oop_work(p); } template void do_oop_work(T* p) { assert(_containing_obj != NULL, "Precondition"); assert(!_g1h->is_obj_dead_cond(_containing_obj, _vo), - "Precondition"); + "Precondition"); + verify_liveness(p); + } + + template + void verify_liveness(T* p) { T heap_oop = oopDesc::load_heap_oop(p); LogHandle(gc, verify) log; if (!oopDesc::is_null(heap_oop)) { @@ -648,7 +657,7 @@ bool failed = false; if (!_g1h->is_in_closed_subset(obj) || _g1h->is_obj_dead_cond(obj, _vo)) { MutexLockerEx x(ParGCRareEvent_lock, - Mutex::_no_safepoint_check_flag); + Mutex::_no_safepoint_check_flag); if (!_failures) { log.info("----------"); @@ -657,17 +666,17 @@ if (!_g1h->is_in_closed_subset(obj)) { HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p); log.info("Field " PTR_FORMAT " of live obj " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ")", - p2i(p), p2i(_containing_obj), p2i(from->bottom()), p2i(from->end())); + p2i(p), p2i(_containing_obj), p2i(from->bottom()), p2i(from->end())); print_object(log.info_stream(), _containing_obj); log.info("points to obj " PTR_FORMAT " not in the heap", p2i(obj)); } else { HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p); - HeapRegion* to = _g1h->heap_region_containing((HeapWord*)obj); + HeapRegion* to = _g1h->heap_region_containing((HeapWord*)obj); log.info("Field " PTR_FORMAT " of live obj " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ")", - p2i(p), p2i(_containing_obj), p2i(from->bottom()), p2i(from->end())); + p2i(p), p2i(_containing_obj), p2i(from->bottom()), p2i(from->end())); print_object(log.info_stream(), _containing_obj); log.info("points to dead obj " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ")", - p2i(obj), p2i(to->bottom()), p2i(to->end())); + p2i(obj), p2i(to->bottom()), p2i(to->end())); print_object(log.info_stream(), obj); } log.info("----------"); @@ -675,42 +684,64 @@ failed = true; _n_failures++; } + } + } +}; - if (!_g1h->collector_state()->full_collection() || G1VerifyRSetsDuringFullGC) { - HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p); - HeapRegion* to = _g1h->heap_region_containing(obj); - if (from != NULL && to != NULL && - from != to && - !to->is_pinned()) { - jbyte cv_obj = *_bs->byte_for_const(_containing_obj); - jbyte cv_field = *_bs->byte_for_const(p); - const jbyte dirty = CardTableModRefBS::dirty_card_val(); +class VerifyRemSetClosure : public G1VerificationClosure { +public: + VerifyRemSetClosure(G1CollectedHeap* g1h, VerifyOption vo) : G1VerificationClosure(g1h, vo) {} + virtual void do_oop(narrowOop* p) { do_oop_work(p); } + virtual void do_oop(oop* p) { do_oop_work(p); } + + template + void do_oop_work(T* p) { + assert(_containing_obj != NULL, "Precondition"); + assert(!_g1h->is_obj_dead_cond(_containing_obj, _vo), + "Precondition"); + verify_remembered_set(p); + } - bool is_bad = !(from->is_young() - || to->rem_set()->contains_reference(p) - || !G1HRRSFlushLogBuffersOnVerify && // buffers were not flushed - (_containing_obj->is_objArray() ? - cv_field == dirty - : cv_obj == dirty || cv_field == dirty)); - if (is_bad) { - MutexLockerEx x(ParGCRareEvent_lock, - Mutex::_no_safepoint_check_flag); + template + void verify_remembered_set(T* p) { + T heap_oop = oopDesc::load_heap_oop(p); + LogHandle(gc, verify) log; + if (!oopDesc::is_null(heap_oop)) { + oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + bool failed = false; + HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p); + HeapRegion* to = _g1h->heap_region_containing(obj); + if (from != NULL && to != NULL && + from != to && + !to->is_pinned()) { + jbyte cv_obj = *_bs->byte_for_const(_containing_obj); + jbyte cv_field = *_bs->byte_for_const(p); + const jbyte dirty = CardTableModRefBS::dirty_card_val(); - if (!_failures) { - log.info("----------"); - } - log.info("Missing rem set entry:"); - log.info("Field " PTR_FORMAT " of obj " PTR_FORMAT ", in region " HR_FORMAT, - p2i(p), p2i(_containing_obj), HR_FORMAT_PARAMS(from)); - ResourceMark rm; - _containing_obj->print_on(log.info_stream()); - log.info("points to obj " PTR_FORMAT " in region " HR_FORMAT, p2i(obj), HR_FORMAT_PARAMS(to)); - obj->print_on(log.info_stream()); - log.info("Obj head CTE = %d, field CTE = %d.", cv_obj, cv_field); + bool is_bad = !(from->is_young() + || to->rem_set()->contains_reference(p) + || !G1HRRSFlushLogBuffersOnVerify && // buffers were not flushed + (_containing_obj->is_objArray() ? + cv_field == dirty + : cv_obj == dirty || cv_field == dirty)); + if (is_bad) { + MutexLockerEx x(ParGCRareEvent_lock, + Mutex::_no_safepoint_check_flag); + + if (!_failures) { log.info("----------"); - _failures = true; - if (!failed) _n_failures++; } + log.info("Missing rem set entry:"); + log.info("Field " PTR_FORMAT " of obj " PTR_FORMAT ", in region " HR_FORMAT, + p2i(p), p2i(_containing_obj), HR_FORMAT_PARAMS(from)); + ResourceMark rm; + _containing_obj->print_on(log.info_stream()); + log.info("points to obj " PTR_FORMAT " in region " HR_FORMAT, p2i(obj), HR_FORMAT_PARAMS(to)); + obj->print_on(log.info_stream()); + log.info("Obj head CTE = %d, field CTE = %d.", cv_obj, cv_field); + log.info("----------"); + _failures = true; + if (!failed) _n_failures++; } } } @@ -727,6 +758,7 @@ HeapWord* p = bottom(); HeapWord* prev_p = NULL; VerifyLiveClosure vl_cl(g1, vo); + VerifyRemSetClosure vr_cl(g1, vo); bool is_region_humongous = is_humongous(); size_t object_num = 0; while (p < top()) { @@ -752,7 +784,23 @@ return; } else { vl_cl.set_containing_obj(obj); - obj->oop_iterate_no_header(&vl_cl); + if (!g1->collector_state()->full_collection() || G1VerifyRSetsDuringFullGC) { + // verify liveness and rem_set + vr_cl.set_containing_obj(obj); + G1Mux2Closure mux(&vl_cl, &vr_cl); + obj->oop_iterate_no_header(&mux); + + if (vr_cl.failures()) { + *failures = true; + } + if (G1MaxVerifyFailures >= 0 && + vr_cl.n_failures() >= G1MaxVerifyFailures) { + return; + } + } else { + // verify only liveness + obj->oop_iterate_no_header(&vl_cl); + } if (vl_cl.failures()) { *failures = true; } @@ -762,7 +810,7 @@ } } } else { - log_info(gc, verify)(PTR_FORMAT " no an oop", p2i(obj)); + log_info(gc, verify)(PTR_FORMAT " not an oop", p2i(obj)); *failures = true; return; } @@ -852,6 +900,46 @@ verify(VerifyOption_G1UsePrevMarking, /* failures */ &dummy); } +void HeapRegion::verify_rem_set(VerifyOption vo, bool* failures) const { + G1CollectedHeap* g1 = G1CollectedHeap::heap(); + *failures = false; + HeapWord* p = bottom(); + HeapWord* prev_p = NULL; + VerifyRemSetClosure vr_cl(g1, vo); + while (p < top()) { + oop obj = oop(p); + size_t obj_size = block_size(p); + + if (!g1->is_obj_dead_cond(obj, this, vo)) { + if (obj->is_oop()) { + vr_cl.set_containing_obj(obj); + obj->oop_iterate_no_header(&vr_cl); + + if (vr_cl.failures()) { + *failures = true; + } + if (G1MaxVerifyFailures >= 0 && + vr_cl.n_failures() >= G1MaxVerifyFailures) { + return; + } + } else { + log_info(gc, verify)(PTR_FORMAT " not an oop", p2i(obj)); + *failures = true; + return; + } + } + + prev_p = p; + p += obj_size; + } +} + +void HeapRegion::verify_rem_set() const { + bool failures = false; + verify_rem_set(VerifyOption_G1UsePrevMarking, &failures); + guarantee(!failures, "HeapRegion RemSet verification failed"); +} + void HeapRegion::prepare_for_compaction(CompactPoint* cp) { scan_and_forward(this, cp); } diff -r 252674e1e51d -r 616a5f8dbb98 hotspot/src/share/vm/gc/g1/heapRegion.hpp --- a/hotspot/src/share/vm/gc/g1/heapRegion.hpp Fri Jan 15 15:37:00 2016 -0500 +++ b/hotspot/src/share/vm/gc/g1/heapRegion.hpp Sat Jan 16 00:28:28 2016 +0000 @@ -745,6 +745,9 @@ // Override; it uses the "prev" marking information virtual void verify() const; + + void verify_rem_set(VerifyOption vo, bool *failures) const; + void verify_rem_set() const; }; // HeapRegionClosure is used for iterating over regions. diff -r 252674e1e51d -r 616a5f8dbb98 hotspot/src/share/vm/memory/universe.cpp --- a/hotspot/src/share/vm/memory/universe.cpp Fri Jan 15 15:37:00 2016 -0500 +++ b/hotspot/src/share/vm/memory/universe.cpp Sat Jan 16 00:28:28 2016 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -129,6 +129,7 @@ objArrayOop Universe::_preallocated_out_of_memory_error_array = NULL; volatile jint Universe::_preallocated_out_of_memory_error_avail_count = 0; bool Universe::_verify_in_progress = false; +long Universe::verify_flags = Universe::Verify_All; oop Universe::_null_ptr_exception_instance = NULL; oop Universe::_arithmetic_exception_instance = NULL; oop Universe::_virtual_machine_error_instance = NULL; @@ -669,6 +670,9 @@ MetaspaceShared::prepare_for_dumping(); } } + if (strlen(VerifySubSet) > 0) { + Universe::initialize_verify_flags(); + } return JNI_OK; } @@ -1103,6 +1107,53 @@ } } +void Universe::initialize_verify_flags() { + verify_flags = 0; + const char delimiter[] = " ,"; + + size_t length = strlen(VerifySubSet); + char* subset_list = NEW_C_HEAP_ARRAY(char, length + 1, mtInternal); + strncpy(subset_list, VerifySubSet, length + 1); + + char* token = strtok(subset_list, delimiter); + while (token != NULL) { + if (strcmp(token, "threads") == 0) { + verify_flags |= Verify_Threads; + } else if (strcmp(token, "heap") == 0) { + verify_flags |= Verify_Heap; + } else if (strcmp(token, "symbol_table") == 0) { + verify_flags |= Verify_SymbolTable; + } else if (strcmp(token, "string_table") == 0) { + verify_flags |= Verify_StringTable; + } else if (strcmp(token, "codecache") == 0) { + verify_flags |= Verify_CodeCache; + } else if (strcmp(token, "dictionary") == 0) { + verify_flags |= Verify_SystemDictionary; + } else if (strcmp(token, "classloader_data_graph") == 0) { + verify_flags |= Verify_ClassLoaderDataGraph; + } else if (strcmp(token, "metaspace") == 0) { + verify_flags |= Verify_MetaspaceAux; + } else if (strcmp(token, "jni_handles") == 0) { + verify_flags |= Verify_JNIHandles; + } else if (strcmp(token, "c-heap") == 0) { + verify_flags |= Verify_CHeap; + } else if (strcmp(token, "codecache_oops") == 0) { + verify_flags |= Verify_CodeCacheOops; + } else { + vm_exit_during_initialization(err_msg("VerifySubSet: \'%s\' memory sub-system is unknown, please correct it", token)); + } + token = strtok(NULL, delimiter); + } + FREE_C_HEAP_ARRAY(char, subset_list); +} + +bool Universe::should_verify_subset(uint subset) { + if (verify_flags & subset) { + return true; + } + return false; +} + void Universe::verify(VerifyOption option, const char* prefix) { // The use of _verify_in_progress is a temporary work around for // 6320749. Don't bother with a creating a class to set and clear @@ -1122,33 +1173,55 @@ FormatBuffer<> title("Verifying %s", prefix); GCTraceTime(Info, gc, verify) tm(title.buffer()); - log_debug(gc, verify)("Threads"); - Threads::verify(); - log_debug(gc, verify)("Heap"); - heap()->verify(option); - log_debug(gc, verify)("SymbolTable"); - SymbolTable::verify(); - log_debug(gc, verify)("StringTable"); - StringTable::verify(); + if (should_verify_subset(Verify_Threads)) { + log_debug(gc, verify)("Threads"); + Threads::verify(); + } + if (should_verify_subset(Verify_Heap)) { + log_debug(gc, verify)("Heap"); + heap()->verify(option); + } + if (should_verify_subset(Verify_SymbolTable)) { + log_debug(gc, verify)("SymbolTable"); + SymbolTable::verify(); + } + if (should_verify_subset(Verify_StringTable)) { + log_debug(gc, verify)("StringTable"); + StringTable::verify(); + } + if (should_verify_subset(Verify_CodeCache)) { { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); log_debug(gc, verify)("CodeCache"); CodeCache::verify(); } - log_debug(gc, verify)("SystemDictionary"); - SystemDictionary::verify(); + } + if (should_verify_subset(Verify_SystemDictionary)) { + log_debug(gc, verify)("SystemDictionary"); + SystemDictionary::verify(); + } #ifndef PRODUCT - log_debug(gc, verify)("ClassLoaderDataGraph"); - ClassLoaderDataGraph::verify(); + if (should_verify_subset(Verify_ClassLoaderDataGraph)) { + log_debug(gc, verify)("ClassLoaderDataGraph"); + ClassLoaderDataGraph::verify(); + } #endif - log_debug(gc, verify)("MetaspaceAux"); - MetaspaceAux::verify_free_chunks(); - log_debug(gc, verify)("JNIHandles"); - JNIHandles::verify(); - log_debug(gc, verify)("C-heap"); - os::check_heap(); - log_debug(gc, verify)("CodeCache Oops"); - CodeCache::verify_oops(); + if (should_verify_subset(Verify_MetaspaceAux)) { + log_debug(gc, verify)("MetaspaceAux"); + MetaspaceAux::verify_free_chunks(); + } + if (should_verify_subset(Verify_JNIHandles)) { + log_debug(gc, verify)("JNIHandles"); + JNIHandles::verify(); + } + if (should_verify_subset(Verify_CHeap)) { + log_debug(gc, verify)("C-heap"); + os::check_heap(); + } + if (should_verify_subset(Verify_CodeCacheOops)) { + log_debug(gc, verify)("CodeCache Oops"); + CodeCache::verify_oops(); + } _verify_in_progress = false; } diff -r 252674e1e51d -r 616a5f8dbb98 hotspot/src/share/vm/memory/universe.hpp --- a/hotspot/src/share/vm/memory/universe.hpp Fri Jan 15 15:37:00 2016 -0500 +++ b/hotspot/src/share/vm/memory/universe.hpp Sat Jan 16 00:28:28 2016 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -255,6 +255,7 @@ // True during call to verify(). Should only be set/cleared in verify(). static bool _verify_in_progress; + static long verify_flags; static uintptr_t _verify_oop_mask; static uintptr_t _verify_oop_bits; @@ -463,6 +464,22 @@ static void init_self_patching_vtbl_list(void** list, int count); // Debugging + enum VERIFY_FLAGS { + Verify_Threads = 1, + Verify_Heap = 2, + Verify_SymbolTable = 4, + Verify_StringTable = 8, + Verify_CodeCache = 16, + Verify_SystemDictionary = 32, + Verify_ClassLoaderDataGraph = 64, + Verify_MetaspaceAux = 128, + Verify_JNIHandles = 256, + Verify_CHeap = 512, + Verify_CodeCacheOops = 1024, + Verify_All = -1 + }; + static void initialize_verify_flags(); + static bool should_verify_subset(uint subset); static bool verify_in_progress() { return _verify_in_progress; } static void verify(VerifyOption option, const char* prefix); static void verify(const char* prefix) { diff -r 252674e1e51d -r 616a5f8dbb98 hotspot/src/share/vm/runtime/globals.hpp --- a/hotspot/src/share/vm/runtime/globals.hpp Fri Jan 15 15:37:00 2016 -0500 +++ b/hotspot/src/share/vm/runtime/globals.hpp Sat Jan 16 00:28:28 2016 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -2334,6 +2334,14 @@ diagnostic(bool, VerifyDuringGC, false, \ "Verify memory system during GC (between phases)") \ \ + diagnostic(ccstrlist, VerifySubSet, "", \ + "Memory sub-systems to verify when Verify*GC flag(s) " \ + "are enabled. One or more sub-systems can be specified " \ + "in a comma separated string. Sub-systems are: " \ + "threads, heap, symbol_table, string_table, codecache, " \ + "dictionary, classloader_data_graph, metaspace, jni_handles, " \ + "c-heap, codecache_oops") \ + \ diagnostic(bool, GCParallelVerificationEnabled, true, \ "Enable parallel memory system verification") \ \ diff -r 252674e1e51d -r 616a5f8dbb98 hotspot/test/gc/TestVerifySubSet.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/gc/TestVerifySubSet.java Sat Jan 16 00:28:28 2016 +0000 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2016, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test TestVerifySubSet.java + * @key gc + * @bug 8072725 + * @summary Test VerifySubSet option + * @library /testlibrary + * @modules java.base/sun.misc + * java.management + */ + +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; +import java.util.ArrayList; +import java.util.Collections; + +class RunSystemGC { + public static void main(String args[]) throws Exception { + System.gc(); + } +} + +public class TestVerifySubSet { + private static String[] getTestJavaOpts() { + String testVmOptsStr = System.getProperty("test.java.opts"); + if (!testVmOptsStr.isEmpty()) { + return testVmOptsStr.split(" "); + } else { + return new String[] {}; + } + } + + private static OutputAnalyzer runTest(String subset) throws Exception { + ArrayList vmOpts = new ArrayList(); + + Collections.addAll(vmOpts, getTestJavaOpts()); + Collections.addAll(vmOpts, new String[] {"-XX:+UnlockDiagnosticVMOptions", + "-XX:+VerifyBeforeGC", + "-XX:+VerifyAfterGC", + "-Xlog:gc+verify=debug", + "-XX:VerifySubSet="+subset, + RunSystemGC.class.getName()}); + ProcessBuilder pb = + ProcessTools.createJavaProcessBuilder(vmOpts.toArray(new String[vmOpts.size()])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + System.out.println("Output:\n" + output.getOutput()); + return output; + } + + public static void main(String args[]) throws Exception { + + OutputAnalyzer output; + + output = runTest("heap, threads, codecache, metaspace"); + output.shouldContain("Heap"); + output.shouldContain("Threads"); + output.shouldContain("CodeCache"); + output.shouldContain("MetaspaceAux"); + output.shouldNotContain("SymbolTable"); + output.shouldNotContain("StringTable"); + output.shouldNotContain("SystemDictionary"); + output.shouldNotContain("CodeCache Oops"); + output.shouldHaveExitValue(0); + + output = runTest("hello, threads, codecache, metaspace"); + output.shouldContain("memory sub-system is unknown, please correct it"); + output.shouldNotContain("Threads"); + output.shouldNotContain("CodeCache"); + output.shouldNotContain("MetaspaceAux"); + output.shouldHaveExitValue(1); + } +}