Mercurial > hg > icedtea7-forest > hotspot
changeset 5377:2d053c4fd767 jdk7u60-b07
Merge
author | lana |
---|---|
date | Sat, 15 Feb 2014 17:57:06 -0800 |
parents | 2d75b3d4ca1d (current diff) 7baccd19a1ae (diff) |
children | 45d0a54c0df1 |
files | |
diffstat | 30 files changed, 421 insertions(+), 187 deletions(-) [+] |
line wrap: on
line diff
--- a/agent/src/share/classes/sun/jvm/hotspot/interpreter/Bytecodes.java Wed Feb 12 14:56:19 2014 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/interpreter/Bytecodes.java Sat Feb 15 17:57:06 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, 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 @@ -272,9 +272,10 @@ public static final int _fast_aldc = 229; public static final int _fast_aldc_w = 230; public static final int _return_register_finalizer = 231; - public static final int _shouldnotreachhere = 232; // For debugging + public static final int _invokehandle = 232; + public static final int _shouldnotreachhere = 233; // For debugging - public static final int number_of_codes = 233; + public static final int number_of_codes = 234; // Flag bits derived from format strings, can_trap, can_rewrite, etc.: // semantic flags: @@ -798,6 +799,9 @@ def(_return_register_finalizer, "return_register_finalizer", "b" , null , BasicType.getTVoid() , 0, true, _return ); + def(_invokehandle , "invokehandle" , "bJJ" , null , BasicType.getTIllegal(), -1, true, _invokevirtual ); + + def(_fast_aldc , "fast_aldc" , "bj" , null , BasicType.getTObject(), 1, true, _ldc ); def(_fast_aldc_w , "fast_aldc_w" , "bJJ" , null , BasicType.getTObject(), 1, true, _ldc_w );
--- a/make/hotspot_version Wed Feb 12 14:56:19 2014 -0800 +++ b/make/hotspot_version Sat Feb 15 17:57:06 2014 -0800 @@ -35,7 +35,7 @@ HS_MAJOR_VER=24 HS_MINOR_VER=60 -HS_BUILD_NUMBER=08 +HS_BUILD_NUMBER=09 JDK_MAJOR_VER=1 JDK_MINOR_VER=7
--- a/src/cpu/sparc/vm/assembler_sparc.cpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/cpu/sparc/vm/assembler_sparc.cpp Sat Feb 15 17:57:06 2014 -0800 @@ -4512,7 +4512,7 @@ #define __ masm. address start = __ pc(); - Label not_already_dirty, restart, refill; + Label not_already_dirty, restart, refill, young_card; #ifdef _LP64 __ srlx(O0, CardTableModRefBS::card_shift, O0); @@ -4523,9 +4523,15 @@ __ set(addrlit, O1); // O1 := <card table base> __ ldub(O0, O1, O2); // O2 := [O0 + O1] + __ cmp_and_br_short(O2, G1SATBCardTableModRefBS::g1_young_card_val(), Assembler::equal, Assembler::pt, young_card); + + __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); + __ ldub(O0, O1, O2); // O2 := [O0 + O1] + assert(CardTableModRefBS::dirty_card_val() == 0, "otherwise check this code"); __ cmp_and_br_short(O2, G0, Assembler::notEqual, Assembler::pt, not_already_dirty); + __ bind(young_card); // We didn't take the branch, so we're already dirty: return. // Use return-from-leaf __ retl();
--- a/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Sat Feb 15 17:57:06 2014 -0800 @@ -36,6 +36,9 @@ #include "runtime/signature.hpp" #include "runtime/vframeArray.hpp" #include "vmreg_sparc.inline.hpp" +#ifndef SERIALGC +#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" +#endif // Implementation of StubAssembler @@ -898,7 +901,7 @@ Register tmp2 = G3_scratch; jbyte* byte_map_base = ((CardTableModRefBS*)bs)->byte_map_base; - Label not_already_dirty, restart, refill; + Label not_already_dirty, restart, refill, young_card; #ifdef _LP64 __ srlx(addr, CardTableModRefBS::card_shift, addr); @@ -910,9 +913,15 @@ __ set(rs, cardtable); // cardtable := <card table base> __ ldub(addr, cardtable, tmp); // tmp := [addr + cardtable] + __ cmp_and_br_short(tmp, G1SATBCardTableModRefBS::g1_young_card_val(), Assembler::equal, Assembler::pt, young_card); + + __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); + __ ldub(addr, cardtable, tmp); // tmp := [addr + cardtable] + assert(CardTableModRefBS::dirty_card_val() == 0, "otherwise check this code"); __ cmp_and_br_short(tmp, G0, Assembler::notEqual, Assembler::pt, not_already_dirty); + __ bind(young_card); // We didn't take the branch, so we're already dirty: return. // Use return-from-leaf __ retl();
--- a/src/cpu/x86/vm/assembler_x86.cpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/cpu/x86/vm/assembler_x86.cpp Sat Feb 15 17:57:06 2014 -0800 @@ -8754,13 +8754,18 @@ const Register card_addr = tmp; lea(card_addr, as_Address(ArrayAddress(cardtable, index))); #endif - cmpb(Address(card_addr, 0), 0); + cmpb(Address(card_addr, 0), (int)G1SATBCardTableModRefBS::g1_young_card_val()); jcc(Assembler::equal, done); + membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); + cmpb(Address(card_addr, 0), (int)CardTableModRefBS::dirty_card_val()); + jcc(Assembler::equal, done); + + // storing a region crossing, non-NULL oop, card is clean. // dirty card and log. - movb(Address(card_addr, 0), 0); + movb(Address(card_addr, 0), (int)CardTableModRefBS::dirty_card_val()); cmpl(queue_index, 0); jcc(Assembler::equal, runtime);
--- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp Sat Feb 15 17:57:06 2014 -0800 @@ -37,6 +37,9 @@ #include "runtime/signature.hpp" #include "runtime/vframeArray.hpp" #include "vmreg_x86.inline.hpp" +#ifndef SERIALGC +#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" +#endif // Implementation of StubAssembler @@ -1743,13 +1746,17 @@ __ leal(card_addr, __ as_Address(ArrayAddress(cardtable, index))); #endif - __ cmpb(Address(card_addr, 0), 0); + __ cmpb(Address(card_addr, 0), (int)G1SATBCardTableModRefBS::g1_young_card_val()); + __ jcc(Assembler::equal, done); + + __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); + __ cmpb(Address(card_addr, 0), (int)CardTableModRefBS::dirty_card_val()); __ jcc(Assembler::equal, done); // storing region crossing non-NULL, card is clean. // dirty card and log. - __ movb(Address(card_addr, 0), 0); + __ movb(Address(card_addr, 0), (int)CardTableModRefBS::dirty_card_val()); __ cmpl(queue_index, 0); __ jcc(Assembler::equal, runtime);
--- a/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp Sat Feb 15 17:57:06 2014 -0800 @@ -81,7 +81,7 @@ size_t* marked_bytes_array, BitMap* task_card_bm) { G1CollectedHeap* g1h = _g1h; - CardTableModRefBS* ct_bs = (CardTableModRefBS*) (g1h->barrier_set()); + CardTableModRefBS* ct_bs = g1h->g1_barrier_set(); HeapWord* start = mr.start(); HeapWord* end = mr.end();
--- a/src/share/vm/gc_implementation/g1/g1CardCounts.cpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CardCounts.cpp Sat Feb 15 17:57:06 2014 -0800 @@ -65,9 +65,7 @@ // threshold limit is no more than this. guarantee(G1ConcRSHotCardLimit <= max_jubyte, "sanity"); - ModRefBarrierSet* bs = _g1h->mr_bs(); - guarantee(bs->is_a(BarrierSet::CardTableModRef), "Precondition"); - _ct_bs = (CardTableModRefBS*)bs; + _ct_bs = _g1h->g1_barrier_set(); _ct_bot = _ct_bs->byte_for_const(_g1h->reserved_region().start()); // Allocate/Reserve the counts table
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Sat Feb 15 17:57:06 2014 -0800 @@ -127,10 +127,8 @@ int _histo[256]; public: ClearLoggedCardTableEntryClosure() : - _calls(0) + _calls(0), _g1h(G1CollectedHeap::heap()), _ctbs(_g1h->g1_barrier_set()) { - _g1h = G1CollectedHeap::heap(); - _ctbs = (CardTableModRefBS*)_g1h->barrier_set(); for (int i = 0; i < 256; i++) _histo[i] = 0; } bool do_card_ptr(jbyte* card_ptr, int worker_i) { @@ -160,11 +158,8 @@ CardTableModRefBS* _ctbs; public: RedirtyLoggedCardTableEntryClosure() : - _calls(0) - { - _g1h = G1CollectedHeap::heap(); - _ctbs = (CardTableModRefBS*)_g1h->barrier_set(); - } + _calls(0), _g1h(G1CollectedHeap::heap()), _ctbs(_g1h->g1_barrier_set()) {} + bool do_card_ptr(jbyte* card_ptr, int worker_i) { if (_g1h->is_in_reserved(_ctbs->addr_for(card_ptr))) { _calls++; @@ -479,7 +474,7 @@ void G1CollectedHeap::check_ct_logs_at_safepoint() { DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); - CardTableModRefBS* ct_bs = (CardTableModRefBS*)barrier_set(); + CardTableModRefBS* ct_bs = g1_barrier_set(); // Count the dirty cards at the start. CountNonCleanMemRegionClosure count1(this); @@ -1186,7 +1181,7 @@ }; void G1CollectedHeap::clear_rsets_post_compaction() { - PostMCRemSetClearClosure rs_clear(this, mr_bs()); + PostMCRemSetClearClosure rs_clear(this, g1_barrier_set()); heap_region_iterate(&rs_clear); } @@ -1554,8 +1549,6 @@ void G1CollectedHeap:: resize_if_necessary_after_full_collection(size_t word_size) { - assert(MinHeapFreeRatio <= MaxHeapFreeRatio, "sanity check"); - // Include the current allocation, if any, and bytes that will be // pre-allocated to support collections, as "used". const size_t used_after_gc = used(); @@ -2068,20 +2061,13 @@ // Create the gen rem set (and barrier set) for the entire reserved region. _rem_set = collector_policy()->create_rem_set(_reserved, 2); set_barrier_set(rem_set()->bs()); - if (barrier_set()->is_a(BarrierSet::ModRef)) { - _mr_bs = (ModRefBarrierSet*)_barrier_set; - } else { - vm_exit_during_initialization("G1 requires a mod ref bs."); + if (!barrier_set()->is_a(BarrierSet::G1SATBCTLogging)) { + vm_exit_during_initialization("G1 requires a G1SATBLoggingCardTableModRefBS"); return JNI_ENOMEM; } // Also create a G1 rem set. - if (mr_bs()->is_a(BarrierSet::CardTableModRef)) { - _g1_rem_set = new G1RemSet(this, (CardTableModRefBS*)mr_bs()); - } else { - vm_exit_during_initialization("G1 requires a cardtable mod ref bs."); - return JNI_ENOMEM; - } + _g1_rem_set = new G1RemSet(this, g1_barrier_set()); // Carve out the G1 part of the heap. @@ -4579,7 +4565,7 @@ : _g1h(g1h), _refs(g1h->task_queue(queue_num)), _dcq(&g1h->dirty_card_queue_set()), - _ct_bs((CardTableModRefBS*)_g1h->barrier_set()), + _ct_bs(g1h->g1_barrier_set()), _g1_rem(g1h->g1_rem_set()), _hash_seed(17), _queue_num(queue_num), _term_attempts(0), @@ -5217,9 +5203,12 @@ bool _process_symbols; int _symbols_processed; int _symbols_removed; + + bool _do_in_parallel; public: G1StringSymbolTableUnlinkTask(BoolObjectClosure* is_alive, bool process_strings, bool process_symbols) : AbstractGangTask("Par String/Symbol table unlink"), _is_alive(is_alive), + _do_in_parallel(G1CollectedHeap::use_parallel_gc_threads()), _process_strings(process_strings), _strings_processed(0), _strings_removed(0), _process_symbols(process_symbols), _symbols_processed(0), _symbols_removed(0) { @@ -5234,17 +5223,16 @@ } ~G1StringSymbolTableUnlinkTask() { - guarantee(!_process_strings || StringTable::parallel_claimed_index() >= _initial_string_table_size, + guarantee(!_process_strings || !_do_in_parallel || StringTable::parallel_claimed_index() >= _initial_string_table_size, err_msg("claim value "INT32_FORMAT" after unlink less than initial string table size "INT32_FORMAT, StringTable::parallel_claimed_index(), _initial_string_table_size)); - guarantee(!_process_symbols || SymbolTable::parallel_claimed_index() >= _initial_symbol_table_size, + guarantee(!_process_symbols || !_do_in_parallel || SymbolTable::parallel_claimed_index() >= _initial_symbol_table_size, err_msg("claim value "INT32_FORMAT" after unlink less than initial symbol table size "INT32_FORMAT, SymbolTable::parallel_claimed_index(), _initial_symbol_table_size)); - } void work(uint worker_id) { - if (G1CollectedHeap::use_parallel_gc_threads()) { + if (_do_in_parallel) { int strings_processed = 0; int strings_removed = 0; int symbols_processed = 0; @@ -6067,11 +6055,11 @@ } class G1ParCleanupCTTask : public AbstractGangTask { - CardTableModRefBS* _ct_bs; + G1SATBCardTableModRefBS* _ct_bs; G1CollectedHeap* _g1h; HeapRegion* volatile _su_head; public: - G1ParCleanupCTTask(CardTableModRefBS* ct_bs, + G1ParCleanupCTTask(G1SATBCardTableModRefBS* ct_bs, G1CollectedHeap* g1h) : AbstractGangTask("G1 Par Cleanup CT Task"), _ct_bs(ct_bs), _g1h(g1h) { } @@ -6094,9 +6082,9 @@ #ifndef PRODUCT class G1VerifyCardTableCleanup: public HeapRegionClosure { G1CollectedHeap* _g1h; - CardTableModRefBS* _ct_bs; + G1SATBCardTableModRefBS* _ct_bs; public: - G1VerifyCardTableCleanup(G1CollectedHeap* g1h, CardTableModRefBS* ct_bs) + G1VerifyCardTableCleanup(G1CollectedHeap* g1h, G1SATBCardTableModRefBS* ct_bs) : _g1h(g1h), _ct_bs(ct_bs) { } virtual bool doHeapRegion(HeapRegion* r) { if (r->is_survivor()) { @@ -6110,7 +6098,7 @@ void G1CollectedHeap::verify_not_dirty_region(HeapRegion* hr) { // All of the region should be clean. - CardTableModRefBS* ct_bs = (CardTableModRefBS*)barrier_set(); + G1SATBCardTableModRefBS* ct_bs = g1_barrier_set(); MemRegion mr(hr->bottom(), hr->end()); ct_bs->verify_not_dirty_region(mr); } @@ -6123,13 +6111,17 @@ // not dirty that area (one less thing to have to do while holding // a lock). So we can only verify that [bottom(),pre_dummy_top()] // is dirty. - CardTableModRefBS* ct_bs = (CardTableModRefBS*) barrier_set(); + G1SATBCardTableModRefBS* ct_bs = g1_barrier_set(); MemRegion mr(hr->bottom(), hr->pre_dummy_top()); - ct_bs->verify_dirty_region(mr); + if (hr->is_young()) { + ct_bs->verify_g1_young_region(mr); + } else { + ct_bs->verify_dirty_region(mr); + } } void G1CollectedHeap::verify_dirty_young_list(HeapRegion* head) { - CardTableModRefBS* ct_bs = (CardTableModRefBS*) barrier_set(); + G1SATBCardTableModRefBS* ct_bs = g1_barrier_set(); for (HeapRegion* hr = head; hr != NULL; hr = hr->get_next_young_region()) { verify_dirty_region(hr); } @@ -6141,7 +6133,7 @@ #endif void G1CollectedHeap::cleanUpCardTable() { - CardTableModRefBS* ct_bs = (CardTableModRefBS*) (barrier_set()); + G1SATBCardTableModRefBS* ct_bs = g1_barrier_set(); double start = os::elapsedTime(); {
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Sat Feb 15 17:57:06 2014 -0800 @@ -31,6 +31,7 @@ #include "gc_implementation/g1/g1HRPrinter.hpp" #include "gc_implementation/g1/g1MonitoringSupport.hpp" #include "gc_implementation/g1/g1RemSet.hpp" +#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" #include "gc_implementation/g1/g1YCTypes.hpp" #include "gc_implementation/g1/heapRegionSeq.hpp" #include "gc_implementation/g1/heapRegionSets.hpp" @@ -795,8 +796,6 @@ // The g1 remembered set of the heap. G1RemSet* _g1_rem_set; - // And it's mod ref barrier set, used to track updates for the above. - ModRefBarrierSet* _mr_bs; // A set of cards that cover the objects for which the Rsets should be updated // concurrently after the collection. @@ -1131,7 +1130,6 @@ // The rem set and barrier set. G1RemSet* g1_rem_set() const { return _g1_rem_set; } - ModRefBarrierSet* mr_bs() const { return _mr_bs; } // The rem set iterator. HeapRegionRemSetIterator* rem_set_iterator(int i) { @@ -1365,6 +1363,10 @@ virtual bool is_in_closed_subset(const void* p) const; + G1SATBCardTableModRefBS* g1_barrier_set() { + return (G1SATBCardTableModRefBS*) barrier_set(); + } + // This resets the card table to all zeros. It is used after // a collection pause which used the card table to claim cards. void cleanUpCardTable(); @@ -1834,7 +1836,7 @@ G1CollectedHeap* _g1h; RefToScanQueue* _refs; DirtyCardQueue _dcq; - CardTableModRefBS* _ct_bs; + G1SATBCardTableModRefBS* _ct_bs; G1RemSet* _g1_rem; G1ParGCAllocBuffer _surviving_alloc_buffer; @@ -1873,7 +1875,7 @@ void add_to_undo_waste(size_t waste) { _undo_waste += waste; } DirtyCardQueue& dirty_card_queue() { return _dcq; } - CardTableModRefBS* ctbs() { return _ct_bs; } + G1SATBCardTableModRefBS* ctbs() { return _ct_bs; } template <class T> void immediate_rs_update(HeapRegion* from, T* p, int tid) { if (!from->is_survivor()) {
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Sat Feb 15 17:57:06 2014 -0800 @@ -29,6 +29,7 @@ #include "gc_implementation/g1/g1CollectedHeap.hpp" #include "gc_implementation/g1/g1AllocRegion.inline.hpp" #include "gc_implementation/g1/g1CollectorPolicy.hpp" +#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" #include "gc_implementation/g1/heapRegionSeq.inline.hpp" #include "utilities/taskqueue.hpp" @@ -131,7 +132,7 @@ assert(containing_hr->is_in(end - 1), "it should also contain end - 1"); MemRegion mr(start, end); - ((CardTableModRefBS*)_g1h->barrier_set())->dirty(mr); + g1_barrier_set()->g1_mark_as_young(mr); } inline RefToScanQueue* G1CollectedHeap::task_queue(int i) const {
--- a/src/share/vm/gc_implementation/g1/g1EvacFailure.hpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/g1EvacFailure.hpp Sat Feb 15 17:57:06 2014 -0800 @@ -41,11 +41,11 @@ private: G1CollectedHeap* _g1; DirtyCardQueue *_dcq; - CardTableModRefBS* _ct_bs; + G1SATBCardTableModRefBS* _ct_bs; public: UpdateRSetDeferred(G1CollectedHeap* g1, DirtyCardQueue* dcq) : - _g1(g1), _ct_bs((CardTableModRefBS*)_g1->barrier_set()), _dcq(dcq) {} + _g1(g1), _ct_bs(_g1->g1_barrier_set()), _dcq(dcq) {} virtual void do_oop(narrowOop* p) { do_oop_work(p); } virtual void do_oop( oop* p) { do_oop_work(p); }
--- a/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Sat Feb 15 17:57:06 2014 -0800 @@ -234,7 +234,7 @@ public: G1PrepareCompactClosure(CompactibleSpace* cs) : _g1h(G1CollectedHeap::heap()), - _mrbs(G1CollectedHeap::heap()->mr_bs()), + _mrbs(_g1h->g1_barrier_set()), _cp(NULL, cs, cs->initialize_threshold()), _humongous_proxy_set("G1MarkSweep Humongous Proxy Set") { }
--- a/src/share/vm/gc_implementation/g1/g1RemSet.cpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.cpp Sat Feb 15 17:57:06 2014 -0800 @@ -111,7 +111,7 @@ CodeBlobToOopClosure* _code_root_cl; G1BlockOffsetSharedArray* _bot_shared; - CardTableModRefBS *_ct_bs; + G1SATBCardTableModRefBS *_ct_bs; double _strong_code_root_scan_time_sec; int _worker_i; @@ -132,7 +132,7 @@ { _g1h = G1CollectedHeap::heap(); _bot_shared = _g1h->bot_shared(); - _ct_bs = (CardTableModRefBS*) (_g1h->barrier_set()); + _ct_bs = _g1h->g1_barrier_set(); _block_size = MAX2<int>(G1RSetScanBlockSize, 1); } @@ -508,12 +508,7 @@ ScrubRSClosure(BitMap* region_bm, BitMap* card_bm) : _g1h(G1CollectedHeap::heap()), _region_bm(region_bm), _card_bm(card_bm), - _ctbs(NULL) - { - ModRefBarrierSet* bs = _g1h->mr_bs(); - guarantee(bs->is_a(BarrierSet::CardTableModRef), "Precondition"); - _ctbs = (CardTableModRefBS*)bs; - } + _ctbs(_g1h->g1_barrier_set()) {} bool doHeapRegion(HeapRegion* r) { if (!r->continuesHumongous()) {
--- a/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp Sat Feb 15 17:57:06 2014 -0800 @@ -76,6 +76,46 @@ } } +bool G1SATBCardTableModRefBS::mark_card_deferred(size_t card_index) { + jbyte val = _byte_map[card_index]; + // It's already processed + if ((val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val()) { + return false; + } + + if (val == g1_young_gen) { + // the card is for a young gen region. We don't need to keep track of all pointers into young + return false; + } + + // Cached bit can be installed either on a clean card or on a claimed card. + jbyte new_val = val; + if (val == clean_card_val()) { + new_val = (jbyte)deferred_card_val(); + } else { + if (val & claimed_card_val()) { + new_val = val | (jbyte)deferred_card_val(); + } + } + if (new_val != val) { + Atomic::cmpxchg(new_val, &_byte_map[card_index], val); + } + return true; +} + +void G1SATBCardTableModRefBS::g1_mark_as_young(const MemRegion& mr) { + jbyte *const first = byte_for(mr.start()); + jbyte *const last = byte_after(mr.last()); + + memset(first, g1_young_gen, last - first); +} + +#ifndef PRODUCT +void G1SATBCardTableModRefBS::verify_g1_young_region(MemRegion mr) { + verify_region(mr, g1_young_gen, true); +} +#endif + G1SATBCardTableLoggingModRefBS:: G1SATBCardTableLoggingModRefBS(MemRegion whole_heap, int max_covered_regions) : @@ -88,7 +128,11 @@ void G1SATBCardTableLoggingModRefBS::write_ref_field_work(void* field, oop new_val) { - jbyte* byte = byte_for(field); + volatile jbyte* byte = byte_for(field); + if (*byte == g1_young_gen) { + return; + } + OrderAccess::storeload(); if (*byte != dirty_card) { *byte = dirty_card; Thread* thr = Thread::current(); @@ -120,7 +164,7 @@ void G1SATBCardTableLoggingModRefBS::invalidate(MemRegion mr, bool whole_heap) { - jbyte* byte = byte_for(mr.start()); + volatile jbyte* byte = byte_for(mr.start()); jbyte* last_byte = byte_for(mr.last()); Thread* thr = Thread::current(); if (whole_heap) { @@ -129,25 +173,35 @@ byte++; } } else { - // Enqueue if necessary. - if (thr->is_Java_thread()) { - JavaThread* jt = (JavaThread*)thr; - while (byte <= last_byte) { - if (*byte != dirty_card) { - *byte = dirty_card; - jt->dirty_card_queue().enqueue(byte); + // skip all consecutive young cards + for (; byte <= last_byte && *byte == g1_young_gen; byte++); + + if (byte <= last_byte) { + OrderAccess::storeload(); + // Enqueue if necessary. + if (thr->is_Java_thread()) { + JavaThread* jt = (JavaThread*)thr; + for (; byte <= last_byte; byte++) { + if (*byte == g1_young_gen) { + continue; + } + if (*byte != dirty_card) { + *byte = dirty_card; + jt->dirty_card_queue().enqueue(byte); + } } - byte++; - } - } else { - MutexLockerEx x(Shared_DirtyCardQ_lock, - Mutex::_no_safepoint_check_flag); - while (byte <= last_byte) { - if (*byte != dirty_card) { - *byte = dirty_card; - _dcqs.shared_dirty_card_queue()->enqueue(byte); + } else { + MutexLockerEx x(Shared_DirtyCardQ_lock, + Mutex::_no_safepoint_check_flag); + for (; byte <= last_byte; byte++) { + if (*byte == g1_young_gen) { + continue; + } + if (*byte != dirty_card) { + *byte = dirty_card; + _dcqs.shared_dirty_card_queue()->enqueue(byte); + } } - byte++; } } }
--- a/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp Sat Feb 15 17:57:06 2014 -0800 @@ -37,7 +37,14 @@ // snapshot-at-the-beginning marking. class G1SATBCardTableModRefBS: public CardTableModRefBSForCTRS { +protected: + enum G1CardValues { + g1_young_gen = CT_MR_BS_last_reserved << 1 + }; + public: + static int g1_young_card_val() { return g1_young_gen; } + // Add "pre_val" to a set of objects that may have been disconnected from the // pre-marking object graph. static void enqueue(oop pre_val); @@ -88,6 +95,45 @@ write_ref_array_pre_work(dst, count); } } + +/* + Claimed and deferred bits are used together in G1 during the evacuation + pause. These bits can have the following state transitions: + 1. The claimed bit can be put over any other card state. Except that + the "dirty -> dirty and claimed" transition is checked for in + G1 code and is not used. + 2. Deferred bit can be set only if the previous state of the card + was either clean or claimed. mark_card_deferred() is wait-free. + We do not care if the operation is be successful because if + it does not it will only result in duplicate entry in the update + buffer because of the "cache-miss". So it's not worth spinning. + */ + + bool is_card_claimed(size_t card_index) { + jbyte val = _byte_map[card_index]; + return (val & (clean_card_mask_val() | claimed_card_val())) == claimed_card_val(); + } + + void set_card_claimed(size_t card_index) { + jbyte val = _byte_map[card_index]; + if (val == clean_card_val()) { + val = (jbyte)claimed_card_val(); + } else { + val |= (jbyte)claimed_card_val(); + } + _byte_map[card_index] = val; + } + + void verify_g1_young_region(MemRegion mr) PRODUCT_RETURN; + void g1_mark_as_young(const MemRegion& mr); + + bool mark_card_deferred(size_t card_index); + + bool is_card_deferred(size_t card_index) { + jbyte val = _byte_map[card_index]; + return (val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val(); + } + }; // Adds card-table logging to the post-barrier.
--- a/src/share/vm/gc_implementation/g1/ptrQueue.hpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/ptrQueue.hpp Sat Feb 15 17:57:06 2014 -0800 @@ -79,6 +79,10 @@ void reset() { if (_buf != NULL) _index = _sz; } + void enqueue(volatile void* ptr) { + enqueue((void*)(ptr)); + } + // Enqueues the given "obj". void enqueue(void* ptr) { if (!_active) return;
--- a/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp Sat Feb 15 17:57:06 2014 -0800 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "gc_implementation/parallelScavenge/generationSizer.hpp" +#include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" #include "gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp" #include "gc_implementation/parallelScavenge/psGCAdaptivePolicyCounters.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" @@ -78,6 +79,38 @@ _old_gen_policy_is_ready = false; } +size_t PSAdaptiveSizePolicy::calculate_free_based_on_live(size_t live, uintx ratio_as_percentage) { + // We want to calculate how much free memory there can be based on the + // amount of live data currently in the old gen. Using the formula: + // ratio * (free + live) = free + // Some equation solving later we get: + // free = (live * ratio) / (1 - ratio) + + const double ratio = ratio_as_percentage / 100.0; + const double ratio_inverse = 1.0 - ratio; + const double tmp = live * ratio; + size_t free = (size_t)(tmp / ratio_inverse); + + return free; +} + +size_t PSAdaptiveSizePolicy::calculated_old_free_size_in_bytes() const { + size_t free_size = (size_t)(_promo_size + avg_promoted()->padded_average()); + size_t live = ParallelScavengeHeap::heap()->old_gen()->used_in_bytes(); + + if (MinHeapFreeRatio != 0) { + size_t min_free = calculate_free_based_on_live(live, MinHeapFreeRatio); + free_size = MAX2(free_size, min_free); + } + + if (MaxHeapFreeRatio != 100) { + size_t max_free = calculate_free_based_on_live(live, MaxHeapFreeRatio); + free_size = MIN2(max_free, free_size); + } + + return free_size; +} + void PSAdaptiveSizePolicy::major_collection_begin() { // Update the interval time _major_timer.stop(); @@ -1107,3 +1140,18 @@ st, PSScavenge::tenuring_threshold()); } + +#ifndef PRODUCT + +void TestOldFreeSpaceCalculation_test() { + assert(PSAdaptiveSizePolicy::calculate_free_based_on_live(100, 20) == 25, "Calculation of free memory failed"); + assert(PSAdaptiveSizePolicy::calculate_free_based_on_live(100, 50) == 100, "Calculation of free memory failed"); + assert(PSAdaptiveSizePolicy::calculate_free_based_on_live(100, 60) == 150, "Calculation of free memory failed"); + assert(PSAdaptiveSizePolicy::calculate_free_based_on_live(100, 75) == 300, "Calculation of free memory failed"); + assert(PSAdaptiveSizePolicy::calculate_free_based_on_live(400, 20) == 100, "Calculation of free memory failed"); + assert(PSAdaptiveSizePolicy::calculate_free_based_on_live(400, 50) == 400, "Calculation of free memory failed"); + assert(PSAdaptiveSizePolicy::calculate_free_based_on_live(400, 60) == 600, "Calculation of free memory failed"); + assert(PSAdaptiveSizePolicy::calculate_free_based_on_live(400, 75) == 1200, "Calculation of free memory failed"); +} + +#endif /* !PRODUCT */
--- a/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp Sat Feb 15 17:57:06 2014 -0800 @@ -238,7 +238,6 @@ void major_collection_begin(); void major_collection_end(size_t amount_live, GCCause::Cause gc_cause); - // void tenured_allocation(size_t size) { _avg_pretenured->sample(size); } @@ -246,9 +245,9 @@ // Accessors // NEEDS_CLEANUP should use sizes.hpp - size_t calculated_old_free_size_in_bytes() const { - return (size_t)(_promo_size + avg_promoted()->padded_average()); - } + static size_t calculate_free_based_on_live(size_t live, uintx ratio_as_percentage); + + size_t calculated_old_free_size_in_bytes() const; size_t average_old_live_in_bytes() const { return (size_t) avg_old_live()->average();
--- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Sat Feb 15 17:57:06 2014 -0800 @@ -535,8 +535,19 @@ counters->update_survivor_overflowed(_survivor_overflow); } + size_t max_young_size = young_gen->max_size(); + + // Deciding a free ratio in the young generation is tricky, so if + // MinHeapFreeRatio or MaxHeapFreeRatio are in use (implicating + // that the old generation size may have been limited because of them) we + // should then limit our young generation size using NewRatio to have it + // follow the old generation size. + if (MinHeapFreeRatio != 0 || MaxHeapFreeRatio != 100) { + max_young_size = MIN2(old_gen->capacity_in_bytes() / NewRatio, young_gen->max_size()); + } + size_t survivor_limit = - size_policy->max_survivor_size(young_gen->max_size()); + size_policy->max_survivor_size(max_young_size); _tenuring_threshold = size_policy->compute_survivor_space_size_and_threshold( _survivor_overflow, @@ -559,8 +570,7 @@ // Do call at minor collections? // Don't check if the size_policy is ready at this // level. Let the size_policy check that internally. - if (UseAdaptiveSizePolicy && - UseAdaptiveGenerationSizePolicyAtMinorCollection && + if (UseAdaptiveGenerationSizePolicyAtMinorCollection && ((gc_cause != GCCause::_java_lang_system_gc) || UseAdaptiveSizePolicyWithSystemGC)) { @@ -569,7 +579,7 @@ young_gen->from_space()->capacity_in_bytes() + young_gen->to_space()->capacity_in_bytes(), "Sizes of space in young gen are out-of-bounds"); - size_t max_eden_size = young_gen->max_size() - + size_t max_eden_size = max_young_size - young_gen->from_space()->capacity_in_bytes() - young_gen->to_space()->capacity_in_bytes(); size_policy->compute_generation_free_space(young_gen->used_in_bytes(),
--- a/src/share/vm/memory/cardTableModRefBS.cpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/memory/cardTableModRefBS.cpp Sat Feb 15 17:57:06 2014 -0800 @@ -400,60 +400,6 @@ inline_write_ref_field(field, newVal); } -/* - Claimed and deferred bits are used together in G1 during the evacuation - pause. These bits can have the following state transitions: - 1. The claimed bit can be put over any other card state. Except that - the "dirty -> dirty and claimed" transition is checked for in - G1 code and is not used. - 2. Deferred bit can be set only if the previous state of the card - was either clean or claimed. mark_card_deferred() is wait-free. - We do not care if the operation is be successful because if - it does not it will only result in duplicate entry in the update - buffer because of the "cache-miss". So it's not worth spinning. - */ - - -bool CardTableModRefBS::claim_card(size_t card_index) { - jbyte val = _byte_map[card_index]; - assert(val != dirty_card_val(), "Shouldn't claim a dirty card"); - while (val == clean_card_val() || - (val & (clean_card_mask_val() | claimed_card_val())) != claimed_card_val()) { - jbyte new_val = val; - if (val == clean_card_val()) { - new_val = (jbyte)claimed_card_val(); - } else { - new_val = val | (jbyte)claimed_card_val(); - } - jbyte res = Atomic::cmpxchg(new_val, &_byte_map[card_index], val); - if (res == val) { - return true; - } - val = res; - } - return false; -} - -bool CardTableModRefBS::mark_card_deferred(size_t card_index) { - jbyte val = _byte_map[card_index]; - // It's already processed - if ((val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val()) { - return false; - } - // Cached bit can be installed either on a clean card or on a claimed card. - jbyte new_val = val; - if (val == clean_card_val()) { - new_val = (jbyte)deferred_card_val(); - } else { - if (val & claimed_card_val()) { - new_val = val | (jbyte)deferred_card_val(); - } - } - if (new_val != val) { - Atomic::cmpxchg(new_val, &_byte_map[card_index], val); - } - return true; -} void CardTableModRefBS::non_clean_card_iterate_possibly_parallel(Space* sp, MemRegion mr,
--- a/src/share/vm/memory/cardTableModRefBS.hpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/memory/cardTableModRefBS.hpp Sat Feb 15 17:57:06 2014 -0800 @@ -344,34 +344,10 @@ _byte_map[card_index] = dirty_card_val(); } - bool is_card_claimed(size_t card_index) { - jbyte val = _byte_map[card_index]; - return (val & (clean_card_mask_val() | claimed_card_val())) == claimed_card_val(); - } - - void set_card_claimed(size_t card_index) { - jbyte val = _byte_map[card_index]; - if (val == clean_card_val()) { - val = (jbyte)claimed_card_val(); - } else { - val |= (jbyte)claimed_card_val(); - } - _byte_map[card_index] = val; - } - - bool claim_card(size_t card_index); - bool is_card_clean(size_t card_index) { return _byte_map[card_index] == clean_card_val(); } - bool is_card_deferred(size_t card_index) { - jbyte val = _byte_map[card_index]; - return (val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val(); - } - - bool mark_card_deferred(size_t card_index); - // Card marking array base (adjusted for heap low boundary) // This would be the 0th element of _byte_map, if the heap started at 0x0. // But since the heap starts at some higher address, this points to somewhere
--- a/src/share/vm/opto/graphKit.cpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/opto/graphKit.cpp Sat Feb 15 17:57:06 2014 -0800 @@ -3701,7 +3701,8 @@ Node* no_base = __ top(); float likely = PROB_LIKELY(0.999); float unlikely = PROB_UNLIKELY(0.999); - Node* zero = __ ConI(0); + Node* young_card = __ ConI((jint)G1SATBCardTableModRefBS::g1_young_card_val()); + Node* dirty_card = __ ConI((jint)CardTableModRefBS::dirty_card_val()); Node* zeroX = __ ConX(0); // Get the alias_index for raw card-mark memory @@ -3757,8 +3758,16 @@ // load the original value of the card Node* card_val = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw); - __ if_then(card_val, BoolTest::ne, zero); { - g1_mark_card(ideal, card_adr, oop_store, alias_idx, index, index_adr, buffer, tf); + __ if_then(card_val, BoolTest::ne, young_card); { + sync_kit(ideal); + // Use Op_MemBarVolatile to achieve the effect of a StoreLoad barrier. + insert_mem_bar(Op_MemBarVolatile, oop_store); + __ sync_kit(this); + + Node* card_val_reload = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw); + __ if_then(card_val_reload, BoolTest::ne, dirty_card); { + g1_mark_card(ideal, card_adr, oop_store, alias_idx, index, index_adr, buffer, tf); + } __ end_if(); } __ end_if(); } __ end_if(); } __ end_if();
--- a/src/share/vm/prims/jni.cpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/prims/jni.cpp Sat Feb 15 17:57:06 2014 -0800 @@ -5045,6 +5045,7 @@ // Forward declaration void TestReservedSpace_test(); void TestReserveMemorySpecial_test(); +void TestOldFreeSpaceCalculation_test(); void execute_internal_vm_tests() { if (ExecuteInternalVMTests) { @@ -5056,6 +5057,7 @@ run_unit_test(CollectedHeap::test_is_in()); run_unit_test(QuickSort::test_quick_sort()); run_unit_test(AltHashing::test_alt_hash()); + run_unit_test(TestOldFreeSpaceCalculation_test()); tty->print_cr("All internal VM tests passed"); } }
--- a/src/share/vm/runtime/arguments.cpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/runtime/arguments.cpp Sat Feb 15 17:57:06 2014 -0800 @@ -1447,6 +1447,17 @@ } FLAG_SET_DEFAULT(UseParallelGC, true); + if (UseAdaptiveSizePolicy) { + // We don't want to limit adaptive heap sizing's freedom to adjust the heap + // unless the user actually sets these flags. + if (FLAG_IS_DEFAULT(MinHeapFreeRatio)) { + FLAG_SET_DEFAULT(MinHeapFreeRatio, 0); + } + if (FLAG_IS_DEFAULT(MaxHeapFreeRatio)) { + FLAG_SET_DEFAULT(MaxHeapFreeRatio, 100); + } + } + // If no heap maximum was requested explicitly, use some reasonable fraction // of the physical memory, up to a maximum of 1GB. if (UseParallelGC) { @@ -1719,7 +1730,7 @@ } bool Arguments::verify_percentage(uintx value, const char* name) { - if (value <= 100) { + if (is_percentage(value)) { return true; } jio_fprintf(defaultStream::error_stream(), @@ -1768,6 +1779,34 @@ } } +bool Arguments::verify_MinHeapFreeRatio(FormatBuffer<80>& err_msg, uintx min_heap_free_ratio) { + if (!is_percentage(min_heap_free_ratio)) { + err_msg.print("MinHeapFreeRatio must have a value between 0 and 100"); + return false; + } + if (min_heap_free_ratio > MaxHeapFreeRatio) { + err_msg.print("MinHeapFreeRatio (" UINTX_FORMAT ") must be less than or " + "equal to MaxHeapFreeRatio (" UINTX_FORMAT ")", min_heap_free_ratio, + MaxHeapFreeRatio); + return false; + } + return true; +} + +bool Arguments::verify_MaxHeapFreeRatio(FormatBuffer<80>& err_msg, uintx max_heap_free_ratio) { + if (!is_percentage(max_heap_free_ratio)) { + err_msg.print("MaxHeapFreeRatio must have a value between 0 and 100"); + return false; + } + if (max_heap_free_ratio < MinHeapFreeRatio) { + err_msg.print("MaxHeapFreeRatio (" UINTX_FORMAT ") must be greater than or " + "equal to MinHeapFreeRatio (" UINTX_FORMAT ")", max_heap_free_ratio, + MinHeapFreeRatio); + return false; + } + return true; +} + // Check consistency of GC selection bool Arguments::check_gc_consistency() { check_gclog_consistency(); @@ -1852,15 +1891,19 @@ "AdaptiveSizePolicyWeight"); status = status && verify_percentage(AdaptivePermSizeWeight, "AdaptivePermSizeWeight"); status = status && verify_percentage(ThresholdTolerance, "ThresholdTolerance"); - status = status && verify_percentage(MinHeapFreeRatio, "MinHeapFreeRatio"); - status = status && verify_percentage(MaxHeapFreeRatio, "MaxHeapFreeRatio"); - - if (MinHeapFreeRatio > MaxHeapFreeRatio) { - jio_fprintf(defaultStream::error_stream(), - "MinHeapFreeRatio (" UINTX_FORMAT ") must be less than or " - "equal to MaxHeapFreeRatio (" UINTX_FORMAT ")\n", - MinHeapFreeRatio, MaxHeapFreeRatio); - status = false; + + { + // Using "else if" below to avoid printing two error messages if min > max. + // This will also prevent us from reporting both min>100 and max>100 at the + // same time, but that is less annoying than printing two identical errors IMHO. + FormatBuffer<80> err_msg(""); + if (!verify_MinHeapFreeRatio(err_msg, MinHeapFreeRatio)) { + jio_fprintf(defaultStream::error_stream(), "%s\n", err_msg.buffer()); + status = false; + } else if (!verify_MaxHeapFreeRatio(err_msg, MaxHeapFreeRatio)) { + jio_fprintf(defaultStream::error_stream(), "%s\n", err_msg.buffer()); + status = false; + } } // Keeping the heap 100% free is hard ;-) so limit it to 99%. MinHeapFreeRatio = MIN2(MinHeapFreeRatio, (uintx) 99);
--- a/src/share/vm/runtime/arguments.hpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/runtime/arguments.hpp Sat Feb 15 17:57:06 2014 -0800 @@ -27,6 +27,7 @@ #include "runtime/java.hpp" #include "runtime/perfData.hpp" +#include "utilities/debug.hpp" #include "utilities/top.hpp" // Arguments parses the command line and recognizes options @@ -350,6 +351,9 @@ static bool is_bad_option(const JavaVMOption* option, jboolean ignore) { return is_bad_option(option, ignore, NULL); } + static bool is_percentage(uintx val) { + return val <= 100; + } static bool verify_interval(uintx val, uintx min, uintx max, const char* name); static bool verify_min_value(intx val, intx min, const char* name); @@ -411,6 +415,12 @@ public: // Parses the arguments static jint parse(const JavaVMInitArgs* args); + // Verifies that the given value will fit as a MinHeapFreeRatio. If not, an error + // message is returned in the provided buffer. + static bool verify_MinHeapFreeRatio(FormatBuffer<80>& err_msg, uintx min_heap_free_ratio); + // Verifies that the given value will fit as a MaxHeapFreeRatio. If not, an error + // message is returned in the provided buffer. + static bool verify_MaxHeapFreeRatio(FormatBuffer<80>& err_msg, uintx max_heap_free_ratio); // Check for consistency in the selection of the garbage collector. static bool check_gc_consistency(); // Check consistecy or otherwise of VM argument settings
--- a/src/share/vm/runtime/globals.hpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/runtime/globals.hpp Sat Feb 15 17:57:06 2014 -0800 @@ -3020,10 +3020,10 @@ product_pd(uintx, MaxPermSize, \ "Maximum size of permanent generation (in bytes)") \ \ - product(uintx, MinHeapFreeRatio, 40, \ + manageable(uintx, MinHeapFreeRatio, 40, \ "Min percentage of heap free after GC to avoid expansion") \ \ - product(uintx, MaxHeapFreeRatio, 70, \ + manageable(uintx, MaxHeapFreeRatio, 70, \ "Max percentage of heap free after GC to avoid shrinking") \ \ product(intx, SoftRefLRUPolicyMSPerMB, 1000, \
--- a/src/share/vm/services/attachListener.cpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/services/attachListener.cpp Sat Feb 15 17:57:06 2014 -0800 @@ -282,6 +282,20 @@ return JNI_ERR; } } + + if (strncmp(name, "MaxHeapFreeRatio", 17) == 0) { + FormatBuffer<80> err_msg(""); + if (!Arguments::verify_MaxHeapFreeRatio(err_msg, value)) { + out->print_cr(err_msg.buffer()); + return JNI_ERR; + } + } else if (strncmp(name, "MinHeapFreeRatio", 17) == 0) { + FormatBuffer<80> err_msg(""); + if (!Arguments::verify_MinHeapFreeRatio(err_msg, value)) { + out->print_cr(err_msg.buffer()); + return JNI_ERR; + } + } bool res = CommandLineFlags::uintxAtPut((char*)name, &value, ATTACH_ON_DEMAND); if (! res) { out->print_cr("setting flag %s failed", name);
--- a/src/share/vm/services/management.cpp Wed Feb 12 14:56:19 2014 -0800 +++ b/src/share/vm/services/management.cpp Sat Feb 15 17:57:06 2014 -0800 @@ -1800,6 +1800,18 @@ succeed = CommandLineFlags::intxAtPut(name, &ivalue, MANAGEMENT); } else if (flag->is_uintx()) { uintx uvalue = (uintx)new_value.j; + + if (strncmp(name, "MaxHeapFreeRatio", 17) == 0) { + FormatBuffer<80> err_msg(""); + if (!Arguments::verify_MaxHeapFreeRatio(err_msg, uvalue)) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), err_msg.buffer()); + } + } else if (strncmp(name, "MinHeapFreeRatio", 17) == 0) { + FormatBuffer<80> err_msg(""); + if (!Arguments::verify_MinHeapFreeRatio(err_msg, uvalue)) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), err_msg.buffer()); + } + } succeed = CommandLineFlags::uintxAtPut(name, &uvalue, MANAGEMENT); } else if (flag->is_uint64_t()) { uint64_t uvalue = (uint64_t)new_value.j;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/8000311/Test8000311.java Sat Feb 15 17:57:06 2014 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2013, 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 Test8000311 + * @key gc + * @bug 8000311 + * @summary G1: ParallelGCThreads==0 broken + * @run main/othervm -XX:+UseG1GC -XX:ParallelGCThreads=0 -XX:+ResizePLAB -XX:+ExplicitGCInvokesConcurrent Test8000311 + * @author filipp.zhinkin@oracle.com + */ + +import java.util.*; + +public class Test8000311 { + public static void main(String args[]) { + for(int i = 0; i<100; i++) { + byte[] garbage = new byte[1000]; + System.gc(); + } + } +}