# HG changeset patch # User amurillo # Date 1398445184 25200 # Node ID 3d9b5fbd157c8b463e5883e73f9d8887c764f1f2 # Parent 0809c9a4d36e6291f1c4384604c4bbf29e975722# Parent 47f5725e0d7ca0ffe6a0113663aea3792ce70b0f Merge diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -2003,7 +2003,7 @@ } } else { assert(MethodData::profile_return(), "either profile call args or call ret"); - update_mdp_by_constant(in_bytes(ReturnTypeEntry::size())); + update_mdp_by_constant(in_bytes(TypeEntriesAtCall::return_only_size())); } // mdp points right after the end of the diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/cpu/x86/vm/interp_masm_x86.cpp --- a/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -137,7 +137,7 @@ movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp); } else { assert(MethodData::profile_return(), "either profile call args or call ret"); - update_mdp_by_constant(mdp, in_bytes(ReturnTypeEntry::size())); + update_mdp_by_constant(mdp, in_bytes(TypeEntriesAtCall::return_only_size())); } // mdp points right after the end of the diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/c1/c1_LIRGenerator.cpp --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -3188,8 +3188,8 @@ #ifdef ASSERT Bytecodes::Code code = x->method()->raw_code_at_bci(x->bci_of_invoke()); int n = x->nb_profiled_args(); - assert(MethodData::profile_parameters() && x->inlined() && - ((code == Bytecodes::_invokedynamic && n <= 1) || (code == Bytecodes::_invokehandle && n <= 2)), + assert(MethodData::profile_parameters() && (MethodData::profile_arguments_jsr292_only() || + (x->inlined() && ((code == Bytecodes::_invokedynamic && n <= 1) || (code == Bytecodes::_invokehandle && n <= 2)))), "only at JSR292 bytecodes"); #endif } diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/classfile/classFileParser.cpp --- a/hotspot/src/share/vm/classfile/classFileParser.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -2831,7 +2831,6 @@ } } - assert(operand_fill_index == operands->length(), "exact fill"); assert(ConstantPool::operand_array_length(operands) == attribute_array_length, "correct decode"); u1* current_end = cfs->current(); diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -564,11 +564,11 @@ "--------------------------------\n"); size_t total_size = totalSizeInIndexedFreeLists(); size_t free_blocks = numFreeBlocksInIndexedFreeLists(); - gclog_or_tty->print("Total Free Space: %d\n", total_size); - gclog_or_tty->print("Max Chunk Size: %d\n", maxChunkSizeInIndexedFreeLists()); - gclog_or_tty->print("Number of Blocks: %d\n", free_blocks); + gclog_or_tty->print("Total Free Space: " SIZE_FORMAT "\n", total_size); + gclog_or_tty->print("Max Chunk Size: " SIZE_FORMAT "\n", maxChunkSizeInIndexedFreeLists()); + gclog_or_tty->print("Number of Blocks: " SIZE_FORMAT "\n", free_blocks); if (free_blocks != 0) { - gclog_or_tty->print("Av. Block Size: %d\n", total_size/free_blocks); + gclog_or_tty->print("Av. Block Size: " SIZE_FORMAT "\n", total_size/free_blocks); } } @@ -2152,7 +2152,7 @@ for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) { AdaptiveFreeList* fl = &_indexedFreeList[i]; if (PrintFLSStatistics > 1) { - gclog_or_tty->print("size[%d] : ", i); + gclog_or_tty->print("size[" SIZE_FORMAT "] : ", i); } fl->compute_desired(inter_sweep_current, inter_sweep_estimate, intra_sweep_estimate); fl->set_coal_desired((ssize_t)((double)fl->desired() * CMSSmallCoalSurplusPercent)); @@ -2683,7 +2683,8 @@ _global_num_workers[i] = 0; _global_num_blocks[i] = 0; if (PrintOldPLAB) { - gclog_or_tty->print_cr("[%d]: %d", i, (size_t)_blocks_to_claim[i].average()); + gclog_or_tty->print_cr("[" SIZE_FORMAT "]: " SIZE_FORMAT, + i, (size_t)_blocks_to_claim[i].average()); } } } @@ -2722,7 +2723,7 @@ } } if (PrintOldPLAB) { - gclog_or_tty->print_cr("%d[%d]: %d/%d/%d", + gclog_or_tty->print_cr("%d[" SIZE_FORMAT "]: " SIZE_FORMAT "/" SIZE_FORMAT "/" SIZE_FORMAT, tid, i, num_retire, _num_blocks[i], (size_t)_blocks_to_claim[i].average()); } // Reset stats for next round diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -1512,6 +1512,8 @@ gclog_or_tty->print_cr("cms_allocation_rate=%g", stats().cms_allocation_rate()); gclog_or_tty->print_cr("occupancy=%3.7f", _cmsGen->occupancy()); gclog_or_tty->print_cr("initiatingOccupancy=%3.7f", _cmsGen->initiating_occupancy()); + gclog_or_tty->print_cr("cms_time_since_begin=%3.7f", stats().cms_time_since_begin()); + gclog_or_tty->print_cr("cms_time_since_end=%3.7f", stats().cms_time_since_end()); gclog_or_tty->print_cr("metadata initialized %d", MetaspaceGC::should_concurrent_collect()); } @@ -1574,6 +1576,28 @@ return true; } + // CMSTriggerInterval starts a CMS cycle if enough time has passed. + if (CMSTriggerInterval >= 0) { + if (CMSTriggerInterval == 0) { + // Trigger always + return true; + } + + // Check the CMS time since begin (we do not check the stats validity + // as we want to be able to trigger the first CMS cycle as well) + if (stats().cms_time_since_begin() >= (CMSTriggerInterval / ((double) MILLIUNITS))) { + if (Verbose && PrintGCDetails) { + if (stats().valid()) { + gclog_or_tty->print_cr("CMSCollector: collect because of trigger interval (time since last begin %3.7f secs)", + stats().cms_time_since_begin()); + } else { + gclog_or_tty->print_cr("CMSCollector: collect because of trigger interval (first collection)"); + } + } + return true; + } + } + return false; } @@ -2894,13 +2918,13 @@ // Clear the marking bit map array before starting, but, just // for kicks, first report if the given address is already marked - gclog_or_tty->print_cr("Start: Address 0x%x is%s marked", addr, + gclog_or_tty->print_cr("Start: Address " PTR_FORMAT " is%s marked", addr, _markBitMap.isMarked(addr) ? "" : " not"); if (verify_after_remark()) { MutexLockerEx x(verification_mark_bm()->lock(), Mutex::_no_safepoint_check_flag); bool result = verification_mark_bm()->isMarked(addr); - gclog_or_tty->print_cr("TransitiveMark: Address 0x%x %s marked", addr, + gclog_or_tty->print_cr("TransitiveMark: Address " PTR_FORMAT " %s marked", addr, result ? "IS" : "is NOT"); return result; } else { @@ -4569,7 +4593,7 @@ } } if (PrintCMSStatistics > 0) { - gclog_or_tty->print(" [%d iterations, %d waits, %d cards)] ", + gclog_or_tty->print(" [" SIZE_FORMAT " iterations, " SIZE_FORMAT " waits, " SIZE_FORMAT " cards)] ", loops, waited, cumworkdone); } } @@ -4721,7 +4745,7 @@ numIter++, lastNumCards = curNumCards, cumNumCards += curNumCards) { curNumCards = preclean_mod_union_table(_cmsGen, &smoac_cl); if (Verbose && PrintGCDetails) { - gclog_or_tty->print(" (modUnionTable: %d cards)", curNumCards); + gclog_or_tty->print(" (modUnionTable: " SIZE_FORMAT " cards)", curNumCards); } // Either there are very few dirty cards, so re-mark // pause will be small anyway, or our pre-cleaning isn't @@ -4743,7 +4767,7 @@ curNumCards = preclean_card_table(_cmsGen, &smoac_cl); cumNumCards += curNumCards; if (PrintGCDetails && PrintCMSStatistics != 0) { - gclog_or_tty->print_cr(" (cardTable: %d cards, re-scanned %d cards, %d iterations)", + gclog_or_tty->print_cr(" (cardTable: " SIZE_FORMAT " cards, re-scanned " SIZE_FORMAT " cards, " SIZE_FORMAT " iterations)", curNumCards, cumNumCards, numIter); } return cumNumCards; // as a measure of useful work done @@ -8205,7 +8229,7 @@ void SweepClosure::initialize_free_range(HeapWord* freeFinger, bool freeRangeInFreeLists) { if (CMSTraceSweeper) { - gclog_or_tty->print("---- Start free range at 0x%x with free block (%d)\n", + gclog_or_tty->print("---- Start free range at " PTR_FORMAT " with free block (%d)\n", freeFinger, freeRangeInFreeLists); } assert(!inFreeRange(), "Trampling existing free range"); @@ -8275,10 +8299,10 @@ pointer_delta(addr, freeFinger())); if (CMSTraceSweeper) { gclog_or_tty->print("Sweep: last chunk: "); - gclog_or_tty->print("put_free_blk 0x%x ("SIZE_FORMAT") " - "[coalesced:"SIZE_FORMAT"]\n", + gclog_or_tty->print("put_free_blk " PTR_FORMAT " ("SIZE_FORMAT") " + "[coalesced:%d]\n", freeFinger(), pointer_delta(addr, freeFinger()), - lastFreeRangeCoalesced()); + lastFreeRangeCoalesced() ? 1 : 0); } } @@ -8421,7 +8445,7 @@ // the midst of a free range, we are coalescing print_free_block_coalesced(fc); if (CMSTraceSweeper) { - gclog_or_tty->print(" -- pick up free block 0x%x (%d)\n", fc, size); + gclog_or_tty->print(" -- pick up free block " PTR_FORMAT " (" SIZE_FORMAT ")\n", fc, size); } // remove it from the free lists _sp->removeFreeChunkFromFreeLists(fc); @@ -8483,7 +8507,7 @@ // this will be swept up when we hit the end of the // free range if (CMSTraceSweeper) { - gclog_or_tty->print(" -- pick up garbage 0x%x (%d) \n", fc, size); + gclog_or_tty->print(" -- pick up garbage " PTR_FORMAT " (" SIZE_FORMAT ")\n", fc, size); } // If the chunk is being coalesced and the current free range is // in the free lists, remove the current free range so that it @@ -8576,7 +8600,7 @@ } if (CMSTraceSweeper) { - gclog_or_tty->print_cr(" -- pick up another chunk at 0x%x (%d)", fc, chunkSize); + gclog_or_tty->print_cr(" -- pick up another chunk at " PTR_FORMAT " (" SIZE_FORMAT ")", fc, chunkSize); } HeapWord* const fc_addr = (HeapWord*) fc; @@ -8705,7 +8729,7 @@ "chunk should not be in free lists yet"); } if (CMSTraceSweeper) { - gclog_or_tty->print_cr(" -- add free block 0x%x (%d) to free lists", + gclog_or_tty->print_cr(" -- add free block " PTR_FORMAT " (" SIZE_FORMAT ") to free lists", chunk, size); } // A new free range is going to be starting. The current diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -265,7 +265,7 @@ slots += _spoolHead->bufferSize - 1; blocks++; } - gclog_or_tty->print_cr(" [worker %d] promo_blocks = %d, promo_slots = %d ", + gclog_or_tty->print_cr(" [worker %d] promo_blocks = " SIZE_FORMAT ", promo_slots = " SIZE_FORMAT, worker_id, blocks, slots); } diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -29,7 +29,7 @@ #include "gc_implementation/g1/g1HotCardCache.hpp" #include "runtime/java.hpp" -ConcurrentG1Refine::ConcurrentG1Refine(G1CollectedHeap* g1h) : +ConcurrentG1Refine::ConcurrentG1Refine(G1CollectedHeap* g1h, CardTableEntryClosure* refine_closure) : _threads(NULL), _n_threads(0), _hot_card_cache(g1h) { @@ -61,7 +61,7 @@ ConcurrentG1RefineThread *next = NULL; for (uint i = _n_threads - 1; i != UINT_MAX; i--) { - ConcurrentG1RefineThread* t = new ConcurrentG1RefineThread(this, next, worker_id_offset, i); + ConcurrentG1RefineThread* t = new ConcurrentG1RefineThread(this, next, refine_closure, worker_id_offset, i); assert(t != NULL, "Conc refine should have been created"); if (t->osthread() == NULL) { vm_shutdown_during_initialization("Could not create ConcurrentG1RefineThread"); diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -71,7 +71,7 @@ void reset_threshold_step(); public: - ConcurrentG1Refine(G1CollectedHeap* g1h); + ConcurrentG1Refine(G1CollectedHeap* g1h, CardTableEntryClosure* refine_closure); ~ConcurrentG1Refine(); void init(); // Accomplish some initialization that has to wait. diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -33,8 +33,10 @@ ConcurrentG1RefineThread:: ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread *next, + CardTableEntryClosure* refine_closure, uint worker_id_offset, uint worker_id) : ConcurrentGCThread(), + _refine_closure(refine_closure), _worker_id_offset(worker_id_offset), _worker_id(worker_id), _active(false), @@ -71,6 +73,7 @@ } void ConcurrentG1RefineThread::sample_young_list_rs_lengths() { + SuspendibleThreadSetJoiner sts; G1CollectedHeap* g1h = G1CollectedHeap::heap(); G1CollectorPolicy* g1p = g1h->g1_policy(); if (g1p->adaptive_young_list_length()) { @@ -82,8 +85,8 @@ // we try to yield every time we visit 10 regions if (regions_visited == 10) { - if (_sts.should_yield()) { - _sts.yield("G1 refine"); + if (sts.should_yield()) { + sts.yield(); // we just abandon the iteration break; } @@ -99,9 +102,7 @@ DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); _vtime_start = os::elapsedVTime(); while(!_should_terminate) { - _sts.join(); sample_young_list_rs_lengths(); - _sts.leave(); if (os::supports_vtime()) { _vtime_accum = (os::elapsedVTime() - _vtime_start); @@ -182,37 +183,37 @@ break; } - _sts.join(); + { + SuspendibleThreadSetJoiner sts; + + do { + int curr_buffer_num = (int)dcqs.completed_buffers_num(); + // If the number of the buffers falls down into the yellow zone, + // that means that the transition period after the evacuation pause has ended. + if (dcqs.completed_queue_padding() > 0 && curr_buffer_num <= cg1r()->yellow_zone()) { + dcqs.set_completed_queue_padding(0); + } - do { - int curr_buffer_num = (int)dcqs.completed_buffers_num(); - // If the number of the buffers falls down into the yellow zone, - // that means that the transition period after the evacuation pause has ended. - if (dcqs.completed_queue_padding() > 0 && curr_buffer_num <= cg1r()->yellow_zone()) { - dcqs.set_completed_queue_padding(0); - } + if (_worker_id > 0 && curr_buffer_num <= _deactivation_threshold) { + // If the number of the buffer has fallen below our threshold + // we should deactivate. The predecessor will reactivate this + // thread should the number of the buffers cross the threshold again. + deactivate(); + break; + } - if (_worker_id > 0 && curr_buffer_num <= _deactivation_threshold) { - // If the number of the buffer has fallen below our threshold - // we should deactivate. The predecessor will reactivate this - // thread should the number of the buffers cross the threshold again. + // Check if we need to activate the next thread. + if (_next != NULL && !_next->is_active() && curr_buffer_num > _next->_threshold) { + _next->activate(); + } + } while (dcqs.apply_closure_to_completed_buffer(_refine_closure, _worker_id + _worker_id_offset, cg1r()->green_zone())); + + // We can exit the loop above while being active if there was a yield request. + if (is_active()) { deactivate(); - break; } - - // Check if we need to activate the next thread. - if (_next != NULL && !_next->is_active() && curr_buffer_num > _next->_threshold) { - _next->activate(); - } - } while (dcqs.apply_closure_to_completed_buffer(_worker_id + _worker_id_offset, cg1r()->green_zone())); - - // We can exit the loop above while being active if there was a yield request. - if (is_active()) { - deactivate(); } - _sts.leave(); - if (os::supports_vtime()) { _vtime_accum = (os::elapsedVTime() - _vtime_start); } else { @@ -223,17 +224,6 @@ terminate(); } - -void ConcurrentG1RefineThread::yield() { - if (G1TraceConcRefinement) { - gclog_or_tty->print_cr("G1-Refine-yield"); - } - _sts.yield("G1 refine"); - if (G1TraceConcRefinement) { - gclog_or_tty->print_cr("G1-Refine-yield-end"); - } -} - void ConcurrentG1RefineThread::stop() { // it is ok to take late safepoints here, if needed { diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -28,6 +28,7 @@ #include "gc_implementation/shared/concurrentGCThread.hpp" // Forward Decl. +class CardTableEntryClosure; class ConcurrentG1Refine; // The G1 Concurrent Refinement Thread (could be several in the future). @@ -49,6 +50,9 @@ Monitor* _monitor; ConcurrentG1Refine* _cg1r; + // The closure applied to completed log buffers. + CardTableEntryClosure* _refine_closure; + int _thread_threshold_step; // This thread activation threshold int _threshold; @@ -64,13 +68,11 @@ void activate(); void deactivate(); - // For use by G1CollectedHeap, which is a friend. - static SuspendibleThreadSet* sts() { return &_sts; } - public: virtual void run(); // Constructor ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread* next, + CardTableEntryClosure* refine_closure, uint worker_id_offset, uint worker_id); void initialize(); @@ -84,8 +86,6 @@ ConcurrentG1Refine* cg1r() { return _cg1r; } - // Yield for GC - void yield(); // shutdown void stop(); }; diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -976,11 +976,11 @@ } if (concurrent()) { - ConcurrentGCThread::stsLeave(); + SuspendibleThreadSet::leave(); } _first_overflow_barrier_sync.enter(); if (concurrent()) { - ConcurrentGCThread::stsJoin(); + SuspendibleThreadSet::join(); } // at this point everyone should have synced up and not be doing any // more work @@ -1024,11 +1024,11 @@ } if (concurrent()) { - ConcurrentGCThread::stsLeave(); + SuspendibleThreadSet::leave(); } _second_overflow_barrier_sync.enter(); if (concurrent()) { - ConcurrentGCThread::stsJoin(); + SuspendibleThreadSet::join(); } // at this point everything should be re-initialized and ready to go @@ -1076,7 +1076,7 @@ double start_vtime = os::elapsedVTime(); - ConcurrentGCThread::stsJoin(); + SuspendibleThreadSet::join(); assert(worker_id < _cm->active_tasks(), "invariant"); CMTask* the_task = _cm->task(worker_id); @@ -1103,9 +1103,9 @@ if (!_cm->has_aborted() && the_task->has_aborted()) { sleep_time_ms = (jlong) (elapsed_vtime_sec * _cm->sleep_factor() * 1000.0); - ConcurrentGCThread::stsLeave(); + SuspendibleThreadSet::leave(); os::sleep(Thread::current(), sleep_time_ms, false); - ConcurrentGCThread::stsJoin(); + SuspendibleThreadSet::join(); } double end_time2_sec = os::elapsedTime(); double elapsed_time2_sec = end_time2_sec - start_time_sec; @@ -1123,7 +1123,7 @@ the_task->record_end_time(); guarantee(!the_task->has_aborted() || _cm->has_aborted(), "invariant"); - ConcurrentGCThread::stsLeave(); + SuspendibleThreadSet::leave(); double end_vtime = os::elapsedVTime(); _cm->update_accum_task_vtime(worker_id, end_vtime - start_vtime); @@ -2655,7 +2655,6 @@ str = " O"; } else { HeapRegion* hr = _g1h->heap_region_containing(obj); - guarantee(hr != NULL, "invariant"); bool over_tams = _g1h->allocated_since_marking(obj, hr, _vo); bool marked = _g1h->is_marked(obj, _vo); @@ -3302,21 +3301,17 @@ // We take a break if someone is trying to stop the world. bool ConcurrentMark::do_yield_check(uint worker_id) { - if (should_yield()) { + if (SuspendibleThreadSet::should_yield()) { if (worker_id == 0) { _g1h->g1_policy()->record_concurrent_pause(); } - cmThread()->yield(); + SuspendibleThreadSet::yield(); return true; } else { return false; } } -bool ConcurrentMark::should_yield() { - return cmThread()->should_yield(); -} - bool ConcurrentMark::containing_card_is_marked(void* p) { size_t offset = pointer_delta(p, _g1h->reserved_region().start(), 1); return _card_bm.at(offset >> CardTableModRefBS::card_shift); @@ -3417,9 +3412,8 @@ } void CMTask::setup_for_region(HeapRegion* hr) { - // Separated the asserts so that we know which one fires. assert(hr != NULL, - "claim_region() should have filtered out continues humongous regions"); + "claim_region() should have filtered out NULL regions"); assert(!hr->continuesHumongous(), "claim_region() should have filtered out continues humongous regions"); @@ -3605,7 +3599,7 @@ #endif // _MARKING_STATS_ // (4) We check whether we should yield. If we have to, then we abort. - if (_cm->should_yield()) { + if (SuspendibleThreadSet::should_yield()) { // We should yield. To do this we abort the task. The caller is // responsible for yielding. set_has_aborted(); @@ -3754,7 +3748,7 @@ if (_task_queue->size() > target_size) { if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%u] draining local queue, target size = %d", + gclog_or_tty->print_cr("[%u] draining local queue, target size = " SIZE_FORMAT, _worker_id, target_size); } @@ -3782,7 +3776,7 @@ } if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%u] drained local queue, size = %d", + gclog_or_tty->print_cr("[%u] drained local queue, size = %u", _worker_id, _task_queue->size()); } } @@ -3810,7 +3804,7 @@ if (_cm->mark_stack_size() > target_size) { if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%u] draining global_stack, target size %d", + gclog_or_tty->print_cr("[%u] draining global_stack, target size " SIZE_FORMAT, _worker_id, target_size); } @@ -3820,7 +3814,7 @@ } if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%u] drained global stack, size = %d", + gclog_or_tty->print_cr("[%u] drained global stack, size = " SIZE_FORMAT, _worker_id, _cm->mark_stack_size()); } } diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -814,7 +814,6 @@ } inline bool do_yield_check(uint worker_i = 0); - inline bool should_yield(); // Called to abort the marking cycle after a Full GC takes place. void abort(); diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -89,6 +89,10 @@ while (!_should_terminate) { // wait until started is set. sleepBeforeNextCycle(); + if (_should_terminate) { + break; + } + { ResourceMark rm; HandleMark hm; @@ -190,9 +194,8 @@ } else { // We don't want to update the marking status if a GC pause // is already underway. - _sts.join(); + SuspendibleThreadSetJoiner sts; g1h->set_marking_complete(); - _sts.leave(); } // Check if cleanup set the free_regions_coming flag. If it @@ -262,11 +265,12 @@ // record_concurrent_mark_cleanup_completed() (and, in fact, it's // not needed any more as the concurrent mark state has been // already reset). - _sts.join(); - if (!cm()->has_aborted()) { - g1_policy->record_concurrent_mark_cleanup_completed(); + { + SuspendibleThreadSetJoiner sts; + if (!cm()->has_aborted()) { + g1_policy->record_concurrent_mark_cleanup_completed(); + } } - _sts.leave(); if (cm()->has_aborted()) { if (G1Log::fine()) { @@ -278,36 +282,43 @@ // We now want to allow clearing of the marking bitmap to be // suspended by a collection pause. - _sts.join(); - _cm->clearNextBitmap(); - _sts.leave(); + { + SuspendibleThreadSetJoiner sts; + _cm->clearNextBitmap(); + } } // Update the number of full collections that have been // completed. This will also notify the FullGCCount_lock in case a // Java thread is waiting for a full GC to happen (e.g., it // called System.gc() with +ExplicitGCInvokesConcurrent). - _sts.join(); - g1h->increment_old_marking_cycles_completed(true /* concurrent */); - g1h->register_concurrent_cycle_end(); - _sts.leave(); + { + SuspendibleThreadSetJoiner sts; + g1h->increment_old_marking_cycles_completed(true /* concurrent */); + g1h->register_concurrent_cycle_end(); + } } assert(_should_terminate, "just checking"); terminate(); } - -void ConcurrentMarkThread::yield() { - _sts.yield("Concurrent Mark"); -} +void ConcurrentMarkThread::stop() { + { + MutexLockerEx ml(Terminator_lock); + _should_terminate = true; + } -void ConcurrentMarkThread::stop() { - // it is ok to take late safepoints here, if needed - MutexLockerEx mu(Terminator_lock); - _should_terminate = true; - while (!_has_terminated) { - Terminator_lock->wait(); + { + MutexLockerEx ml(CGC_lock, Mutex::_no_safepoint_check_flag); + CGC_lock->notify_all(); + } + + { + MutexLockerEx ml(Terminator_lock); + while (!_has_terminated) { + Terminator_lock->wait(); + } } } @@ -327,11 +338,14 @@ assert(!in_progress(), "should have been cleared"); MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag); - while (!started()) { + while (!started() && !_should_terminate) { CGC_lock->wait(Mutex::_no_safepoint_check_flag); } - set_in_progress(); - clear_started(); + + if (started()) { + set_in_progress(); + clear_started(); + } } // Note: As is the case with CMS - this method, although exported diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -89,9 +89,6 @@ // that started() is set and set in_progress(). bool during_cycle() { return started() || in_progress(); } - // Yield for GC - void yield(); - // shutdown void stop(); }; diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -70,7 +70,7 @@ DirtyCardQueueSet::DirtyCardQueueSet(bool notify_when_complete) : PtrQueueSet(notify_when_complete), - _closure(NULL), + _mut_process_closure(NULL), _shared_dirty_card_queue(this, true /*perm*/), _free_ids(NULL), _processed_buffers_mut(0), _processed_buffers_rs_thread(0) @@ -83,10 +83,11 @@ return (uint)os::processor_count(); } -void DirtyCardQueueSet::initialize(Monitor* cbl_mon, Mutex* fl_lock, +void DirtyCardQueueSet::initialize(CardTableEntryClosure* cl, Monitor* cbl_mon, Mutex* fl_lock, int process_completed_threshold, int max_completed_queue, Mutex* lock, PtrQueueSet* fl_owner) { + _mut_process_closure = cl; PtrQueueSet::initialize(cbl_mon, fl_lock, process_completed_threshold, max_completed_queue, fl_owner); set_buffer_size(G1UpdateBufferSize); @@ -98,18 +99,15 @@ t->dirty_card_queue().handle_zero_index(); } -void DirtyCardQueueSet::set_closure(CardTableEntryClosure* closure) { - _closure = closure; -} - -void DirtyCardQueueSet::iterate_closure_all_threads(bool consume, +void DirtyCardQueueSet::iterate_closure_all_threads(CardTableEntryClosure* cl, + bool consume, uint worker_i) { assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); for(JavaThread* t = Threads::first(); t; t = t->next()) { - bool b = t->dirty_card_queue().apply_closure(_closure, consume); + bool b = t->dirty_card_queue().apply_closure(cl, consume); guarantee(b, "Should not be interrupted."); } - bool b = shared_dirty_card_queue()->apply_closure(_closure, + bool b = shared_dirty_card_queue()->apply_closure(cl, consume, worker_i); guarantee(b, "Should not be interrupted."); @@ -143,7 +141,7 @@ bool b = false; if (worker_i != UINT_MAX) { - b = DirtyCardQueue::apply_closure_to_buffer(_closure, buf, 0, + b = DirtyCardQueue::apply_closure_to_buffer(_mut_process_closure, buf, 0, _sz, true, worker_i); if (b) Atomic::inc(&_processed_buffers_mut); @@ -218,18 +216,11 @@ return res; } -bool DirtyCardQueueSet::apply_closure_to_completed_buffer(uint worker_i, - int stop_at, - bool during_pause) { - return apply_closure_to_completed_buffer(_closure, worker_i, - stop_at, during_pause); -} - -void DirtyCardQueueSet::apply_closure_to_all_completed_buffers() { +void DirtyCardQueueSet::apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl) { BufferNode* nd = _completed_buffers_head; while (nd != NULL) { bool b = - DirtyCardQueue::apply_closure_to_buffer(_closure, + DirtyCardQueue::apply_closure_to_buffer(cl, BufferNode::make_buffer_from_node(nd), 0, _sz, false); guarantee(b, "Should not stop early."); @@ -237,6 +228,24 @@ } } +void DirtyCardQueueSet::par_apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl) { + BufferNode* nd = _cur_par_buffer_node; + while (nd != NULL) { + BufferNode* next = (BufferNode*)nd->next(); + BufferNode* actual = (BufferNode*)Atomic::cmpxchg_ptr((void*)next, (volatile void*)&_cur_par_buffer_node, (void*)nd); + if (actual == nd) { + bool b = + DirtyCardQueue::apply_closure_to_buffer(cl, + BufferNode::make_buffer_from_node(actual), + 0, _sz, false); + guarantee(b, "Should not stop early."); + nd = next; + } else { + nd = actual; + } + } +} + // Deallocates any completed log buffers void DirtyCardQueueSet::clear() { BufferNode* buffers_to_delete = NULL; diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -73,7 +73,8 @@ class DirtyCardQueueSet: public PtrQueueSet { - CardTableEntryClosure* _closure; + // The closure used in mut_process_buffer(). + CardTableEntryClosure* _mut_process_closure; DirtyCardQueue _shared_dirty_card_queue; @@ -88,10 +89,12 @@ jint _processed_buffers_mut; jint _processed_buffers_rs_thread; + // Current buffer node used for parallel iteration. + BufferNode* volatile _cur_par_buffer_node; public: DirtyCardQueueSet(bool notify_when_complete = true); - void initialize(Monitor* cbl_mon, Mutex* fl_lock, + void initialize(CardTableEntryClosure* cl, Monitor* cbl_mon, Mutex* fl_lock, int process_completed_threshold, int max_completed_queue, Mutex* lock, PtrQueueSet* fl_owner = NULL); @@ -102,33 +105,15 @@ static void handle_zero_index_for_thread(JavaThread* t); - // Register "blk" as "the closure" for all queues. Only one such closure - // is allowed. The "apply_closure_to_completed_buffer" method will apply - // this closure to a completed buffer, and "iterate_closure_all_threads" - // applies it to partially-filled buffers (the latter should only be done - // with the world stopped). - void set_closure(CardTableEntryClosure* closure); - - // If there is a registered closure for buffers, apply it to all entries - // in all currently-active buffers. This should only be applied at a - // safepoint. (Currently must not be called in parallel; this should - // change in the future.) If "consume" is true, processed entries are - // discarded. - void iterate_closure_all_threads(bool consume = true, + // Apply the given closure to all entries in all currently-active buffers. + // This should only be applied at a safepoint. (Currently must not be called + // in parallel; this should change in the future.) If "consume" is true, + // processed entries are discarded. + void iterate_closure_all_threads(CardTableEntryClosure* cl, + bool consume = true, uint worker_i = 0); // If there exists some completed buffer, pop it, then apply the - // registered closure to all its elements, nulling out those elements - // processed. If all elements are processed, returns "true". If no - // completed buffers exist, returns false. If a completed buffer exists, - // but is only partially completed before a "yield" happens, the - // partially completed buffer (with its processed elements set to NULL) - // is returned to the completed buffer set, and this call returns false. - bool apply_closure_to_completed_buffer(uint worker_i = 0, - int stop_at = 0, - bool during_pause = false); - - // If there exists some completed buffer, pop it, then apply the // specified closure to all its elements, nulling out those elements // processed. If all elements are processed, returns "true". If no // completed buffers exist, returns false. If a completed buffer exists, @@ -149,7 +134,12 @@ // Applies the current closure to all completed buffers, // non-consumptively. - void apply_closure_to_all_completed_buffers(); + void apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl); + + void reset_for_par_iteration() { _cur_par_buffer_node = _completed_buffers_head; } + // Applies the current closure to all completed buffers, non-consumptively. + // Parallel version. + void par_apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl); DirtyCardQueue* shared_dirty_card_queue() { return &_shared_dirty_card_queue; diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -45,32 +45,27 @@ } } -FreeList G1CodeRootSet::_free_list; -size_t G1CodeRootSet::_num_chunks_handed_out = 0; - -G1CodeRootChunk* G1CodeRootSet::new_chunk() { - G1CodeRootChunk* result = _free_list.get_chunk_at_head(); - if (result == NULL) { - result = new G1CodeRootChunk(); - } - G1CodeRootSet::_num_chunks_handed_out++; - result->reset(); - return result; +G1CodeRootChunkManager::G1CodeRootChunkManager() : _free_list(), _num_chunks_handed_out(0) { + _free_list.initialize(); + _free_list.set_size(G1CodeRootChunk::word_size()); } -void G1CodeRootSet::free_chunk(G1CodeRootChunk* chunk) { - _free_list.return_chunk_at_head(chunk); - G1CodeRootSet::_num_chunks_handed_out--; +size_t G1CodeRootChunkManager::fl_mem_size() { + return _free_list.count() * _free_list.size(); } -void G1CodeRootSet::free_all_chunks(FreeList* list) { - G1CodeRootSet::_num_chunks_handed_out -= list->count(); +void G1CodeRootChunkManager::free_all_chunks(FreeList* list) { + _num_chunks_handed_out -= list->count(); _free_list.prepend(list); } -void G1CodeRootSet::purge_chunks(size_t keep_ratio) { - size_t keep = G1CodeRootSet::_num_chunks_handed_out * keep_ratio / 100; +void G1CodeRootChunkManager::free_chunk(G1CodeRootChunk* chunk) { + _free_list.return_chunk_at_head(chunk); + _num_chunks_handed_out--; +} +void G1CodeRootChunkManager::purge_chunks(size_t keep_ratio) { + size_t keep = _num_chunks_handed_out * keep_ratio / 100; if (keep >= (size_t)_free_list.count()) { return; } @@ -88,20 +83,51 @@ } } -size_t G1CodeRootSet::static_mem_size() { - return sizeof(_free_list) + sizeof(_num_chunks_handed_out); +size_t G1CodeRootChunkManager::static_mem_size() { + return sizeof(G1CodeRootChunkManager); +} + + +G1CodeRootChunk* G1CodeRootChunkManager::new_chunk() { + G1CodeRootChunk* result = _free_list.get_chunk_at_head(); + if (result == NULL) { + result = new G1CodeRootChunk(); + } + _num_chunks_handed_out++; + result->reset(); + return result; +} + +#ifndef PRODUCT + +size_t G1CodeRootChunkManager::num_chunks_handed_out() const { + return _num_chunks_handed_out; } -size_t G1CodeRootSet::fl_mem_size() { - return _free_list.count() * _free_list.size(); +size_t G1CodeRootChunkManager::num_free_chunks() const { + return (size_t)_free_list.count(); +} + +#endif + +G1CodeRootChunkManager G1CodeRootSet::_default_chunk_manager; + +void G1CodeRootSet::purge_chunks(size_t keep_ratio) { + _default_chunk_manager.purge_chunks(keep_ratio); } -void G1CodeRootSet::initialize() { - _free_list.initialize(); - _free_list.set_size(G1CodeRootChunk::word_size()); +size_t G1CodeRootSet::free_chunks_static_mem_size() { + return _default_chunk_manager.static_mem_size(); } -G1CodeRootSet::G1CodeRootSet() : _list(), _length(0) { +size_t G1CodeRootSet::free_chunks_mem_size() { + return _default_chunk_manager.fl_mem_size(); +} + +G1CodeRootSet::G1CodeRootSet(G1CodeRootChunkManager* manager) : _manager(manager), _list(), _length(0) { + if (_manager == NULL) { + _manager = &_default_chunk_manager; + } _list.initialize(); _list.set_size(G1CodeRootChunk::word_size()); } @@ -187,28 +213,38 @@ } } +size_t G1CodeRootSet::static_mem_size() { + return sizeof(G1CodeRootSet); +} + size_t G1CodeRootSet::mem_size() { - return sizeof(this) + _list.count() * _list.size(); + return G1CodeRootSet::static_mem_size() + _list.count() * _list.size(); } #ifndef PRODUCT void G1CodeRootSet::test() { - initialize(); + G1CodeRootChunkManager mgr; - assert(_free_list.count() == 0, "Free List must be empty"); - assert(_num_chunks_handed_out == 0, "No elements must have been handed out yet"); + assert(mgr.num_chunks_handed_out() == 0, "Must not have handed out chunks yet"); + + assert(G1CodeRootChunkManager::static_mem_size() > sizeof(void*), + err_msg("The chunk manager's static memory usage seems too small, is only "SIZE_FORMAT" bytes.", G1CodeRootChunkManager::static_mem_size())); // The number of chunks that we allocate for purge testing. size_t const num_chunks = 10; + { - G1CodeRootSet set1; + G1CodeRootSet set1(&mgr); assert(set1.is_empty(), "Code root set must be initially empty but is not."); + assert(G1CodeRootSet::static_mem_size() > sizeof(void*), + err_msg("The code root set's static memory usage seems too small, is only "SIZE_FORMAT" bytes", G1CodeRootSet::static_mem_size())); + set1.add((nmethod*)1); - assert(_num_chunks_handed_out == 1, + assert(mgr.num_chunks_handed_out() == 1, err_msg("Must have allocated and handed out one chunk, but handed out " - SIZE_FORMAT" chunks", _num_chunks_handed_out)); + SIZE_FORMAT" chunks", mgr.num_chunks_handed_out())); assert(set1.length() == 1, err_msg("Added exactly one element, but set contains " SIZE_FORMAT" elements", set1.length())); @@ -217,19 +253,19 @@ for (uint i = 0; i < G1CodeRootChunk::word_size() + 1; i++) { set1.add((nmethod*)1); } - assert(_num_chunks_handed_out == 1, + assert(mgr.num_chunks_handed_out() == 1, err_msg("Duplicate detection must have prevented allocation of further " - "chunks but contains "SIZE_FORMAT, _num_chunks_handed_out)); + "chunks but allocated "SIZE_FORMAT, mgr.num_chunks_handed_out())); assert(set1.length() == 1, err_msg("Duplicate detection should not have increased the set size but " "is "SIZE_FORMAT, set1.length())); size_t num_total_after_add = G1CodeRootChunk::word_size() + 1; for (size_t i = 0; i < num_total_after_add - 1; i++) { - set1.add((nmethod*)(2 + i)); + set1.add((nmethod*)(uintptr_t)(2 + i)); } - assert(_num_chunks_handed_out > 1, - "After adding more code roots, more than one chunks should have been handed out"); + assert(mgr.num_chunks_handed_out() > 1, + "After adding more code roots, more than one additional chunk should have been handed out"); assert(set1.length() == num_total_after_add, err_msg("After adding in total "SIZE_FORMAT" distinct code roots, they " "need to be in the set, but there are only "SIZE_FORMAT, @@ -242,27 +278,27 @@ assert(num_popped == num_total_after_add, err_msg("Managed to pop "SIZE_FORMAT" code roots, but only "SIZE_FORMAT" " "were added", num_popped, num_total_after_add)); - assert(_num_chunks_handed_out == 0, + assert(mgr.num_chunks_handed_out() == 0, err_msg("After popping all elements, all chunks must have been returned " - "but are still "SIZE_FORMAT, _num_chunks_handed_out)); + "but there are still "SIZE_FORMAT" additional", mgr.num_chunks_handed_out())); - purge_chunks(0); - assert(_free_list.count() == 0, + mgr.purge_chunks(0); + assert(mgr.num_free_chunks() == 0, err_msg("After purging everything, the free list must be empty but still " - "contains "SIZE_FORMAT" chunks", _free_list.count())); + "contains "SIZE_FORMAT" chunks", mgr.num_free_chunks())); // Add some more handed out chunks. size_t i = 0; - while (_num_chunks_handed_out < num_chunks) { + while (mgr.num_chunks_handed_out() < num_chunks) { set1.add((nmethod*)i); i++; } { // Generate chunks on the free list. - G1CodeRootSet set2; + G1CodeRootSet set2(&mgr); size_t i = 0; - while (_num_chunks_handed_out < num_chunks * 2) { + while (mgr.num_chunks_handed_out() < (num_chunks * 2)) { set2.add((nmethod*)i); i++; } @@ -270,45 +306,45 @@ // num_chunks elements on the free list. } - assert(_num_chunks_handed_out == num_chunks, + assert(mgr.num_chunks_handed_out() == num_chunks, err_msg("Deletion of the second set must have resulted in giving back " - "those, but there is still "SIZE_FORMAT" handed out, expecting " - SIZE_FORMAT, _num_chunks_handed_out, num_chunks)); - assert((size_t)_free_list.count() == num_chunks, + "those, but there are still "SIZE_FORMAT" additional handed out, expecting " + SIZE_FORMAT, mgr.num_chunks_handed_out(), num_chunks)); + assert(mgr.num_free_chunks() == num_chunks, err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list " - "but there are only "SIZE_FORMAT, num_chunks, _free_list.count())); + "but there are only "SIZE_FORMAT, num_chunks, mgr.num_free_chunks())); size_t const test_percentage = 50; - purge_chunks(test_percentage); - assert(_num_chunks_handed_out == num_chunks, + mgr.purge_chunks(test_percentage); + assert(mgr.num_chunks_handed_out() == num_chunks, err_msg("Purging must not hand out chunks but there are "SIZE_FORMAT, - _num_chunks_handed_out)); - assert((size_t)_free_list.count() == (ssize_t)(num_chunks * test_percentage / 100), + mgr.num_chunks_handed_out())); + assert(mgr.num_free_chunks() == (size_t)(mgr.num_chunks_handed_out() * test_percentage / 100), err_msg("Must have purged "SIZE_FORMAT" percent of "SIZE_FORMAT" chunks" - "but there are "SSIZE_FORMAT, test_percentage, num_chunks, - _free_list.count())); + "but there are "SIZE_FORMAT, test_percentage, num_chunks, + mgr.num_free_chunks())); // Purge the remainder of the chunks on the free list. - purge_chunks(0); - assert(_free_list.count() == 0, "Free List must be empty"); - assert(_num_chunks_handed_out == num_chunks, + mgr.purge_chunks(0); + assert(mgr.num_free_chunks() == 0, "Free List must be empty"); + assert(mgr.num_chunks_handed_out() == num_chunks, err_msg("Expected to be "SIZE_FORMAT" chunks handed out from the first set " - "but there are "SIZE_FORMAT, num_chunks, _num_chunks_handed_out)); + "but there are "SIZE_FORMAT, num_chunks, mgr.num_chunks_handed_out())); // Exit of the scope of the set1 object will call the destructor that generates // num_chunks additional elements on the free list. - } + } - assert(_num_chunks_handed_out == 0, + assert(mgr.num_chunks_handed_out() == 0, err_msg("Deletion of the only set must have resulted in no chunks handed " - "out, but there is still "SIZE_FORMAT" handed out", _num_chunks_handed_out)); - assert((size_t)_free_list.count() == num_chunks, + "out, but there is still "SIZE_FORMAT" handed out", mgr.num_chunks_handed_out())); + assert(mgr.num_free_chunks() == num_chunks, err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list " - "but there are only "SSIZE_FORMAT, num_chunks, _free_list.count())); + "but there are only "SIZE_FORMAT, num_chunks, mgr.num_free_chunks())); // Restore initial state. - purge_chunks(0); - assert(_free_list.count() == 0, "Free List must be empty"); - assert(_num_chunks_handed_out == 0, "No elements must have been handed out yet"); + mgr.purge_chunks(0); + assert(mgr.num_free_chunks() == 0, "Free List must be empty"); + assert(mgr.num_chunks_handed_out() == 0, "No additional elements must have been handed out yet"); } void TestCodeCacheRemSet_test() { diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -128,19 +128,45 @@ } }; +// Manages free chunks. +class G1CodeRootChunkManager VALUE_OBJ_CLASS_SPEC { + private: + // Global free chunk list management + FreeList _free_list; + // Total number of chunks handed out + size_t _num_chunks_handed_out; + + public: + G1CodeRootChunkManager(); + + G1CodeRootChunk* new_chunk(); + void free_chunk(G1CodeRootChunk* chunk); + // Free all elements of the given list. + void free_all_chunks(FreeList* list); + + void initialize(); + void purge_chunks(size_t keep_ratio); + + static size_t static_mem_size(); + size_t fl_mem_size(); + +#ifndef PRODUCT + size_t num_chunks_handed_out() const; + size_t num_free_chunks() const; +#endif +}; + // Implements storage for a set of code roots. // All methods that modify the set are not thread-safe except if otherwise noted. class G1CodeRootSet VALUE_OBJ_CLASS_SPEC { private: - // Global free chunk list management - static FreeList _free_list; - // Total number of chunks handed out - static size_t _num_chunks_handed_out; + // Global default free chunk manager instance. + static G1CodeRootChunkManager _default_chunk_manager; - static G1CodeRootChunk* new_chunk(); - static void free_chunk(G1CodeRootChunk* chunk); + G1CodeRootChunk* new_chunk() { return _manager->new_chunk(); } + void free_chunk(G1CodeRootChunk* chunk) { _manager->free_chunk(chunk); } // Free all elements of the given list. - static void free_all_chunks(FreeList* list); + void free_all_chunks(FreeList* list) { _manager->free_all_chunks(list); } // Return the chunk that contains the given nmethod, NULL otherwise. // Scans the list of chunks backwards, as this method is used to add new @@ -150,16 +176,18 @@ size_t _length; FreeList _list; + G1CodeRootChunkManager* _manager; public: - G1CodeRootSet(); + // If an instance is initialized with a chunk manager of NULL, use the global + // default one. + G1CodeRootSet(G1CodeRootChunkManager* manager = NULL); ~G1CodeRootSet(); - static void initialize(); static void purge_chunks(size_t keep_ratio); - static size_t static_mem_size(); - static size_t fl_mem_size(); + static size_t free_chunks_static_mem_size(); + static size_t free_chunks_mem_size(); // Search for the code blob from the recently allocated ones to find duplicates more quickly, as this // method is likely to be repeatedly called with the same nmethod. @@ -179,6 +207,8 @@ // Length in elements size_t length() const { return _length; } + // Static data memory size in bytes of this set. + static size_t static_mem_size(); // Memory size in bytes taken by this set. size_t mem_size(); diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -57,6 +57,7 @@ #include "oops/oop.inline.hpp" #include "oops/oop.pcgc.inline.hpp" #include "runtime/vmThread.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/ticks.hpp" size_t G1CollectedHeap::_humongous_object_threshold_in_words = 0; @@ -92,56 +93,54 @@ // Local to this file. class RefineCardTableEntryClosure: public CardTableEntryClosure { - SuspendibleThreadSet* _sts; - G1RemSet* _g1rs; - ConcurrentG1Refine* _cg1r; bool _concurrent; public: - RefineCardTableEntryClosure(SuspendibleThreadSet* sts, - G1RemSet* g1rs, - ConcurrentG1Refine* cg1r) : - _sts(sts), _g1rs(g1rs), _cg1r(cg1r), _concurrent(true) - {} + RefineCardTableEntryClosure() : _concurrent(true) { } + bool do_card_ptr(jbyte* card_ptr, uint worker_i) { - bool oops_into_cset = _g1rs->refine_card(card_ptr, worker_i, false); + bool oops_into_cset = G1CollectedHeap::heap()->g1_rem_set()->refine_card(card_ptr, worker_i, false); // This path is executed by the concurrent refine or mutator threads, // concurrently, and so we do not care if card_ptr contains references // that point into the collection set. assert(!oops_into_cset, "should be"); - if (_concurrent && _sts->should_yield()) { + if (_concurrent && SuspendibleThreadSet::should_yield()) { // Caller will actually yield. return false; } // Otherwise, we finished successfully; return true. return true; } + void set_concurrent(bool b) { _concurrent = b; } }; class ClearLoggedCardTableEntryClosure: public CardTableEntryClosure { - int _calls; - G1CollectedHeap* _g1h; + size_t _num_processed; CardTableModRefBS* _ctbs; int _histo[256]; -public: + + public: ClearLoggedCardTableEntryClosure() : - _calls(0), _g1h(G1CollectedHeap::heap()), _ctbs(_g1h->g1_barrier_set()) + _num_processed(0), _ctbs(G1CollectedHeap::heap()->g1_barrier_set()) { for (int i = 0; i < 256; i++) _histo[i] = 0; } + bool do_card_ptr(jbyte* card_ptr, uint worker_i) { - if (_g1h->is_in_reserved(_ctbs->addr_for(card_ptr))) { - _calls++; - unsigned char* ujb = (unsigned char*)card_ptr; - int ind = (int)(*ujb); - _histo[ind]++; - *card_ptr = -1; - } + unsigned char* ujb = (unsigned char*)card_ptr; + int ind = (int)(*ujb); + _histo[ind]++; + + *card_ptr = (jbyte)CardTableModRefBS::clean_card_val(); + _num_processed++; + return true; } - int calls() { return _calls; } + + size_t num_processed() { return _num_processed; } + void print_histo() { gclog_or_tty->print_cr("Card table value histogram:"); for (int i = 0; i < 256; i++) { @@ -152,22 +151,20 @@ } }; -class RedirtyLoggedCardTableEntryClosure: public CardTableEntryClosure { - int _calls; - G1CollectedHeap* _g1h; - CardTableModRefBS* _ctbs; -public: - RedirtyLoggedCardTableEntryClosure() : - _calls(0), _g1h(G1CollectedHeap::heap()), _ctbs(_g1h->g1_barrier_set()) {} +class RedirtyLoggedCardTableEntryClosure : public CardTableEntryClosure { + private: + size_t _num_processed; + + public: + RedirtyLoggedCardTableEntryClosure() : CardTableEntryClosure(), _num_processed(0) { } bool do_card_ptr(jbyte* card_ptr, uint worker_i) { - if (_g1h->is_in_reserved(_ctbs->addr_for(card_ptr))) { - _calls++; - *card_ptr = 0; - } + *card_ptr = CardTableModRefBS::dirty_card_val(); + _num_processed++; return true; } - int calls() { return _calls; } + + size_t num_processed() const { return _num_processed; } }; YoungList::YoungList(G1CollectedHeap* g1h) : @@ -431,6 +428,9 @@ void G1CollectedHeap::stop_conc_gc_threads() { _cg1r->stop(); _cmThread->stop(); + if (G1StringDedup::is_enabled()) { + G1StringDedup::stop(); + } } #ifdef ASSERT @@ -445,24 +445,18 @@ // implementation of is_scavengable() for G1 will indicate that // all nmethods must be scanned during a partial collection. bool G1CollectedHeap::is_in_partial_collection(const void* p) { - HeapRegion* hr = heap_region_containing(p); - return hr != NULL && hr->in_collection_set(); + if (p == NULL) { + return false; + } + return heap_region_containing(p)->in_collection_set(); } #endif // Returns true if the reference points to an object that // can move in an incremental collection. bool G1CollectedHeap::is_scavengable(const void* p) { - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - G1CollectorPolicy* g1p = g1h->g1_policy(); HeapRegion* hr = heap_region_containing(p); - if (hr == NULL) { - // null - assert(p == NULL, err_msg("Not NULL " PTR_FORMAT ,p)); - return false; - } else { - return !hr->isHumongous(); - } + return !hr->isHumongous(); } void G1CollectedHeap::check_ct_logs_at_safepoint() { @@ -476,9 +470,8 @@ // First clear the logged cards. ClearLoggedCardTableEntryClosure clear; - dcqs.set_closure(&clear); - dcqs.apply_closure_to_all_completed_buffers(); - dcqs.iterate_closure_all_threads(false); + dcqs.apply_closure_to_all_completed_buffers(&clear); + dcqs.iterate_closure_all_threads(&clear, false); clear.print_histo(); // Now ensure that there's no dirty cards. @@ -491,13 +484,13 @@ guarantee(count2.n() == 0, "Card table should be clean."); RedirtyLoggedCardTableEntryClosure redirty; - JavaThread::dirty_card_queue_set().set_closure(&redirty); - dcqs.apply_closure_to_all_completed_buffers(); - dcqs.iterate_closure_all_threads(false); + dcqs.apply_closure_to_all_completed_buffers(&redirty); + dcqs.iterate_closure_all_threads(&redirty, false); gclog_or_tty->print_cr("Log entries = %d, dirty cards = %d.", - clear.calls(), orig_count); - guarantee(redirty.calls() == clear.calls(), - "Or else mechanism is broken."); + clear.num_processed(), orig_count); + guarantee(redirty.num_processed() == clear.num_processed(), + err_msg("Redirtied "SIZE_FORMAT" cards, bug cleared "SIZE_FORMAT, + redirty.num_processed(), clear.num_processed())); CountNonCleanMemRegionClosure count3(this); ct_bs->mod_card_iterate(&count3); @@ -506,8 +499,6 @@ orig_count, count3.n()); guarantee(count3.n() >= orig_count, "Should have restored them all."); } - - JavaThread::dirty_card_queue_set().set_closure(_refine_cte_cl); } // Private class members. @@ -1512,9 +1503,6 @@ assert(g1_policy()->collection_set() == NULL, "must be"); g1_policy()->start_incremental_cset_building(); - // Clear the _cset_fast_test bitmap in anticipation of adding - // regions to the incremental collection set for the next - // evacuation pause. clear_cset_fast_test(); init_mutator_alloc_region(); @@ -1934,8 +1922,7 @@ _old_marking_cycles_started(0), _old_marking_cycles_completed(0), _concurrent_cycle_started(false), - _in_cset_fast_test(NULL), - _in_cset_fast_test_base(NULL), + _in_cset_fast_test(), _dirty_cards_region_list(NULL), _worker_cset_start_region(NULL), _worker_cset_start_region_time_stamp(NULL), @@ -2005,7 +1992,9 @@ Universe::check_alignment(max_byte_size, HeapRegion::GrainBytes, "g1 heap"); Universe::check_alignment(max_byte_size, heap_alignment, "g1 heap"); - _cg1r = new ConcurrentG1Refine(this); + _refine_cte_cl = new RefineCardTableEntryClosure(); + + _cg1r = new ConcurrentG1Refine(this, _refine_cte_cl); // Reserve the maximum. @@ -2077,20 +2066,7 @@ _g1h = this; - _in_cset_fast_test_length = max_regions(); - _in_cset_fast_test_base = - NEW_C_HEAP_ARRAY(bool, (size_t) _in_cset_fast_test_length, mtGC); - - // We're biasing _in_cset_fast_test to avoid subtracting the - // beginning of the heap every time we want to index; basically - // it's the same with what we do with the card table. - _in_cset_fast_test = _in_cset_fast_test_base - - ((uintx) _g1_reserved.start() >> HeapRegion::LogOfHRGrainBytes); - - // Clear the _cset_fast_test bitmap in anticipation of adding - // regions to the incremental collection set for the first - // evacuation pause. - clear_cset_fast_test(); + _in_cset_fast_test.initialize(_g1_reserved.start(), _g1_reserved.end(), HeapRegion::GrainBytes); // Create the ConcurrentMark data structure and thread. // (Must do this late, so that "max_regions" is defined.) @@ -2113,25 +2089,21 @@ // Perform any initialization actions delegated to the policy. g1_policy()->init(); - _refine_cte_cl = - new RefineCardTableEntryClosure(ConcurrentG1RefineThread::sts(), - g1_rem_set(), - concurrent_g1_refine()); - JavaThread::dirty_card_queue_set().set_closure(_refine_cte_cl); - JavaThread::satb_mark_queue_set().initialize(SATB_Q_CBL_mon, SATB_Q_FL_lock, G1SATBProcessCompletedThreshold, Shared_SATB_Q_lock); - JavaThread::dirty_card_queue_set().initialize(DirtyCardQ_CBL_mon, + JavaThread::dirty_card_queue_set().initialize(_refine_cte_cl, + DirtyCardQ_CBL_mon, DirtyCardQ_FL_lock, concurrent_g1_refine()->yellow_zone(), concurrent_g1_refine()->red_zone(), Shared_DirtyCardQ_lock); if (G1DeferredRSUpdate) { - dirty_card_queue_set().initialize(DirtyCardQ_CBL_mon, + dirty_card_queue_set().initialize(NULL, // Should never be called by the Java code + DirtyCardQ_CBL_mon, DirtyCardQ_FL_lock, -1, // never trigger processing -1, // no limit on length @@ -2141,7 +2113,8 @@ // Initialize the card queue set used to hold cards containing // references into the collection set. - _into_cset_dirty_card_queue_set.initialize(DirtyCardQ_CBL_mon, + _into_cset_dirty_card_queue_set.initialize(NULL, // Should never be called by the Java code + DirtyCardQ_CBL_mon, DirtyCardQ_FL_lock, -1, // never trigger processing -1, // no limit on length @@ -2178,6 +2151,23 @@ return JNI_OK; } +void G1CollectedHeap::stop() { +#if 0 + // Stopping concurrent worker threads is currently disabled until + // some bugs in concurrent mark has been resolve. Without fixing + // those bugs first we risk haning during VM exit when trying to + // stop these threads. + + // Abort any ongoing concurrent root region scanning and stop all + // concurrent threads. We do this to make sure these threads do + // not continue to execute and access resources (e.g. gclog_or_tty) + // that are destroyed during shutdown. + _cm->root_regions()->abort(); + _cm->root_regions()->wait_until_scan_finished(); + stop_conc_gc_threads(); +#endif +} + size_t G1CollectedHeap::conservative_max_heap_alignment() { return HeapRegion::max_region_size(); } @@ -2963,21 +2953,16 @@ Space* G1CollectedHeap::space_containing(const void* addr) const { - Space* res = heap_region_containing(addr); - return res; + return heap_region_containing(addr); } HeapWord* G1CollectedHeap::block_start(const void* addr) const { Space* sp = space_containing(addr); - if (sp != NULL) { - return sp->block_start(addr); - } - return NULL; + return sp->block_start(addr); } size_t G1CollectedHeap::block_size(const HeapWord* addr) const { Space* sp = space_containing(addr); - assert(sp != NULL, "block_size of address outside of heap"); return sp->block_size(addr); } @@ -3212,7 +3197,7 @@ _young_ref_counter_closure.reset_count(); k->oops_do(&_young_ref_counter_closure); if (_young_ref_counter_closure.count() > 0) { - guarantee(k->has_modified_oops(), err_msg("Klass %p, has young refs but is not dirty.", k)); + guarantee(k->has_modified_oops(), err_msg("Klass " PTR_FORMAT ", has young refs but is not dirty.", k)); } } }; @@ -3296,7 +3281,7 @@ int *val; for (cur = start; cur < end; cur++) { val = (int *) cur; - gclog_or_tty->print("\t "PTR_FORMAT":"PTR_FORMAT"\n", val, *val); + gclog_or_tty->print("\t "PTR_FORMAT":%d\n", val, *val); } } } @@ -4125,9 +4110,6 @@ // Start a new incremental collection set for the next pause. g1_policy()->start_incremental_cset_building(); - // Clear the _cset_fast_test bitmap in anticipation of adding - // regions to the incremental collection set for the next - // evacuation pause. clear_cset_fast_test(); _young_list->reset_sampled_info(); @@ -4304,7 +4286,7 @@ // this point does not assume that we are the only GC thread // running. Note: of course, the actual marking work will // not start until the safepoint itself is released in - // ConcurrentGCThread::safepoint_desynchronize(). + // SuspendibleThreadSet::desynchronize(). doConcurrentMark(); } @@ -4571,7 +4553,7 @@ } G1ParGCAllocBuffer::G1ParGCAllocBuffer(size_t gclab_word_size) : - ParGCAllocBuffer(gclab_word_size), _retired(false) { } + ParGCAllocBuffer(gclab_word_size), _retired(true) { } G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, uint queue_num, ReferenceProcessor* rp) : _g1h(g1h), @@ -4694,30 +4676,19 @@ _worker_id(par_scan_state->queue_num()) { } void G1ParCopyHelper::mark_object(oop obj) { -#ifdef ASSERT - HeapRegion* hr = _g1->heap_region_containing(obj); - assert(hr != NULL, "sanity"); - assert(!hr->in_collection_set(), "should not mark objects in the CSet"); -#endif // ASSERT + assert(!_g1->heap_region_containing(obj)->in_collection_set(), "should not mark objects in the CSet"); // We know that the object is not moving so it's safe to read its size. _cm->grayRoot(obj, (size_t) obj->size(), _worker_id); } void G1ParCopyHelper::mark_forwarded_object(oop from_obj, oop to_obj) { -#ifdef ASSERT assert(from_obj->is_forwarded(), "from obj should be forwarded"); assert(from_obj->forwardee() == to_obj, "to obj should be the forwardee"); assert(from_obj != to_obj, "should not be self-forwarded"); - HeapRegion* from_hr = _g1->heap_region_containing(from_obj); - assert(from_hr != NULL, "sanity"); - assert(from_hr->in_collection_set(), "from obj should be in the CSet"); - - HeapRegion* to_hr = _g1->heap_region_containing(to_obj); - assert(to_hr != NULL, "sanity"); - assert(!to_hr->in_collection_set(), "should not mark objects in the CSet"); -#endif // ASSERT + assert(_g1->heap_region_containing(from_obj)->in_collection_set(), "from obj should be in the CSet"); + assert(!_g1->heap_region_containing(to_obj)->in_collection_set(), "should not mark objects in the CSet"); // The object might be in the process of being copied by another // worker so we cannot trust that its to-space image is @@ -4935,8 +4906,6 @@ pss->trim_queue(); } } while (!offer_termination()); - - pss->retire_alloc_buffers(); } class G1KlassScanClosure : public KlassClosure { @@ -5273,11 +5242,25 @@ } } -class RedirtyLoggedCardTableEntryFastClosure : public CardTableEntryClosure { -public: - bool do_card_ptr(jbyte* card_ptr, uint worker_i) { - *card_ptr = CardTableModRefBS::dirty_card_val(); - return true; +class G1RedirtyLoggedCardsTask : public AbstractGangTask { + private: + DirtyCardQueueSet* _queue; + public: + G1RedirtyLoggedCardsTask(DirtyCardQueueSet* queue) : AbstractGangTask("Redirty Cards"), _queue(queue) { } + + virtual void work(uint worker_id) { + double start_time = os::elapsedTime(); + + RedirtyLoggedCardTableEntryClosure cl; + if (G1CollectedHeap::heap()->use_parallel_gc_threads()) { + _queue->par_apply_closure_to_all_completed_buffers(&cl); + } else { + _queue->apply_closure_to_all_completed_buffers(&cl); + } + + G1GCPhaseTimes* timer = G1CollectedHeap::heap()->g1_policy()->phase_times(); + timer->record_redirty_logged_cards_time_ms(worker_id, (os::elapsedTime() - start_time) * 1000.0); + timer->record_redirty_logged_cards_processed_cards(worker_id, cl.num_processed()); } }; @@ -5285,9 +5268,18 @@ guarantee(G1DeferredRSUpdate, "Must only be called when using deferred RS updates."); double redirty_logged_cards_start = os::elapsedTime(); - RedirtyLoggedCardTableEntryFastClosure redirty; - dirty_card_queue_set().set_closure(&redirty); - dirty_card_queue_set().apply_closure_to_all_completed_buffers(); + uint n_workers = (G1CollectedHeap::use_parallel_gc_threads() ? + _g1h->workers()->active_workers() : 1); + + G1RedirtyLoggedCardsTask redirty_task(&dirty_card_queue_set()); + dirty_card_queue_set().reset_for_par_iteration(); + if (use_parallel_gc_threads()) { + set_par_threads(n_workers); + workers()->run_task(&redirty_task); + set_par_threads(0); + } else { + redirty_task.work(0); + } DirtyCardQueueSet& dcq = JavaThread::dirty_card_queue_set(); dcq.merge_bufferlists(&dirty_card_queue_set()); @@ -5762,10 +5754,8 @@ } _gc_tracer_stw->report_gc_reference_stats(stats); - // We have completed copying any necessary live referent objects - // (that were not copied during the actual pause) so we can - // retire any active alloc buffers - pss.retire_alloc_buffers(); + + // We have completed copying any necessary live referent objects. assert(pss.refs()->is_empty(), "both queue and overflow should be empty"); double ref_proc_time = os::elapsedTime() - ref_proc_start; @@ -6456,11 +6446,7 @@ bool G1CollectedHeap::is_in_closed_subset(const void* p) const { HeapRegion* hr = heap_region_containing(p); - if (hr == NULL) { - return false; - } else { - return hr->is_in(p); - } + return hr->is_in(p); } // Methods for the mutator alloc region diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -28,6 +28,7 @@ #include "gc_implementation/g1/concurrentMark.hpp" #include "gc_implementation/g1/evacuationInfo.hpp" #include "gc_implementation/g1/g1AllocRegion.hpp" +#include "gc_implementation/g1/g1BiasedArray.hpp" #include "gc_implementation/g1/g1HRPrinter.hpp" #include "gc_implementation/g1/g1MonitoringSupport.hpp" #include "gc_implementation/g1/g1RemSet.hpp" @@ -197,6 +198,16 @@ bool do_object_b(oop p); }; +// Instances of this class are used for quick tests on whether a reference points +// into the collection set. Each of the array's elements denotes whether the +// corresponding region is in the collection set. +class G1FastCSetBiasedMappedArray : public G1BiasedMappedArray { + protected: + bool default_value() const { return false; } + public: + void clear() { G1BiasedMappedArray::clear(); } +}; + class RefineCardTableEntryClosure; class G1CollectedHeap : public SharedHeap { @@ -353,26 +364,10 @@ // than the current allocation region. size_t _summary_bytes_used; - // This is used for a quick test on whether a reference points into - // the collection set or not. Basically, we have an array, with one - // byte per region, and that byte denotes whether the corresponding - // region is in the collection set or not. The entry corresponding - // the bottom of the heap, i.e., region 0, is pointed to by - // _in_cset_fast_test_base. The _in_cset_fast_test field has been - // biased so that it actually points to address 0 of the address - // space, to make the test as fast as possible (we can simply shift - // the address to address into it, instead of having to subtract the - // bottom of the heap from the address before shifting it; basically - // it works in the same way the card table works). - bool* _in_cset_fast_test; - - // The allocated array used for the fast test on whether a reference - // points into the collection set or not. This field is also used to - // free the array. - bool* _in_cset_fast_test_base; - - // The length of the _in_cset_fast_test_base array. - uint _in_cset_fast_test_length; + // This array is used for a quick test on whether a reference points into + // the collection set or not. Each of the array's elements denotes whether the + // corresponding region is in the collection set or not. + G1FastCSetBiasedMappedArray _in_cset_fast_test; volatile unsigned _gc_time_stamp; @@ -695,12 +690,7 @@ // We register a region with the fast "in collection set" test. We // simply set to true the array slot corresponding to this region. void register_region_with_in_cset_fast_test(HeapRegion* r) { - assert(_in_cset_fast_test_base != NULL, "sanity"); - assert(r->in_collection_set(), "invariant"); - uint index = r->hrs_index(); - assert(index < _in_cset_fast_test_length, "invariant"); - assert(!_in_cset_fast_test_base[index], "invariant"); - _in_cset_fast_test_base[index] = true; + _in_cset_fast_test.set_by_index(r->hrs_index(), true); } // This is a fast test on whether a reference points into the @@ -709,9 +699,7 @@ inline bool in_cset_fast_test(oop obj); void clear_cset_fast_test() { - assert(_in_cset_fast_test_base != NULL, "sanity"); - memset(_in_cset_fast_test_base, false, - (size_t) _in_cset_fast_test_length * sizeof(bool)); + _in_cset_fast_test.clear(); } // This is called at the start of either a concurrent cycle or a Full @@ -1077,6 +1065,8 @@ // specified by the policy object. jint initialize(); + virtual void stop(); + // Return the (conservative) maximum heap alignment for any G1 heap static size_t conservative_max_heap_alignment(); @@ -1390,17 +1380,15 @@ // space containing a given address, or else returns NULL. virtual Space* space_containing(const void* addr) const; - // A G1CollectedHeap will contain some number of heap regions. This - // finds the region containing a given address, or else returns NULL. + // Returns the HeapRegion that contains addr. addr must not be NULL. + template + inline HeapRegion* heap_region_containing_raw(const T addr) const; + + // Returns the HeapRegion that contains addr. addr must not be NULL. + // If addr is within a humongous continues region, it returns its humongous start region. template inline HeapRegion* heap_region_containing(const T addr) const; - // Like the above, but requires "addr" to be in the heap (to avoid a - // null-check), and unlike the above, may return an continuing humongous - // region. - template - inline HeapRegion* heap_region_containing_raw(const T addr) const; - // A CollectedHeap is divided into a dense sequence of "blocks"; that is, // each address in the (reserved) heap is a member of exactly // one block. The defining characteristic of a block is that it is @@ -1542,7 +1530,6 @@ // the region to which the object belongs. An object is dead // iff a) it was not allocated since the last mark and b) it // is not marked. - bool is_obj_dead(const oop obj, const HeapRegion* hr) const { return !hr->obj_allocated_since_prev_marking(obj) && @@ -1552,7 +1539,6 @@ // This function returns true when an object has been // around since the previous marking and hasn't yet // been marked during this marking. - bool is_obj_ill(const oop obj, const HeapRegion* hr) const { return !hr->obj_allocated_since_next_marking(obj) && @@ -1698,15 +1684,19 @@ public: G1ParGCAllocBuffer(size_t gclab_word_size); + virtual ~G1ParGCAllocBuffer() { + guarantee(_retired, "Allocation buffer has not been retired"); + } - void set_buf(HeapWord* buf) { + virtual void set_buf(HeapWord* buf) { ParGCAllocBuffer::set_buf(buf); _retired = false; } - void retire(bool end_of_gc, bool retain) { - if (_retired) + virtual void retire(bool end_of_gc, bool retain) { + if (_retired) { return; + } ParGCAllocBuffer::retire(end_of_gc, retain); _retired = true; } @@ -1776,6 +1766,7 @@ G1ParScanThreadState(G1CollectedHeap* g1h, uint queue_num, ReferenceProcessor* rp); ~G1ParScanThreadState() { + retire_alloc_buffers(); FREE_C_HEAP_ARRAY(size_t, _surviving_young_words_base, mtGC); } @@ -1886,6 +1877,7 @@ return _surviving_young_words; } +private: void retire_alloc_buffers() { for (int ap = 0; ap < GCAllocPurposeCount; ++ap) { size_t waste = _alloc_buffers[ap]->words_remaining(); @@ -1895,8 +1887,8 @@ false /* retain */); } } -private: - #define G1_PARTIAL_ARRAY_MASK 0x2 + +#define G1_PARTIAL_ARRAY_MASK 0x2 inline bool has_partial_array_mask(oop* ref) const { return ((uintptr_t)ref & G1_PARTIAL_ARRAY_MASK) == G1_PARTIAL_ARRAY_MASK; diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -42,21 +42,22 @@ template inline HeapRegion* -G1CollectedHeap::heap_region_containing(const T addr) const { - HeapRegion* hr = _hrs.addr_to_region((HeapWord*) addr); - // hr can be null if addr in perm_gen - if (hr != NULL && hr->continuesHumongous()) { - hr = hr->humongous_start_region(); - } - return hr; +G1CollectedHeap::heap_region_containing_raw(const T addr) const { + assert(addr != NULL, "invariant"); + assert(_g1_reserved.contains((const void*) addr), + err_msg("Address "PTR_FORMAT" is outside of the heap ranging from ["PTR_FORMAT" to "PTR_FORMAT")", + (void*)addr, _g1_reserved.start(), _g1_reserved.end())); + return _hrs.addr_to_region((HeapWord*) addr); } template inline HeapRegion* -G1CollectedHeap::heap_region_containing_raw(const T addr) const { - assert(_g1_reserved.contains((const void*) addr), "invariant"); - HeapRegion* res = _hrs.addr_to_region_unsafe((HeapWord*) addr); - return res; +G1CollectedHeap::heap_region_containing(const T addr) const { + HeapRegion* hr = heap_region_containing_raw(addr); + if (hr->continuesHumongous()) { + return hr->humongous_start_region(); + } + return hr; } inline void G1CollectedHeap::old_set_remove(HeapRegion* hr) { @@ -134,8 +135,7 @@ // have to keep calling heap_region_containing_raw() in the // asserts below. DEBUG_ONLY(HeapRegion* containing_hr = heap_region_containing_raw(start);) - assert(containing_hr != NULL && start != NULL && word_size > 0, - "pre-condition"); + assert(word_size > 0, "pre-condition"); assert(containing_hr->is_in(start), "it should contain start"); assert(containing_hr->is_young(), "it should be young"); assert(!containing_hr->isHumongous(), "it should not be humongous"); @@ -164,12 +164,7 @@ // collection set or not. Assume that the reference // points into the heap. inline bool G1CollectedHeap::in_cset_fast_test(oop obj) { - assert(_in_cset_fast_test != NULL, "sanity"); - assert(_g1_committed.contains((HeapWord*) obj), err_msg("Given reference outside of heap, is "PTR_FORMAT, (HeapWord*)obj)); - // no need to subtract the bottom of the heap from obj, - // _in_cset_fast_test is biased - uintx index = cast_from_oop(obj) >> HeapRegion::LogOfHRGrainBytes; - bool ret = _in_cset_fast_test[index]; + bool ret = _in_cset_fast_test.get_by_address((HeapWord*)obj); // let's make sure the result is consistent with what the slower // test returns assert( ret || !obj_in_cs(obj), "sanity"); @@ -251,8 +246,10 @@ #endif // #ifndef PRODUCT inline bool G1CollectedHeap::is_in_young(const oop obj) { - HeapRegion* hr = heap_region_containing(obj); - return hr != NULL && hr->is_young(); + if (obj == NULL) { + return false; + } + return heap_region_containing(obj)->is_young(); } // We don't need barriers for initializing stores to objects @@ -265,21 +262,17 @@ } inline bool G1CollectedHeap::is_obj_dead(const oop obj) const { - const HeapRegion* hr = heap_region_containing(obj); - if (hr == NULL) { - if (obj == NULL) return false; - else return true; + if (obj == NULL) { + return false; } - else return is_obj_dead(obj, hr); + return is_obj_dead(obj, heap_region_containing(obj)); } inline bool G1CollectedHeap::is_obj_ill(const oop obj) const { - const HeapRegion* hr = heap_region_containing(obj); - if (hr == NULL) { - if (obj == NULL) return false; - else return true; + if (obj == NULL) { + return false; } - else return is_obj_ill(obj, hr); + return is_obj_ill(obj, heap_region_containing(obj)); } template inline void G1ParScanThreadState::immediate_rs_update(HeapRegion* from, T* p, int tid) { diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -170,6 +170,8 @@ _last_gc_worker_end_times_ms(_max_gc_threads, "%.1lf", false), _last_gc_worker_times_ms(_max_gc_threads, "%.1lf"), _last_gc_worker_other_times_ms(_max_gc_threads, "%.1lf"), + _last_redirty_logged_cards_time_ms(_max_gc_threads, "%.1lf"), + _last_redirty_logged_cards_processed_cards(_max_gc_threads, SIZE_FORMAT), _cur_string_dedup_queue_fixup_worker_times_ms(_max_gc_threads, "%.1lf"), _cur_string_dedup_table_fixup_worker_times_ms(_max_gc_threads, "%.1lf") { @@ -195,6 +197,10 @@ _last_gc_worker_end_times_ms.reset(); _last_gc_worker_times_ms.reset(); _last_gc_worker_other_times_ms.reset(); + + _last_redirty_logged_cards_time_ms.reset(); + _last_redirty_logged_cards_processed_cards.reset(); + } void G1GCPhaseTimes::note_gc_end() { @@ -230,6 +236,9 @@ _last_gc_worker_times_ms.verify(); _last_gc_worker_other_times_ms.verify(); + + _last_redirty_logged_cards_time_ms.verify(); + _last_redirty_logged_cards_processed_cards.verify(); } void G1GCPhaseTimes::note_string_dedup_fixup_start() { @@ -349,6 +358,10 @@ print_stats(2, "Ref Enq", _cur_ref_enq_time_ms); if (G1DeferredRSUpdate) { print_stats(2, "Redirty Cards", _recorded_redirty_logged_cards_time_ms); + if (G1Log::finest()) { + _last_redirty_logged_cards_time_ms.print(3, "Parallel Redirty"); + _last_redirty_logged_cards_processed_cards.print(3, "Redirtied Cards"); + } } print_stats(2, "Free CSet", (_recorded_young_free_cset_time_ms + diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -151,6 +151,8 @@ double _recorded_young_cset_choice_time_ms; double _recorded_non_young_cset_choice_time_ms; + WorkerDataArray _last_redirty_logged_cards_time_ms; + WorkerDataArray _last_redirty_logged_cards_processed_cards; double _recorded_redirty_logged_cards_time_ms; double _recorded_young_free_cset_time_ms; @@ -293,6 +295,14 @@ _recorded_non_young_cset_choice_time_ms = time_ms; } + void record_redirty_logged_cards_time_ms(uint worker_i, double time_ms) { + _last_redirty_logged_cards_time_ms.set(worker_i, time_ms); + } + + void record_redirty_logged_cards_processed_cards(uint worker_i, size_t processed_buffers) { + _last_redirty_logged_cards_processed_cards.set(worker_i, processed_buffers); + } + void record_redirty_logged_cards_time_ms(double time_ms) { _recorded_redirty_logged_cards_time_ms = time_ms; } diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -125,9 +125,7 @@ if (!oopDesc::is_null(heap_oop)) { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); HeapRegion* hr = _g1h->heap_region_containing((HeapWord*) obj); - if (hr != NULL) { - _cm->grayRoot(obj, obj->size(), _worker_id, hr); - } + _cm->grayRoot(obj, obj->size(), _worker_id, hr); } } @@ -154,57 +152,63 @@ template inline void G1UpdateRSOrPushRefOopClosure::do_oop_nv(T* p) { oop obj = oopDesc::load_decode_heap_oop(p); + if (obj == NULL) { + return; + } + #ifdef ASSERT // can't do because of races // assert(obj == NULL || obj->is_oop(), "expected an oop"); // Do the safe subset of is_oop - if (obj != NULL) { #ifdef CHECK_UNHANDLED_OOPS - oopDesc* o = obj.obj(); + oopDesc* o = obj.obj(); #else - oopDesc* o = obj; + oopDesc* o = obj; #endif // CHECK_UNHANDLED_OOPS - assert((intptr_t)o % MinObjAlignmentInBytes == 0, "not oop aligned"); - assert(Universe::heap()->is_in_reserved(obj), "must be in heap"); - } + assert((intptr_t)o % MinObjAlignmentInBytes == 0, "not oop aligned"); + assert(Universe::heap()->is_in_reserved(obj), "must be in heap"); #endif // ASSERT assert(_from != NULL, "from region must be non-NULL"); assert(_from->is_in_reserved(p), "p is not in from"); HeapRegion* to = _g1->heap_region_containing(obj); - if (to != NULL && _from != to) { - // The _record_refs_into_cset flag is true during the RSet - // updating part of an evacuation pause. It is false at all - // other times: - // * rebuilding the remembered sets after a full GC - // * during concurrent refinement. - // * updating the remembered sets of regions in the collection - // set in the event of an evacuation failure (when deferred - // updates are enabled). + if (_from == to) { + // Normally this closure should only be called with cross-region references. + // But since Java threads are manipulating the references concurrently and we + // reload the values things may have changed. + return; + } - if (_record_refs_into_cset && to->in_collection_set()) { - // We are recording references that point into the collection - // set and this particular reference does exactly that... - // If the referenced object has already been forwarded - // to itself, we are handling an evacuation failure and - // we have already visited/tried to copy this object - // there is no need to retry. - if (!self_forwarded(obj)) { - assert(_push_ref_cl != NULL, "should not be null"); - // Push the reference in the refs queue of the G1ParScanThreadState - // instance for this worker thread. - _push_ref_cl->do_oop(p); - } + // The _record_refs_into_cset flag is true during the RSet + // updating part of an evacuation pause. It is false at all + // other times: + // * rebuilding the remembered sets after a full GC + // * during concurrent refinement. + // * updating the remembered sets of regions in the collection + // set in the event of an evacuation failure (when deferred + // updates are enabled). - // Deferred updates to the CSet are either discarded (in the normal case), - // or processed (if an evacuation failure occurs) at the end - // of the collection. - // See G1RemSet::cleanup_after_oops_into_collection_set_do(). - return; + if (_record_refs_into_cset && to->in_collection_set()) { + // We are recording references that point into the collection + // set and this particular reference does exactly that... + // If the referenced object has already been forwarded + // to itself, we are handling an evacuation failure and + // we have already visited/tried to copy this object + // there is no need to retry. + if (!self_forwarded(obj)) { + assert(_push_ref_cl != NULL, "should not be null"); + // Push the reference in the refs queue of the G1ParScanThreadState + // instance for this worker thread. + _push_ref_cl->do_oop(p); } + // Deferred updates to the CSet are either discarded (in the normal case), + // or processed (if an evacuation failure occurs) at the end + // of the collection. + // See G1RemSet::cleanup_after_oops_into_collection_set_do(). + } else { // We either don't care about pushing references that point into the // collection set (i.e. we're not during an evacuation pause) _or_ // the reference doesn't point into the collection set. Either way diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -36,6 +36,7 @@ #include "gc_implementation/g1/heapRegionRemSet.hpp" #include "memory/iterator.hpp" #include "oops/oop.inline.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/intHisto.hpp" #define CARD_REPEAT_HISTO 0 @@ -163,7 +164,7 @@ void printCard(HeapRegion* card_region, size_t card_index, HeapWord* card_start) { gclog_or_tty->print_cr("T %u Region [" PTR_FORMAT ", " PTR_FORMAT ") " - "RS names card %p: " + "RS names card " SIZE_FORMAT_HEX ": " "[" PTR_FORMAT ", " PTR_FORMAT ")", _worker_i, card_region->bottom(), card_region->end(), @@ -209,7 +210,6 @@ #endif HeapRegion* card_region = _g1h->heap_region_containing(card_start); - assert(card_region != NULL, "Yielding cards not in the heap?"); _cards++; if (!card_region->is_on_dirty_cards_region_list()) { @@ -404,7 +404,6 @@ HeapWord* start = _ct_bs->addr_for(card_ptr); // And find the region containing it. HeapRegion* r = _g1->heap_region_containing(start); - assert(r != NULL, "unexpected null"); // Scan oops in the card looking for references into the collection set // Don't use addr_for(card_ptr + 1) which can ask for @@ -566,11 +565,6 @@ HeapWord* start = _ct_bs->addr_for(card_ptr); // And find the region containing it. HeapRegion* r = _g1->heap_region_containing(start); - if (r == NULL) { - // Again no need to return that this card contains refs that - // point into the collection set. - return false; // Not in the G1 heap (might be in perm, for example.) - } // Why do we have to check here whether a card is on a young region, // given that we dirty young regions and, as a result, the @@ -623,10 +617,6 @@ start = _ct_bs->addr_for(card_ptr); r = _g1->heap_region_containing(start); - if (r == NULL) { - // Not in the G1 heap - return false; - } // Checking whether the region we got back from the cache // is young here is inappropriate. The region could have been diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -45,26 +45,28 @@ template inline void G1RemSet::par_write_ref(HeapRegion* from, T* p, int tid) { oop obj = oopDesc::load_decode_heap_oop(p); + if (obj == NULL) { + return; + } + #ifdef ASSERT // can't do because of races // assert(obj == NULL || obj->is_oop(), "expected an oop"); // Do the safe subset of is_oop - if (obj != NULL) { #ifdef CHECK_UNHANDLED_OOPS - oopDesc* o = obj.obj(); + oopDesc* o = obj.obj(); #else - oopDesc* o = obj; + oopDesc* o = obj; #endif // CHECK_UNHANDLED_OOPS - assert((intptr_t)o % MinObjAlignmentInBytes == 0, "not oop aligned"); - assert(Universe::heap()->is_in_reserved(obj), "must be in heap"); - } + assert((intptr_t)o % MinObjAlignmentInBytes == 0, "not oop aligned"); + assert(Universe::heap()->is_in_reserved(obj), "must be in heap"); #endif // ASSERT assert(from == NULL || from->is_in_reserved(p), "p is not in from"); HeapRegion* to = _g1->heap_region_containing(obj); - if (to != NULL && from != to) { + if (from != to) { assert(to->rem_set() != NULL, "Need per-region 'into' remsets."); to->rem_set()->add_reference(p, tid); } diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/g1StringDedup.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedup.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedup.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -44,6 +44,11 @@ } } +void G1StringDedup::stop() { + assert(is_enabled(), "String deduplication not enabled"); + G1StringDedupThread::stop(); +} + bool G1StringDedup::is_candidate_from_mark(oop obj) { if (java_lang_String::is_instance(obj)) { bool from_young = G1CollectedHeap::heap()->heap_region_containing_raw(obj)->is_young(); diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/g1StringDedup.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedup.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedup.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -110,8 +110,12 @@ return _enabled; } + // Initialize string deduplication. static void initialize(); + // Stop the deduplication thread. + static void stop(); + // Immediately deduplicates the given String object, bypassing the // the deduplication queue. static void deduplicate(oop java_string); diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -35,6 +35,7 @@ G1StringDedupQueue::G1StringDedupQueue() : _cursor(0), + _cancel(false), _empty(true), _dropped(0) { _nqueues = MAX2(ParallelGCThreads, (size_t)1); @@ -55,11 +56,17 @@ void G1StringDedupQueue::wait() { MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag); - while (_queue->_empty) { + while (_queue->_empty && !_queue->_cancel) { ml.wait(Mutex::_no_safepoint_check_flag); } } +void G1StringDedupQueue::cancel_wait() { + MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag); + _queue->_cancel = true; + ml.notify(); +} + void G1StringDedupQueue::push(uint worker_id, oop java_string) { assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint"); assert(worker_id < _queue->_nqueues, "Invalid queue"); diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -65,6 +65,7 @@ G1StringDedupWorkerQueue* _queues; size_t _nqueues; size_t _cursor; + bool _cancel; volatile bool _empty; // Statistics counter, only used for logging. @@ -81,6 +82,9 @@ // Blocks and waits for the queue to become non-empty. static void wait(); + // Wakes up any thread blocked waiting for the queue to become non-empty. + static void cancel_wait(); + // Pushes a deduplication candidate onto a specific GC worker queue. static void push(uint worker_id, oop java_string); diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -73,42 +73,60 @@ // Wait for the queue to become non-empty G1StringDedupQueue::wait(); + if (_should_terminate) { + break; + } - // Include this thread in safepoints - stsJoin(); + { + // Include thread in safepoints + SuspendibleThreadSetJoiner sts; - stat.mark_exec(); + stat.mark_exec(); - // Process the queue - for (;;) { - oop java_string = G1StringDedupQueue::pop(); - if (java_string == NULL) { - break; + // Process the queue + for (;;) { + oop java_string = G1StringDedupQueue::pop(); + if (java_string == NULL) { + break; + } + + G1StringDedupTable::deduplicate(java_string, stat); + + // Safepoint this thread if needed + if (sts.should_yield()) { + stat.mark_block(); + sts.yield(); + stat.mark_unblock(); + } } - G1StringDedupTable::deduplicate(java_string, stat); + G1StringDedupTable::trim_entry_cache(); - // Safepoint this thread if needed - if (stsShouldYield()) { - stat.mark_block(); - stsYield(NULL); - stat.mark_unblock(); - } - } + stat.mark_done(); - G1StringDedupTable::trim_entry_cache(); - - stat.mark_done(); - - // Print statistics - total_stat.add(stat); - print(gclog_or_tty, stat, total_stat); - - // Exclude this thread from safepoints - stsLeave(); + // Print statistics + total_stat.add(stat); + print(gclog_or_tty, stat, total_stat); + } } - ShouldNotReachHere(); + terminate(); +} + +void G1StringDedupThread::stop() { + { + MonitorLockerEx ml(Terminator_lock); + _thread->_should_terminate = true; + } + + G1StringDedupQueue::cancel_wait(); + + { + MonitorLockerEx ml(Terminator_lock); + while (!_thread->_has_terminated) { + ml.wait(); + } + } } void G1StringDedupThread::print(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) { diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -47,6 +47,8 @@ public: static void create(); + static void stop(); + static G1StringDedupThread* thread(); virtual void run(); diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -167,7 +167,7 @@ // Mem size in bytes. size_t mem_size() const { - return sizeof(this) + _bm.size_in_words() * HeapWordSize; + return sizeof(PerRegionTable) + _bm.size_in_words() * HeapWordSize; } // Requires "from" to be in "hr()". @@ -491,7 +491,7 @@ } else { if (G1TraceHeapRegionRememberedSet) { gclog_or_tty->print_cr(" [tid %d] sparse table entry " - "overflow(f: %d, t: %d)", + "overflow(f: %d, t: %u)", tid, from_hrs_ind, cur_hrs_ind); } } @@ -610,7 +610,7 @@ _n_coarse_entries++; if (G1TraceHeapRegionRememberedSet) { gclog_or_tty->print("Coarsened entry in region [" PTR_FORMAT "...] " - "for region [" PTR_FORMAT "...] (%d coarse entries).\n", + "for region [" PTR_FORMAT "...] (" SIZE_FORMAT " coarse entries).\n", hr()->bottom(), max->hr()->bottom(), _n_coarse_entries); @@ -733,7 +733,7 @@ sum += (sizeof(PerRegionTable*) * _max_fine_entries); sum += (_coarse_map.size_in_words() * HeapWordSize); sum += (_sparse_table.mem_size()); - sum += sizeof(*this) - sizeof(_sparse_table); // Avoid double counting above. + sum += sizeof(OtherRegionsTable) - sizeof(_sparse_table); // Avoid double counting above. return sum; } @@ -768,30 +768,6 @@ clear_fcc(); } -void OtherRegionsTable::clear_incoming_entry(HeapRegion* from_hr) { - MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag); - size_t hrs_ind = (size_t) from_hr->hrs_index(); - size_t ind = hrs_ind & _mod_max_fine_entries_mask; - if (del_single_region_table(ind, from_hr)) { - assert(!_coarse_map.at(hrs_ind), "Inv"); - } else { - _coarse_map.par_at_put(hrs_ind, 0); - } - // Check to see if any of the fcc entries come from here. - uint hr_ind = hr()->hrs_index(); - for (uint tid = 0; tid < HeapRegionRemSet::num_par_rem_sets(); tid++) { - int fcc_ent = FromCardCache::at(tid, hr_ind); - if (fcc_ent != FromCardCache::InvalidCard) { - HeapWord* card_addr = (HeapWord*) - (uintptr_t(fcc_ent) << CardTableModRefBS::card_shift); - if (hr()->is_in_reserved(card_addr)) { - // Clear the from card cache. - FromCardCache::set(tid, hr_ind, FromCardCache::InvalidCard); - } - } - } -} - bool OtherRegionsTable::del_single_region_table(size_t ind, HeapRegion* hr) { assert(0 <= ind && ind < _max_fine_entries, "Preconditions."); @@ -821,7 +797,6 @@ bool OtherRegionsTable::contains_reference_locked(OopOrNarrowOopStar from) const { HeapRegion* hr = _g1h->heap_region_containing_raw(from); - if (hr == NULL) return false; RegionIdx_t hr_ind = (RegionIdx_t) hr->hrs_index(); // Is this region in the coarse map? if (_coarse_map.at(hr_ind)) return true; @@ -903,10 +878,12 @@ } if (iter.n_yielded() != occupied()) { gclog_or_tty->print_cr("Yielded disagrees with occupied:"); - gclog_or_tty->print_cr(" %6d yielded (%6d coarse, %6d fine).", + gclog_or_tty->print_cr(" " SIZE_FORMAT_W(6) " yielded (" SIZE_FORMAT_W(6) + " coarse, " SIZE_FORMAT_W(6) " fine).", iter.n_yielded(), iter.n_yielded_coarse(), iter.n_yielded_fine()); - gclog_or_tty->print_cr(" %6d occ (%6d coarse, %6d fine).", + gclog_or_tty->print_cr(" " SIZE_FORMAT_W(6) " occ (" SIZE_FORMAT_W(6) + " coarse, " SIZE_FORMAT_W(6) " fine).", occupied(), occ_coarse(), occ_fine()); } guarantee(iter.n_yielded() == occupied(), @@ -1046,20 +1023,16 @@ return _code_roots.mem_size(); } -//-------------------- Iteration -------------------- - HeapRegionRemSetIterator:: HeapRegionRemSetIterator(HeapRegionRemSet* hrrs) : _hrrs(hrrs), _g1h(G1CollectedHeap::heap()), _coarse_map(&hrrs->_other_regions._coarse_map), - _fine_grain_regions(hrrs->_other_regions._fine_grain_regions), _bosa(hrrs->bosa()), _is(Sparse), // Set these values so that we increment to the first region. _coarse_cur_region_index(-1), _coarse_cur_region_cur_card(HeapRegion::CardsPerRegion-1), - _cur_region_cur_card(0), - _fine_array_index(-1), + _cur_card_in_prt(HeapRegion::CardsPerRegion), _fine_cur_prt(NULL), _n_yielded_coarse(0), _n_yielded_fine(0), @@ -1091,58 +1064,59 @@ return true; } -void HeapRegionRemSetIterator::fine_find_next_non_null_prt() { - // Otherwise, find the next bucket list in the array. - _fine_array_index++; - while (_fine_array_index < (int) OtherRegionsTable::_max_fine_entries) { - _fine_cur_prt = _fine_grain_regions[_fine_array_index]; - if (_fine_cur_prt != NULL) return; - else _fine_array_index++; - } - assert(_fine_cur_prt == NULL, "Loop post"); -} - bool HeapRegionRemSetIterator::fine_has_next(size_t& card_index) { if (fine_has_next()) { - _cur_region_cur_card = - _fine_cur_prt->_bm.get_next_one_offset(_cur_region_cur_card + 1); + _cur_card_in_prt = + _fine_cur_prt->_bm.get_next_one_offset(_cur_card_in_prt + 1); } - while (!fine_has_next()) { - if (_cur_region_cur_card == (size_t) HeapRegion::CardsPerRegion) { - _cur_region_cur_card = 0; - _fine_cur_prt = _fine_cur_prt->collision_list_next(); + if (_cur_card_in_prt == HeapRegion::CardsPerRegion) { + // _fine_cur_prt may still be NULL in case if there are not PRTs at all for + // the remembered set. + if (_fine_cur_prt == NULL || _fine_cur_prt->next() == NULL) { + return false; } - if (_fine_cur_prt == NULL) { - fine_find_next_non_null_prt(); - if (_fine_cur_prt == NULL) return false; - } - assert(_fine_cur_prt != NULL && _cur_region_cur_card == 0, - "inv."); - HeapWord* r_bot = - _fine_cur_prt->hr()->bottom(); - _cur_region_card_offset = _bosa->index_for(r_bot); - _cur_region_cur_card = _fine_cur_prt->_bm.get_next_one_offset(0); + PerRegionTable* next_prt = _fine_cur_prt->next(); + switch_to_prt(next_prt); + _cur_card_in_prt = _fine_cur_prt->_bm.get_next_one_offset(_cur_card_in_prt + 1); } - assert(fine_has_next(), "Or else we exited the loop via the return."); - card_index = _cur_region_card_offset + _cur_region_cur_card; + + card_index = _cur_region_card_offset + _cur_card_in_prt; + guarantee(_cur_card_in_prt < HeapRegion::CardsPerRegion, + err_msg("Card index "SIZE_FORMAT" must be within the region", _cur_card_in_prt)); return true; } bool HeapRegionRemSetIterator::fine_has_next() { - return - _fine_cur_prt != NULL && - _cur_region_cur_card < HeapRegion::CardsPerRegion; + return _cur_card_in_prt != HeapRegion::CardsPerRegion; +} + +void HeapRegionRemSetIterator::switch_to_prt(PerRegionTable* prt) { + assert(prt != NULL, "Cannot switch to NULL prt"); + _fine_cur_prt = prt; + + HeapWord* r_bot = _fine_cur_prt->hr()->bottom(); + _cur_region_card_offset = _bosa->index_for(r_bot); + + // The bitmap scan for the PRT always scans from _cur_region_cur_card + 1. + // To avoid special-casing this start case, and not miss the first bitmap + // entry, initialize _cur_region_cur_card with -1 instead of 0. + _cur_card_in_prt = (size_t)-1; } bool HeapRegionRemSetIterator::has_next(size_t& card_index) { switch (_is) { - case Sparse: + case Sparse: { if (_sparse_iter.has_next(card_index)) { _n_yielded_sparse++; return true; } // Otherwise, deliberate fall-through _is = Fine; + PerRegionTable* initial_fine_prt = _hrrs->_other_regions._first_all_fine_prts; + if (initial_fine_prt != NULL) { + switch_to_prt(_hrrs->_other_regions._first_all_fine_prts); + } + } case Fine: if (fine_has_next(card_index)) { _n_yielded_fine++; @@ -1274,6 +1248,11 @@ #ifndef PRODUCT void PerRegionTable::test_fl_mem_size() { PerRegionTable* dummy = alloc(NULL); + + size_t min_prt_size = sizeof(void*) + dummy->bm()->size_in_words() * HeapWordSize; + assert(dummy->mem_size() > min_prt_size, + err_msg("PerRegionTable memory usage is suspiciously small, only has "SIZE_FORMAT" bytes. " + "Should be at least "SIZE_FORMAT" bytes.", dummy->mem_size(), min_prt_size)); free(dummy); guarantee(dummy->mem_size() == fl_mem_size(), "fl_mem_size() does not return the correct element size"); // try to reset the state diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -206,9 +206,6 @@ // Specifically clear the from_card_cache. void clear_fcc(); - // "from_hr" is being cleared; remove any entries from it. - void clear_incoming_entry(HeapRegion* from_hr); - void do_cleanup_work(HRRSCleanupTask* hrrs_cleanup_task); // Declare the heap size (in # of regions) to the OtherRegionsTable. @@ -338,20 +335,20 @@ return _other_regions.mem_size() // This correction is necessary because the above includes the second // part. - + (sizeof(this) - sizeof(OtherRegionsTable)) + + (sizeof(HeapRegionRemSet) - sizeof(OtherRegionsTable)) + strong_code_roots_mem_size(); } // Returns the memory occupancy of all static data structures associated // with remembered sets. static size_t static_mem_size() { - return OtherRegionsTable::static_mem_size() + G1CodeRootSet::static_mem_size(); + return OtherRegionsTable::static_mem_size() + G1CodeRootSet::free_chunks_static_mem_size(); } // Returns the memory occupancy of all free_list data structures associated // with remembered sets. static size_t fl_mem_size() { - return OtherRegionsTable::fl_mem_size() + G1CodeRootSet::fl_mem_size(); + return OtherRegionsTable::fl_mem_size() + G1CodeRootSet::free_chunks_mem_size(); } bool contains_reference(OopOrNarrowOopStar from) const { @@ -396,7 +393,6 @@ // Declare the heap size (in # of regions) to the HeapRegionRemSet(s). // (Uses it to initialize from_card_cache). static void init_heap(uint max_regions) { - G1CodeRootSet::initialize(); OtherRegionsTable::init_from_card_cache(max_regions); } @@ -429,26 +425,24 @@ }; class HeapRegionRemSetIterator : public StackObj { - - // The region RSet over which we're iterating. + private: + // The region RSet over which we are iterating. HeapRegionRemSet* _hrrs; // Local caching of HRRS fields. const BitMap* _coarse_map; - PerRegionTable** _fine_grain_regions; G1BlockOffsetSharedArray* _bosa; G1CollectedHeap* _g1h; - // The number yielded since initialization. + // The number of cards yielded since initialization. size_t _n_yielded_fine; size_t _n_yielded_coarse; size_t _n_yielded_sparse; - // Indicates what granularity of table that we're currently iterating over. + // Indicates what granularity of table that we are currently iterating over. // We start iterating over the sparse table, progress to the fine grain // table, and then finish with the coarse table. - // See HeapRegionRemSetIterator::has_next(). enum IterState { Sparse, Fine, @@ -456,38 +450,30 @@ }; IterState _is; - // In both kinds of iteration, heap offset of first card of current - // region. + // For both Coarse and Fine remembered set iteration this contains the + // first card number of the heap region we currently iterate over. size_t _cur_region_card_offset; - // Card offset within cur region. - size_t _cur_region_cur_card; - // Coarse table iteration fields: - - // Current region index; + // Current region index for the Coarse remembered set iteration. int _coarse_cur_region_index; size_t _coarse_cur_region_cur_card; bool coarse_has_next(size_t& card_index); - // Fine table iteration fields: - - // Index of bucket-list we're working on. - int _fine_array_index; + // The PRT we are currently iterating over. + PerRegionTable* _fine_cur_prt; + // Card offset within the current PRT. + size_t _cur_card_in_prt; - // Per Region Table we're doing within current bucket list. - PerRegionTable* _fine_cur_prt; - - /* SparsePRT::*/ SparsePRTIter _sparse_iter; - - void fine_find_next_non_null_prt(); - + // Update internal variables when switching to the given PRT. + void switch_to_prt(PerRegionTable* prt); bool fine_has_next(); bool fine_has_next(size_t& card_index); -public: - // We require an iterator to be initialized before use, so the - // constructor does little. + // The Sparse remembered set iterator. + SparsePRTIter _sparse_iter; + + public: HeapRegionRemSetIterator(HeapRegionRemSet* hrrs); // If there remains one or more cards to be yielded, returns true and diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -240,7 +240,6 @@ // Asserts will fire if i is >= _length HeapWord* addr = hr->bottom(); guarantee(addr_to_region(addr) == hr, "sanity"); - guarantee(addr_to_region_unsafe(addr) == hr, "sanity"); } else { guarantee(hr->is_empty(), "sanity"); guarantee(!hr->isHumongous(), "sanity"); diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -110,10 +110,6 @@ // HeapRegion, otherwise return NULL. inline HeapRegion* addr_to_region(HeapWord* addr) const; - // Return the HeapRegion that corresponds to the given - // address. Assume the address is valid. - inline HeapRegion* addr_to_region_unsafe(HeapWord* addr) const; - // Return the number of regions that have been committed in the heap. uint length() const { return _committed_length; } diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.inline.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.inline.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -28,21 +28,17 @@ #include "gc_implementation/g1/heapRegion.hpp" #include "gc_implementation/g1/heapRegionSeq.hpp" -inline HeapRegion* HeapRegionSeq::addr_to_region_unsafe(HeapWord* addr) const { +inline HeapRegion* HeapRegionSeq::addr_to_region(HeapWord* addr) const { + assert(addr < heap_end(), + err_msg("addr: "PTR_FORMAT" end: "PTR_FORMAT, addr, heap_end())); + assert(addr >= heap_bottom(), + err_msg("addr: "PTR_FORMAT" bottom: "PTR_FORMAT, addr, heap_bottom())); + HeapRegion* hr = _regions.get_by_address(addr); assert(hr != NULL, "invariant"); return hr; } -inline HeapRegion* HeapRegionSeq::addr_to_region(HeapWord* addr) const { - if (addr != NULL && addr < heap_end()) { - assert(addr >= heap_bottom(), - err_msg("addr: "PTR_FORMAT" bottom: "PTR_FORMAT, addr, heap_bottom())); - return addr_to_region_unsafe(addr); - } - return NULL; -} - inline HeapRegion* HeapRegionSeq::at(uint index) const { assert(index < length(), "pre-condition"); HeapRegion* hr = _regions.get_by_index(index); diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -370,7 +370,7 @@ } size_t RSHashTable::mem_size() const { - return sizeof(this) + + return sizeof(RSHashTable) + capacity() * (SparsePRTEntry::size() + sizeof(int)); } @@ -472,7 +472,7 @@ size_t SparsePRT::mem_size() const { // We ignore "_cur" here, because it either = _next, or else it is // on the deleted list. - return sizeof(this) + _next->mem_size(); + return sizeof(SparsePRT) + _next->mem_size(); } bool SparsePRT::add_card(RegionIdx_t region_id, CardIdx_t card_index) { diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/g1/survRateGroup.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/survRateGroup.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/survRateGroup.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -187,10 +187,10 @@ #ifndef PRODUCT void SurvRateGroup::print() { - gclog_or_tty->print_cr("Surv Rate Group: %s (%d entries)", + gclog_or_tty->print_cr("Surv Rate Group: %s (" SIZE_FORMAT " entries)", _name, _region_num); for (size_t i = 0; i < _region_num; ++i) { - gclog_or_tty->print_cr(" age %4d surv rate %6.2lf %% pred %6.2lf %%", + gclog_or_tty->print_cr(" age " SIZE_FORMAT_W(4) " surv rate %6.2lf %% pred %6.2lf %%", i, _surv_rate[i] * 100.0, _g1p->get_new_prediction(_surv_rate_pred[i]) * 100.0); } @@ -203,14 +203,15 @@ return; gclog_or_tty->print_cr(""); - gclog_or_tty->print_cr("%s Rate Summary (for up to age %d)", _name, length-1); + gclog_or_tty->print_cr("%s Rate Summary (for up to age " SIZE_FORMAT ")", _name, length-1); gclog_or_tty->print_cr(" age range survival rate (avg) samples (avg)"); gclog_or_tty->print_cr(" ---------------------------------------------------------"); size_t index = 0; size_t limit = MIN2((int) length, 10); while (index < limit) { - gclog_or_tty->print_cr(" %4d %6.2lf%% %6.2lf", + gclog_or_tty->print_cr(" " SIZE_FORMAT_W(4) + " %6.2lf%% %6.2lf", index, _summary_surv_rates[index]->avg() * 100.0, (double) _summary_surv_rates[index]->num()); ++index; @@ -228,7 +229,8 @@ ++index; if (index == length || num % 10 == 0) { - gclog_or_tty->print_cr(" %4d .. %4d %6.2lf%% %6.2lf", + gclog_or_tty->print_cr(" " SIZE_FORMAT_W(4) " .. " SIZE_FORMAT_W(4) + " %6.2lf%% %6.2lf", (index-1) / 10 * 10, index-1, sum / (double) num, (double) samples / (double) num); sum = 0.0; diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -143,7 +143,8 @@ if (TraceAdaptiveGCBoundary) { gclog_or_tty->print_cr("Before expansion of old gen with boundary move"); - gclog_or_tty->print_cr(" Requested change: 0x%x Attempted change: 0x%x", + gclog_or_tty->print_cr(" Requested change: " SIZE_FORMAT_HEX + " Attempted change: " SIZE_FORMAT_HEX, expand_in_bytes, change_in_bytes); if (!PrintHeapAtGC) { Universe::print_on(gclog_or_tty); @@ -201,7 +202,7 @@ if (TraceAdaptiveGCBoundary) { gclog_or_tty->print_cr("Before expansion of young gen with boundary move"); - gclog_or_tty->print_cr(" Requested change: 0x%x Attempted change: 0x%x", + gclog_or_tty->print_cr(" Requested change: " SIZE_FORMAT_HEX " Attempted change: " SIZE_FORMAT_HEX, expand_in_bytes, change_in_bytes); if (!PrintHeapAtGC) { Universe::print_on(gclog_or_tty); diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -127,22 +127,22 @@ size_t result_aligned = align_size_down(result, gen_alignment); if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr("\nASPSOldGen::available_for_contraction:" - " %d K / 0x%x", result_aligned/K, result_aligned); - gclog_or_tty->print_cr(" reserved().byte_size() %d K / 0x%x ", + " " SIZE_FORMAT " K / " SIZE_FORMAT_HEX, result_aligned/K, result_aligned); + gclog_or_tty->print_cr(" reserved().byte_size() " SIZE_FORMAT " K / " SIZE_FORMAT_HEX, reserved().byte_size()/K, reserved().byte_size()); size_t working_promoted = (size_t) policy->avg_promoted()->padded_average(); - gclog_or_tty->print_cr(" padded promoted %d K / 0x%x", + gclog_or_tty->print_cr(" padded promoted " SIZE_FORMAT " K / " SIZE_FORMAT_HEX, working_promoted/K, working_promoted); - gclog_or_tty->print_cr(" used %d K / 0x%x", + gclog_or_tty->print_cr(" used " SIZE_FORMAT " K / " SIZE_FORMAT_HEX, used_in_bytes()/K, used_in_bytes()); - gclog_or_tty->print_cr(" min_gen_size() %d K / 0x%x", + gclog_or_tty->print_cr(" min_gen_size() " SIZE_FORMAT " K / " SIZE_FORMAT_HEX, min_gen_size()/K, min_gen_size()); - gclog_or_tty->print_cr(" max_contraction %d K / 0x%x", + gclog_or_tty->print_cr(" max_contraction " SIZE_FORMAT " K / " SIZE_FORMAT_HEX, max_contraction/K, max_contraction); - gclog_or_tty->print_cr(" without alignment %d K / 0x%x", + gclog_or_tty->print_cr(" without alignment " SIZE_FORMAT " K / " SIZE_FORMAT_HEX, policy->promo_increment(max_contraction)/K, policy->promo_increment(max_contraction)); - gclog_or_tty->print_cr(" alignment 0x%x", gen_alignment); + gclog_or_tty->print_cr(" alignment " SIZE_FORMAT_HEX, gen_alignment); } assert(result_aligned <= max_contraction, "arithmetic is wrong"); return result_aligned; diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -112,11 +112,11 @@ size_t result = policy->eden_increment_aligned_down(max_contraction); size_t result_aligned = align_size_down(result, gen_alignment); if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr("ASPSYoungGen::available_for_contraction: %d K", + gclog_or_tty->print_cr("ASPSYoungGen::available_for_contraction: " SIZE_FORMAT " K", result_aligned/K); - gclog_or_tty->print_cr(" max_contraction %d K", max_contraction/K); - gclog_or_tty->print_cr(" eden_avail %d K", eden_avail/K); - gclog_or_tty->print_cr(" gen_avail %d K", gen_avail/K); + gclog_or_tty->print_cr(" max_contraction " SIZE_FORMAT " K", max_contraction/K); + gclog_or_tty->print_cr(" eden_avail " SIZE_FORMAT " K", eden_avail/K); + gclog_or_tty->print_cr(" gen_avail " SIZE_FORMAT " K", gen_avail/K); } return result_aligned; } diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/parallelScavenge/gcTaskManager.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/gcTaskManager.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/gcTaskManager.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -487,7 +487,7 @@ if (TraceDynamicGCThreads) { gclog_or_tty->print_cr("GCTaskManager::set_active_gang(): " "all_workers_active() %d workers %d " - "active %d ParallelGCThreads %d ", + "active %d ParallelGCThreads " UINTX_FORMAT, all_workers_active(), workers(), active_workers(), ParallelGCThreads); } diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/parallelScavenge/objectStartArray.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/objectStartArray.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/objectStartArray.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -128,8 +128,6 @@ // When doing MT offsets, we can't assert this. //assert(offset > *block, "Found backwards allocation"); *block = (jbyte)offset; - - // tty->print_cr("[%p]", p); } // Optimized for finding the first object that crosses into diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -264,7 +264,7 @@ cm->set_region_stack(ParCompactionManager::region_list(which_stack_index)); if (TraceDynamicGCThreads) { gclog_or_tty->print_cr("StealRegionCompactionTask::do_it " - "region_stack_index %d region_stack = 0x%x " + "region_stack_index %d region_stack = " PTR_FORMAT " " " empty (%d) use all workers %d", which_stack_index, ParCompactionManager::region_list(which_stack_index), cm->region_stack()->is_empty(), @@ -366,7 +366,7 @@ if (TraceDynamicGCThreads) { void* old_region_stack = (void*) cm->region_stack(); int old_region_stack_index = cm->region_stack_index(); - gclog_or_tty->print_cr("Pushing region stack 0x%x/%d", + gclog_or_tty->print_cr("Pushing region stack " PTR_FORMAT "/%d", old_region_stack, old_region_stack_index); } diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -379,7 +379,7 @@ gclog_or_tty->print_cr( "PSAdaptiveSizePolicy::compute_eden_space_size: gc time limit" " gc_cost: %f " - " GCTimeLimit: %d", + " GCTimeLimit: " UINTX_FORMAT, gc_cost(), GCTimeLimit); } } @@ -586,7 +586,7 @@ gclog_or_tty->print_cr( "PSAdaptiveSizePolicy::compute_old_gen_free_space: gc time limit" " gc_cost: %f " - " GCTimeLimit: %d", + " GCTimeLimit: " UINTX_FORMAT, gc_cost(), GCTimeLimit); } } diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -270,7 +270,8 @@ gclog_or_tty->print_cr(" collection: %d ", heap->total_collections()); if (Verbose) { - gclog_or_tty->print("old_gen_capacity: %d young_gen_capacity: %d", + gclog_or_tty->print("old_gen_capacity: " SIZE_FORMAT + " young_gen_capacity: " SIZE_FORMAT, old_gen->capacity_in_bytes(), young_gen->capacity_in_bytes()); } } diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -1428,7 +1428,7 @@ "space_cap=" SIZE_FORMAT, space_live, space_used, space_capacity); - tty->print_cr("dead_wood_limiter(%6.4f, %d)=%6.4f " + tty->print_cr("dead_wood_limiter(%6.4f, " SIZE_FORMAT ")=%6.4f " "dead_wood_max=" SIZE_FORMAT " dead_wood_limit=" SIZE_FORMAT, density, min_percent_free, limiter, dead_wood_max, dead_wood_limit); @@ -2106,7 +2106,8 @@ gclog_or_tty->print_cr(" collection: %d ", heap->total_collections()); if (Verbose) { - gclog_or_tty->print("old_gen_capacity: %d young_gen_capacity: %d", + gclog_or_tty->print("old_gen_capacity: " SIZE_FORMAT + " young_gen_capacity: " SIZE_FORMAT, old_gen->capacity_in_bytes(), young_gen->capacity_in_bytes()); } } @@ -2559,7 +2560,7 @@ if (TraceParallelOldGCCompactionPhase) { if (Verbose && (fillable_regions & 7) != 0) gclog_or_tty->cr(); - gclog_or_tty->print_cr("%u initially fillable regions", fillable_regions); + gclog_or_tty->print_cr(SIZE_FORMAT " initially fillable regions", fillable_regions); } } diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -330,7 +330,7 @@ #ifndef PRODUCT if (TraceScavenge) { - gclog_or_tty->print_cr("{%s %s 0x%x (%d)}", + gclog_or_tty->print_cr("{%s %s " PTR_FORMAT " (%d)}", "promotion-failure", obj->klass()->internal_name(), (void *)obj, obj->size()); diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -510,7 +510,8 @@ heap->total_collections()); if (Verbose) { - gclog_or_tty->print("old_gen_capacity: %d young_gen_capacity: %d", + gclog_or_tty->print("old_gen_capacity: " SIZE_FORMAT + " young_gen_capacity: " SIZE_FORMAT, old_gen->capacity_in_bytes(), young_gen->capacity_in_bytes()); } } @@ -728,7 +729,7 @@ young_gen->object_iterate(&unforward_closure); if (PrintGC && Verbose) { - gclog_or_tty->print_cr("Restoring %d marks", _preserved_oop_stack.size()); + gclog_or_tty->print_cr("Restoring " SIZE_FORMAT " marks", _preserved_oop_stack.size()); } // Restore any saved marks. diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -31,6 +31,7 @@ #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" #include "memory/iterator.hpp" +#include "utilities/globalDefinitions.hpp" inline void PSScavenge::save_to_space_top_before_gc() { ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); @@ -178,7 +179,7 @@ #ifndef PRODUCT if (TraceScavenge) { ResourceMark rm; - gclog_or_tty->print_cr("PSScavengeKlassClosure::do_klass %p, %s, dirty: %s", + gclog_or_tty->print_cr("PSScavengeKlassClosure::do_klass " PTR_FORMAT ", %s, dirty: %s", klass, klass->external_name(), klass->has_modified_oops() ? "true" : "false"); diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/shared/adaptiveSizePolicy.cpp --- a/hotspot/src/share/vm/gc_implementation/shared/adaptiveSizePolicy.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/shared/adaptiveSizePolicy.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -168,9 +168,9 @@ if (TraceDynamicGCThreads) { gclog_or_tty->print_cr("GCTaskManager::calc_default_active_workers() : " - "active_workers(): %d new_active_workers: %d " - "prev_active_workers: %d\n" - " active_workers_by_JT: %d active_workers_by_heap_size: %d", + "active_workers(): " UINTX_FORMAT " new_active_workers: " UINTX_FORMAT " " + "prev_active_workers: " UINTX_FORMAT "\n" + " active_workers_by_JT: " UINTX_FORMAT " active_workers_by_heap_size: " UINTX_FORMAT, active_workers, new_active_workers, prev_active_workers, active_workers_by_JT, active_workers_by_heap_size); } @@ -545,12 +545,12 @@ if (UseGCOverheadLimit && PrintGCDetails && Verbose) { if (gc_overhead_limit_exceeded()) { gclog_or_tty->print_cr(" GC is exceeding overhead limit " - "of %d%%", GCTimeLimit); + "of " UINTX_FORMAT "%%", GCTimeLimit); reset_gc_overhead_limit_count(); } else if (print_gc_overhead_limit_would_be_exceeded) { assert(gc_overhead_limit_count() > 0, "Should not be printing"); gclog_or_tty->print_cr(" GC would exceed overhead limit " - "of %d%% %d consecutive time(s)", + "of " UINTX_FORMAT "%% %d consecutive time(s)", GCTimeLimit, gc_overhead_limit_count()); } } diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/shared/allocationStats.hpp --- a/hotspot/src/share/vm/gc_implementation/shared/allocationStats.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/shared/allocationStats.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -120,8 +120,9 @@ float delta_ise = (CMSExtrapolateSweep ? intra_sweep_estimate : 0.0); _desired = (ssize_t)(new_rate * (inter_sweep_estimate + delta_ise)); if (PrintFLSStatistics > 1) { - gclog_or_tty->print_cr("demand: %d, old_rate: %f, current_rate: %f, new_rate: %f, old_desired: %d, new_desired: %d", - demand, old_rate, rate, new_rate, old_desired, _desired); + gclog_or_tty->print_cr("demand: " SSIZE_FORMAT ", old_rate: %f, current_rate: %f, " + "new_rate: %f, old_desired: " SSIZE_FORMAT ", new_desired: " SSIZE_FORMAT, + demand, old_rate, rate, new_rate, old_desired, _desired); } } } diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.cpp --- a/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -37,21 +37,10 @@ int ConcurrentGCThread::_CGC_flag = CGC_nil; -SuspendibleThreadSet ConcurrentGCThread::_sts; - ConcurrentGCThread::ConcurrentGCThread() : _should_terminate(false), _has_terminated(false) { - _sts.initialize(); }; -void ConcurrentGCThread::safepoint_synchronize() { - _sts.suspend_all(); -} - -void ConcurrentGCThread::safepoint_desynchronize() { - _sts.resume_all(); -} - void ConcurrentGCThread::create_and_start() { if (os::create_thread(this, os::cgc_thread)) { // XXX: need to set this to low priority @@ -92,78 +81,6 @@ ThreadLocalStorage::set_thread(NULL); } - -void SuspendibleThreadSet::initialize_work() { - MutexLocker x(STS_init_lock); - if (!_initialized) { - _m = new Monitor(Mutex::leaf, - "SuspendibleThreadSetLock", true); - _async = 0; - _async_stop = false; - _async_stopped = 0; - _initialized = true; - } -} - -void SuspendibleThreadSet::join() { - initialize(); - MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag); - while (_async_stop) _m->wait(Mutex::_no_safepoint_check_flag); - _async++; - assert(_async > 0, "Huh."); -} - -void SuspendibleThreadSet::leave() { - assert(_initialized, "Must be initialized."); - MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag); - _async--; - assert(_async >= 0, "Huh."); - if (_async_stop) _m->notify_all(); -} - -void SuspendibleThreadSet::yield(const char* id) { - assert(_initialized, "Must be initialized."); - if (_async_stop) { - MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag); - if (_async_stop) { - _async_stopped++; - assert(_async_stopped > 0, "Huh."); - if (_async_stopped == _async) { - if (ConcGCYieldTimeout > 0) { - double now = os::elapsedTime(); - guarantee((now - _suspend_all_start) * 1000.0 < - (double)ConcGCYieldTimeout, - "Long delay; whodunit?"); - } - } - _m->notify_all(); - while (_async_stop) _m->wait(Mutex::_no_safepoint_check_flag); - _async_stopped--; - assert(_async >= 0, "Huh"); - _m->notify_all(); - } - } -} - -void SuspendibleThreadSet::suspend_all() { - initialize(); // If necessary. - if (ConcGCYieldTimeout > 0) { - _suspend_all_start = os::elapsedTime(); - } - MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag); - assert(!_async_stop, "Only one at a time."); - _async_stop = true; - while (_async_stopped < _async) _m->wait(Mutex::_no_safepoint_check_flag); -} - -void SuspendibleThreadSet::resume_all() { - assert(_initialized, "Must be initialized."); - MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag); - assert(_async_stopped == _async, "Huh."); - _async_stop = false; - _m->notify_all(); -} - static void _sltLoop(JavaThread* thread, TRAPS) { SurrogateLockerThread* slt = (SurrogateLockerThread*)thread; slt->loop(); @@ -283,30 +200,3 @@ } assert(!_monitor.owned_by_self(), "Should unlock before exit."); } - - -// ===== STS Access From Outside CGCT ===== - -void ConcurrentGCThread::stsYield(const char* id) { - assert( Thread::current()->is_ConcurrentGC_thread(), - "only a conc GC thread can call this" ); - _sts.yield(id); -} - -bool ConcurrentGCThread::stsShouldYield() { - assert( Thread::current()->is_ConcurrentGC_thread(), - "only a conc GC thread can call this" ); - return _sts.should_yield(); -} - -void ConcurrentGCThread::stsJoin() { - assert( Thread::current()->is_ConcurrentGC_thread(), - "only a conc GC thread can call this" ); - _sts.join(); -} - -void ConcurrentGCThread::stsLeave() { - assert( Thread::current()->is_ConcurrentGC_thread(), - "only a conc GC thread can call this" ); - _sts.leave(); -} diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp --- a/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -26,55 +26,8 @@ #define SHARE_VM_GC_IMPLEMENTATION_SHARED_CONCURRENTGCTHREAD_HPP #include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS +#include "gc_implementation/shared/suspendibleThreadSet.hpp" #include "runtime/thread.hpp" -#endif // INCLUDE_ALL_GCS - -class VoidClosure; - -// A SuspendibleThreadSet is (obviously) a set of threads that can be -// suspended. A thread can join and later leave the set, and periodically -// yield. If some thread (not in the set) requests, via suspend_all, that -// the threads be suspended, then the requesting thread is blocked until -// all the threads in the set have yielded or left the set. (Threads may -// not enter the set when an attempted suspension is in progress.) The -// suspending thread later calls resume_all, allowing the suspended threads -// to continue. - -class SuspendibleThreadSet { - Monitor* _m; - int _async; - bool _async_stop; - int _async_stopped; - bool _initialized; - double _suspend_all_start; - - void initialize_work(); - - public: - SuspendibleThreadSet() : _initialized(false) {} - - // Add the current thread to the set. May block if a suspension - // is in progress. - void join(); - // Removes the current thread from the set. - void leave(); - // Returns "true" iff an suspension is in progress. - bool should_yield() { return _async_stop; } - // Suspends the current thread if a suspension is in progress (for - // the duration of the suspension.) - void yield(const char* id); - // Return when all threads in the set are suspended. - void suspend_all(); - // Allow suspended threads to resume. - void resume_all(); - // Redundant initializations okay. - void initialize() { - // Double-check dirty read idiom. - if (!_initialized) initialize_work(); - } -}; - class ConcurrentGCThread: public NamedThread { friend class VMStructs; @@ -96,9 +49,6 @@ static int set_CGC_flag(int b) { return _CGC_flag |= b; } static int reset_CGC_flag(int b) { return _CGC_flag &= ~b; } - // All instances share this one set. - static SuspendibleThreadSet _sts; - // Create and start the thread (setting it's priority high.) void create_and_start(); @@ -121,25 +71,6 @@ // Tester bool is_ConcurrentGC_thread() const { return true; } - - static void safepoint_synchronize(); - static void safepoint_desynchronize(); - - // All overridings should probably do _sts::yield, but we allow - // overriding for distinguished debugging messages. Default is to do - // nothing. - virtual void yield() {} - - bool should_yield() { return _sts.should_yield(); } - - // they are prefixed by sts since there are already yield() and - // should_yield() (non-static) methods in this class and it was an - // easy way to differentiate them. - static void stsYield(const char* id); - static bool stsShouldYield(); - static void stsJoin(); - static void stsLeave(); - }; // The SurrogateLockerThread is used by concurrent GC threads for diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/shared/markSweep.cpp --- a/hotspot/src/share/vm/gc_implementation/shared/markSweep.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/shared/markSweep.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -131,7 +131,7 @@ assert(_preserved_oop_stack.size() == _preserved_mark_stack.size(), "inconsistent preserved oop stacks"); if (PrintGC && Verbose) { - gclog_or_tty->print_cr("Restoring %d marks", + gclog_or_tty->print_cr("Restoring " SIZE_FORMAT " marks", _preserved_count + _preserved_oop_stack.size()); } diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp --- a/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -888,7 +888,9 @@ for (int i = 0; i < lgrp_spaces()->length(); i++) { lgrp_spaces()->at(i)->accumulate_statistics(page_size()); } - st->print(" local/remote/unbiased/uncommitted: %dK/%dK/%dK/%dK, large/small pages: %d/%d\n", + st->print(" local/remote/unbiased/uncommitted: " SIZE_FORMAT "K/" + SIZE_FORMAT "K/" SIZE_FORMAT "K/" SIZE_FORMAT + "K, large/small pages: " SIZE_FORMAT "/" SIZE_FORMAT "\n", ls->space_stats()->_local_space / K, ls->space_stats()->_remote_space / K, ls->space_stats()->_unbiased_space / K, diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.cpp --- a/hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -27,6 +27,7 @@ #include "memory/sharedHeap.hpp" #include "oops/arrayOop.hpp" #include "oops/oop.inline.hpp" +#include "utilities/globalDefinitions.hpp" ParGCAllocBuffer::ParGCAllocBuffer(size_t desired_plab_sz_) : _word_sz(desired_plab_sz_), _bottom(NULL), _top(NULL), @@ -112,7 +113,7 @@ } _used = _allocated - _wasted - _unused; size_t plab_sz = _used/(target_refills*no_of_gc_workers); - if (PrintPLAB) gclog_or_tty->print(" (plab_sz = %d ", plab_sz); + if (PrintPLAB) gclog_or_tty->print(" (plab_sz = " SIZE_FORMAT " ", plab_sz); // Take historical weighted average _filter.sample(plab_sz); // Clip from above and below, and align to object boundary @@ -120,7 +121,7 @@ plab_sz = MIN2(max_size(), plab_sz); plab_sz = align_object_size(plab_sz); // Latch the result - if (PrintPLAB) gclog_or_tty->print(" desired_plab_sz = %d) ", plab_sz); + if (PrintPLAB) gclog_or_tty->print(" desired_plab_sz = " SIZE_FORMAT ") ", plab_sz); _desired_plab_sz = plab_sz; // Now clear the accumulators for next round: // note this needs to be fixed in the case where we @@ -132,8 +133,9 @@ #ifndef PRODUCT void ParGCAllocBuffer::print() { - gclog_or_tty->print("parGCAllocBuffer: _bottom: %p _top: %p _end: %p _hard_end: %p" - "_retained: %c _retained_filler: [%p,%p)\n", + gclog_or_tty->print("parGCAllocBuffer: _bottom: " PTR_FORMAT " _top: " PTR_FORMAT + " _end: " PTR_FORMAT " _hard_end: " PTR_FORMAT " _retained: %c" + " _retained_filler: [" PTR_FORMAT "," PTR_FORMAT ")\n", _bottom, _top, _end, _hard_end, "FT"[_retained], _retained_filler.start(), _retained_filler.end()); } diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp --- a/hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -60,6 +60,7 @@ // Initializes the buffer to be empty, but with the given "word_sz". // Must get initialized with "set_buf" for an allocation to succeed. ParGCAllocBuffer(size_t word_sz); + virtual ~ParGCAllocBuffer() {} static const size_t min_size() { return ThreadLocalAllocBuffer::min_size(); @@ -113,7 +114,7 @@ } // Sets the space of the buffer to be [buf, space+word_sz()). - void set_buf(HeapWord* buf) { + virtual void set_buf(HeapWord* buf) { _bottom = buf; _top = _bottom; _hard_end = _bottom + word_sz(); @@ -158,7 +159,7 @@ // Fills in the unallocated portion of the buffer with a garbage object. // If "end_of_gc" is TRUE, is after the last use in the GC. IF "retain" // is true, attempt to re-use the unused portion in the next GC. - void retire(bool end_of_gc, bool retain); + virtual void retire(bool end_of_gc, bool retain); void print() PRODUCT_RETURN; }; @@ -238,14 +239,14 @@ void undo_allocation(HeapWord* obj, size_t word_sz); - void set_buf(HeapWord* buf_start) { + virtual void set_buf(HeapWord* buf_start) { ParGCAllocBuffer::set_buf(buf_start); _true_end = _hard_end; _bt.set_region(MemRegion(buf_start, word_sz())); _bt.initialize_threshold(); } - void retire(bool end_of_gc, bool retain); + virtual void retire(bool end_of_gc, bool retain); MemRegion range() { return MemRegion(_top, _true_end); diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/shared/spaceDecorator.cpp --- a/hotspot/src/share/vm/gc_implementation/shared/spaceDecorator.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/shared/spaceDecorator.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -84,7 +84,7 @@ assert(ZapUnusedHeapArea, "Mangling should not be in use"); #ifdef ASSERT if(TraceZapUnusedHeapArea) { - gclog_or_tty->print("Mangling [0x%x to 0x%x)", mr.start(), mr.end()); + gclog_or_tty->print("Mangling [" PTR_FORMAT " to " PTR_FORMAT ")", mr.start(), mr.end()); } Copy::fill_to_words(mr.start(), mr.word_size(), badHeapWord); if(TraceZapUnusedHeapArea) { diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/shared/suspendibleThreadSet.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/gc_implementation/shared/suspendibleThreadSet.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 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 + * 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. + * + */ + +#include "precompiled.hpp" +#include "gc_implementation/shared/suspendibleThreadSet.hpp" +#include "runtime/mutexLocker.hpp" +#include "runtime/thread.inline.hpp" + +uint SuspendibleThreadSet::_nthreads = 0; +uint SuspendibleThreadSet::_nthreads_stopped = 0; +bool SuspendibleThreadSet::_suspend_all = false; +double SuspendibleThreadSet::_suspend_all_start = 0.0; + +void SuspendibleThreadSet::join() { + MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); + while (_suspend_all) { + ml.wait(Mutex::_no_safepoint_check_flag); + } + _nthreads++; +} + +void SuspendibleThreadSet::leave() { + MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); + assert(_nthreads > 0, "Invalid"); + _nthreads--; + if (_suspend_all) { + ml.notify_all(); + } +} + +void SuspendibleThreadSet::yield() { + if (_suspend_all) { + MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); + if (_suspend_all) { + _nthreads_stopped++; + if (_nthreads_stopped == _nthreads) { + if (ConcGCYieldTimeout > 0) { + double now = os::elapsedTime(); + guarantee((now - _suspend_all_start) * 1000.0 < (double)ConcGCYieldTimeout, "Long delay"); + } + } + ml.notify_all(); + while (_suspend_all) { + ml.wait(Mutex::_no_safepoint_check_flag); + } + assert(_nthreads_stopped > 0, "Invalid"); + _nthreads_stopped--; + ml.notify_all(); + } + } +} + +void SuspendibleThreadSet::synchronize() { + assert(Thread::current()->is_VM_thread(), "Must be the VM thread"); + if (ConcGCYieldTimeout > 0) { + _suspend_all_start = os::elapsedTime(); + } + MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); + assert(!_suspend_all, "Only one at a time"); + _suspend_all = true; + while (_nthreads_stopped < _nthreads) { + ml.wait(Mutex::_no_safepoint_check_flag); + } +} + +void SuspendibleThreadSet::desynchronize() { + assert(Thread::current()->is_VM_thread(), "Must be the VM thread"); + MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); + assert(_nthreads_stopped == _nthreads, "Invalid"); + _suspend_all = false; + ml.notify_all(); +} diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_implementation/shared/suspendibleThreadSet.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/gc_implementation/shared/suspendibleThreadSet.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 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 + * 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. + * + */ + +#ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_SUSPENDIBLETHREADSET_HPP +#define SHARE_VM_GC_IMPLEMENTATION_SHARED_SUSPENDIBLETHREADSET_HPP + +#include "memory/allocation.hpp" + +// A SuspendibleThreadSet is a set of threads that can be suspended. +// A thread can join and later leave the set, and periodically yield. +// If some thread (not in the set) requests, via synchronize(), that +// the threads be suspended, then the requesting thread is blocked +// until all the threads in the set have yielded or left the set. Threads +// may not enter the set when an attempted suspension is in progress. The +// suspending thread later calls desynchronize(), allowing the suspended +// threads to continue. +class SuspendibleThreadSet : public AllStatic { +private: + static uint _nthreads; + static uint _nthreads_stopped; + static bool _suspend_all; + static double _suspend_all_start; + +public: + // Add the current thread to the set. May block if a suspension is in progress. + static void join(); + + // Removes the current thread from the set. + static void leave(); + + // Returns true if an suspension is in progress. + static bool should_yield() { return _suspend_all; } + + // Suspends the current thread if a suspension is in progress. + static void yield(); + + // Returns when all threads in the set are suspended. + static void synchronize(); + + // Resumes all suspended threads in the set. + static void desynchronize(); +}; + +class SuspendibleThreadSetJoiner : public StackObj { +public: + SuspendibleThreadSetJoiner() { + SuspendibleThreadSet::join(); + } + + ~SuspendibleThreadSetJoiner() { + SuspendibleThreadSet::leave(); + } + + bool should_yield() { + return SuspendibleThreadSet::should_yield(); + } + + void yield() { + SuspendibleThreadSet::yield(); + } +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_SUSPENDIBLETHREADSET_HPP diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/gc_interface/collectedHeap.hpp --- a/hotspot/src/share/vm/gc_interface/collectedHeap.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -208,6 +208,9 @@ // This is the correct place to place such initialization methods. virtual void post_initialize() = 0; + // Stop any onging concurrent work and prepare for exit. + virtual void stop() {} + MemRegion reserved_region() const { return _reserved; } address base() const { return (address)reserved_region().start(); } diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/memory/binaryTreeDictionary.cpp --- a/hotspot/src/share/vm/memory/binaryTreeDictionary.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/memory/binaryTreeDictionary.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -1205,13 +1205,13 @@ "------------------------------------\n"); size_t total_size = total_chunk_size(debug_only(NULL)); size_t free_blocks = num_free_blocks(); - gclog_or_tty->print("Total Free Space: %d\n", total_size); - gclog_or_tty->print("Max Chunk Size: %d\n", max_chunk_size()); - gclog_or_tty->print("Number of Blocks: %d\n", free_blocks); + gclog_or_tty->print("Total Free Space: " SIZE_FORMAT "\n", total_size); + gclog_or_tty->print("Max Chunk Size: " SIZE_FORMAT "\n", max_chunk_size()); + gclog_or_tty->print("Number of Blocks: " SIZE_FORMAT "\n", free_blocks); if (free_blocks > 0) { - gclog_or_tty->print("Av. Block Size: %d\n", total_size/free_blocks); + gclog_or_tty->print("Av. Block Size: " SIZE_FORMAT "\n", total_size/free_blocks); } - gclog_or_tty->print("Tree Height: %d\n", tree_height()); + gclog_or_tty->print("Tree Height: " SIZE_FORMAT "\n", tree_height()); } // Print census information - counts, births, deaths, etc. diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/memory/defNewGeneration.cpp --- a/hotspot/src/share/vm/memory/defNewGeneration.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/memory/defNewGeneration.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -44,6 +44,7 @@ #include "runtime/java.hpp" #include "runtime/thread.inline.hpp" #include "utilities/copy.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/stack.inline.hpp" // @@ -131,7 +132,7 @@ #ifndef PRODUCT if (TraceScavenge) { ResourceMark rm; - gclog_or_tty->print_cr("KlassScanClosure::do_klass %p, %s, dirty: %s", + gclog_or_tty->print_cr("KlassScanClosure::do_klass " PTR_FORMAT ", %s, dirty: %s", klass, klass->external_name(), klass->has_modified_oops() ? "true" : "false"); @@ -511,7 +512,7 @@ HeapWord* DefNewGeneration::allocate_from_space(size_t size) { HeapWord* result = NULL; if (Verbose && PrintGCDetails) { - gclog_or_tty->print("DefNewGeneration::allocate_from_space(%u):" + gclog_or_tty->print("DefNewGeneration::allocate_from_space(" SIZE_FORMAT "):" " will_fail: %s" " heap_lock: %s" " free: " SIZE_FORMAT, @@ -756,7 +757,7 @@ void DefNewGeneration::handle_promotion_failure(oop old) { if (PrintPromotionFailure && !_promotion_failed) { - gclog_or_tty->print(" (promotion failure size = " SIZE_FORMAT ") ", + gclog_or_tty->print(" (promotion failure size = %d) ", old->size()); } _promotion_failed = true; diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/memory/generation.cpp --- a/hotspot/src/share/vm/memory/generation.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/memory/generation.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -573,8 +573,8 @@ maximum_desired_capacity / (double) K); gclog_or_tty->print_cr(" " " shrink_bytes: %.1fK" - " current_shrink_factor: %d" - " new shrink factor: %d" + " current_shrink_factor: " SIZE_FORMAT + " new shrink factor: " SIZE_FORMAT " _min_heap_delta_bytes: %.1fK", shrink_bytes / (double) K, current_shrink_factor, diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/memory/sharedHeap.cpp --- a/hotspot/src/share/vm/memory/sharedHeap.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/memory/sharedHeap.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -257,7 +257,7 @@ size_t bytes_before, size_t bytes_after, size_t capacity) { - out->print(" %d%s->%d%s(%d%s)", + out->print(" " SIZE_FORMAT "%s->" SIZE_FORMAT "%s(" SIZE_FORMAT "%s)", byte_size_in_proper_unit(bytes_before), proper_unit_for_byte_size(bytes_before), byte_size_in_proper_unit(bytes_after), diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/oops/methodData.hpp --- a/hotspot/src/share/vm/oops/methodData.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/oops/methodData.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -1012,6 +1012,11 @@ static ByteSize argument_type_offset(int i) { return in_ByteSize(argument_type_local_offset(i) * DataLayout::cell_size); } + + static ByteSize return_only_size() { + return ReturnTypeEntry::size() + in_ByteSize(header_cell_count() * DataLayout::cell_size); + } + }; // CallTypeData @@ -2143,7 +2148,6 @@ static bool profile_jsr292(methodHandle m, int bci); static int profile_arguments_flag(); - static bool profile_arguments_jsr292_only(); static bool profile_all_arguments(); static bool profile_arguments_for_invoke(methodHandle m, int bci); static int profile_return_flag(); @@ -2442,6 +2446,7 @@ static bool profile_parameters_for_method(methodHandle m); static bool profile_arguments(); + static bool profile_arguments_jsr292_only(); static bool profile_return(); static bool profile_parameters(); static bool profile_return_jsr292_only(); diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/opto/superword.cpp --- a/hotspot/src/share/vm/opto/superword.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/opto/superword.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -1266,8 +1266,9 @@ memops.clear(); for (DUIterator i = upper_insert_pt->outs(); upper_insert_pt->has_out(i); i++) { Node* use = upper_insert_pt->out(i); - if (!use->is_Store()) + if (use->is_Mem() && !use->is_Store()) { memops.push(use); + } } MemNode* lower_insert_pt = last; diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/runtime/globals.hpp --- a/hotspot/src/share/vm/runtime/globals.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/runtime/globals.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -1931,6 +1931,10 @@ "not just one of the generations (e.g., G1). A value of 0 " \ "denotes 'do constant GC cycles'.") \ \ + manageable(intx, CMSTriggerInterval, -1, \ + "Commence a CMS collection cycle (at least) every so many " \ + "milliseconds (0 permanently, -1 disabled)") \ + \ product(bool, UseCMSInitiatingOccupancyOnly, false, \ "Only use occupancy as a criterion for starting a CMS collection")\ \ diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/runtime/java.cpp --- a/hotspot/src/share/vm/runtime/java.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/runtime/java.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -499,6 +499,9 @@ os::infinite_sleep(); } + // Stop any ongoing concurrent GC work + Universe::heap()->stop(); + // Terminate watcher thread - must before disenrolling any periodic task if (PeriodicTask::num_tasks() > 0) WatcherThread::stop(); diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/runtime/mutexLocker.cpp --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -69,7 +69,7 @@ Monitor* SerializePage_lock = NULL; Monitor* Threads_lock = NULL; Monitor* CGC_lock = NULL; -Mutex* STS_init_lock = NULL; +Monitor* STS_lock = NULL; Monitor* SLT_lock = NULL; Monitor* iCMS_lock = NULL; Monitor* FullGCCount_lock = NULL; @@ -173,7 +173,7 @@ def(tty_lock , Mutex , event, true ); // allow to lock in VM def(CGC_lock , Monitor, special, true ); // coordinate between fore- and background GC - def(STS_init_lock , Mutex, leaf, true ); + def(STS_lock , Monitor, leaf, true ); if (UseConcMarkSweepGC) { def(iCMS_lock , Monitor, special, true ); // CMS incremental mode start/stop notification } diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/runtime/mutexLocker.hpp --- a/hotspot/src/share/vm/runtime/mutexLocker.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -79,7 +79,7 @@ // (also used by Safepoints too to block threads creation/destruction) extern Monitor* CGC_lock; // used for coordination between // fore- & background GC threads. -extern Mutex* STS_init_lock; // coordinate initialization of SuspendibleThreadSets. +extern Monitor* STS_lock; // used for joining/leaving SuspendibleThreadSet. extern Monitor* SLT_lock; // used in CMS GC for acquiring PLL extern Monitor* iCMS_lock; // CMS incremental mode start/stop notification extern Monitor* FullGCCount_lock; // in support of "concurrent" full gc diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/runtime/safepoint.cpp --- a/hotspot/src/share/vm/runtime/safepoint.cpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/runtime/safepoint.cpp Fri Apr 25 09:59:44 2014 -0700 @@ -75,7 +75,7 @@ #endif #if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp" -#include "gc_implementation/shared/concurrentGCThread.hpp" +#include "gc_implementation/shared/suspendibleThreadSet.hpp" #endif // INCLUDE_ALL_GCS #ifdef COMPILER1 #include "c1/c1_globals.hpp" @@ -110,7 +110,7 @@ // more-general mechanism below. DLD (01/05). ConcurrentMarkSweepThread::synchronize(false); } else if (UseG1GC) { - ConcurrentGCThread::safepoint_synchronize(); + SuspendibleThreadSet::synchronize(); } #endif // INCLUDE_ALL_GCS @@ -486,7 +486,7 @@ if (UseConcMarkSweepGC) { ConcurrentMarkSweepThread::desynchronize(false); } else if (UseG1GC) { - ConcurrentGCThread::safepoint_desynchronize(); + SuspendibleThreadSet::desynchronize(); } #endif // INCLUDE_ALL_GCS // record this time so VMThread can keep track how much time has elapsed diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/src/share/vm/utilities/globalDefinitions.hpp --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp Fri Apr 25 09:59:44 2014 -0700 @@ -1324,10 +1324,12 @@ #define PTR_FORMAT "0x%08" PRIxPTR #endif // _LP64 -#define SSIZE_FORMAT "%" PRIdPTR -#define SIZE_FORMAT "%" PRIuPTR -#define SSIZE_FORMAT_W(width) "%" #width PRIdPTR -#define SIZE_FORMAT_W(width) "%" #width PRIuPTR +#define SSIZE_FORMAT "%" PRIdPTR +#define SIZE_FORMAT "%" PRIuPTR +#define SIZE_FORMAT_HEX "0x%" PRIxPTR +#define SSIZE_FORMAT_W(width) "%" #width PRIdPTR +#define SIZE_FORMAT_W(width) "%" #width PRIuPTR +#define SIZE_FORMAT_HEX_W(width) "0x%" #width PRIxPTR #define INTX_FORMAT "%" PRIdPTR #define UINTX_FORMAT "%" PRIuPTR diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/test/TEST.groups --- a/hotspot/test/TEST.groups Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/test/TEST.groups Fri Apr 25 09:59:44 2014 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 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 @@ -127,10 +127,12 @@ gc/6581734/Test6581734.java \ gc/7072527/TestFullGCCount.java \ gc/g1/TestHumongousAllocInitialMark.java \ + gc/g1/TestHumongousShrinkHeap.java \ gc/arguments/TestG1HeapRegionSize.java \ gc/metaspace/TestMetaspaceMemoryPool.java \ gc/arguments/TestDynMinHeapFreeRatio.java \ gc/arguments/TestDynMaxHeapFreeRatio.java \ + gc/parallelScavenge/TestDynShrinkHeap.java \ runtime/InternalApi/ThreadCpuTimesDeadlock.java \ serviceability/threads/TestFalseDeadLock.java \ compiler/tiered/NonTieredLevelsTest.java \ diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/test/gc/g1/TestGCLogMessages.java --- a/hotspot/test/gc/g1/TestGCLogMessages.java Wed Jul 05 19:38:35 2017 +0200 +++ b/hotspot/test/gc/g1/TestGCLogMessages.java Fri Apr 25 09:59:44 2014 -0700 @@ -23,7 +23,7 @@ /* * @test TestPrintGCDetails - * @bug 8035406 8027295 8035398 + * @bug 8035406 8027295 8035398 8019342 * @summary Ensure that the PrintGCDetails output for a minor GC with G1 * includes the expected necessary messages. * @key gc @@ -48,6 +48,8 @@ OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldNotContain("[Redirty Cards"); + output.shouldNotContain("[Parallel Redirty"); + output.shouldNotContain("[Redirtied Cards"); output.shouldNotContain("[Code Root Purge"); output.shouldNotContain("[String Dedup Fixup"); output.shouldNotContain("[Young Free CSet"); @@ -63,6 +65,8 @@ output = new OutputAnalyzer(pb.start()); output.shouldContain("[Redirty Cards"); + output.shouldNotContain("[Parallel Redirty"); + output.shouldNotContain("[Redirtied Cards"); output.shouldContain("[Code Root Purge"); output.shouldContain("[String Dedup Fixup"); output.shouldNotContain("[Young Free CSet"); @@ -80,6 +84,8 @@ output = new OutputAnalyzer(pb.start()); output.shouldContain("[Redirty Cards"); + output.shouldContain("[Parallel Redirty"); + output.shouldContain("[Redirtied Cards"); output.shouldContain("[Code Root Purge"); output.shouldContain("[String Dedup Fixup"); output.shouldContain("[Young Free CSet"); diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/test/gc/g1/TestHumongousShrinkHeap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/gc/g1/TestHumongousShrinkHeap.java Fri Apr 25 09:59:44 2014 -0700 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 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 + * 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 TestHumongousShrinkHeap + * @bug 8036025 + * @summary Verify that heap shrinks after GC in the presence of fragmentation due to humongous objects + * @library /testlibrary + * @run main/othervm -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=50 -XX:+UseG1GC -XX:G1HeapRegionSize=1M -verbose:gc TestHumongousShrinkHeap + */ + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryUsage; +import java.util.ArrayList; +import java.util.List; +import sun.management.ManagementFactoryHelper; +import static com.oracle.java.testlibrary.Asserts.*; + +public class TestHumongousShrinkHeap { + + public static final String MIN_FREE_RATIO_FLAG_NAME = "MinHeapFreeRatio"; + public static final String MAX_FREE_RATIO_FLAG_NAME = "MaxHeapFreeRatio"; + + private static final ArrayList> garbage = new ArrayList<>(); + private static final int PAGE_SIZE = 1024 * 1024; // 1M + private static final int PAGES_NUM = 5; + + + public static void main(String[] args) { + new TestHumongousShrinkHeap().test(); + } + + private final void test() { + System.gc(); + MemoryUsagePrinter.printMemoryUsage("init"); + + eat(); + MemoryUsagePrinter.printMemoryUsage("eaten"); + MemoryUsage muFull = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); + + free(); + MemoryUsagePrinter.printMemoryUsage("free"); + MemoryUsage muFree = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); + + assertLessThan(muFree.getCommitted(), muFull.getCommitted(), String.format( + "committed free heap size is not less than committed full heap size, heap hasn't been shrunk?%n" + + "%s = %s%n%s = %s", + MIN_FREE_RATIO_FLAG_NAME, + ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MIN_FREE_RATIO_FLAG_NAME).getValue(), + MAX_FREE_RATIO_FLAG_NAME, + ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MAX_FREE_RATIO_FLAG_NAME).getValue() + )); + } + + private void eat() { + int HumongousObjectSize = Math.round(.9f * PAGE_SIZE); + System.out.println("Will allocate objects of size=" + + MemoryUsagePrinter.humanReadableByteCount(HumongousObjectSize, true)); + + for (int i = 0; i < PAGES_NUM; i++) { + ArrayList stuff = new ArrayList<>(); + eatList(stuff, 100, HumongousObjectSize); + MemoryUsagePrinter.printMemoryUsage("eat #" + i); + garbage.add(stuff); + } + } + + private void free() { + // do not free last one list + garbage.subList(0, garbage.size() - 1).clear(); + + // do not free last one element from last list + ArrayList stuff = garbage.get(garbage.size() - 1); + stuff.subList(0, stuff.size() - 1).clear(); + System.gc(); + } + + private static void eatList(List garbage, int count, int size) { + for (int i = 0; i < count; i++) { + garbage.add(new byte[size]); + } + } +} + +/** + * Prints memory usage to standard output + */ +class MemoryUsagePrinter { + + public static String humanReadableByteCount(long bytes, boolean si) { + int unit = si ? 1000 : 1024; + if (bytes < unit) { + return bytes + " B"; + } + int exp = (int) (Math.log(bytes) / Math.log(unit)); + String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i"); + return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); + } + + public static void printMemoryUsage(String label) { + MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); + float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted(); + System.out.format("[%-24s] init: %-7s, used: %-7s, comm: %-7s, freeRatio ~= %.1f%%%n", + label, + humanReadableByteCount(memusage.getInit(), true), + humanReadableByteCount(memusage.getUsed(), true), + humanReadableByteCount(memusage.getCommitted(), true), + freeratio * 100 + ); + } +} diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/test/gc/parallelScavenge/TestDynShrinkHeap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/gc/parallelScavenge/TestDynShrinkHeap.java Fri Apr 25 09:59:44 2014 -0700 @@ -0,0 +1,125 @@ +/* + * Copyright (c) 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 + * 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 TestDynShrinkHeap + * @bug 8016479 + * @summary Verify that the heap shrinks after full GC according to the current values of the Min/MaxHeapFreeRatio flags + * @library /testlibrary + * @run main/othervm -XX:+UseAdaptiveSizePolicyWithSystemGC -XX:+UseParallelGC -XX:MinHeapFreeRatio=0 -XX:MaxHeapFreeRatio=100 -verbose:gc TestDynShrinkHeap + */ + +import com.oracle.java.testlibrary.TestDynamicVMOption; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryUsage; +import java.util.ArrayList; +import sun.management.ManagementFactoryHelper; +import static com.oracle.java.testlibrary.Asserts.*; + +public class TestDynShrinkHeap { + + public static final String MIN_FREE_RATIO_FLAG_NAME = "MinHeapFreeRatio"; + public static final String MAX_FREE_RATIO_FLAG_NAME = "MaxHeapFreeRatio"; + + private static ArrayList list = new ArrayList<>(0); + private static final int M = 1024 * 1024; // to make heap more manageable by test code + + private final TestDynamicVMOption maxRatioOption; + private final TestDynamicVMOption minRatioOption; + + public TestDynShrinkHeap() { + minRatioOption = new TestDynamicVMOption(MIN_FREE_RATIO_FLAG_NAME); + maxRatioOption = new TestDynamicVMOption(MAX_FREE_RATIO_FLAG_NAME); + } + + private final void test() { + System.gc(); + MemoryUsagePrinter.printMemoryUsage("init"); + + eat(); + MemoryUsagePrinter.printMemoryUsage("eaten"); + MemoryUsage muFull = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); + + free(); + MemoryUsagePrinter.printMemoryUsage("free"); + MemoryUsage muFree = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); + + assertLessThan(muFree.getCommitted(), muFull.getCommitted(), String.format( + "committed free heap size is not less than committed full heap size, heap hasn't been shrunk?%n" + + "%s = %s%n%s = %s", + MIN_FREE_RATIO_FLAG_NAME, + ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MIN_FREE_RATIO_FLAG_NAME).getValue(), + MAX_FREE_RATIO_FLAG_NAME, + ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MAX_FREE_RATIO_FLAG_NAME).getValue() + )); + } + + private void eat() { + for (int i = 0; i < M; i++) { + list.add(new byte[1024]); + } + MemoryUsagePrinter.printMemoryUsage("allocated " + M + " arrays"); + + list.subList(0, M / 2).clear(); + System.gc(); + MemoryUsagePrinter.printMemoryUsage("array halved"); + } + + private void free() { + maxRatioOption.setIntValue(minRatioOption.getIntValue() + 1); + System.gc(); + MemoryUsagePrinter.printMemoryUsage("under pressure"); + } + + public static void main(String[] args) { + new TestDynShrinkHeap().test(); + } +} + +/** + * Prints memory usage to standard output + */ +class MemoryUsagePrinter { + + public static String humanReadableByteCount(long bytes, boolean si) { + int unit = si ? 1000 : 1024; + if (bytes < unit) { + return bytes + " B"; + } + int exp = (int) (Math.log(bytes) / Math.log(unit)); + String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i"); + return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); + } + + public static void printMemoryUsage(String label) { + MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); + float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted(); + System.out.format("[%-24s] init: %-7s, used: %-7s, comm: %-7s, freeRatio ~= %.1f%%%n", + label, + humanReadableByteCount(memusage.getInit(), true), + humanReadableByteCount(memusage.getUsed(), true), + humanReadableByteCount(memusage.getCommitted(), true), + freeratio * 100 + ); + } +} diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/test/runtime/6925573/SortMethodsTest.java --- a/hotspot/test/runtime/6925573/SortMethodsTest.java Wed Jul 05 19:38:35 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2008, 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 - * 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. - * - */ - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.io.StringWriter; - -import java.lang.reflect.Method; -import java.net.URI; -import java.util.Arrays; -import java.util.Vector; - -import javax.tools.Diagnostic; -import javax.tools.DiagnosticCollector; -import javax.tools.FileObject; -import javax.tools.ForwardingJavaFileManager; -import javax.tools.JavaCompiler; -import javax.tools.JavaCompiler.CompilationTask; -import javax.tools.JavaFileManager; -import javax.tools.JavaFileObject; -import javax.tools.JavaFileObject.Kind; -import javax.tools.SimpleJavaFileObject; -import javax.tools.StandardJavaFileManager; -import javax.tools.ToolProvider; - -/* - * @ignore 6959423 - * @test SortMethodsTest - * @bug 6925573 - * @summary verify that class loading does not need quadratic time with regard to the number of class -methods. - * @run main SortMethodsTest - * @author volker.simonis@gmail.com -*/ - -public class SortMethodsTest { - - static String createClass(String name, int nrOfMethods) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - pw.println("public class " + name + "{"); - for (int i = 0; i < nrOfMethods; i++) { - pw.println(" public void m" + i + "() {}"); - } - pw.println(" public static String sayHello() {"); - pw.println(" return \"Hello from class \" + " + name + - ".class.getName() + \" with \" + " + name + - ".class.getDeclaredMethods().length + \" methods\";"); - pw.println(" }"); - pw.println("}"); - pw.close(); - return sw.toString(); - } - - public static void main(String args[]) { - - JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); - DiagnosticCollector diags = new DiagnosticCollector(); - final String cName = new String("ManyMethodsClass"); - Vector results = new Vector(); - - for (int i = 6; i < 600000; i*=10) { - String klass = createClass(cName, i); - JavaMemoryFileObject file = new JavaMemoryFileObject(cName, klass); - MemoryFileManager mfm = new MemoryFileManager(comp.getStandardFileManager(diags, null, null), file); - CompilationTask task = comp.getTask(null, mfm, diags, null, null, Arrays.asList(file)); - - if (task.call()) { - try { - MemoryClassLoader mcl = new MemoryClassLoader(file); - long start = System.nanoTime(); - Class c = Class.forName(cName, true, mcl); - long end = System.nanoTime(); - results.add(end - start); - Method m = c.getDeclaredMethod("sayHello", new Class[0]); - String ret = (String)m.invoke(null, new Object[0]); - System.out.println(ret + " (loaded and resloved in " + (end - start) + "ns)"); - } catch (Exception e) { - System.err.println(e); - } - } - else { - System.out.println(klass); - System.out.println(); - for (Diagnostic diag : diags.getDiagnostics()) { - System.out.println(diag.getCode() + "\n" + diag.getKind() + "\n" + diag.getPosition()); - System.out.println(diag.getSource() + "\n" + diag.getMessage(null)); - } - } - } - - long lastRatio = 0; - for (int i = 2; i < results.size(); i++) { - long normalized1 = Math.max(results.get(i-1) - results.get(0), 1); - long normalized2 = Math.max(results.get(i) - results.get(0), 1); - long ratio = normalized2/normalized1; - lastRatio = ratio; - System.out.println("10 x more methods requires " + ratio + " x more time"); - } - // The following is just vague estimation but seems to work on current x86_64 and sparcv9 machines - if (lastRatio > 80) { - throw new RuntimeException("ATTENTION: it seems that class loading needs quadratic time with regard to the number of class methods!!!"); - } - } -} - -class JavaMemoryFileObject extends SimpleJavaFileObject { - - private final String code; - private ByteArrayOutputStream byteCode; - - JavaMemoryFileObject(String name, String code) { - super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension), Kind.SOURCE); - this.code = code; - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return code; - } - - @Override - public OutputStream openOutputStream() { - byteCode = new ByteArrayOutputStream(); - return byteCode; - } - - byte[] getByteCode() { - return byteCode.toByteArray(); - } -} - -class MemoryClassLoader extends ClassLoader { - - private final JavaMemoryFileObject jfo; - - public MemoryClassLoader(JavaMemoryFileObject jfo) { - this.jfo = jfo; - } - - public Class findClass(String name) { - byte[] b = jfo.getByteCode(); - return defineClass(name, b, 0, b.length); - } -} - -class MemoryFileManager extends ForwardingJavaFileManager { - - private final JavaFileObject jfo; - - public MemoryFileManager(StandardJavaFileManager jfm, JavaFileObject jfo) { - super(jfm); - this.jfo = jfo; - } - - @Override - public FileObject getFileForInput(Location location, String packageName, - String relativeName) throws IOException { - return jfo; - } - - @Override - public JavaFileObject getJavaFileForOutput(Location location, String qualifiedName, - Kind kind, FileObject outputFile) throws IOException { - return jfo; - } - -} diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/test/runtime/classFileParserBug/ClassFileParserBug.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/classFileParserBug/ClassFileParserBug.java Fri Apr 25 09:59:44 2014 -0700 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 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 + * 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 + * @bug 8040018 + * @library /testlibrary + * @summary Check for exception instead of assert. + * @run main ClassFileParserBug + */ + +import java.io.File; +import com.oracle.java.testlibrary.*; + +public class ClassFileParserBug { + public static void main(String args[]) throws Throwable { + + System.out.println("Regression test for bug 8040018"); + String testsrc = System.getProperty("test.src") + "/"; + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-jar", testsrc + File.separator + "test.jar"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("java.lang.ClassFormatError: Bad length on BootstrapMethods"); + output.shouldHaveExitValue(1); + } +} diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/test/runtime/classFileParserBug/LambdaMath.jcod --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/classFileParserBug/LambdaMath.jcod Fri Apr 25 09:59:44 2014 -0700 @@ -0,0 +1,609 @@ +/* + * Copyright (c) 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 + * 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. + */ + +/* + * This test contains a BootstrapMethods attribute with a fuzzied + * attribute_length field that is larger than it should be. This + * should cause a java.lang.ClassFormatError exception to be thrown. + */ +class LambdaMath { + 0xCAFEBABE; + 0; // minor version + 52; // version + [162] { // Constant Pool + ; // first element is empty + Method #31 #69; // #1 at 0x0A + class #70; // #2 at 0x0F + Method #2 #71; // #3 at 0x12 + Method #72 #73; // #4 at 0x17 + Field #74 #75; // #5 at 0x1C + String #76; // #6 at 0x21 + Method #77 #78; // #7 at 0x24 + InvokeDynamic 0s #84; // #8 at 0x29 + Method #30 #85; // #9 at 0x2E + String #86; // #10 at 0x33 + InvokeDynamic 1s #84; // #11 at 0x36 + String #88; // #12 at 0x3B + InvokeDynamic 2s #84; // #13 at 0x3E + String #90; // #14 at 0x43 + InvokeDynamic 3s #84; // #15 at 0x46 + String #92; // #16 at 0x4B + InvokeDynamic 4s #84; // #17 at 0x4E + InterfaceMethod #94 #95; // #18 at 0x53 + InterfaceMethod #96 #97; // #19 at 0x58 + InterfaceMethod #96 #98; // #20 at 0x5D + InterfaceMethod #99 #100; // #21 at 0x62 + class #101; // #22 at 0x67 + Method #22 #69; // #23 at 0x6A + Method #22 #102; // #24 at 0x6F + String #103; // #25 at 0x74 + Method #22 #104; // #26 at 0x77 + Method #22 #105; // #27 at 0x7C + class #106; // #28 at 0x81 + Method #2 #107; // #29 at 0x84 + class #108; // #30 at 0x89 + class #109; // #31 at 0x8C + Utf8 ""; // #32 at 0x8F + Utf8 "()V"; // #33 at 0x98 + Utf8 "Code"; // #34 at 0x9E + Utf8 "LineNumberTable"; // #35 at 0xA5 + Utf8 "LocalVariableTable"; // #36 at 0xB7 + Utf8 "this"; // #37 at 0xCC + Utf8 "LLambdaMath;"; // #38 at 0xD3 + Utf8 "main"; // #39 at 0xE2 + Utf8 "([Ljava/lang/String;)V"; // #40 at 0xE9 + Utf8 "a"; // #41 at 0x0102 + Utf8 "[Ljava/lang/String;"; // #42 at 0x0106 + Utf8 "list"; // #43 at 0x011C + Utf8 "Ljava/util/List;"; // #44 at 0x0123 + Utf8 "LocalVariableTypeTable"; // #45 at 0x0136 + Utf8 "Ljava/util/List;"; // #46 at 0x014F + Utf8 "evaluate"; // #47 at 0x0177 + Utf8 "(Ljava/util/List;Ljava/util/function/Predicate;)V"; // #48 at 0x0182 + Utf8 "n"; // #49 at 0x01B6 + Utf8 "Ljava/lang/Integer;"; // #50 at 0x01BA + Utf8 "e"; // #51 at 0x01D0 + Utf8 "Ljava/lang/Throwable;"; // #52 at 0x01D4 + Utf8 "predicate"; // #53 at 0x01EC + Utf8 "Ljava/util/function/PrediCate;"; // #54 at 0x01F8 + Utf8 "Ljava/util/function/Predicate;"; // #55 at 0x0219 + Utf8 "StackMapTable"; // #56 at 0x024F + class #110; // #57 at 0x025F + class #106; // #58 at 0x0262 + Utf8 "Signature"; // #59 at 0x0265 + Utf8 "(Ljava/util/List;Ljava/util/function/Predicate;)V"; // #60 at 0x0271 + Utf8 "lambda$main$4"; // #61 at 0x02CF + Utf8 "(Ljava/lang/Integer;)Z"; // #62 at 0x02DF + Utf8 "lambda$main$3"; // #63 at 0x02F8 + Utf8 "lambda$main$2"; // #64 at 0x0308 + Utf8 "lambda$main$1"; // #65 at 0x0318 + Utf8 "lambda$main$0"; // #66 at 0x0328 + Utf8 "SourceFile"; // #67 at 0x0338 + Utf8 "LambdaMath.java"; // #68 at 0x0345 + NameAndType #32 #33; // #69 at 0x0357 + Utf8 "java/lang/Integer"; // #70 at 0x035C + NameAndType #111 #112; // #71 at 0x0370 + class #113; // #72 at 0x0375 + NameAndType #114 #115; // #73 at 0x0378 + class #116; // #74 at 0x037D + NameAndType #117 #118; // #75 at 0x0380 + Utf8 "Print all numbers:"; // #76 at 0x0385 + class #119; // #77 at 0x039A + NameAndType #120 #121; // #78 at 0x039D + Utf8 "BootstrapMethods"; // #79 at 0x03A2 + MethodHandle 6b #122; // #80 at 0x03B5 + MethodType #123; // #81 at 0x03B9 + MethodHandle 6b #124; // #82 at 0x03BC + MethodType #62; // #83 at 0x03C0 + NameAndType #125 #126; // #84 at 0x03C3 + NameAndType #47 #48; // #85 at 0x03C8 + Utf8 "Print no numbers:"; // #86 at 0x03CD + MethodHandle 6b #127; // #87 at 0x03E1 + Utf8 "Print even numbers:"; // #88 at 0x03E5 + MethodHandle 6b #128; // #89 at 0x03FB + Utf8 "Print odd numbers:"; // #90 at 0x03FF + MethodHandle 6b #129; // #91 at 0x0414 + Utf8 "Print numbers greater than 5:"; // #92 at 0x0418 + MethodHandle 6b #130; // #93 at 0x0438 + class #131; // #94 at 0x043C + NameAndType #132 #133; // #95 at 0x043F + class #110; // #96 at 0x0444 + NameAndType #134 #135; // #97 at 0x0447 + NameAndType #136 #137; // #98 at 0x044C + class #138; // #99 at 0x0451 + NameAndType #125 #123; // #100 at 0x0454 + Utf8 "java/lang/StringFuilder"; // #101 at 0x0459 + NameAndType #139 #140; // #102 at 0x0473 + Utf8 " "; // #103 at 0x0478 + NameAndType #139 #141; // #104 at 0x047C + NameAndType #142 #143; // #105 at 0x0481 + Utf8 "java/lang/Throwable"; // #106 at 0x0486 + NameAndType #144 #145; // #107 at 0x049C + Utf8 "LambdaMath"; // #108 at 0x04A1 + Utf8 "java/lang/Object"; // #109 at 0x04AE + Utf8 "java/util/Iterator"; // #110 at 0x04C1 + Utf8 "valueOf"; // #111 at 0x04D6 + Utf8 "(I)Ljava/lang/Integer;"; // #112 at 0x04E0 + Utf8 "java/util/Arrays"; // #113 at 0x04F9 + Utf8 "asList"; // #114 at 0x050C + Utf8 "([Ljava/lang/Object;)Ljava/util/List;"; // #115 at 0x0515 + Utf8 "java/lang/System"; // #116 at 0x053D + Utf8 "out"; // #117 at 0x0550 + Utf8 "Ljava/io/PrintStream;"; // #118 at 0x0556 + Utf8 "java/io/PrintStream"; // #119 at 0x056E + Utf8 "println"; // #120 at 0x0584 + Utf8 "(Ljava/lang/String;)V"; // #121 at 0x058E + Method #146 #147; // #122 at 0x05A6 + Utf8 "(Ljava/lang/Object;)Z"; // #123 at 0x05AB + Method #30 #148; // #124 at 0x05C3 + Utf8 "test"; // #125 at 0x05C8 + Utf8 "()Ljava/util/function/Predicate;"; // #126 at 0x05CF + Method #30 #149; // #127 at 0x05F2 + Method #30 #150; // #128 at 0x05F7 + Method #30 #151; // #129 at 0x05FC + Method #30 #152; // #130 at 0x0601 + Utf8 "java/util/List"; // #131 at 0x0606 + Utf8 "iterator"; // #132 at 0x0617 + Utf8 "()Ljava/util/Iterator;"; // #133 at 0x0622 + Utf8 "hasNext"; // #134 at 0x063B + Utf8 "()Z"; // #135 at 0x0645 + Utf8 "next"; // #136 at 0x064B + Utf8 "()Ljava/lang/Object;"; // #137 at 0x0652 + Utf8 "java/util/function/Predicate"; // #138 at 0x0669 + Utf8 "append"; // #139 at 0x0688 + Utf8 "(Ljava/lang/Object;)Ljava/lang/StringBuilder;"; // #140 at 0x0691 + Utf8 "(Ljava/lang/String;)Ljava/lang/StringBuilder;"; // #141 at 0x06C1 + Utf8 "toString"; // #142 at 0x06F1 + Utf8 "()Ljava/lang/String;"; // #143 at 0x06FC + Utf8 "intValue"; // #144 at 0x0713 + Utf8 "()I"; // #145 at 0x071E + class #153; // #146 at 0x0724 + NameAndType #154 #158; // #147 at 0x0727 + NameAndType #66 #62; // #148 at 0x072C + NameAndType #65 #62; // #149 at 0x0731 + NameAndType #64 #62; // #150 at 0x0736 + NameAndType #63 #62; // #151 at 0x073B + NameAndType #61 #62; // #152 at 0x0740 + Utf8 "java/lang/invoke/LambdaMetafactory"; // #153 at 0x0745 + Utf8 "metafactory"; // #154 at 0x076A + class #160; // #155 at 0x0778 + Utf8 "Lookup"; // #156 at 0x077B + Utf8 "InnerClasses"; // #157 at 0x0784 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;"; // #158 at 0x0793 + class #161; // #159 at 0x0862 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #160 at 0x0865 + Utf8 "java/lang/invoke/MethodHandles"; // #161 at 0x088D + } // Constant Pool + + 0x0021; // access + #30;// this_cpx + #31;// super_cpx + + [0] { // Interfaces + } // Interfaces + + [0] { // fields + } // fields + + [8] { // methods + { // Member at 0x08BA + 0x0001; // access + #32; // name_cpx + #33; // sig_cpx + [1] { // Attributes + Attr(#34, 47) { // Code at 0x08C2 + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2AB70001B1; + }; + [0] { // Traps + } // end Traps + [2] { // Attributes + Attr(#35, 6) { // LineNumberTable at 0x08D9 + [1] { // LineNumberTable + 0 5; // at 0x08E5 + } + } // end LineNumberTable + ; + Attr(#36, 12) { // LocalVariableTable at 0x08E5 + [1] { // LocalVariableTable + 0 5 37 38 0; // at 0x08F7 + } + } // end LocalVariableTable + } // Attributes + } // end Code + } // Attributes + } // Member + ; + { // Member at 0x08F7 + 0x0009; // access + #39; // name_cpx + #40; // sig_cpx + [1] { // Attributes + Attr(#34, 261) { // Code at 0x08FF + 4; // max_stack + 2; // max_locals + Bytes[147]{ + 0x1007BD0002590304; + 0xB8000353590405B8; + 0x000353590506B800; + 0x0353590607B80003; + 0x53590708B8000353; + 0x59081006B8000353; + 0x5910061007B80003; + 0x53B800044CB20005; + 0x1206B600072BBA00; + 0x080000B80009B200; + 0x05120AB600072BBA; + 0x000B0000B80009B2; + 0x0005120CB600072B; + 0xBA000D0000B80009; + 0xB20005120EB60007; + 0x2BBA000F0000B800; + 0x09B200051210B600; + 0x072BBA00110000B8; + 0x0009B1; + }; + [0] { // Traps + } // end Traps + [3] { // Attributes + Attr(#35, 50) { // LineNumberTable at 0x09A4 + [12] { // LineNumberTable + 0 9; // at 0x09B0 + 61 11; // at 0x09B4 + 69 12; // at 0x09B8 + 78 14; // at 0x09BC + 86 15; // at 0x09C0 + 95 17; // at 0x09C4 + 103 18; // at 0x09C8 + 112 20; // at 0x09CC + 120 21; // at 0x09D0 + 129 23; // at 0x09D4 + 137 24; // at 0x09D8 + 146 26; // at 0x09DC + } + } // end LineNumberTable + ; + Attr(#36, 22) { // LocalVariableTable at 0x09DC + [2] { // LocalVariableTable + 0 147 41 42 0; // at 0x09EE + 61 86 43 44 1; // at 0x09F8 + } + } // end LocalVariableTable + ; + Attr(#45, 12) { // LocalVariableTypeTable at 0x09F8 + [1] { // LocalVariableTypeTable + 61 86 43 46 1; // at 0x0A0A + } + } // end LocalVariableTypeTable + } // Attributes + } // end Code + } // Attributes + } // Member + ; + { // Member at 0x0A0A + 0x0009; // access + #47; // name_cpx + #48; // sig_cpx + [2] { // Attributes + Attr(#34, 224) { // Code at 0x0A12 + 3; // max_stack + 4; // max_locals + Bytes[69]{ + 0x2AB9001201004D2C; + 0xB900130100990033; + 0x2CB900140100C200; + 0x024E2B2DB9001502; + 0x0099001CB20005BB; + 0x001659B700172DB6; + 0x00181219B6001AB6; + 0x001BB60007A7FFCA; + 0xA700044DB1; + }; + [1] { // Traps + 0 64 67 28; // at 0x0A6F + } // end Traps + [4] { // Attributes + Attr(#35, 30) { // LineNumberTable at 0x0A71 + [7] { // LineNumberTable + 0 30; // at 0x0A7D + 26 31; // at 0x0A81 + 36 32; // at 0x0A85 + 61 34; // at 0x0A89 + 64 38; // at 0x0A8D + 67 37; // at 0x0A91 + 68 39; // at 0x0A95 + } + } // end LineNumberTable + ; + Attr(#36, 42) { // LocalVariableTable at 0x0A95 + [4] { // LocalVariableTable + 26 35 49 50 3; // at 0x0AA7 + 68 0 51 52 2; // at 0x0AB1 + 0 69 43 44 0; // at 0x0ABB + 0 69 53 54 1; // at 0x0AC5 + } + } // end LocalVariableTable + ; + Attr(#45, 22) { // LocalVariableTypeTable at 0x0AC5 + [2] { // LocalVariableTypeTable + 0 69 43 46 0; // at 0x0AD7 + 0 69 53 55 1; // at 0x0AE1 + } + } // end LocalVariableTypeTable + ; + Attr(#56, 17) { // StackMapTable at 0x0AE1 + [5] { // + 252b, 7, [1]z{7b,57}; // append_frame 1 + 53b; // same_frame + 250b, 2; // chop_frame 1 + 66b, [1]z{7b,58}; // same_locals_1_stack_item_frame + 0b; // same_frame + } + } // end StackMapTable + } // Attributes + } // end Code + ; + Attr(#59, 2) { // Signature at 0x0AF8 + #60; + } // end Signature + } // Attributes + } // Member + ; + { // Member at 0x0B00 + 0x100A; // access + #61; // name_cpx + #62; // sig_cpx + [1] { // Attributes + Attr(#34, 67) { // Code at 0x0B08 + 2; // max_stack + 1; // max_locals + Bytes[14]{ + 0x2AB6001D08A40007; + 0x04A7000403AC; + }; + [0] { // Traps + } // end Traps + [3] { // Attributes + Attr(#35, 6) { // LineNumberTable at 0x0B28 + [1] { // LineNumberTable + 0 24; // at 0x0B34 + } + } // end LineNumberTable + ; + Attr(#36, 12) { // LocalVariableTable at 0x0B34 + [1] { // LocalVariableTable + 0 14 49 50 0; // at 0x0B46 + } + } // end LocalVariableTable + ; + Attr(#56, 5) { // StackMapTable at 0x0B46 + [2] { // + 12b; // same_frame + 64b, [1]z{1b}; // same_locals_1_stack_item_frame + } + } // end StackMapTable + } // Attributes + } // end Code + } // Attributes + } // Member + ; + { // Member at 0x0B51 + 0x100A; // access + #63; // name_cpx + #62; // sig_cpx + [1] { // Attributes + Attr(#34, 69) { // Code at 0x0B59 + 2; // max_stack + 1; // max_locals + Bytes[16]{ + 0x2AB6001D057004A0; + 0x000704A7000403AC; + }; + [0] { // Traps + } // end Traps + [3] { // Attributes + Attr(#35, 6) { // LineNumberTable at 0x0B7B + [1] { // LineNumberTable + 0 21; // at 0x0B87 + } + } // end LineNumberTable + ; + Attr(#36, 12) { // LocalVariableTable at 0x0B87 + [1] { // LocalVariableTable + 0 16 49 50 0; // at 0x0B99 + } + } // end LocalVariableTable + ; + Attr(#56, 5) { // StackMapTable at 0x0B99 + [2] { // + 14b; // same_frame + 64b, [1]z{1b}; // same_locals_1_stack_item_frame + } + } // end StackMapTable + } // Attributes + } // end Code + } // Attributes + } // Member + ; + { // Member at 0x0BA4 + 0x100A; // access + #64; // name_cpx + #62; // sig_cpx + [1] { // Attributes + Attr(#34, 68) { // Code at 0x0BAC + 2; // max_stack + 1; // max_locals + Bytes[15]{ + 0x2AB6001D05709A00; + 0x0704A7000403AC; + }; + [0] { // Traps + } // end Traps + [3] { // Attributes + Attr(#35, 6) { // LineNumberTable at 0x0BCD + [1] { // LineNumberTable + 0 18; // at 0x0BD9 + } + } // end LineNumberTable + ; + Attr(#36, 12) { // LocalVariableTable at 0x0BD9 + [1] { // LocalVariableTable + 0 15 49 50 0; // at 0x0BEB + } + } // end LocalVariableTable + ; + Attr(#56, 5) { // StackMapTable at 0x0BEB + [2] { // + 13b; // same_frame + 64b, [1]z{1b}; // same_locals_1_stack_item_frame + } + } // end StackMapTable + } // Attributes + } // end Code + } // Attributes + } // Member + ; + { // Member at 0x0BF6 + 0x100A; // access + #65; // name_cpx + #62; // sig_cpx + [1] { // Attributes + Attr(#34, 44) { // Code at 0x0BFE + 1; // max_stack + 1; // max_locals + Bytes[2]{ + 0x03AC; + }; + [0] { // Traps + } // end Traps + [2] { // Attributes + Attr(#35, 6) { // LineNumberTable at 0x0C12 + [1] { // LineNumberTable + 0 15; // at 0x0C1E + } + } // end LineNumberTable + ; + Attr(#36, 12) { // LocalVariableTable at 0x0C1E + [1] { // LocalVariableTable + 0 2 49 50 0; // at 0x0C30 + } + } // end LocalVariableTable + } // Attributes + } // end Code + } // Attributes + } // Member + ; + { // Member at 0x0C30 + 0x100A; // access + #66; // name_cpx + #62; // sig_cpx + [1] { // Attributes + Attr(#34, 44) { // Code at 0x0C38 + 1; // max_stack + 1; // max_locals + Bytes[2]{ + 0x04AC; + }; + [0] { // Traps + } // end Traps + [2] { // Attributes + Attr(#35, 6) { // LineNumberTable at 0x0C4C + [1] { // LineNumberTable + 0 12; // at 0x0C58 + } + } // end LineNumberTable + ; + Attr(#36, 12) { // LocalVariableTable at 0x0C58 + [1] { // LocalVariableTable + 0 2 49 50 0; // at 0x0C6A + } + } // end LocalVariableTable + } // Attributes + } // end Code + } // Attributes + } // Member + } // methods + + [3] { // Attributes + Attr(#67, 2) { // SourceFile at 0x0C6C + #68; + } // end SourceFile + ; + Attr(#157, 10) { // InnerClasses at 0x0C74 + [1] { // InnerClasses + #155 #159 #156 25; // at 0x0C84 + } + } // end InnerClasses + ; + Attr(#79, 52) { // BootstrapMethods at 0x0C84 + [5] { // bootstrap_methods + { // bootstrap_method + #80; // bootstrap_method_ref + [3] { // bootstrap_arguments + #81; // at 0x0C92 + #82; // at 0x0C94 + #83; // at 0x0C96 + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #80; // bootstrap_method_ref + [3] { // bootstrap_arguments + #81; // at 0x0C9C + #87; // at 0x0C9E + #83; // at 0x0CA0 + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #80; // bootstrap_method_ref + [3] { // bootstrap_arguments + #81; // at 0x0CA6 + #89; // at 0x0CA8 + #83; // at 0x0CAA + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #80; // bootstrap_method_ref + [3] { // bootstrap_arguments + #81; // at 0x0CB0 + #91; // at 0x0CB2 + #83; // at 0x0CB4 + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #80; // bootstrap_method_ref + [1] { // bootstrap_arguments + #81; // at 0x0CBA + } // bootstrap_arguments + } // bootstrap_method + } +// ======== attribute array started at 0x0C84 has 4 bytes more: + 0x005D0053; + } // end BootstrapMethods + } // Attributes +} // end class LambdaMath diff -r 0809c9a4d36e -r 3d9b5fbd157c hotspot/test/runtime/classFileParserBug/test.jar Binary file hotspot/test/runtime/classFileParserBug/test.jar has changed