From e9f0b9af4a914228ab4bb70d779649010264763b Mon Sep 17 00:00:00 2001 From: Jungwoo Ha Date: Wed, 16 Oct 2013 15:14:37 -0700 Subject: [PATCH 001/110] 8024954: CMS: CMSClassUnloadingMaxInterval is not implemented correctly. This change is also part of the fix for 8024483 Reviewed-by: mgerdin, brutisso, tschatzl --- .../concurrentMarkSweepGeneration.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index bf4ac21e346..97437bfafe2 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -594,9 +594,9 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen, _verification_mark_bm(0, Mutex::leaf + 1, "CMS_verification_mark_bm_lock"), _completed_initialization(false), _collector_policy(cp), - _should_unload_classes(false), + _should_unload_classes(CMSClassUnloadingEnabled), _concurrent_cycles_since_last_unload(0), - _roots_scanning_options(0), + _roots_scanning_options(SharedHeap::SO_None), _inter_sweep_estimate(CMS_SweepWeight, CMS_SweepPadding), _intra_sweep_estimate(CMS_SweepWeight, CMS_SweepPadding), _gc_tracer_cm(new (ResourceObj::C_HEAP, mtGC) CMSTracer()), @@ -788,14 +788,6 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen, && _survivor_chunk_index == 0), "Error"); - // Choose what strong roots should be scanned depending on verification options - if (!CMSClassUnloadingEnabled) { - // If class unloading is disabled we want to include all classes into the root set. - add_root_scanning_option(SharedHeap::SO_AllClasses); - } else { - add_root_scanning_option(SharedHeap::SO_SystemClasses); - } - NOT_PRODUCT(_overflow_counter = CMSMarkStackOverflowInterval;) _gc_counters = new CollectorCounters("CMS", 1); _completed_initialization = true; @@ -3310,7 +3302,10 @@ void CMSCollector::setup_cms_unloading_and_verification_state() { || VerifyBeforeExit; const int rso = SharedHeap::SO_Strings | SharedHeap::SO_CodeCache; + // We set the proper root for this CMS cycle here. if (should_unload_classes()) { // Should unload classes this cycle + remove_root_scanning_option(SharedHeap::SO_AllClasses); + add_root_scanning_option(SharedHeap::SO_SystemClasses); remove_root_scanning_option(rso); // Shrink the root set appropriately set_verifying(should_verify); // Set verification state for this cycle return; // Nothing else needs to be done at this time @@ -3318,6 +3313,9 @@ void CMSCollector::setup_cms_unloading_and_verification_state() { // Not unloading classes this cycle assert(!should_unload_classes(), "Inconsitency!"); + remove_root_scanning_option(SharedHeap::SO_SystemClasses); + add_root_scanning_option(SharedHeap::SO_AllClasses); + if ((!verifying() || unloaded_classes_last_cycle()) && should_verify) { // Include symbols, strings and code cache elements to prevent their resurrection. add_root_scanning_option(rso); From 1123a5596ce984f13e4385cffbe246cd12fa67fa Mon Sep 17 00:00:00 2001 From: Jesper Wilhelmsson Date: Mon, 21 Oct 2013 18:51:37 +0200 Subject: [PATCH 002/110] 8026851: Remove unnecessary code in GenRemSet Removed the GenRemSet::rem_set_name() since we only have one remset. Reviewed-by: stefank, mgerdin, tschatzl --- hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp | 2 +- hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp | 2 -- hotspot/src/share/vm/memory/collectorPolicy.cpp | 1 - hotspot/src/share/vm/memory/collectorPolicy.hpp | 2 -- 4 files changed, 1 insertion(+), 6 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp index 92eee2e8eb9..ad1dce1750b 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp @@ -320,7 +320,7 @@ G1CollectorPolicy::G1CollectorPolicy() : void G1CollectorPolicy::initialize_flags() { _min_alignment = HeapRegion::GrainBytes; - size_t card_table_alignment = GenRemSet::max_alignment_constraint(rem_set_name()); + size_t card_table_alignment = GenRemSet::max_alignment_constraint(GenRemSet::CardTable); size_t page_size = UseLargePages ? os::large_page_size() : os::vm_page_size(); _max_alignment = MAX3(card_table_alignment, _min_alignment, page_size); if (SurvivorRatio < 1) { diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp index a497f2fa3b6..d5bdc08698f 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp @@ -665,8 +665,6 @@ public: BarrierSet::Name barrier_set_name() { return BarrierSet::G1SATBCTLogging; } - GenRemSet::Name rem_set_name() { return GenRemSet::CardTable; } - bool need_to_start_conc_mark(const char* source, size_t alloc_word_size = 0); // Record the start and end of an evacuation pause. diff --git a/hotspot/src/share/vm/memory/collectorPolicy.cpp b/hotspot/src/share/vm/memory/collectorPolicy.cpp index a3c466327ef..d6c4afe2f01 100644 --- a/hotspot/src/share/vm/memory/collectorPolicy.cpp +++ b/hotspot/src/share/vm/memory/collectorPolicy.cpp @@ -105,7 +105,6 @@ bool CollectorPolicy::use_should_clear_all_soft_refs(bool v) { GenRemSet* CollectorPolicy::create_rem_set(MemRegion whole_heap, int max_covered_regions) { - assert(rem_set_name() == GenRemSet::CardTable, "unrecognized GenRemSet::Name"); return new CardTableRS(whole_heap, max_covered_regions); } diff --git a/hotspot/src/share/vm/memory/collectorPolicy.hpp b/hotspot/src/share/vm/memory/collectorPolicy.hpp index 42976b34563..a86f45c54d7 100644 --- a/hotspot/src/share/vm/memory/collectorPolicy.hpp +++ b/hotspot/src/share/vm/memory/collectorPolicy.hpp @@ -151,7 +151,6 @@ class CollectorPolicy : public CHeapObj { virtual BarrierSet::Name barrier_set_name() = 0; - virtual GenRemSet::Name rem_set_name() = 0; // Create the remembered set (to cover the given reserved region, // allowing breaking up into at most "max_covered_regions"). @@ -303,7 +302,6 @@ class TwoGenerationCollectorPolicy : public GenCollectorPolicy { int number_of_generations() { return 2; } BarrierSet::Name barrier_set_name() { return BarrierSet::CardTableModRef; } - GenRemSet::Name rem_set_name() { return GenRemSet::CardTable; } virtual CollectorPolicy::Name kind() { return CollectorPolicy::TwoGenerationCollectorPolicyKind; From 5976b6915a7936491afed94515031cded77e83c2 Mon Sep 17 00:00:00 2001 From: Jesper Wilhelmsson Date: Mon, 21 Oct 2013 18:52:13 +0200 Subject: [PATCH 003/110] 8026852: Use restricted_align_down in collector policy code Moved restricted_align_down to globalDefinitions and renamed it align_size_down_bounded Reviewed-by: stefank, mgerdin, tschatzl --- hotspot/src/share/vm/memory/collectorPolicy.cpp | 14 +++----------- hotspot/src/share/vm/memory/metaspace.cpp | 15 +++++---------- .../src/share/vm/utilities/globalDefinitions.hpp | 7 +++++++ 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/hotspot/src/share/vm/memory/collectorPolicy.cpp b/hotspot/src/share/vm/memory/collectorPolicy.cpp index d6c4afe2f01..585c7d06cab 100644 --- a/hotspot/src/share/vm/memory/collectorPolicy.cpp +++ b/hotspot/src/share/vm/memory/collectorPolicy.cpp @@ -146,11 +146,7 @@ size_t CollectorPolicy::compute_max_alignment() { // GenCollectorPolicy methods. size_t GenCollectorPolicy::scale_by_NewRatio_aligned(size_t base_size) { - size_t x = base_size / (NewRatio+1); - size_t new_gen_size = x > _min_alignment ? - align_size_down(x, _min_alignment) : - _min_alignment; - return new_gen_size; + return align_size_down_bounded(base_size / (NewRatio + 1), _min_alignment); } size_t GenCollectorPolicy::bound_minus_alignment(size_t desired_size, @@ -410,15 +406,11 @@ bool TwoGenerationCollectorPolicy::adjust_gen0_sizes(size_t* gen0_size_ptr, if ((heap_size < (*gen0_size_ptr + min_gen1_size)) && (heap_size >= min_gen1_size + _min_alignment)) { // Adjust gen0 down to accommodate min_gen1_size - *gen0_size_ptr = heap_size - min_gen1_size; - *gen0_size_ptr = - MAX2((uintx)align_size_down(*gen0_size_ptr, _min_alignment), _min_alignment); + *gen0_size_ptr = align_size_down_bounded(heap_size - min_gen1_size, _min_alignment); assert(*gen0_size_ptr > 0, "Min gen0 is too large"); result = true; } else { - *gen1_size_ptr = heap_size - *gen0_size_ptr; - *gen1_size_ptr = - MAX2((uintx)align_size_down(*gen1_size_ptr, _min_alignment), _min_alignment); + *gen1_size_ptr = align_size_down_bounded(heap_size - *gen0_size_ptr, _min_alignment); } } return result; diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index 1877967408d..7ab68dd1ea7 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -2965,11 +2965,6 @@ void Metaspace::initialize_class_space(ReservedSpace rs) { #endif -// Align down. If the aligning result in 0, return 'alignment'. -static size_t restricted_align_down(size_t size, size_t alignment) { - return MAX2(alignment, align_size_down_(size, alignment)); -} - void Metaspace::ergo_initialize() { if (DumpSharedSpaces) { // Using large pages when dumping the shared archive is currently not implemented. @@ -2992,13 +2987,13 @@ void Metaspace::ergo_initialize() { // Ideally, we would be able to set the default value of MaxMetaspaceSize in // globals.hpp to the aligned value, but this is not possible, since the // alignment depends on other flags being parsed. - MaxMetaspaceSize = restricted_align_down(MaxMetaspaceSize, _reserve_alignment); + MaxMetaspaceSize = align_size_down_bounded(MaxMetaspaceSize, _reserve_alignment); if (MetaspaceSize > MaxMetaspaceSize) { MetaspaceSize = MaxMetaspaceSize; } - MetaspaceSize = restricted_align_down(MetaspaceSize, _commit_alignment); + MetaspaceSize = align_size_down_bounded(MetaspaceSize, _commit_alignment); assert(MetaspaceSize <= MaxMetaspaceSize, "MetaspaceSize should be limited by MaxMetaspaceSize"); @@ -3006,10 +3001,10 @@ void Metaspace::ergo_initialize() { vm_exit_during_initialization("Too small initial Metaspace size"); } - MinMetaspaceExpansion = restricted_align_down(MinMetaspaceExpansion, _commit_alignment); - MaxMetaspaceExpansion = restricted_align_down(MaxMetaspaceExpansion, _commit_alignment); + MinMetaspaceExpansion = align_size_down_bounded(MinMetaspaceExpansion, _commit_alignment); + MaxMetaspaceExpansion = align_size_down_bounded(MaxMetaspaceExpansion, _commit_alignment); - CompressedClassSpaceSize = restricted_align_down(CompressedClassSpaceSize, _reserve_alignment); + CompressedClassSpaceSize = align_size_down_bounded(CompressedClassSpaceSize, _reserve_alignment); set_class_metaspace_size(CompressedClassSpaceSize); } diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp index 06a32dc9037..c558574ebbd 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp @@ -458,6 +458,13 @@ inline void* align_pointer_up(const void* addr, size_t size) { return (void*) align_size_up_((uintptr_t)addr, size); } +// Align down with a lower bound. If the aligning results in 0, return 'alignment'. + +inline size_t align_size_down_bounded(size_t size, size_t alignment) { + size_t aligned_size = align_size_down_(size, alignment); + return aligned_size > 0 ? aligned_size : alignment; +} + // Clamp an address to be within a specific page // 1. If addr is on the page it is returned as is // 2. If addr is above the page_address the start of the *next* page will be returned From 9705a6e3f94aee2f8862d84d71df4a94b9c3d3f8 Mon Sep 17 00:00:00 2001 From: Jesper Wilhelmsson Date: Mon, 21 Oct 2013 18:56:20 +0200 Subject: [PATCH 004/110] 8026853: Prepare GC code for collector policy regression fix Cleanup related to the NewSize and MaxNewSize bugs Reviewed-by: tschatzl, jcoomes, ehelin --- .../g1/g1CollectorPolicy.hpp | 1 - .../vm/gc_implementation/g1/g1RemSet.cpp | 5 ---- .../parallelScavenge/asPSOldGen.cpp | 3 -- .../parallelScavenge/asPSYoungGen.cpp | 3 -- .../parallelScavenge/parallelScavengeHeap.hpp | 28 +++++++++---------- .../parallelScavenge/psAdaptiveSizePolicy.cpp | 3 +- .../src/share/vm/memory/collectorPolicy.cpp | 15 +++++----- .../src/share/vm/memory/collectorPolicy.hpp | 17 +++++++---- .../src/share/vm/memory/genCollectedHeap.cpp | 6 ---- .../src/share/vm/memory/genCollectedHeap.hpp | 4 --- hotspot/src/share/vm/memory/universe.cpp | 2 +- hotspot/src/share/vm/runtime/arguments.cpp | 7 +++-- 12 files changed, 39 insertions(+), 55 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp index d5bdc08698f..037876e07e7 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp @@ -217,7 +217,6 @@ private: return _during_marking; } -private: enum PredictionConstants { TruncatedSeqLength = 10 }; diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp index 0ed37e6c5a5..a11be17ef53 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp @@ -377,11 +377,6 @@ void G1RemSet::prepare_for_oops_into_collection_set_do() { DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); dcqs.concatenate_logs(); - if (G1CollectedHeap::use_parallel_gc_threads()) { - // Don't set the number of workers here. It will be set - // when the task is run - // _seq_task->set_n_termination((int)n_workers()); - } guarantee( _cards_scanned == NULL, "invariant" ); _cards_scanned = NEW_C_HEAP_ARRAY(size_t, n_workers(), mtGC); for (uint i = 0; i < n_workers(); ++i) { diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp index 39f5835ffe5..6f7026e5a0c 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp @@ -54,7 +54,6 @@ ASPSOldGen::ASPSOldGen(size_t initial_size, int level) : PSOldGen(initial_size, min_size, size_limit, gen_name, level), _gen_size_limit(size_limit) - {} ASPSOldGen::ASPSOldGen(PSVirtualSpace* vs, @@ -65,13 +64,11 @@ ASPSOldGen::ASPSOldGen(PSVirtualSpace* vs, int level) : PSOldGen(initial_size, min_size, size_limit, gen_name, level), _gen_size_limit(size_limit) - { _virtual_space = vs; } void ASPSOldGen::initialize_work(const char* perf_data_name, int level) { - PSOldGen::initialize_work(perf_data_name, level); // The old gen can grow to gen_size_limit(). _reserve reflects only diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp index 73b63043b71..a7b2eb28ef2 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp @@ -70,7 +70,6 @@ void ASPSYoungGen::initialize(ReservedSpace rs, size_t alignment) { } size_t ASPSYoungGen::available_for_expansion() { - size_t current_committed_size = virtual_space()->committed_size(); assert((gen_size_limit() >= current_committed_size), "generation size limit is wrong"); @@ -85,7 +84,6 @@ size_t ASPSYoungGen::available_for_expansion() { // Future implementations could check the survivors and if to_space is in the // right place (below from_space), take a chunk from to_space. size_t ASPSYoungGen::available_for_contraction() { - size_t uncommitted_bytes = virtual_space()->uncommitted_size(); if (uncommitted_bytes != 0) { return uncommitted_bytes; @@ -121,7 +119,6 @@ size_t ASPSYoungGen::available_for_contraction() { gclog_or_tty->print_cr(" gen_avail %d K", gen_avail/K); } return result_aligned; - } return 0; diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp index 4e458efa903..2ef42c86660 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp @@ -35,7 +35,6 @@ #include "utilities/ostream.hpp" class AdjoiningGenerations; -class CollectorPolicy; class GCHeapSummary; class GCTaskManager; class GenerationSizer; @@ -50,8 +49,8 @@ class ParallelScavengeHeap : public CollectedHeap { static PSOldGen* _old_gen; // Sizing policy for entire heap - static PSAdaptiveSizePolicy* _size_policy; - static PSGCAdaptivePolicyCounters* _gc_policy_counters; + static PSAdaptiveSizePolicy* _size_policy; + static PSGCAdaptivePolicyCounters* _gc_policy_counters; static ParallelScavengeHeap* _psh; @@ -67,7 +66,8 @@ class ParallelScavengeHeap : public CollectedHeap { AdjoiningGenerations* _gens; unsigned int _death_march_count; - static GCTaskManager* _gc_task_manager; // The task manager. + // The task manager + static GCTaskManager* _gc_task_manager; void trace_heap(GCWhen::Type when, GCTracer* tracer); @@ -80,15 +80,14 @@ class ParallelScavengeHeap : public CollectedHeap { HeapWord* mem_allocate_old_gen(size_t size); public: - ParallelScavengeHeap() : CollectedHeap() { - _death_march_count = 0; + ParallelScavengeHeap() : CollectedHeap(), _death_march_count(0) { set_alignment(_young_gen_alignment, intra_heap_alignment()); set_alignment(_old_gen_alignment, intra_heap_alignment()); } // Return the (conservative) maximum heap alignment static size_t conservative_max_heap_alignment() { - return intra_heap_alignment(); + return GenCollectorPolicy::intra_heap_alignment(); } // For use by VM operations @@ -103,8 +102,8 @@ class ParallelScavengeHeap : public CollectedHeap { virtual CollectorPolicy* collector_policy() const { return (CollectorPolicy*) _collector_policy; } - static PSYoungGen* young_gen() { return _young_gen; } - static PSOldGen* old_gen() { return _old_gen; } + static PSYoungGen* young_gen() { return _young_gen; } + static PSOldGen* old_gen() { return _old_gen; } virtual PSAdaptiveSizePolicy* size_policy() { return _size_policy; } @@ -127,7 +126,7 @@ class ParallelScavengeHeap : public CollectedHeap { // The alignment used for eden and survivors within the young gen // and for boundary between young gen and old gen. - static size_t intra_heap_alignment() { return 64 * K * HeapWordSize; } + size_t intra_heap_alignment() { return GenCollectorPolicy::intra_heap_alignment(); } size_t capacity() const; size_t used() const; @@ -157,16 +156,15 @@ class ParallelScavengeHeap : public CollectedHeap { virtual bool is_in_partial_collection(const void *p); #endif - bool is_in_young(oop p); // reserved part - bool is_in_old(oop p); // reserved part + bool is_in_young(oop p); // reserved part + bool is_in_old(oop p); // reserved part // Memory allocation. "gc_time_limit_was_exceeded" will // be set to true if the adaptive size policy determine that // an excessive amount of time is being spent doing collections // and caused a NULL to be returned. If a NULL is not returned, // "gc_time_limit_was_exceeded" has an undefined meaning. - HeapWord* mem_allocate(size_t size, - bool* gc_overhead_limit_was_exceeded); + HeapWord* mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded); // Allocation attempt(s) during a safepoint. It should never be called // to allocate a new TLAB as this allocation might be satisfied out @@ -257,7 +255,7 @@ class ParallelScavengeHeap : public CollectedHeap { // Call these in sequential code around the processing of strong roots. class ParStrongRootsScope : public MarkingCodeBlobClosure::MarkScope { - public: + public: ParStrongRootsScope(); ~ParStrongRootsScope(); }; diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp index 8d411811b3c..1ffdf64e2aa 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp @@ -46,8 +46,7 @@ PSAdaptiveSizePolicy::PSAdaptiveSizePolicy(size_t init_eden_size, init_survivor_size, gc_pause_goal_sec, gc_cost_ratio), - _collection_cost_margin_fraction(AdaptiveSizePolicyCollectionCostMargin/ - 100.0), + _collection_cost_margin_fraction(AdaptiveSizePolicyCollectionCostMargin / 100.0), _intra_generation_alignment(intra_generation_alignment), _live_at_last_full_gc(init_promo_size), _gc_minor_pause_goal_sec(gc_minor_pause_goal_sec), diff --git a/hotspot/src/share/vm/memory/collectorPolicy.cpp b/hotspot/src/share/vm/memory/collectorPolicy.cpp index 585c7d06cab..8cd11de6ef2 100644 --- a/hotspot/src/share/vm/memory/collectorPolicy.cpp +++ b/hotspot/src/share/vm/memory/collectorPolicy.cpp @@ -160,7 +160,7 @@ size_t GenCollectorPolicy::bound_minus_alignment(size_t desired_size, void GenCollectorPolicy::initialize_size_policy(size_t init_eden_size, size_t init_promo_size, size_t init_survivor_size) { - const double max_gc_pause_sec = ((double) MaxGCPauseMillis)/1000.0; + const double max_gc_pause_sec = ((double) MaxGCPauseMillis) / 1000.0; _size_policy = new AdaptiveSizePolicy(init_eden_size, init_promo_size, init_survivor_size, @@ -192,6 +192,7 @@ void GenCollectorPolicy::initialize_flags() { // make sure there room for eden and two survivor spaces vm_exit_during_initialization("Too small new size specified"); } + if (SurvivorRatio < 1 || NewRatio < 1) { vm_exit_during_initialization("Invalid young gen ratio specified"); } @@ -465,7 +466,7 @@ void TwoGenerationCollectorPolicy::initialize_size_info() { "generation sizes: using minimum heap = " SIZE_FORMAT, _min_heap_byte_size); } - if ((OldSize > _max_gen1_size)) { + if (OldSize > _max_gen1_size) { warning("Inconsistency between maximum heap size and maximum " "generation sizes: using maximum heap = " SIZE_FORMAT " -XX:OldSize flag is being ignored", @@ -596,9 +597,7 @@ HeapWord* GenCollectorPolicy::mem_allocate_work(size_t size, gc_count_before = Universe::heap()->total_collections(); } - VM_GenCollectForAllocation op(size, - is_tlab, - gc_count_before); + VM_GenCollectForAllocation op(size, is_tlab, gc_count_before); VMThread::execute(&op); if (op.prologue_succeeded()) { result = op.result(); @@ -833,8 +832,9 @@ MarkSweepPolicy::MarkSweepPolicy() { void MarkSweepPolicy::initialize_generations() { _generations = NEW_C_HEAP_ARRAY3(GenerationSpecPtr, number_of_generations(), mtGC, 0, AllocFailStrategy::RETURN_NULL); - if (_generations == NULL) + if (_generations == NULL) { vm_exit_during_initialization("Unable to allocate gen spec"); + } if (UseParNewGC) { _generations[0] = new GenerationSpec(Generation::ParNew, _initial_gen0_size, _max_gen0_size); @@ -843,8 +843,9 @@ void MarkSweepPolicy::initialize_generations() { } _generations[1] = new GenerationSpec(Generation::MarkSweepCompact, _initial_gen1_size, _max_gen1_size); - if (_generations[0] == NULL || _generations[1] == NULL) + if (_generations[0] == NULL || _generations[1] == NULL) { vm_exit_during_initialization("Unable to allocate gen spec"); + } } void MarkSweepPolicy::initialize_gc_policy_counters() { diff --git a/hotspot/src/share/vm/memory/collectorPolicy.hpp b/hotspot/src/share/vm/memory/collectorPolicy.hpp index a86f45c54d7..bbfccdd644c 100644 --- a/hotspot/src/share/vm/memory/collectorPolicy.hpp +++ b/hotspot/src/share/vm/memory/collectorPolicy.hpp @@ -79,6 +79,7 @@ class CollectorPolicy : public CHeapObj { // Set to true when policy wants soft refs cleared. // Reset to false by gc after it clears all soft refs. bool _should_clear_all_soft_refs; + // Set to true by the GC if the just-completed gc cleared all // softrefs. This is set to true whenever a gc clears all softrefs, and // set to false each time gc returns to the mutator. For example, in the @@ -101,8 +102,8 @@ class CollectorPolicy : public CHeapObj { // Return maximum heap alignment that may be imposed by the policy static size_t compute_max_alignment(); - size_t min_alignment() { return _min_alignment; } - size_t max_alignment() { return _max_alignment; } + size_t min_alignment() { return _min_alignment; } + size_t max_alignment() { return _max_alignment; } size_t initial_heap_byte_size() { return _initial_heap_byte_size; } size_t max_heap_byte_size() { return _max_heap_byte_size; } @@ -248,7 +249,7 @@ class GenCollectorPolicy : public CollectorPolicy { virtual int number_of_generations() = 0; - virtual GenerationSpec **generations() { + virtual GenerationSpec **generations() { assert(_generations != NULL, "Sanity check"); return _generations; } @@ -273,6 +274,12 @@ class GenCollectorPolicy : public CollectorPolicy { virtual void initialize_size_policy(size_t init_eden_size, size_t init_promo_size, size_t init_survivor_size); + + // The alignment used for eden and survivors within the young gen + // and for boundary between young gen and old gen. + static size_t intra_heap_alignment() { + return 64 * K * HeapWordSize; + } }; // All of hotspot's current collectors are subtypes of this @@ -300,8 +307,8 @@ class TwoGenerationCollectorPolicy : public GenCollectorPolicy { // Inherited methods TwoGenerationCollectorPolicy* as_two_generation_policy() { return this; } - int number_of_generations() { return 2; } - BarrierSet::Name barrier_set_name() { return BarrierSet::CardTableModRef; } + int number_of_generations() { return 2; } + BarrierSet::Name barrier_set_name() { return BarrierSet::CardTableModRef; } virtual CollectorPolicy::Name kind() { return CollectorPolicy::TwoGenerationCollectorPolicyKind; diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.cpp b/hotspot/src/share/vm/memory/genCollectedHeap.cpp index 3a5ab210c83..2b84542ef48 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp @@ -1053,12 +1053,6 @@ void GenCollectedHeap::save_marks() { } } -void GenCollectedHeap::compute_new_generation_sizes(int collectedGen) { - for (int i = 0; i <= collectedGen; i++) { - _gens[i]->compute_new_size(); - } -} - GenCollectedHeap* GenCollectedHeap::heap() { assert(_gch != NULL, "Uninitialized access to GenCollectedHeap::heap()"); assert(_gch->kind() == CollectedHeap::GenCollectedHeap, "not a generational heap"); diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.hpp b/hotspot/src/share/vm/memory/genCollectedHeap.hpp index 8f814132a78..5cd8a71280a 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.hpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.hpp @@ -86,10 +86,6 @@ public: NOT_PRODUCT(static size_t _skip_header_HeapWords;) protected: - // Directs each generation up to and including "collectedGen" to recompute - // its desired size. - void compute_new_generation_sizes(int collectedGen); - // Helper functions for allocation HeapWord* attempt_allocation(size_t size, bool is_tlab, diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index 1f632ae478f..18c9733076c 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -1021,7 +1021,7 @@ bool universe_post_init() { Universe::_virtual_machine_error_instance = InstanceKlass::cast(k)->allocate_instance(CHECK_false); - Universe::_vm_exception = InstanceKlass::cast(k)->allocate_instance(CHECK_false); + Universe::_vm_exception = InstanceKlass::cast(k)->allocate_instance(CHECK_false); if (!DumpSharedSpaces) { // These are the only Java fields that are currently set during shared space dumping. diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 8060dae0377..1e82e5bdca8 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -1408,7 +1408,7 @@ uintx Arguments::max_heap_for_compressed_oops() { // NULL page is located before the heap, we pad the NULL page to the conservative // maximum alignment that the GC may ever impose upon the heap. size_t displacement_due_to_null_page = align_size_up_(os::vm_page_size(), - Arguments::conservative_max_heap_alignment()); + _conservative_max_heap_alignment); LP64_ONLY(return OopEncodingHeapMax - displacement_due_to_null_page); NOT_LP64(ShouldNotReachHere(); return 0); @@ -2681,9 +2681,10 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, describe_range_error(errcode); return JNI_EINVAL; } - FLAG_SET_CMDLINE(uintx, InitialHeapSize, (uintx)long_initial_heap_size); + set_min_heap_size((uintx)long_initial_heap_size); // Currently the minimum size and the initial heap sizes are the same. - set_min_heap_size(InitialHeapSize); + // Can be overridden with -XX:InitialHeapSize. + FLAG_SET_CMDLINE(uintx, InitialHeapSize, (uintx)long_initial_heap_size); // -Xmx } else if (match_option(option, "-Xmx", &tail) || match_option(option, "-XX:MaxHeapSize=", &tail)) { julong long_max_heap_size = 0; From 8fe7a15c08336c8428c4470605da77c2fa4bff43 Mon Sep 17 00:00:00 2001 From: Staffan Larsen Date: Fri, 1 Nov 2013 10:08:10 +0100 Subject: [PATCH 005/110] 8027692: Remove java/lang/management/MemoryMXBean/LowMemoryTest2.sh from ProblemList.txt Reviewed-by: stefank, alanb --- jdk/test/ProblemList.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index ea99549a0f7..202f703b713 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -128,9 +128,6 @@ java/lang/management/ThreadMXBean/ThreadStateTest.java generic-all # 7067973 java/lang/management/MemoryMXBean/CollectionUsageThreshold.java generic-all -# 7196801 -java/lang/management/MemoryMXBean/LowMemoryTest2.sh generic-all - # 8021230 java/lang/ThreadLocal/ThreadLocalSupplierTest.java generic-all From fdbeb8e0fb4a958fb8a95e70466e51a7acfc7375 Mon Sep 17 00:00:00 2001 From: Staffan Larsen Date: Fri, 1 Nov 2013 15:10:10 +0100 Subject: [PATCH 006/110] 8027705: com/sun/jdi/JdbMethodExitTest.sh fails when a background thread is generating events Reviewed-by: dcubed --- jdk/test/com/sun/jdi/JdbMethodExitTest.sh | 20 +++++---- jdk/test/com/sun/jdi/ShellScaffold.sh | 52 +++++++++++++++++++++++ 2 files changed, 64 insertions(+), 8 deletions(-) diff --git a/jdk/test/com/sun/jdi/JdbMethodExitTest.sh b/jdk/test/com/sun/jdi/JdbMethodExitTest.sh index 52c0fe7becf..ab00816ca6e 100644 --- a/jdk/test/com/sun/jdi/JdbMethodExitTest.sh +++ b/jdk/test/com/sun/jdi/JdbMethodExitTest.sh @@ -156,7 +156,7 @@ class $classname { // a resume. $classname xx = new $classname(); - + System.out.println("threadid="+Thread.currentThread().getId()); bkpt(); // test all possible return types @@ -197,6 +197,8 @@ dojdbCmds() # test all possible return types runToBkpt @1 + debuggeeMatchRegexp "s/threadid=\(.*\)/\1/g" + threadid=$? cmd untrace cmd trace methods @@ -226,7 +228,7 @@ dojdbCmds() # trace exit of methods with all the return values # (but just check a couple of them) - cmd trace go exits + cmd trace go method exits $threadid cmd cont jdbFailIfNotPresent "instance of JdbMethodExitTest" jdbFailIfNotPresent "return value = 8" @@ -235,7 +237,7 @@ dojdbCmds() cmd step up - cmd trace methods + cmd trace methods $threadid cmd cont jdbFailIfNotPresent "Method entered:" cmd cont @@ -243,7 +245,9 @@ dojdbCmds() cmd step up - cmd trace go methods + cmd trace go methods $threadid + cmd cont + cmd cont cmd cont jdbFailIfNotPresent "Method entered: \"thread=main\", JdbMethodExitTest.traceMethods1" jdbFailIfNotPresent 'Method exited: .* JdbMethodExitTest.traceMethods1' @@ -251,14 +255,14 @@ dojdbCmds() cmd step up - cmd trace method exits + cmd trace method exits $threadid cmd cont jdbFailIfNotPresent "Method exited: return value = \"traceExits\"" cmd untrace cmd step up - cmd trace go method exits + cmd trace go method exits $threadid cmd cont jdbFailIfNotPresent 'Method exited: .* JdbMethodExitTest.traceExits1' cmd untrace @@ -266,7 +270,7 @@ dojdbCmds() cmd step # step into traceExit() - cmd trace method exit + cmd trace method exit $threadid cmd cont jdbFailIfNotPresent "Method exited: return value = \"traceExit\"" cmd untrace @@ -275,7 +279,7 @@ dojdbCmds() cmd step cmd step # skip over setting return value in caller :-( - cmd trace go method exit + cmd trace go method exit $threadid cmd cont jdbFailIfNotPresent 'Method exited: .*JdbMethodExitTest.traceExit1' cmd quit diff --git a/jdk/test/com/sun/jdi/ShellScaffold.sh b/jdk/test/com/sun/jdi/ShellScaffold.sh index d8635e3dda9..6ed55c1ae91 100644 --- a/jdk/test/com/sun/jdi/ShellScaffold.sh +++ b/jdk/test/com/sun/jdi/ShellScaffold.sh @@ -1004,6 +1004,50 @@ grepForString() return $stat } +# $1 is the filename, $2 is the regexp to match and return, +# $3 is the number of lines to search (from the end) +matchRegexp() +{ + if [ -z "$3" ] ; then + theCmd=cat + else + theCmd="tail -$3" + fi + + case "$2" in + *\>*) + # Target string contains a '>' so we better not ignore it + res=`$theCmd $1 | sed -e "$2"` + ;; + *) + # Target string does not contain a '>'. + # NOTE: if $1 does not end with a new line, piping it to sed + # doesn't include the chars on the last line. Detect this + # case, and add a new line. + theFile="$1" + if [ `tail -1 "$theFile" | wc -l | sed -e 's@ @@g'` = 0 ] ; then + # The target file doesn't end with a new line so we have + # add one to a copy of the target file so the sed command + # below can filter that last line. + cp "$theFile" "$theFile.tmp" + theFile="$theFile.tmp" + echo >> "$theFile" + fi + + # See bug 6220903. Sometimes the jdb prompt chars ('> ') can + # get interleaved in the target file which can keep us from + # matching the target string. + res=`$theCmd "$theFile" | sed -e 's@> @@g' -e 's@>@@g' \ + | sed -e "$2"` + if [ "$theFile" != "$1" ]; then + # remove the copy of the target file + rm -f "$theFile" + fi + unset theFile + esac + return $res +} + # $1 is the filename, $2 is the string to look for, # $3 is the number of lines to search (from the end) failIfPresent() @@ -1058,6 +1102,14 @@ debuggeeFailIfPresent() failIfPresent $debuggeeOutFile "$1" $2 } +# match and return the output from the regexp $1 in the debuggee output +# $2 is the number of lines to search (from the end) +debuggeeMatchRegexp() +{ + matchRegexp $debuggeeOutFile "$1" $2 +} + + # This should really be named 'done' instead of pass. pass() { From 0fa3a71c8a4821327ebada5673596889f8df8a7d Mon Sep 17 00:00:00 2001 From: Jesper Wilhelmsson Date: Fri, 1 Nov 2013 17:09:38 +0100 Subject: [PATCH 007/110] 8016309: assert(eden_size > 0 && survivor_size > 0) failed: just checking 7057939: jmap shows MaxNewSize=4GB when Java is using parallel collector Major cleanup of the collectorpolicy classes Reviewed-by: tschatzl, jcoomes --- .../cmsCollectorPolicy.cpp | 5 +- .../cmsCollectorPolicy.hpp | 3 +- .../gc_implementation/g1/g1CollectedHeap.cpp | 2 +- .../g1/g1CollectorPolicy.cpp | 76 +++- .../g1/g1CollectorPolicy.hpp | 15 +- .../vm/gc_implementation/g1/heapRegion.cpp | 5 - .../parallelScavenge/adjoiningGenerations.cpp | 19 +- .../parallelScavenge/adjoiningGenerations.hpp | 10 +- .../parallelScavenge/asPSOldGen.cpp | 4 +- .../parallelScavenge/asPSYoungGen.cpp | 10 +- .../parallelScavenge/generationSizer.cpp | 84 ++++ .../parallelScavenge/generationSizer.hpp | 40 +- .../parallelScavenge/parallelScavengeHeap.cpp | 85 +--- .../parallelScavenge/parallelScavengeHeap.hpp | 40 +- .../parallelScavenge/psAdaptiveSizePolicy.cpp | 46 +- .../parallelScavenge/psAdaptiveSizePolicy.hpp | 6 +- .../parallelScavenge/psYoungGen.cpp | 13 +- .../share/vm/gc_interface/collectedHeap.cpp | 4 + .../src/share/vm/memory/collectorPolicy.cpp | 422 ++++++++++++------ .../src/share/vm/memory/collectorPolicy.hpp | 83 ++-- .../src/share/vm/memory/defNewGeneration.cpp | 6 +- .../src/share/vm/memory/genCollectedHeap.cpp | 2 +- hotspot/src/share/vm/memory/sharedHeap.cpp | 1 + hotspot/src/share/vm/memory/universe.cpp | 2 + hotspot/src/share/vm/prims/whitebox.cpp | 2 +- hotspot/src/share/vm/runtime/arguments.cpp | 6 +- .../gc/arguments/TestMaxHeapSizeTools.java | 33 +- hotspot/test/gc/arguments/TestMaxNewSize.java | 122 +++++ 28 files changed, 718 insertions(+), 428 deletions(-) create mode 100644 hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp create mode 100644 hotspot/test/gc/arguments/TestMaxNewSize.java diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.cpp index c2aafb7bc20..a236a10efb3 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.cpp @@ -47,8 +47,9 @@ // ConcurrentMarkSweepPolicy methods // -ConcurrentMarkSweepPolicy::ConcurrentMarkSweepPolicy() { - initialize_all(); +void ConcurrentMarkSweepPolicy::initialize_alignments() { + _space_alignment = _gen_alignment = (uintx)Generation::GenGrain; + _heap_alignment = compute_heap_alignment(); } void ConcurrentMarkSweepPolicy::initialize_generations() { diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.hpp index 1483bca13eb..d26959f3d9f 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.hpp @@ -29,10 +29,11 @@ class ConcurrentMarkSweepPolicy : public TwoGenerationCollectorPolicy { protected: + void initialize_alignments(); void initialize_generations(); public: - ConcurrentMarkSweepPolicy(); + ConcurrentMarkSweepPolicy() {} ConcurrentMarkSweepPolicy* as_concurrent_mark_sweep_policy() { return this; } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 3f53067ca8d..85709465b3e 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -2008,7 +2008,7 @@ jint G1CollectedHeap::initialize() { size_t init_byte_size = collector_policy()->initial_heap_byte_size(); size_t max_byte_size = collector_policy()->max_heap_byte_size(); - size_t heap_alignment = collector_policy()->max_alignment(); + size_t heap_alignment = collector_policy()->heap_alignment(); // Ensure that the sizes are properly aligned. Universe::check_alignment(init_byte_size, HeapRegion::GrainBytes, "g1 heap"); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp index ad1dce1750b..b4f9a0b0007 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp @@ -313,27 +313,38 @@ G1CollectorPolicy::G1CollectorPolicy() : // for the first time during initialization. _reserve_regions = 0; - initialize_all(); _collectionSetChooser = new CollectionSetChooser(); - _young_gen_sizer = new G1YoungGenSizer(); // Must be after call to initialize_flags +} + +void G1CollectorPolicy::initialize_alignments() { + _space_alignment = HeapRegion::GrainBytes; + size_t card_table_alignment = GenRemSet::max_alignment_constraint(GenRemSet::CardTable); + size_t page_size = UseLargePages ? os::large_page_size() : os::vm_page_size(); + _heap_alignment = MAX3(card_table_alignment, _space_alignment, page_size); } void G1CollectorPolicy::initialize_flags() { - _min_alignment = HeapRegion::GrainBytes; - size_t card_table_alignment = GenRemSet::max_alignment_constraint(GenRemSet::CardTable); - size_t page_size = UseLargePages ? os::large_page_size() : os::vm_page_size(); - _max_alignment = MAX3(card_table_alignment, _min_alignment, page_size); + if (G1HeapRegionSize != HeapRegion::GrainBytes) { + FLAG_SET_ERGO(uintx, G1HeapRegionSize, HeapRegion::GrainBytes); + } + if (SurvivorRatio < 1) { vm_exit_during_initialization("Invalid survivor ratio specified"); } CollectorPolicy::initialize_flags(); + _young_gen_sizer = new G1YoungGenSizer(); // Must be after call to initialize_flags } -G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), _adaptive_size(true) { - assert(G1NewSizePercent <= G1MaxNewSizePercent, "Min larger than max"); - assert(G1NewSizePercent > 0 && G1NewSizePercent < 100, "Min out of bounds"); - assert(G1MaxNewSizePercent > 0 && G1MaxNewSizePercent < 100, "Max out of bounds"); +void G1CollectorPolicy::post_heap_initialize() { + uintx max_regions = G1CollectedHeap::heap()->max_regions(); + size_t max_young_size = (size_t)_young_gen_sizer->max_young_length(max_regions) * HeapRegion::GrainBytes; + if (max_young_size != MaxNewSize) { + FLAG_SET_ERGO(uintx, MaxNewSize, max_young_size); + } +} +G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), _adaptive_size(true), + _min_desired_young_length(0), _max_desired_young_length(0) { if (FLAG_IS_CMDLINE(NewRatio)) { if (FLAG_IS_CMDLINE(NewSize) || FLAG_IS_CMDLINE(MaxNewSize)) { warning("-XX:NewSize and -XX:MaxNewSize override -XX:NewRatio"); @@ -344,8 +355,13 @@ G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), _adaptive_size( } } - if (FLAG_IS_CMDLINE(NewSize) && FLAG_IS_CMDLINE(MaxNewSize) && NewSize > MaxNewSize) { - vm_exit_during_initialization("Initial young gen size set larger than the maximum young gen size"); + if (NewSize > MaxNewSize) { + if (FLAG_IS_CMDLINE(MaxNewSize)) { + warning("NewSize (" SIZE_FORMAT "k) is greater than the MaxNewSize (" SIZE_FORMAT "k). " + "A new max generation size of " SIZE_FORMAT "k will be used.", + NewSize/K, MaxNewSize/K, NewSize/K); + } + MaxNewSize = NewSize; } if (FLAG_IS_CMDLINE(NewSize)) { @@ -378,34 +394,48 @@ uint G1YoungGenSizer::calculate_default_max_length(uint new_number_of_heap_regio return MAX2(1U, default_value); } -void G1YoungGenSizer::heap_size_changed(uint new_number_of_heap_regions) { - assert(new_number_of_heap_regions > 0, "Heap must be initialized"); +void G1YoungGenSizer::recalculate_min_max_young_length(uint number_of_heap_regions, uint* min_young_length, uint* max_young_length) { + assert(number_of_heap_regions > 0, "Heap must be initialized"); switch (_sizer_kind) { case SizerDefaults: - _min_desired_young_length = calculate_default_min_length(new_number_of_heap_regions); - _max_desired_young_length = calculate_default_max_length(new_number_of_heap_regions); + *min_young_length = calculate_default_min_length(number_of_heap_regions); + *max_young_length = calculate_default_max_length(number_of_heap_regions); break; case SizerNewSizeOnly: - _max_desired_young_length = calculate_default_max_length(new_number_of_heap_regions); - _max_desired_young_length = MAX2(_min_desired_young_length, _max_desired_young_length); + *max_young_length = calculate_default_max_length(number_of_heap_regions); + *max_young_length = MAX2(*min_young_length, *max_young_length); break; case SizerMaxNewSizeOnly: - _min_desired_young_length = calculate_default_min_length(new_number_of_heap_regions); - _min_desired_young_length = MIN2(_min_desired_young_length, _max_desired_young_length); + *min_young_length = calculate_default_min_length(number_of_heap_regions); + *min_young_length = MIN2(*min_young_length, *max_young_length); break; case SizerMaxAndNewSize: // Do nothing. Values set on the command line, don't update them at runtime. break; case SizerNewRatio: - _min_desired_young_length = new_number_of_heap_regions / (NewRatio + 1); - _max_desired_young_length = _min_desired_young_length; + *min_young_length = number_of_heap_regions / (NewRatio + 1); + *max_young_length = *min_young_length; break; default: ShouldNotReachHere(); } - assert(_min_desired_young_length <= _max_desired_young_length, "Invalid min/max young gen size values"); + assert(*min_young_length <= *max_young_length, "Invalid min/max young gen size values"); +} + +uint G1YoungGenSizer::max_young_length(uint number_of_heap_regions) { + // We need to pass the desired values because recalculation may not update these + // values in some cases. + uint temp = _min_desired_young_length; + uint result = _max_desired_young_length; + recalculate_min_max_young_length(number_of_heap_regions, &temp, &result); + return result; +} + +void G1YoungGenSizer::heap_size_changed(uint new_number_of_heap_regions) { + recalculate_min_max_young_length(new_number_of_heap_regions, &_min_desired_young_length, + &_max_desired_young_length); } void G1CollectorPolicy::init() { diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp index 037876e07e7..438bec82c51 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp @@ -136,8 +136,16 @@ private: uint calculate_default_min_length(uint new_number_of_heap_regions); uint calculate_default_max_length(uint new_number_of_heap_regions); + // Update the given values for minimum and maximum young gen length in regions + // given the number of heap regions depending on the kind of sizing algorithm. + void recalculate_min_max_young_length(uint number_of_heap_regions, uint* min_young_length, uint* max_young_length); + public: G1YoungGenSizer(); + // Calculate the maximum length of the young gen given the number of regions + // depending on the sizing algorithm. + uint max_young_length(uint number_of_heap_regions); + void heap_size_changed(uint new_number_of_heap_regions); uint min_desired_young_length() { return _min_desired_young_length; @@ -165,13 +173,9 @@ private: G1MMUTracker* _mmu_tracker; + void initialize_alignments(); void initialize_flags(); - void initialize_all() { - initialize_flags(); - initialize_size_info(); - } - CollectionSetChooser* _collectionSetChooser; double _full_collection_start_sec; @@ -931,6 +935,7 @@ public: // Calculates survivor space parameters. void update_survivors_policy(); + virtual void post_heap_initialize(); }; // This should move to some place more general... diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp index 00eec548995..e4f534ab5a2 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp @@ -174,11 +174,6 @@ void HeapRegion::setup_heap_region_size(size_t initial_heap_size, size_t max_hea region_size = MAX_REGION_SIZE; } - if (region_size != G1HeapRegionSize) { - // Update the flag to make sure that PrintFlagsFinal logs the correct value - FLAG_SET_ERGO(uintx, G1HeapRegionSize, region_size); - } - // And recalculate the log. region_size_log = log2_long((jlong) region_size); diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.cpp index 996a522927b..90bf630fe36 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "gc_implementation/parallelScavenge/adjoiningGenerations.hpp" #include "gc_implementation/parallelScavenge/adjoiningVirtualSpaces.hpp" +#include "gc_implementation/parallelScavenge/generationSizer.hpp" #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" // If boundary moving is being used, create the young gen and old @@ -32,15 +33,17 @@ // the old behavior otherwise (with PSYoungGen and PSOldGen). AdjoiningGenerations::AdjoiningGenerations(ReservedSpace old_young_rs, - size_t init_low_byte_size, - size_t min_low_byte_size, - size_t max_low_byte_size, - size_t init_high_byte_size, - size_t min_high_byte_size, - size_t max_high_byte_size, + GenerationSizer* policy, size_t alignment) : - _virtual_spaces(old_young_rs, min_low_byte_size, - min_high_byte_size, alignment) { + _virtual_spaces(old_young_rs, policy->min_gen1_size(), + policy->min_gen0_size(), alignment) { + size_t init_low_byte_size = policy->initial_gen1_size(); + size_t min_low_byte_size = policy->min_gen1_size(); + size_t max_low_byte_size = policy->max_gen1_size(); + size_t init_high_byte_size = policy->initial_gen0_size(); + size_t min_high_byte_size = policy->min_gen0_size(); + size_t max_high_byte_size = policy->max_gen0_size(); + assert(min_low_byte_size <= init_low_byte_size && init_low_byte_size <= max_low_byte_size, "Parameter check"); assert(min_high_byte_size <= init_high_byte_size && diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.hpp index 70afb9996ae..950baa1d53f 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.hpp @@ -28,6 +28,7 @@ #include "gc_implementation/parallelScavenge/adjoiningVirtualSpaces.hpp" #include "gc_implementation/parallelScavenge/asPSOldGen.hpp" #include "gc_implementation/parallelScavenge/asPSYoungGen.hpp" +#include "gc_implementation/parallelScavenge/generationSizer.hpp" // Contains two generations that both use an AdjoiningVirtualSpaces. @@ -56,14 +57,7 @@ class AdjoiningGenerations : public CHeapObj { bool request_young_gen_expansion(size_t desired_change_in_bytes); public: - AdjoiningGenerations(ReservedSpace rs, - size_t init_low_byte_size, - size_t min_low_byte_size, - size_t max_low_byte_size, - size_t init_high_byte_size, - size_t min_high_byte_size, - size_t max_high_bytes_size, - size_t alignment); + AdjoiningGenerations(ReservedSpace rs, GenerationSizer* policy, size_t alignment); // Accessors PSYoungGen* young_gen() { return _young_gen; } diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp index 6f7026e5a0c..9d2e8182e06 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp @@ -91,7 +91,7 @@ size_t ASPSOldGen::available_for_expansion() { ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); size_t result = gen_size_limit() - virtual_space()->committed_size(); - size_t result_aligned = align_size_down(result, heap->old_gen_alignment()); + size_t result_aligned = align_size_down(result, heap->generation_alignment()); return result_aligned; } @@ -102,7 +102,7 @@ size_t ASPSOldGen::available_for_contraction() { } ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - const size_t gen_alignment = heap->old_gen_alignment(); + const size_t gen_alignment = heap->generation_alignment(); PSAdaptiveSizePolicy* policy = heap->size_policy(); const size_t working_size = used_in_bytes() + (size_t) policy->avg_promoted()->padded_average(); diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp index a7b2eb28ef2..105772487c0 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp @@ -75,7 +75,7 @@ size_t ASPSYoungGen::available_for_expansion() { "generation size limit is wrong"); ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); size_t result = gen_size_limit() - current_committed_size; - size_t result_aligned = align_size_down(result, heap->young_gen_alignment()); + size_t result_aligned = align_size_down(result, heap->generation_alignment()); return result_aligned; } @@ -92,8 +92,8 @@ size_t ASPSYoungGen::available_for_contraction() { if (eden_space()->is_empty()) { // Respect the minimum size for eden and for the young gen as a whole. ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - const size_t eden_alignment = heap->intra_heap_alignment(); - const size_t gen_alignment = heap->young_gen_alignment(); + const size_t eden_alignment = heap->space_alignment(); + const size_t gen_alignment = heap->generation_alignment(); assert(eden_space()->capacity_in_bytes() >= eden_alignment, "Alignment is wrong"); @@ -129,7 +129,7 @@ size_t ASPSYoungGen::available_for_contraction() { // to_space can be. size_t ASPSYoungGen::available_to_live() { ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - const size_t alignment = heap->intra_heap_alignment(); + const size_t alignment = heap->space_alignment(); // Include any space that is committed but is not in eden. size_t available = pointer_delta(eden_space()->bottom(), @@ -293,7 +293,7 @@ void ASPSYoungGen::resize_spaces(size_t requested_eden_size, assert(eden_start < from_start, "Cannot push into from_space"); ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - const size_t alignment = heap->intra_heap_alignment(); + const size_t alignment = heap->space_alignment(); const bool maintain_minimum = (requested_eden_size + 2 * requested_survivor_size) <= min_gen_size(); diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp new file mode 100644 index 00000000000..638460524eb --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc_implementation/parallelScavenge/generationSizer.hpp" +#include "memory/collectorPolicy.hpp" + +void GenerationSizer::trace_gen_sizes(const char* const str) { + if (TracePageSizes) { + tty->print_cr("%s: " SIZE_FORMAT "," SIZE_FORMAT " " + SIZE_FORMAT "," SIZE_FORMAT " " + SIZE_FORMAT, + str, + _min_gen1_size / K, _max_gen1_size / K, + _min_gen0_size / K, _max_gen0_size / K, + _max_heap_byte_size / K); + } +} + +void GenerationSizer::initialize_alignments() { + _space_alignment = _gen_alignment = default_gen_alignment(); + _heap_alignment = compute_heap_alignment(); +} + +void GenerationSizer::initialize_flags() { + // Do basic sizing work + TwoGenerationCollectorPolicy::initialize_flags(); + + assert(UseSerialGC || + !FLAG_IS_DEFAULT(ParallelGCThreads) || + (ParallelGCThreads > 0), + "ParallelGCThreads should be set before flag initialization"); + + // The survivor ratio's are calculated "raw", unlike the + // default gc, which adds 2 to the ratio value. We need to + // make sure the values are valid before using them. + if (MinSurvivorRatio < 3) { + FLAG_SET_ERGO(uintx, MinSurvivorRatio, 3); + } + + if (InitialSurvivorRatio < 3) { + FLAG_SET_ERGO(uintx, InitialSurvivorRatio, 3); + } +} + +void GenerationSizer::initialize_size_info() { + trace_gen_sizes("ps heap raw"); + const size_t page_sz = os::page_size_for_region(_min_heap_byte_size, + _max_heap_byte_size, + 8); + + // Can a page size be something else than a power of two? + assert(is_power_of_2((intptr_t)page_sz), "must be a power of 2"); + size_t new_alignment = round_to(page_sz, _gen_alignment); + if (new_alignment != _gen_alignment) { + _gen_alignment = new_alignment; + // Redo everything from the start + initialize_flags(); + } + TwoGenerationCollectorPolicy::initialize_size_info(); + + trace_gen_sizes("ps heap rnd"); +} diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp index f7be7671ff9..eb8c78a8c81 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp @@ -31,41 +31,17 @@ // TwoGenerationCollectorPolicy. Lets reuse it! class GenerationSizer : public TwoGenerationCollectorPolicy { - public: - GenerationSizer() { - // Partial init only! - initialize_flags(); - initialize_size_info(); - } + private: - void initialize_flags() { - // Do basic sizing work - TwoGenerationCollectorPolicy::initialize_flags(); + void trace_gen_sizes(const char* const str); - assert(UseSerialGC || - !FLAG_IS_DEFAULT(ParallelGCThreads) || - (ParallelGCThreads > 0), - "ParallelGCThreads should be set before flag initialization"); + // The alignment used for boundary between young gen and old gen + static size_t default_gen_alignment() { return 64 * K * HeapWordSize; } - // The survivor ratio's are calculated "raw", unlike the - // default gc, which adds 2 to the ratio value. We need to - // make sure the values are valid before using them. - if (MinSurvivorRatio < 3) { - MinSurvivorRatio = 3; - } + protected: - if (InitialSurvivorRatio < 3) { - InitialSurvivorRatio = 3; - } - } - - size_t min_young_gen_size() { return _min_gen0_size; } - size_t young_gen_size() { return _initial_gen0_size; } - size_t max_young_gen_size() { return _max_gen0_size; } - - size_t min_old_gen_size() { return _min_gen1_size; } - size_t old_gen_size() { return _initial_gen1_size; } - size_t max_old_gen_size() { return _max_gen1_size; } + void initialize_alignments(); + void initialize_flags(); + void initialize_size_info(); }; - #endif // SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_GENERATIONSIZER_HPP diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp index e5d5229d30c..f93f2e8991f 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp @@ -52,76 +52,20 @@ PSGCAdaptivePolicyCounters* ParallelScavengeHeap::_gc_policy_counters = NULL; ParallelScavengeHeap* ParallelScavengeHeap::_psh = NULL; GCTaskManager* ParallelScavengeHeap::_gc_task_manager = NULL; -static void trace_gen_sizes(const char* const str, - size_t og_min, size_t og_max, - size_t yg_min, size_t yg_max) -{ - if (TracePageSizes) { - tty->print_cr("%s: " SIZE_FORMAT "," SIZE_FORMAT " " - SIZE_FORMAT "," SIZE_FORMAT " " - SIZE_FORMAT, - str, - og_min / K, og_max / K, - yg_min / K, yg_max / K, - (og_max + yg_max) / K); - } -} - jint ParallelScavengeHeap::initialize() { CollectedHeap::pre_initialize(); - // Cannot be initialized until after the flags are parsed - // GenerationSizer flag_parser; + // Initialize collector policy _collector_policy = new GenerationSizer(); + _collector_policy->initialize_all(); - size_t yg_min_size = _collector_policy->min_young_gen_size(); - size_t yg_max_size = _collector_policy->max_young_gen_size(); - size_t og_min_size = _collector_policy->min_old_gen_size(); - size_t og_max_size = _collector_policy->max_old_gen_size(); - - trace_gen_sizes("ps heap raw", - og_min_size, og_max_size, - yg_min_size, yg_max_size); - - const size_t og_page_sz = os::page_size_for_region(yg_min_size + og_min_size, - yg_max_size + og_max_size, - 8); - - const size_t og_align = set_alignment(_old_gen_alignment, og_page_sz); - const size_t yg_align = set_alignment(_young_gen_alignment, og_page_sz); - - // Update sizes to reflect the selected page size(s). - // - // NEEDS_CLEANUP. The default TwoGenerationCollectorPolicy uses NewRatio; it - // should check UseAdaptiveSizePolicy. Changes from generationSizer could - // move to the common code. - yg_min_size = align_size_up(yg_min_size, yg_align); - yg_max_size = align_size_up(yg_max_size, yg_align); - size_t yg_cur_size = - align_size_up(_collector_policy->young_gen_size(), yg_align); - yg_cur_size = MAX2(yg_cur_size, yg_min_size); - - og_min_size = align_size_up(og_min_size, og_align); - // Align old gen size down to preserve specified heap size. - assert(og_align == yg_align, "sanity"); - og_max_size = align_size_down(og_max_size, og_align); - og_max_size = MAX2(og_max_size, og_min_size); - size_t og_cur_size = - align_size_down(_collector_policy->old_gen_size(), og_align); - og_cur_size = MAX2(og_cur_size, og_min_size); - - trace_gen_sizes("ps heap rnd", - og_min_size, og_max_size, - yg_min_size, yg_max_size); - - const size_t heap_size = og_max_size + yg_max_size; - - ReservedSpace heap_rs = Universe::reserve_heap(heap_size, og_align); + const size_t heap_size = _collector_policy->max_heap_byte_size(); + ReservedSpace heap_rs = Universe::reserve_heap(heap_size, _collector_policy->heap_alignment()); MemTracker::record_virtual_memory_type((address)heap_rs.base(), mtJavaHeap); - os::trace_page_sizes("ps main", og_min_size + yg_min_size, - og_max_size + yg_max_size, og_page_sz, + os::trace_page_sizes("ps main", _collector_policy->min_heap_byte_size(), + heap_size, generation_alignment(), heap_rs.base(), heap_rs.size()); if (!heap_rs.is_reserved()) { @@ -142,12 +86,6 @@ jint ParallelScavengeHeap::initialize() { return JNI_ENOMEM; } - // Initial young gen size is 4 Mb - // - // XXX - what about flag_parser.young_gen_size()? - const size_t init_young_size = align_size_up(4 * M, yg_align); - yg_cur_size = MAX2(MIN2(init_young_size, yg_max_size), yg_cur_size); - // Make up the generations // Calculate the maximum size that a generation can grow. This // includes growth into the other generation. Note that the @@ -157,14 +95,7 @@ jint ParallelScavengeHeap::initialize() { double max_gc_pause_sec = ((double) MaxGCPauseMillis)/1000.0; double max_gc_minor_pause_sec = ((double) MaxGCMinorPauseMillis)/1000.0; - _gens = new AdjoiningGenerations(heap_rs, - og_cur_size, - og_min_size, - og_max_size, - yg_cur_size, - yg_min_size, - yg_max_size, - yg_align); + _gens = new AdjoiningGenerations(heap_rs, _collector_policy, generation_alignment()); _old_gen = _gens->old_gen(); _young_gen = _gens->young_gen(); @@ -176,7 +107,7 @@ jint ParallelScavengeHeap::initialize() { new PSAdaptiveSizePolicy(eden_capacity, initial_promo_size, young_gen()->to_space()->capacity_in_bytes(), - intra_heap_alignment(), + _collector_policy->gen_alignment(), max_gc_pause_sec, max_gc_minor_pause_sec, GCTimeRatio diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp index 2ef42c86660..51f40d8c62b 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PARALLELSCAVENGEHEAP_HPP #define SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PARALLELSCAVENGEHEAP_HPP +#include "gc_implementation/parallelScavenge/generationSizer.hpp" #include "gc_implementation/parallelScavenge/objectStartArray.hpp" #include "gc_implementation/parallelScavenge/psGCAdaptivePolicyCounters.hpp" #include "gc_implementation/parallelScavenge/psOldGen.hpp" @@ -32,13 +33,12 @@ #include "gc_implementation/shared/gcPolicyCounters.hpp" #include "gc_implementation/shared/gcWhen.hpp" #include "gc_interface/collectedHeap.inline.hpp" +#include "memory/collectorPolicy.hpp" #include "utilities/ostream.hpp" class AdjoiningGenerations; class GCHeapSummary; class GCTaskManager; -class GenerationSizer; -class CollectorPolicy; class PSAdaptiveSizePolicy; class PSHeapSummary; @@ -54,13 +54,8 @@ class ParallelScavengeHeap : public CollectedHeap { static ParallelScavengeHeap* _psh; - size_t _young_gen_alignment; - size_t _old_gen_alignment; - GenerationSizer* _collector_policy; - inline size_t set_alignment(size_t& var, size_t val); - // Collection of generations that are adjacent in the // space reserved for the heap. AdjoiningGenerations* _gens; @@ -80,15 +75,7 @@ class ParallelScavengeHeap : public CollectedHeap { HeapWord* mem_allocate_old_gen(size_t size); public: - ParallelScavengeHeap() : CollectedHeap(), _death_march_count(0) { - set_alignment(_young_gen_alignment, intra_heap_alignment()); - set_alignment(_old_gen_alignment, intra_heap_alignment()); - } - - // Return the (conservative) maximum heap alignment - static size_t conservative_max_heap_alignment() { - return GenCollectorPolicy::intra_heap_alignment(); - } + ParallelScavengeHeap() : CollectedHeap(), _death_march_count(0) { } // For use by VM operations enum CollectionType { @@ -120,13 +107,15 @@ class ParallelScavengeHeap : public CollectedHeap { void post_initialize(); void update_counters(); - // The alignment used for the various generations. - size_t young_gen_alignment() const { return _young_gen_alignment; } - size_t old_gen_alignment() const { return _old_gen_alignment; } - // The alignment used for eden and survivors within the young gen - // and for boundary between young gen and old gen. - size_t intra_heap_alignment() { return GenCollectorPolicy::intra_heap_alignment(); } + // The alignment used for the various areas + size_t space_alignment() { return _collector_policy->space_alignment(); } + size_t generation_alignment() { return _collector_policy->gen_alignment(); } + + // Return the (conservative) maximum heap alignment + static size_t conservative_max_heap_alignment() { + return CollectorPolicy::compute_heap_alignment(); + } size_t capacity() const; size_t used() const; @@ -261,11 +250,4 @@ class ParallelScavengeHeap : public CollectedHeap { }; }; -inline size_t ParallelScavengeHeap::set_alignment(size_t& var, size_t val) -{ - assert(is_power_of_2((intptr_t)val), "must be a power of 2"); - var = round_to(val, intra_heap_alignment()); - return var; -} - #endif // SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PARALLELSCAVENGEHEAP_HPP diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp index 1ffdf64e2aa..a2f2fa722bf 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp @@ -37,7 +37,7 @@ PSAdaptiveSizePolicy::PSAdaptiveSizePolicy(size_t init_eden_size, size_t init_promo_size, size_t init_survivor_size, - size_t intra_generation_alignment, + size_t space_alignment, double gc_pause_goal_sec, double gc_minor_pause_goal_sec, uint gc_cost_ratio) : @@ -47,7 +47,7 @@ PSAdaptiveSizePolicy::PSAdaptiveSizePolicy(size_t init_eden_size, gc_pause_goal_sec, gc_cost_ratio), _collection_cost_margin_fraction(AdaptiveSizePolicyCollectionCostMargin / 100.0), - _intra_generation_alignment(intra_generation_alignment), + _space_alignment(space_alignment), _live_at_last_full_gc(init_promo_size), _gc_minor_pause_goal_sec(gc_minor_pause_goal_sec), _latest_major_mutator_interval_seconds(0), @@ -352,11 +352,10 @@ void PSAdaptiveSizePolicy::compute_eden_space_size( } // Align everything and make a final limit check - const size_t alignment = _intra_generation_alignment; - desired_eden_size = align_size_up(desired_eden_size, alignment); - desired_eden_size = MAX2(desired_eden_size, alignment); + desired_eden_size = align_size_up(desired_eden_size, _space_alignment); + desired_eden_size = MAX2(desired_eden_size, _space_alignment); - eden_limit = align_size_down(eden_limit, alignment); + eden_limit = align_size_down(eden_limit, _space_alignment); // And one last limit check, now that we've aligned things. if (desired_eden_size > eden_limit) { @@ -560,11 +559,10 @@ void PSAdaptiveSizePolicy::compute_old_gen_free_space( } // Align everything and make a final limit check - const size_t alignment = _intra_generation_alignment; - desired_promo_size = align_size_up(desired_promo_size, alignment); - desired_promo_size = MAX2(desired_promo_size, alignment); + desired_promo_size = align_size_up(desired_promo_size, _space_alignment); + desired_promo_size = MAX2(desired_promo_size, _space_alignment); - promo_limit = align_size_down(promo_limit, alignment); + promo_limit = align_size_down(promo_limit, _space_alignment); // And one last limit check, now that we've aligned things. desired_promo_size = MIN2(desired_promo_size, promo_limit); @@ -649,7 +647,7 @@ void PSAdaptiveSizePolicy::adjust_promo_for_minor_pause_time(bool is_full_gc, } // If the desired eden size is as small as it will get, // try to adjust the old gen size. - if (*desired_eden_size_ptr <= _intra_generation_alignment) { + if (*desired_eden_size_ptr <= _space_alignment) { // Vary the old gen size to reduce the young gen pause. This // may not be a good idea. This is just a test. if (minor_pause_old_estimator()->decrement_will_decrease()) { @@ -754,7 +752,7 @@ void PSAdaptiveSizePolicy::adjust_eden_for_pause_time(bool is_full_gc, // If the promo size is at the minimum (i.e., the old gen // size will not actually decrease), consider changing the // young gen size. - if (*desired_promo_size_ptr < _intra_generation_alignment) { + if (*desired_promo_size_ptr < _space_alignment) { // If increasing the young generation will decrease the old gen // pause, do it. // During startup there is noise in the statistics for deciding @@ -1065,24 +1063,24 @@ size_t PSAdaptiveSizePolicy::eden_increment(size_t cur_eden) { size_t PSAdaptiveSizePolicy::eden_increment_aligned_up(size_t cur_eden) { size_t result = eden_increment(cur_eden, YoungGenerationSizeIncrement); - return align_size_up(result, _intra_generation_alignment); + return align_size_up(result, _space_alignment); } size_t PSAdaptiveSizePolicy::eden_increment_aligned_down(size_t cur_eden) { size_t result = eden_increment(cur_eden); - return align_size_down(result, _intra_generation_alignment); + return align_size_down(result, _space_alignment); } size_t PSAdaptiveSizePolicy::eden_increment_with_supplement_aligned_up( size_t cur_eden) { size_t result = eden_increment(cur_eden, YoungGenerationSizeIncrement + _young_gen_size_increment_supplement); - return align_size_up(result, _intra_generation_alignment); + return align_size_up(result, _space_alignment); } size_t PSAdaptiveSizePolicy::eden_decrement_aligned_down(size_t cur_eden) { size_t eden_heap_delta = eden_decrement(cur_eden); - return align_size_down(eden_heap_delta, _intra_generation_alignment); + return align_size_down(eden_heap_delta, _space_alignment); } size_t PSAdaptiveSizePolicy::eden_decrement(size_t cur_eden) { @@ -1104,24 +1102,24 @@ size_t PSAdaptiveSizePolicy::promo_increment(size_t cur_promo) { size_t PSAdaptiveSizePolicy::promo_increment_aligned_up(size_t cur_promo) { size_t result = promo_increment(cur_promo, TenuredGenerationSizeIncrement); - return align_size_up(result, _intra_generation_alignment); + return align_size_up(result, _space_alignment); } size_t PSAdaptiveSizePolicy::promo_increment_aligned_down(size_t cur_promo) { size_t result = promo_increment(cur_promo, TenuredGenerationSizeIncrement); - return align_size_down(result, _intra_generation_alignment); + return align_size_down(result, _space_alignment); } size_t PSAdaptiveSizePolicy::promo_increment_with_supplement_aligned_up( size_t cur_promo) { size_t result = promo_increment(cur_promo, TenuredGenerationSizeIncrement + _old_gen_size_increment_supplement); - return align_size_up(result, _intra_generation_alignment); + return align_size_up(result, _space_alignment); } size_t PSAdaptiveSizePolicy::promo_decrement_aligned_down(size_t cur_promo) { size_t promo_heap_delta = promo_decrement(cur_promo); - return align_size_down(promo_heap_delta, _intra_generation_alignment); + return align_size_down(promo_heap_delta, _space_alignment); } size_t PSAdaptiveSizePolicy::promo_decrement(size_t cur_promo) { @@ -1134,9 +1132,9 @@ uint PSAdaptiveSizePolicy::compute_survivor_space_size_and_threshold( bool is_survivor_overflow, uint tenuring_threshold, size_t survivor_limit) { - assert(survivor_limit >= _intra_generation_alignment, + assert(survivor_limit >= _space_alignment, "survivor_limit too small"); - assert((size_t)align_size_down(survivor_limit, _intra_generation_alignment) + assert((size_t)align_size_down(survivor_limit, _space_alignment) == survivor_limit, "survivor_limit not aligned"); // This method is called even if the tenuring threshold and survivor @@ -1200,8 +1198,8 @@ uint PSAdaptiveSizePolicy::compute_survivor_space_size_and_threshold( // We're trying to pad the survivor size as little as possible without // overflowing the survivor spaces. size_t target_size = align_size_up((size_t)_avg_survived->padded_average(), - _intra_generation_alignment); - target_size = MAX2(target_size, _intra_generation_alignment); + _space_alignment); + target_size = MAX2(target_size, _space_alignment); if (target_size > survivor_limit) { // Target size is bigger than we can handle. Let's also reduce diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp index d88af2bf6ef..3389911876f 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp @@ -91,7 +91,7 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy { // for making ergonomic decisions. double _latest_major_mutator_interval_seconds; - const size_t _intra_generation_alignment; // alignment for eden, survivors + const size_t _space_alignment; // alignment for eden, survivors const double _gc_minor_pause_goal_sec; // goal for maximum minor gc pause @@ -229,7 +229,7 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy { PSAdaptiveSizePolicy(size_t init_eden_size, size_t init_promo_size, size_t init_survivor_size, - size_t intra_generation_alignment, + size_t space_alignment, double gc_pause_goal_sec, double gc_minor_pause_goal_sec, uint gc_time_ratio); @@ -378,7 +378,7 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy { // remain almost full anyway (top() will be near end(), but there will be a // large filler object at the bottom). const size_t sz = gen_size / MinSurvivorRatio; - const size_t alignment = _intra_generation_alignment; + const size_t alignment = _space_alignment; return sz > alignment ? align_size_down(sz, alignment) : alignment; } diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp index 2d8697587ac..c1f5c298794 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp @@ -103,7 +103,7 @@ void PSYoungGen::initialize_work() { // Compute maximum space sizes for performance counters ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - size_t alignment = heap->intra_heap_alignment(); + size_t alignment = heap->space_alignment(); size_t size = virtual_space()->reserved_size(); size_t max_survivor_size; @@ -156,8 +156,9 @@ void PSYoungGen::compute_initial_space_boundaries() { assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); // Compute sizes - size_t alignment = heap->intra_heap_alignment(); + size_t alignment = heap->space_alignment(); size_t size = virtual_space()->committed_size(); + assert(size >= 3 * alignment, "Young space is not large enough for eden + 2 survivors"); size_t survivor_size = size / InitialSurvivorRatio; survivor_size = align_size_down(survivor_size, alignment); @@ -207,7 +208,7 @@ void PSYoungGen::set_space_boundaries(size_t eden_size, size_t survivor_size) { #ifndef PRODUCT void PSYoungGen::space_invariants() { ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - const size_t alignment = heap->intra_heap_alignment(); + const size_t alignment = heap->space_alignment(); // Currently, our eden size cannot shrink to zero guarantee(eden_space()->capacity_in_bytes() >= alignment, "eden too small"); @@ -491,7 +492,7 @@ void PSYoungGen::resize_spaces(size_t requested_eden_size, char* to_end = (char*)to_space()->end(); ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - const size_t alignment = heap->intra_heap_alignment(); + const size_t alignment = heap->space_alignment(); const bool maintain_minimum = (requested_eden_size + 2 * requested_survivor_size) <= min_gen_size(); @@ -840,8 +841,8 @@ size_t PSYoungGen::available_to_min_gen() { size_t PSYoungGen::available_to_live() { size_t delta_in_survivor = 0; ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - const size_t space_alignment = heap->intra_heap_alignment(); - const size_t gen_alignment = heap->young_gen_alignment(); + const size_t space_alignment = heap->space_alignment(); + const size_t gen_alignment = heap->generation_alignment(); MutableSpace* space_shrinking = NULL; if (from_space()->end() > to_space()->end()) { diff --git a/hotspot/src/share/vm/gc_interface/collectedHeap.cpp b/hotspot/src/share/vm/gc_interface/collectedHeap.cpp index bbf5419fd0f..742e3b73be8 100644 --- a/hotspot/src/share/vm/gc_interface/collectedHeap.cpp +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.cpp @@ -469,6 +469,10 @@ void CollectedHeap::fill_with_objects(HeapWord* start, size_t words, bool zap) fill_with_object_impl(start, words, zap); } +void CollectedHeap::post_initialize() { + collector_policy()->post_heap_initialize(); +} + HeapWord* CollectedHeap::allocate_new_tlab(size_t size) { guarantee(false, "thread-local allocation buffers not supported"); return NULL; diff --git a/hotspot/src/share/vm/memory/collectorPolicy.cpp b/hotspot/src/share/vm/memory/collectorPolicy.cpp index 8cd11de6ef2..8c3e95a0550 100644 --- a/hotspot/src/share/vm/memory/collectorPolicy.cpp +++ b/hotspot/src/share/vm/memory/collectorPolicy.cpp @@ -47,54 +47,107 @@ // CollectorPolicy methods. -void CollectorPolicy::initialize_flags() { - assert(_max_alignment >= _min_alignment, - err_msg("max_alignment: " SIZE_FORMAT " less than min_alignment: " SIZE_FORMAT, - _max_alignment, _min_alignment)); - assert(_max_alignment % _min_alignment == 0, - err_msg("max_alignment: " SIZE_FORMAT " not aligned by min_alignment: " SIZE_FORMAT, - _max_alignment, _min_alignment)); +CollectorPolicy::CollectorPolicy() : + _space_alignment(0), + _heap_alignment(0), + _initial_heap_byte_size(InitialHeapSize), + _max_heap_byte_size(MaxHeapSize), + _min_heap_byte_size(Arguments::min_heap_size()), + _max_heap_size_cmdline(false), + _size_policy(NULL), + _should_clear_all_soft_refs(false), + _all_soft_refs_clear(false) +{} - if (MaxHeapSize < InitialHeapSize) { - vm_exit_during_initialization("Incompatible initial and maximum heap sizes specified"); - } - - MinHeapDeltaBytes = align_size_up(MinHeapDeltaBytes, _min_alignment); +#ifdef ASSERT +void CollectorPolicy::assert_flags() { + assert(InitialHeapSize <= MaxHeapSize, "Ergonomics decided on incompatible initial and maximum heap sizes"); + assert(InitialHeapSize % _heap_alignment == 0, "InitialHeapSize alignment"); + assert(MaxHeapSize % _heap_alignment == 0, "MaxHeapSize alignment"); } -void CollectorPolicy::initialize_size_info() { - // User inputs from -mx and ms must be aligned - _min_heap_byte_size = align_size_up(Arguments::min_heap_size(), _min_alignment); - _initial_heap_byte_size = align_size_up(InitialHeapSize, _min_alignment); - _max_heap_byte_size = align_size_up(MaxHeapSize, _max_alignment); +void CollectorPolicy::assert_size_info() { + assert(InitialHeapSize == _initial_heap_byte_size, "Discrepancy between InitialHeapSize flag and local storage"); + assert(MaxHeapSize == _max_heap_byte_size, "Discrepancy between MaxHeapSize flag and local storage"); + assert(_max_heap_byte_size >= _min_heap_byte_size, "Ergonomics decided on incompatible minimum and maximum heap sizes"); + assert(_initial_heap_byte_size >= _min_heap_byte_size, "Ergonomics decided on incompatible initial and minimum heap sizes"); + assert(_max_heap_byte_size >= _initial_heap_byte_size, "Ergonomics decided on incompatible initial and maximum heap sizes"); + assert(_min_heap_byte_size % _heap_alignment == 0, "min_heap_byte_size alignment"); + assert(_initial_heap_byte_size % _heap_alignment == 0, "initial_heap_byte_size alignment"); + assert(_max_heap_byte_size % _heap_alignment == 0, "max_heap_byte_size alignment"); +} +#endif // ASSERT + +void CollectorPolicy::initialize_flags() { + assert(_space_alignment != 0, "Space alignment not set up properly"); + assert(_heap_alignment != 0, "Heap alignment not set up properly"); + assert(_heap_alignment >= _space_alignment, + err_msg("heap_alignment: " SIZE_FORMAT " less than space_alignment: " SIZE_FORMAT, + _heap_alignment, _space_alignment)); + assert(_heap_alignment % _space_alignment == 0, + err_msg("heap_alignment: " SIZE_FORMAT " not aligned by space_alignment: " SIZE_FORMAT, + _heap_alignment, _space_alignment)); + + if (FLAG_IS_CMDLINE(MaxHeapSize)) { + if (FLAG_IS_CMDLINE(InitialHeapSize) && InitialHeapSize > MaxHeapSize) { + vm_exit_during_initialization("Initial heap size set to a larger value than the maximum heap size"); + } + if (_min_heap_byte_size != 0 && MaxHeapSize < _min_heap_byte_size) { + vm_exit_during_initialization("Incompatible minimum and maximum heap sizes specified"); + } + _max_heap_size_cmdline = true; + } // Check heap parameter properties - if (_initial_heap_byte_size < M) { + if (InitialHeapSize < M) { vm_exit_during_initialization("Too small initial heap"); } - // Check heap parameter properties if (_min_heap_byte_size < M) { vm_exit_during_initialization("Too small minimum heap"); } - if (_initial_heap_byte_size <= NewSize) { - // make sure there is at least some room in old space - vm_exit_during_initialization("Too small initial heap for new size specified"); + + // User inputs from -Xmx and -Xms must be aligned + _min_heap_byte_size = align_size_up(_min_heap_byte_size, _heap_alignment); + uintx aligned_initial_heap_size = align_size_up(InitialHeapSize, _heap_alignment); + uintx aligned_max_heap_size = align_size_up(MaxHeapSize, _heap_alignment); + + // Write back to flags if the values changed + if (aligned_initial_heap_size != InitialHeapSize) { + FLAG_SET_ERGO(uintx, InitialHeapSize, aligned_initial_heap_size); } - if (_max_heap_byte_size < _min_heap_byte_size) { - vm_exit_during_initialization("Incompatible minimum and maximum heap sizes specified"); - } - if (_initial_heap_byte_size < _min_heap_byte_size) { - vm_exit_during_initialization("Incompatible minimum and initial heap sizes specified"); - } - if (_max_heap_byte_size < _initial_heap_byte_size) { - vm_exit_during_initialization("Incompatible initial and maximum heap sizes specified"); + if (aligned_max_heap_size != MaxHeapSize) { + FLAG_SET_ERGO(uintx, MaxHeapSize, aligned_max_heap_size); } + if (FLAG_IS_CMDLINE(InitialHeapSize) && _min_heap_byte_size != 0 && + InitialHeapSize < _min_heap_byte_size) { + vm_exit_during_initialization("Incompatible minimum and initial heap sizes specified"); + } + if (!FLAG_IS_DEFAULT(InitialHeapSize) && InitialHeapSize > MaxHeapSize) { + FLAG_SET_ERGO(uintx, MaxHeapSize, InitialHeapSize); + } else if (!FLAG_IS_DEFAULT(MaxHeapSize) && InitialHeapSize > MaxHeapSize) { + FLAG_SET_ERGO(uintx, InitialHeapSize, MaxHeapSize); + if (InitialHeapSize < _min_heap_byte_size) { + _min_heap_byte_size = InitialHeapSize; + } + } + + _initial_heap_byte_size = InitialHeapSize; + _max_heap_byte_size = MaxHeapSize; + + FLAG_SET_ERGO(uintx, MinHeapDeltaBytes, align_size_up(MinHeapDeltaBytes, _space_alignment)); + + DEBUG_ONLY(CollectorPolicy::assert_flags();) +} + +void CollectorPolicy::initialize_size_info() { if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr("Minimum heap " SIZE_FORMAT " Initial heap " SIZE_FORMAT " Maximum heap " SIZE_FORMAT, _min_heap_byte_size, _initial_heap_byte_size, _max_heap_byte_size); } + + DEBUG_ONLY(CollectorPolicy::assert_size_info();) } bool CollectorPolicy::use_should_clear_all_soft_refs(bool v) { @@ -118,7 +171,7 @@ void CollectorPolicy::cleared_all_soft_refs() { _all_soft_refs_clear = true; } -size_t CollectorPolicy::compute_max_alignment() { +size_t CollectorPolicy::compute_heap_alignment() { // The card marking array and the offset arrays for old generations are // committed in os pages as well. Make sure they are entirely full (to // avoid partial page problems), e.g. if 512 bytes heap corresponds to 1 @@ -145,14 +198,21 @@ size_t CollectorPolicy::compute_max_alignment() { // GenCollectorPolicy methods. +GenCollectorPolicy::GenCollectorPolicy() : + _min_gen0_size(0), + _initial_gen0_size(0), + _max_gen0_size(0), + _gen_alignment(0), + _generations(NULL) +{} + size_t GenCollectorPolicy::scale_by_NewRatio_aligned(size_t base_size) { - return align_size_down_bounded(base_size / (NewRatio + 1), _min_alignment); + return align_size_down_bounded(base_size / (NewRatio + 1), _gen_alignment); } size_t GenCollectorPolicy::bound_minus_alignment(size_t desired_size, size_t maximum_size) { - size_t alignment = _min_alignment; - size_t max_minus = maximum_size - alignment; + size_t max_minus = maximum_size - _gen_alignment; return desired_size < max_minus ? desired_size : max_minus; } @@ -168,101 +228,181 @@ void GenCollectorPolicy::initialize_size_policy(size_t init_eden_size, GCTimeRatio); } -void GenCollectorPolicy::initialize_flags() { - // All sizes must be multiples of the generation granularity. - _min_alignment = (uintx) Generation::GenGrain; - _max_alignment = compute_max_alignment(); +size_t GenCollectorPolicy::young_gen_size_lower_bound() { + // The young generation must be aligned and have room for eden + two survivors + return align_size_up(3 * _space_alignment, _gen_alignment); +} +#ifdef ASSERT +void GenCollectorPolicy::assert_flags() { + CollectorPolicy::assert_flags(); + assert(NewSize >= _min_gen0_size, "Ergonomics decided on a too small young gen size"); + assert(NewSize <= MaxNewSize, "Ergonomics decided on incompatible initial and maximum young gen sizes"); + assert(FLAG_IS_DEFAULT(MaxNewSize) || MaxNewSize < MaxHeapSize, "Ergonomics decided on incompatible maximum young gen and heap sizes"); + assert(NewSize % _gen_alignment == 0, "NewSize alignment"); + assert(FLAG_IS_DEFAULT(MaxNewSize) || MaxNewSize % _gen_alignment == 0, "MaxNewSize alignment"); +} + +void TwoGenerationCollectorPolicy::assert_flags() { + GenCollectorPolicy::assert_flags(); + assert(OldSize + NewSize <= MaxHeapSize, "Ergonomics decided on incompatible generation and heap sizes"); + assert(OldSize % _gen_alignment == 0, "OldSize alignment"); +} + +void GenCollectorPolicy::assert_size_info() { + CollectorPolicy::assert_size_info(); + // GenCollectorPolicy::initialize_size_info may update the MaxNewSize + assert(MaxNewSize < MaxHeapSize, "Ergonomics decided on incompatible maximum young and heap sizes"); + assert(NewSize == _initial_gen0_size, "Discrepancy between NewSize flag and local storage"); + assert(MaxNewSize == _max_gen0_size, "Discrepancy between MaxNewSize flag and local storage"); + assert(_min_gen0_size <= _initial_gen0_size, "Ergonomics decided on incompatible minimum and initial young gen sizes"); + assert(_initial_gen0_size <= _max_gen0_size, "Ergonomics decided on incompatible initial and maximum young gen sizes"); + assert(_min_gen0_size % _gen_alignment == 0, "_min_gen0_size alignment"); + assert(_initial_gen0_size % _gen_alignment == 0, "_initial_gen0_size alignment"); + assert(_max_gen0_size % _gen_alignment == 0, "_max_gen0_size alignment"); +} + +void TwoGenerationCollectorPolicy::assert_size_info() { + GenCollectorPolicy::assert_size_info(); + assert(OldSize == _initial_gen1_size, "Discrepancy between OldSize flag and local storage"); + assert(_min_gen1_size <= _initial_gen1_size, "Ergonomics decided on incompatible minimum and initial old gen sizes"); + assert(_initial_gen1_size <= _max_gen1_size, "Ergonomics decided on incompatible initial and maximum old gen sizes"); + assert(_max_gen1_size % _gen_alignment == 0, "_max_gen1_size alignment"); + assert(_initial_gen1_size % _gen_alignment == 0, "_initial_gen1_size alignment"); + assert(_max_heap_byte_size <= (_max_gen0_size + _max_gen1_size), "Total maximum heap sizes must be sum of generation maximum sizes"); +} +#endif // ASSERT + +void GenCollectorPolicy::initialize_flags() { CollectorPolicy::initialize_flags(); - // All generational heaps have a youngest gen; handle those flags here. + assert(_gen_alignment != 0, "Generation alignment not set up properly"); + assert(_heap_alignment >= _gen_alignment, + err_msg("heap_alignment: " SIZE_FORMAT " less than gen_alignment: " SIZE_FORMAT, + _heap_alignment, _gen_alignment)); + assert(_gen_alignment % _space_alignment == 0, + err_msg("gen_alignment: " SIZE_FORMAT " not aligned by space_alignment: " SIZE_FORMAT, + _gen_alignment, _space_alignment)); + assert(_heap_alignment % _gen_alignment == 0, + err_msg("heap_alignment: " SIZE_FORMAT " not aligned by gen_alignment: " SIZE_FORMAT, + _heap_alignment, _gen_alignment)); - // Adjust max size parameters - if (NewSize > MaxNewSize) { - MaxNewSize = NewSize; + // All generational heaps have a youngest gen; handle those flags here + + // Make sure the heap is large enough for two generations + uintx smallest_new_size = young_gen_size_lower_bound(); + uintx smallest_heap_size = align_size_up(smallest_new_size + align_size_up(_space_alignment, _gen_alignment), + _heap_alignment); + if (MaxHeapSize < smallest_heap_size) { + FLAG_SET_ERGO(uintx, MaxHeapSize, smallest_heap_size); + _max_heap_byte_size = MaxHeapSize; + } + // If needed, synchronize _min_heap_byte size and _initial_heap_byte_size + if (_min_heap_byte_size < smallest_heap_size) { + _min_heap_byte_size = smallest_heap_size; + if (InitialHeapSize < _min_heap_byte_size) { + FLAG_SET_ERGO(uintx, InitialHeapSize, smallest_heap_size); + _initial_heap_byte_size = smallest_heap_size; + } } - NewSize = align_size_down(NewSize, _min_alignment); - MaxNewSize = align_size_down(MaxNewSize, _min_alignment); - // Check validity of heap flags - assert(NewSize % _min_alignment == 0, "eden space alignment"); - assert(MaxNewSize % _min_alignment == 0, "survivor space alignment"); + // Now take the actual NewSize into account. We will silently increase NewSize + // if the user specified a smaller value. + smallest_new_size = MAX2(smallest_new_size, (uintx)align_size_down(NewSize, _gen_alignment)); + if (smallest_new_size != NewSize) { + FLAG_SET_ERGO(uintx, NewSize, smallest_new_size); + } + _initial_gen0_size = NewSize; - if (NewSize < 3 * _min_alignment) { - // make sure there room for eden and two survivor spaces - vm_exit_during_initialization("Too small new size specified"); + if (!FLAG_IS_DEFAULT(MaxNewSize)) { + uintx min_new_size = MAX2(_gen_alignment, _min_gen0_size); + + if (MaxNewSize >= MaxHeapSize) { + // Make sure there is room for an old generation + uintx smaller_max_new_size = MaxHeapSize - _gen_alignment; + if (FLAG_IS_CMDLINE(MaxNewSize)) { + warning("MaxNewSize (" SIZE_FORMAT "k) is equal to or greater than the entire " + "heap (" SIZE_FORMAT "k). A new max generation size of " SIZE_FORMAT "k will be used.", + MaxNewSize/K, MaxHeapSize/K, smaller_max_new_size/K); + } + FLAG_SET_ERGO(uintx, MaxNewSize, smaller_max_new_size); + if (NewSize > MaxNewSize) { + FLAG_SET_ERGO(uintx, NewSize, MaxNewSize); + _initial_gen0_size = NewSize; + } + } else if (MaxNewSize < min_new_size) { + FLAG_SET_ERGO(uintx, MaxNewSize, min_new_size); + } else if (!is_size_aligned(MaxNewSize, _gen_alignment)) { + FLAG_SET_ERGO(uintx, MaxNewSize, align_size_down(MaxNewSize, _gen_alignment)); + } + _max_gen0_size = MaxNewSize; + } + + if (NewSize > MaxNewSize) { + // At this point this should only happen if the user specifies a large NewSize and/or + // a small (but not too small) MaxNewSize. + if (FLAG_IS_CMDLINE(MaxNewSize)) { + warning("NewSize (" SIZE_FORMAT "k) is greater than the MaxNewSize (" SIZE_FORMAT "k). " + "A new max generation size of " SIZE_FORMAT "k will be used.", + NewSize/K, MaxNewSize/K, NewSize/K); + } + FLAG_SET_ERGO(uintx, MaxNewSize, NewSize); + _max_gen0_size = MaxNewSize; } if (SurvivorRatio < 1 || NewRatio < 1) { vm_exit_during_initialization("Invalid young gen ratio specified"); } + + DEBUG_ONLY(GenCollectorPolicy::assert_flags();) } void TwoGenerationCollectorPolicy::initialize_flags() { GenCollectorPolicy::initialize_flags(); - OldSize = align_size_down(OldSize, _min_alignment); + if (!is_size_aligned(OldSize, _gen_alignment)) { + FLAG_SET_ERGO(uintx, OldSize, align_size_down(OldSize, _gen_alignment)); + } - if (FLAG_IS_CMDLINE(OldSize) && FLAG_IS_DEFAULT(NewSize)) { + if (FLAG_IS_CMDLINE(OldSize) && FLAG_IS_DEFAULT(MaxHeapSize)) { // NewRatio will be used later to set the young generation size so we use // it to calculate how big the heap should be based on the requested OldSize // and NewRatio. assert(NewRatio > 0, "NewRatio should have been set up earlier"); size_t calculated_heapsize = (OldSize / NewRatio) * (NewRatio + 1); - calculated_heapsize = align_size_up(calculated_heapsize, _max_alignment); - MaxHeapSize = calculated_heapsize; - InitialHeapSize = calculated_heapsize; + calculated_heapsize = align_size_up(calculated_heapsize, _heap_alignment); + FLAG_SET_ERGO(uintx, MaxHeapSize, calculated_heapsize); + _max_heap_byte_size = MaxHeapSize; + FLAG_SET_ERGO(uintx, InitialHeapSize, calculated_heapsize); + _initial_heap_byte_size = InitialHeapSize; } - MaxHeapSize = align_size_up(MaxHeapSize, _max_alignment); // adjust max heap size if necessary if (NewSize + OldSize > MaxHeapSize) { - if (FLAG_IS_CMDLINE(MaxHeapSize)) { + if (_max_heap_size_cmdline) { // somebody set a maximum heap size with the intention that we should not // exceed it. Adjust New/OldSize as necessary. uintx calculated_size = NewSize + OldSize; double shrink_factor = (double) MaxHeapSize / calculated_size; - // align - NewSize = align_size_down((uintx) (NewSize * shrink_factor), _min_alignment); - // OldSize is already aligned because above we aligned MaxHeapSize to - // _max_alignment, and we just made sure that NewSize is aligned to - // _min_alignment. In initialize_flags() we verified that _max_alignment - // is a multiple of _min_alignment. - OldSize = MaxHeapSize - NewSize; - } else { - MaxHeapSize = NewSize + OldSize; - } - } - // need to do this again - MaxHeapSize = align_size_up(MaxHeapSize, _max_alignment); + uintx smaller_new_size = align_size_down((uintx)(NewSize * shrink_factor), _gen_alignment); + FLAG_SET_ERGO(uintx, NewSize, MAX2(young_gen_size_lower_bound(), smaller_new_size)); + _initial_gen0_size = NewSize; - // adjust max heap size if necessary - if (NewSize + OldSize > MaxHeapSize) { - if (FLAG_IS_CMDLINE(MaxHeapSize)) { - // somebody set a maximum heap size with the intention that we should not - // exceed it. Adjust New/OldSize as necessary. - uintx calculated_size = NewSize + OldSize; - double shrink_factor = (double) MaxHeapSize / calculated_size; - // align - NewSize = align_size_down((uintx) (NewSize * shrink_factor), _min_alignment); // OldSize is already aligned because above we aligned MaxHeapSize to - // _max_alignment, and we just made sure that NewSize is aligned to - // _min_alignment. In initialize_flags() we verified that _max_alignment - // is a multiple of _min_alignment. - OldSize = MaxHeapSize - NewSize; + // _heap_alignment, and we just made sure that NewSize is aligned to + // _gen_alignment. In initialize_flags() we verified that _heap_alignment + // is a multiple of _gen_alignment. + FLAG_SET_ERGO(uintx, OldSize, MaxHeapSize - NewSize); } else { - MaxHeapSize = NewSize + OldSize; + FLAG_SET_ERGO(uintx, MaxHeapSize, align_size_up(NewSize + OldSize, _heap_alignment)); + _max_heap_byte_size = MaxHeapSize; } } - // need to do this again - MaxHeapSize = align_size_up(MaxHeapSize, _max_alignment); always_do_update_barrier = UseConcMarkSweepGC; - // Check validity of heap flags - assert(OldSize % _min_alignment == 0, "old space alignment"); - assert(MaxHeapSize % _max_alignment == 0, "maximum heap alignment"); + DEBUG_ONLY(TwoGenerationCollectorPolicy::assert_flags();) } // Values set on the command line win over any ergonomically @@ -277,7 +417,7 @@ void TwoGenerationCollectorPolicy::initialize_flags() { void GenCollectorPolicy::initialize_size_info() { CollectorPolicy::initialize_size_info(); - // _min_alignment is used for alignment within a generation. + // _space_alignment is used for alignment within a generation. // There is additional alignment done down stream for some // collectors that sometimes causes unwanted rounding up of // generations sizes. @@ -285,35 +425,8 @@ void GenCollectorPolicy::initialize_size_info() { // Determine maximum size of gen0 size_t max_new_size = 0; - if (FLAG_IS_CMDLINE(MaxNewSize) || FLAG_IS_ERGO(MaxNewSize)) { - if (MaxNewSize < _min_alignment) { - max_new_size = _min_alignment; - } - if (MaxNewSize >= _max_heap_byte_size) { - max_new_size = align_size_down(_max_heap_byte_size - _min_alignment, - _min_alignment); - warning("MaxNewSize (" SIZE_FORMAT "k) is equal to or " - "greater than the entire heap (" SIZE_FORMAT "k). A " - "new generation size of " SIZE_FORMAT "k will be used.", - MaxNewSize/K, _max_heap_byte_size/K, max_new_size/K); - } else { - max_new_size = align_size_down(MaxNewSize, _min_alignment); - } - - // The case for FLAG_IS_ERGO(MaxNewSize) could be treated - // specially at this point to just use an ergonomically set - // MaxNewSize to set max_new_size. For cases with small - // heaps such a policy often did not work because the MaxNewSize - // was larger than the entire heap. The interpretation given - // to ergonomically set flags is that the flags are set - // by different collectors for their own special needs but - // are not allowed to badly shape the heap. This allows the - // different collectors to decide what's best for themselves - // without having to factor in the overall heap shape. It - // can be the case in the future that the collectors would - // only make "wise" ergonomics choices and this policy could - // just accept those choices. The choices currently made are - // not always "wise". + if (!FLAG_IS_DEFAULT(MaxNewSize)) { + max_new_size = MaxNewSize; } else { max_new_size = scale_by_NewRatio_aligned(_max_heap_byte_size); // Bound the maximum size by NewSize below (since it historically @@ -382,11 +495,22 @@ void GenCollectorPolicy::initialize_size_info() { _min_gen0_size = MIN2(_min_gen0_size, _initial_gen0_size); } + // Write back to flags if necessary + if (NewSize != _initial_gen0_size) { + FLAG_SET_ERGO(uintx, NewSize, _initial_gen0_size); + } + + if (MaxNewSize != _max_gen0_size) { + FLAG_SET_ERGO(uintx, MaxNewSize, _max_gen0_size); + } + if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr("1: Minimum gen0 " SIZE_FORMAT " Initial gen0 " SIZE_FORMAT " Maximum gen0 " SIZE_FORMAT, _min_gen0_size, _initial_gen0_size, _max_gen0_size); } + + DEBUG_ONLY(GenCollectorPolicy::assert_size_info();) } // Call this method during the sizing of the gen1 to make @@ -404,14 +528,15 @@ bool TwoGenerationCollectorPolicy::adjust_gen0_sizes(size_t* gen0_size_ptr, bool result = false; if ((*gen1_size_ptr + *gen0_size_ptr) > heap_size) { + uintx smallest_new_size = young_gen_size_lower_bound(); if ((heap_size < (*gen0_size_ptr + min_gen1_size)) && - (heap_size >= min_gen1_size + _min_alignment)) { + (heap_size >= min_gen1_size + smallest_new_size)) { // Adjust gen0 down to accommodate min_gen1_size - *gen0_size_ptr = align_size_down_bounded(heap_size - min_gen1_size, _min_alignment); + *gen0_size_ptr = align_size_down_bounded(heap_size - min_gen1_size, _gen_alignment); assert(*gen0_size_ptr > 0, "Min gen0 is too large"); result = true; } else { - *gen1_size_ptr = align_size_down_bounded(heap_size - *gen0_size_ptr, _min_alignment); + *gen1_size_ptr = align_size_down_bounded(heap_size - *gen0_size_ptr, _gen_alignment); } } return result; @@ -432,36 +557,31 @@ void TwoGenerationCollectorPolicy::initialize_size_info() { // The maximum gen1 size can be determined from the maximum gen0 // and maximum heap size since no explicit flags exits // for setting the gen1 maximum. - _max_gen1_size = _max_heap_byte_size - _max_gen0_size; - _max_gen1_size = - MAX2((uintx)align_size_down(_max_gen1_size, _min_alignment), _min_alignment); + _max_gen1_size = MAX2(_max_heap_byte_size - _max_gen0_size, _gen_alignment); + // If no explicit command line flag has been set for the // gen1 size, use what is left for gen1. - if (FLAG_IS_DEFAULT(OldSize) || FLAG_IS_ERGO(OldSize)) { - // The user has not specified any value or ergonomics - // has chosen a value (which may or may not be consistent + if (!FLAG_IS_CMDLINE(OldSize)) { + // The user has not specified any value but the ergonomics + // may have chosen a value (which may or may not be consistent // with the overall heap size). In either case make // the minimum, maximum and initial sizes consistent // with the gen0 sizes and the overall heap sizes. - assert(_min_heap_byte_size > _min_gen0_size, - "gen0 has an unexpected minimum size"); - _min_gen1_size = _min_heap_byte_size - _min_gen0_size; - _min_gen1_size = - MAX2((uintx)align_size_down(_min_gen1_size, _min_alignment), _min_alignment); - _initial_gen1_size = _initial_heap_byte_size - _initial_gen0_size; - _initial_gen1_size = - MAX2((uintx)align_size_down(_initial_gen1_size, _min_alignment), _min_alignment); + _min_gen1_size = MAX2(_min_heap_byte_size - _min_gen0_size, _gen_alignment); + _initial_gen1_size = MAX2(_initial_heap_byte_size - _initial_gen0_size, _gen_alignment); + // _max_gen1_size has already been made consistent above + FLAG_SET_ERGO(uintx, OldSize, _initial_gen1_size); } else { // It's been explicitly set on the command line. Use the // OldSize and then determine the consequences. - _min_gen1_size = OldSize; + _min_gen1_size = MIN2(OldSize, _min_heap_byte_size - _min_gen0_size); _initial_gen1_size = OldSize; // If the user has explicitly set an OldSize that is inconsistent // with other command line flags, issue a warning. // The generation minimums and the overall heap mimimum should - // be within one heap alignment. - if ((_min_gen1_size + _min_gen0_size + _min_alignment) < _min_heap_byte_size) { + // be within one generation alignment. + if ((_min_gen1_size + _min_gen0_size + _gen_alignment) < _min_heap_byte_size) { warning("Inconsistency between minimum heap size and minimum " "generation sizes: using minimum heap = " SIZE_FORMAT, _min_heap_byte_size); @@ -475,7 +595,7 @@ void TwoGenerationCollectorPolicy::initialize_size_info() { // If there is an inconsistency between the OldSize and the minimum and/or // initial size of gen0, since OldSize was explicitly set, OldSize wins. if (adjust_gen0_sizes(&_min_gen0_size, &_min_gen1_size, - _min_heap_byte_size, OldSize)) { + _min_heap_byte_size, _min_gen1_size)) { if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr("2: Minimum gen0 " SIZE_FORMAT " Initial gen0 " SIZE_FORMAT " Maximum gen0 " SIZE_FORMAT, @@ -484,7 +604,7 @@ void TwoGenerationCollectorPolicy::initialize_size_info() { } // Initial size if (adjust_gen0_sizes(&_initial_gen0_size, &_initial_gen1_size, - _initial_heap_byte_size, OldSize)) { + _initial_heap_byte_size, _initial_gen1_size)) { if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr("3: Minimum gen0 " SIZE_FORMAT " Initial gen0 " SIZE_FORMAT " Maximum gen0 " SIZE_FORMAT, @@ -499,11 +619,26 @@ void TwoGenerationCollectorPolicy::initialize_size_info() { _initial_gen1_size = MAX2(_initial_gen1_size, _min_gen1_size); _initial_gen1_size = MIN2(_initial_gen1_size, _max_gen1_size); + // Write back to flags if necessary + if (NewSize != _initial_gen0_size) { + FLAG_SET_ERGO(uintx, NewSize, _max_gen0_size); + } + + if (MaxNewSize != _max_gen0_size) { + FLAG_SET_ERGO(uintx, MaxNewSize, _max_gen0_size); + } + + if (OldSize != _initial_gen1_size) { + FLAG_SET_ERGO(uintx, OldSize, _initial_gen1_size); + } + if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr("Minimum gen1 " SIZE_FORMAT " Initial gen1 " SIZE_FORMAT " Maximum gen1 " SIZE_FORMAT, _min_gen1_size, _initial_gen1_size, _max_gen1_size); } + + DEBUG_ONLY(TwoGenerationCollectorPolicy::assert_size_info();) } HeapWord* GenCollectorPolicy::mem_allocate_work(size_t size, @@ -826,8 +961,9 @@ bool GenCollectorPolicy::should_try_older_generation_allocation( // MarkSweepPolicy methods // -MarkSweepPolicy::MarkSweepPolicy() { - initialize_all(); +void MarkSweepPolicy::initialize_alignments() { + _space_alignment = _gen_alignment = (uintx)Generation::GenGrain; + _heap_alignment = compute_heap_alignment(); } void MarkSweepPolicy::initialize_generations() { diff --git a/hotspot/src/share/vm/memory/collectorPolicy.hpp b/hotspot/src/share/vm/memory/collectorPolicy.hpp index bbfccdd644c..509702319d0 100644 --- a/hotspot/src/share/vm/memory/collectorPolicy.hpp +++ b/hotspot/src/share/vm/memory/collectorPolicy.hpp @@ -61,17 +61,23 @@ class CollectorPolicy : public CHeapObj { protected: GCPolicyCounters* _gc_policy_counters; - // Requires that the concrete subclass sets the alignment constraints - // before calling. + virtual void initialize_alignments() = 0; virtual void initialize_flags(); virtual void initialize_size_info(); + DEBUG_ONLY(virtual void assert_flags();) + DEBUG_ONLY(virtual void assert_size_info();) + size_t _initial_heap_byte_size; size_t _max_heap_byte_size; size_t _min_heap_byte_size; - size_t _min_alignment; - size_t _max_alignment; + size_t _space_alignment; + size_t _heap_alignment; + + // Needed to keep information if MaxHeapSize was set on the command line + // when the flag value is aligned etc by ergonomics + bool _max_heap_size_cmdline; // The sizing of the heap are controlled by a sizing policy. AdaptiveSizePolicy* _size_policy; @@ -87,23 +93,20 @@ class CollectorPolicy : public CHeapObj { // mem_allocate() where it returns op.result() bool _all_soft_refs_clear; - CollectorPolicy() : - _min_alignment(1), - _max_alignment(1), - _initial_heap_byte_size(0), - _max_heap_byte_size(0), - _min_heap_byte_size(0), - _size_policy(NULL), - _should_clear_all_soft_refs(false), - _all_soft_refs_clear(false) - {} + CollectorPolicy(); public: - // Return maximum heap alignment that may be imposed by the policy - static size_t compute_max_alignment(); + virtual void initialize_all() { + initialize_alignments(); + initialize_flags(); + initialize_size_info(); + } - size_t min_alignment() { return _min_alignment; } - size_t max_alignment() { return _max_alignment; } + // Return maximum heap alignment that may be imposed by the policy + static size_t compute_heap_alignment(); + + size_t space_alignment() { return _space_alignment; } + size_t heap_alignment() { return _heap_alignment; } size_t initial_heap_byte_size() { return _initial_heap_byte_size; } size_t max_heap_byte_size() { return _max_heap_byte_size; } @@ -195,6 +198,9 @@ class CollectorPolicy : public CHeapObj { return false; } + // Do any updates required to global flags that are due to heap initialization + // changes + virtual void post_heap_initialize() = 0; }; class ClearedAllSoftRefs : public StackObj { @@ -219,6 +225,10 @@ class GenCollectorPolicy : public CollectorPolicy { size_t _initial_gen0_size; size_t _max_gen0_size; + // _gen_alignment and _space_alignment will have the same value most of the + // time. When using large pages they can differ. + size_t _gen_alignment; + GenerationSpec **_generations; // Return true if an allocation should be attempted in the older @@ -229,23 +239,31 @@ class GenCollectorPolicy : public CollectorPolicy { void initialize_flags(); void initialize_size_info(); + DEBUG_ONLY(void assert_flags();) + DEBUG_ONLY(void assert_size_info();) + // Try to allocate space by expanding the heap. virtual HeapWord* expand_heap_and_allocate(size_t size, bool is_tlab); - // Scale the base_size by NewRation according to + // Compute max heap alignment + size_t compute_max_alignment(); + + // Scale the base_size by NewRatio according to // result = base_size / (NewRatio + 1) // and align by min_alignment() size_t scale_by_NewRatio_aligned(size_t base_size); - // Bound the value by the given maximum minus the - // min_alignment. + // Bound the value by the given maximum minus the min_alignment size_t bound_minus_alignment(size_t desired_size, size_t maximum_size); public: + GenCollectorPolicy(); + // Accessors size_t min_gen0_size() { return _min_gen0_size; } size_t initial_gen0_size() { return _initial_gen0_size; } size_t max_gen0_size() { return _max_gen0_size; } + size_t gen_alignment() { return _gen_alignment; } virtual int number_of_generations() = 0; @@ -256,14 +274,15 @@ class GenCollectorPolicy : public CollectorPolicy { virtual GenCollectorPolicy* as_generation_policy() { return this; } - virtual void initialize_generations() = 0; + virtual void initialize_generations() { }; virtual void initialize_all() { - initialize_flags(); - initialize_size_info(); + CollectorPolicy::initialize_all(); initialize_generations(); } + size_t young_gen_size_lower_bound(); + HeapWord* mem_allocate_work(size_t size, bool is_tlab, bool* gc_overhead_limit_was_exceeded); @@ -275,10 +294,8 @@ class GenCollectorPolicy : public CollectorPolicy { size_t init_promo_size, size_t init_survivor_size); - // The alignment used for eden and survivors within the young gen - // and for boundary between young gen and old gen. - static size_t intra_heap_alignment() { - return 64 * K * HeapWordSize; + virtual void post_heap_initialize() { + assert(_max_gen0_size == MaxNewSize, "Should be taken care of by initialize_size_info"); } }; @@ -296,9 +313,14 @@ class TwoGenerationCollectorPolicy : public GenCollectorPolicy { void initialize_flags(); void initialize_size_info(); - void initialize_generations() { ShouldNotReachHere(); } + + DEBUG_ONLY(void assert_flags();) + DEBUG_ONLY(void assert_size_info();) public: + TwoGenerationCollectorPolicy() : GenCollectorPolicy(), _min_gen1_size(0), + _initial_gen1_size(0), _max_gen1_size(0) {} + // Accessors size_t min_gen1_size() { return _min_gen1_size; } size_t initial_gen1_size() { return _initial_gen1_size; } @@ -321,10 +343,11 @@ class TwoGenerationCollectorPolicy : public GenCollectorPolicy { class MarkSweepPolicy : public TwoGenerationCollectorPolicy { protected: + void initialize_alignments(); void initialize_generations(); public: - MarkSweepPolicy(); + MarkSweepPolicy() {} MarkSweepPolicy* as_mark_sweep_policy() { return this; } diff --git a/hotspot/src/share/vm/memory/defNewGeneration.cpp b/hotspot/src/share/vm/memory/defNewGeneration.cpp index 0b4af29a3e3..ca3ff46b167 100644 --- a/hotspot/src/share/vm/memory/defNewGeneration.cpp +++ b/hotspot/src/share/vm/memory/defNewGeneration.cpp @@ -204,7 +204,7 @@ DefNewGeneration::DefNewGeneration(ReservedSpace rs, // Compute the maximum eden and survivor space sizes. These sizes // are computed assuming the entire reserved space is committed. // These values are exported as performance counters. - uintx alignment = GenCollectedHeap::heap()->collector_policy()->min_alignment(); + uintx alignment = GenCollectedHeap::heap()->collector_policy()->space_alignment(); uintx size = _virtual_space.reserved_size(); _max_survivor_size = compute_survivor_size(size, alignment); _max_eden_size = size - (2*_max_survivor_size); @@ -235,7 +235,7 @@ void DefNewGeneration::compute_space_boundaries(uintx minimum_eden_size, bool clear_space, bool mangle_space) { uintx alignment = - GenCollectedHeap::heap()->collector_policy()->min_alignment(); + GenCollectedHeap::heap()->collector_policy()->space_alignment(); // If the spaces are being cleared (only done at heap initialization // currently), the survivor spaces need not be empty. @@ -473,7 +473,7 @@ size_t DefNewGeneration::free() const { } size_t DefNewGeneration::max_capacity() const { - const size_t alignment = GenCollectedHeap::heap()->collector_policy()->min_alignment(); + const size_t alignment = GenCollectedHeap::heap()->collector_policy()->space_alignment(); const size_t reserved_bytes = reserved().byte_size(); return reserved_bytes - compute_survivor_size(reserved_bytes, alignment); } diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.cpp b/hotspot/src/share/vm/memory/genCollectedHeap.cpp index 2b84542ef48..aa6f24bd23e 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp @@ -111,7 +111,7 @@ jint GenCollectedHeap::initialize() { int n_covered_regions = 0; ReservedSpace heap_rs; - size_t heap_alignment = collector_policy()->max_alignment(); + size_t heap_alignment = collector_policy()->heap_alignment(); heap_address = allocate(heap_alignment, &total_reserved, &n_covered_regions, &heap_rs); diff --git a/hotspot/src/share/vm/memory/sharedHeap.cpp b/hotspot/src/share/vm/memory/sharedHeap.cpp index 79455db9b6e..47ebc180c8e 100644 --- a/hotspot/src/share/vm/memory/sharedHeap.cpp +++ b/hotspot/src/share/vm/memory/sharedHeap.cpp @@ -247,6 +247,7 @@ void SharedHeap::set_barrier_set(BarrierSet* bs) { } void SharedHeap::post_initialize() { + CollectedHeap::post_initialize(); ref_processing_init(); } diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index 18c9733076c..5dc76f703d3 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -765,6 +765,7 @@ jint Universe::initialize_heap() { } else if (UseG1GC) { #if INCLUDE_ALL_GCS G1CollectorPolicy* g1p = new G1CollectorPolicy(); + g1p->initialize_all(); G1CollectedHeap* g1h = new G1CollectedHeap(g1p); Universe::_collectedHeap = g1h; #else // INCLUDE_ALL_GCS @@ -789,6 +790,7 @@ jint Universe::initialize_heap() { } else { // default old generation gc_policy = new MarkSweepPolicy(); } + gc_policy->initialize_all(); Universe::_collectedHeap = new GenCollectedHeap(gc_policy); } diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp index 6f6a2000a3f..556de7ec96a 100644 --- a/hotspot/src/share/vm/prims/whitebox.cpp +++ b/hotspot/src/share/vm/prims/whitebox.cpp @@ -105,7 +105,7 @@ WB_ENTRY(void, WB_PrintHeapSizes(JNIEnv* env, jobject o)) { gclog_or_tty->print_cr("Minimum heap "SIZE_FORMAT" Initial heap " SIZE_FORMAT" Maximum heap "SIZE_FORMAT" Min alignment "SIZE_FORMAT" Max alignment "SIZE_FORMAT, p->min_heap_byte_size(), p->initial_heap_byte_size(), p->max_heap_byte_size(), - p->min_alignment(), p->max_alignment()); + p->space_alignment(), p->heap_alignment()); } WB_END diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 1e82e5bdca8..39f94be5c79 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -1505,7 +1505,7 @@ void Arguments::set_conservative_max_heap_alignment() { } #endif // INCLUDE_ALL_GCS _conservative_max_heap_alignment = MAX3(heap_alignment, os::max_page_size(), - CollectorPolicy::compute_max_alignment()); + CollectorPolicy::compute_heap_alignment()); } void Arguments::set_ergonomics_flags() { @@ -2165,6 +2165,10 @@ bool Arguments::check_vm_args_consistency() { #if INCLUDE_ALL_GCS if (UseG1GC) { + status = status && verify_percentage(G1NewSizePercent, "G1NewSizePercent"); + status = status && verify_percentage(G1MaxNewSizePercent, "G1MaxNewSizePercent"); + status = status && verify_interval(G1NewSizePercent, 0, G1MaxNewSizePercent, "G1NewSizePercent"); + status = status && verify_percentage(InitiatingHeapOccupancyPercent, "InitiatingHeapOccupancyPercent"); status = status && verify_min_value(G1RefProcDrainInterval, 1, diff --git a/hotspot/test/gc/arguments/TestMaxHeapSizeTools.java b/hotspot/test/gc/arguments/TestMaxHeapSizeTools.java index cb7d841355e..0e07f794194 100644 --- a/hotspot/test/gc/arguments/TestMaxHeapSizeTools.java +++ b/hotspot/test/gc/arguments/TestMaxHeapSizeTools.java @@ -64,32 +64,29 @@ class TestMaxHeapSizeTools { long newPlusOldSize = values[0] + values[1]; long smallValue = newPlusOldSize / 2; long largeValue = newPlusOldSize * 2; + long maxHeapSize = largeValue + (2 * 1024 * 1024); // -Xms is not set - checkErgonomics(new String[] { gcflag, "-Xmx16M" }, values, -1, -1); - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-XX:InitialHeapSize=" + smallValue }, values, smallValue, smallValue); - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-XX:InitialHeapSize=" + largeValue }, values, -1, largeValue); - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-XX:InitialHeapSize=0" }, values, -1, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize }, values, -1, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:InitialHeapSize=" + smallValue }, values, -1, smallValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:InitialHeapSize=" + largeValue }, values, -1, largeValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:InitialHeapSize=0" }, values, -1, -1); // -Xms is set to zero - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms0" }, values, -1, -1); - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms0", "-XX:InitialHeapSize=" + smallValue }, values, smallValue, smallValue); - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms0", "-XX:InitialHeapSize=" + largeValue }, values, -1, largeValue); - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms0", "-XX:InitialHeapSize=0" }, values, -1, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0" }, values, -1, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:InitialHeapSize=" + smallValue }, values, -1, smallValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:InitialHeapSize=" + largeValue }, values, -1, largeValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:InitialHeapSize=0" }, values, -1, -1); // -Xms is set to small value - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms" + smallValue }, values, -1, -1); - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms" + smallValue, "-XX:InitialHeapSize=" + smallValue }, values, smallValue, smallValue); - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms" + smallValue, "-XX:InitialHeapSize=" + largeValue }, values, smallValue, largeValue); - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms" + smallValue, "-XX:InitialHeapSize=0" }, values, smallValue, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue }, values, -1, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue, "-XX:InitialHeapSize=" + smallValue }, values, smallValue, smallValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue, "-XX:InitialHeapSize=" + largeValue }, values, smallValue, largeValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue, "-XX:InitialHeapSize=0" }, values, smallValue, -1); // -Xms is set to large value - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms" + largeValue }, values, largeValue, largeValue); - // the next case has already been checked elsewhere and gives an error - // checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms" + largeValue, "-XX:InitialHeapSize=" + smallValue }, values, smallValue, smallValue); - // the next case has already been checked elsewhere too - // checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms" + largeValue, "-XX:InitialHeapSize=" + largeValue }, values, values[0], largeValue); - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms" + largeValue, "-XX:InitialHeapSize=0" }, values, largeValue, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + largeValue }, values, largeValue, largeValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + largeValue, "-XX:InitialHeapSize=0" }, values, largeValue, -1); } private static long align_up(long value, long alignment) { diff --git a/hotspot/test/gc/arguments/TestMaxNewSize.java b/hotspot/test/gc/arguments/TestMaxNewSize.java new file mode 100644 index 00000000000..af20cb819e3 --- /dev/null +++ b/hotspot/test/gc/arguments/TestMaxNewSize.java @@ -0,0 +1,122 @@ +/* +* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 only, as +* published by the Free Software Foundation. +* +* This code is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* version 2 for more details (a copy is included in the LICENSE file that +* accompanied this code). +* +* You should have received a copy of the GNU General Public License version +* 2 along with this work; if not, write to the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +* or visit www.oracle.com if you need additional information or have any +* questions. +*/ + +/* + * @test TestMaxNewSize + * @key gc + * @bug 7057939 + * @summary Make sure that MaxNewSize always has a useful value after argument + * processing. + * @library /testlibrary + * @build TestMaxNewSize + * @run main TestMaxNewSize -XX:+UseSerialGC + * @run main TestMaxNewSize -XX:+UseParallelGC + * @run main TestMaxNewSize -XX:+UseConcMarkSweepGC + * @run main TestMaxNewSize -XX:+UseG1GC + * @author thomas.schatzl@oracle.com, jesper.wilhelmsson@oracle.com + */ + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import java.math.BigInteger; + +import java.util.ArrayList; +import java.util.Arrays; + +import com.oracle.java.testlibrary.*; + +public class TestMaxNewSize { + + private static void checkMaxNewSize(String[] flags, int heapsize) throws Exception { + BigInteger actual = new BigInteger(getMaxNewSize(flags)); + System.out.println(actual); + if (actual.compareTo(new BigInteger((new Long(heapsize)).toString())) == 1) { + throw new RuntimeException("MaxNewSize value set to \"" + actual + + "\", expected otherwise when running with the following flags: " + Arrays.asList(flags).toString()); + } + } + + private static void checkIncompatibleNewSize(String[] flags) throws Exception { + ArrayList finalargs = new ArrayList(); + finalargs.addAll(Arrays.asList(flags)); + finalargs.add("-version"); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(finalargs.toArray(new String[0])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Initial young gen size set larger than the maximum young gen size"); + } + + private static boolean isRunningG1(String[] args) { + for (int i = 0; i < args.length; i++) { + if (args[i].contains("+UseG1GC")) { + return true; + } + } + return false; + } + + private static String getMaxNewSize(String[] flags) throws Exception { + ArrayList finalargs = new ArrayList(); + finalargs.addAll(Arrays.asList(flags)); + if (isRunningG1(flags)) { + finalargs.add("-XX:G1HeapRegionSize=1M"); + } + finalargs.add("-XX:+PrintFlagsFinal"); + finalargs.add("-version"); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(finalargs.toArray(new String[0])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + String stdout = output.getStdout(); + //System.out.println(stdout); + return getFlagValue("MaxNewSize", stdout); + } + + private static String getFlagValue(String flag, String where) { + Matcher m = Pattern.compile(flag + "\\s+:?=\\s+\\d+").matcher(where); + if (!m.find()) { + throw new RuntimeException("Could not find value for flag " + flag + " in output string"); + } + String match = m.group(); + return match.substring(match.lastIndexOf(" ") + 1, match.length()); + } + + public static void main(String args[]) throws Exception { + String gcName = args[0]; + final int M32 = 32 * 1024 * 1024; + final int M64 = 64 * 1024 * 1024; + final int M96 = 96 * 1024 * 1024; + final int M128 = 128 * 1024 * 1024; + checkMaxNewSize(new String[] { gcName, "-Xmx128M" }, M128); + checkMaxNewSize(new String[] { gcName, "-Xmx128M", "-XX:NewRatio=5" }, M128); + checkMaxNewSize(new String[] { gcName, "-Xmx128M", "-XX:NewSize=32M" }, M128); + checkMaxNewSize(new String[] { gcName, "-Xmx128M", "-XX:OldSize=96M" }, M128); + checkMaxNewSize(new String[] { gcName, "-Xmx128M", "-XX:MaxNewSize=32M" }, M32); + checkMaxNewSize(new String[] { gcName, "-Xmx128M", "-XX:NewSize=32M", "-XX:MaxNewSize=32M" }, M32); + checkMaxNewSize(new String[] { gcName, "-Xmx128M", "-XX:NewRatio=6", "-XX:MaxNewSize=32M" }, M32); + checkMaxNewSize(new String[] { gcName, "-Xmx128M", "-Xms96M" }, M128); + checkMaxNewSize(new String[] { gcName, "-Xmx96M", "-Xms96M" }, M96); + checkMaxNewSize(new String[] { gcName, "-XX:NewSize=128M", "-XX:MaxNewSize=50M"}, M128); + } +} From 53cdc28a02fcf3df17b2d07ce4cd289524ac4265 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 1 Nov 2013 21:45:02 +0400 Subject: [PATCH 008/110] 8026491: Typos in string literals Reviewed-by: alexsch, anthony --- .../macosx/classes/com/apple/laf/AquaFileChooserUI.java | 2 +- .../classes/com/apple/laf/resources/aqua.properties | 2 +- .../plugins/common/StandardMetadataFormatResources.java | 2 +- .../sun/jmx/snmp/daemon/SnmpSubBulkRequestHandler.java | 4 ++-- .../sun/jmx/snmp/daemon/SnmpSubNextRequestHandler.java | 4 ++-- .../com/sun/jmx/snmp/daemon/SnmpSubRequestHandler.java | 4 ++-- .../sun/tools/example/debug/gui/CommandInterpreter.java | 4 ++-- jdk/src/share/classes/com/sun/tools/script/shell/init.js | 2 +- .../com/sun/tools/script/shell/messages.properties | 2 +- .../javax/management/modelmbean/RequiredModelMBean.java | 4 ++-- jdk/src/share/classes/javax/swing/KeyboardManager.java | 2 +- .../classes/javax/swing/SortingFocusTraversalPolicy.java | 2 +- .../share/classes/javax/swing/text/AbstractDocument.java | 4 ++-- jdk/src/share/classes/sun/awt/AppContext.java | 2 +- .../management/snmp/jvminstr/JVM_MANAGEMENT_MIB_IMPL.java | 4 ++-- jdk/src/share/classes/sun/misc/ExtensionDependency.java | 2 +- jdk/src/share/classes/sun/rmi/rmic/RMIGenerator.java | 4 ++-- .../classes/sun/security/jgss/krb5/InitialToken.java | 2 +- .../classes/sun/security/jgss/spnego/SpNegoContext.java | 8 ++++---- .../share/demo/jfc/FileChooserDemo/FileChooserDemo.java | 4 ++-- .../share/native/sun/security/pkcs11/wrapper/p11_util.c | 6 +++--- jdk/src/share/sample/nio/chatserver/ClientReader.java | 2 +- jdk/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java | 2 +- .../windows/classes/sun/nio/ch/WindowsSelectorImpl.java | 2 +- .../classes/sun/security/krb5/internal/tools/Klist.java | 2 +- .../classes/sun/security/krb5/internal/tools/Ktab.java | 4 ++-- 26 files changed, 41 insertions(+), 41 deletions(-) diff --git a/jdk/src/macosx/classes/com/apple/laf/AquaFileChooserUI.java b/jdk/src/macosx/classes/com/apple/laf/AquaFileChooserUI.java index be4b5b72a32..5669d10b1a4 100644 --- a/jdk/src/macosx/classes/com/apple/laf/AquaFileChooserUI.java +++ b/jdk/src/macosx/classes/com/apple/laf/AquaFileChooserUI.java @@ -227,7 +227,7 @@ public class AquaFileChooserUI extends FileChooserUI { // Exist in basic.properties (though we might want to override) fileDescriptionText = UIManager.getString("FileChooser.fileDescriptionText"); directoryDescriptionText = UIManager.getString("FileChooser.directoryDescriptionText"); - newFolderErrorText = getString("FileChooser.newFolderErrorText", "Error occured during folder creation"); + newFolderErrorText = getString("FileChooser.newFolderErrorText", "Error occurred during folder creation"); saveButtonText = UIManager.getString("FileChooser.saveButtonText"); openButtonText = UIManager.getString("FileChooser.openButtonText"); diff --git a/jdk/src/macosx/classes/com/apple/laf/resources/aqua.properties b/jdk/src/macosx/classes/com/apple/laf/resources/aqua.properties index 17f7a94584a..ac147020ce7 100644 --- a/jdk/src/macosx/classes/com/apple/laf/resources/aqua.properties +++ b/jdk/src/macosx/classes/com/apple/laf/resources/aqua.properties @@ -38,7 +38,7 @@ ############ FILE CHOOSER STRINGS ############# FileChooser.fileDescription.textAndMnemonic=Generic File FileChooser.directoryDescription.textAndMnemonic=Directory -FileChooser.newFolderError.textAndMnemonic=Error occured during folder creation +FileChooser.newFolderError.textAndMnemonic=Error occurred during folder creation FileChooser.newFolderErrorSeparator= : FileChooser.acceptAllFileFilter.textAndMnemonic=All Files FileChooser.cancelButton.textAndMnemonic=Cancel diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormatResources.java b/jdk/src/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormatResources.java index 96f099cf222..00bf1ee323e 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormatResources.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormatResources.java @@ -123,7 +123,7 @@ public class StandardMetadataFormatResources extends ListResourceBundle { "The vertical position, in millimeters, where the image should be rendered on media " }, { "HorizontalPixelOffset", - "The horizonal position, in pixels, where the image should be rendered onto a raster display" }, + "The horizontal position, in pixels, where the image should be rendered onto a raster display" }, { "VerticalPixelOffset", "The vertical position, in pixels, where the image should be rendered onto a raster display" }, diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/daemon/SnmpSubBulkRequestHandler.java b/jdk/src/share/classes/com/sun/jmx/snmp/daemon/SnmpSubBulkRequestHandler.java index 6dc479f242c..aa349526456 100644 --- a/jdk/src/share/classes/com/sun/jmx/snmp/daemon/SnmpSubBulkRequestHandler.java +++ b/jdk/src/share/classes/com/sun/jmx/snmp/daemon/SnmpSubBulkRequestHandler.java @@ -111,7 +111,7 @@ class SnmpSubBulkRequestHandler extends SnmpSubRequestHandler { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpSubRequestHandler.class.getName(), "run", "[" + Thread.currentThread() + - "]:an Snmp error occured during the operation", x); + "]:an Snmp error occurred during the operation", x); } } catch(Exception x) { @@ -119,7 +119,7 @@ class SnmpSubBulkRequestHandler extends SnmpSubRequestHandler { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpSubRequestHandler.class.getName(), "run", "[" + Thread.currentThread() + - "]:a generic error occured during the operation", x); + "]:a generic error occurred during the operation", x); } } if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/daemon/SnmpSubNextRequestHandler.java b/jdk/src/share/classes/com/sun/jmx/snmp/daemon/SnmpSubNextRequestHandler.java index 3ff95f6a001..99eebaa8c22 100644 --- a/jdk/src/share/classes/com/sun/jmx/snmp/daemon/SnmpSubNextRequestHandler.java +++ b/jdk/src/share/classes/com/sun/jmx/snmp/daemon/SnmpSubNextRequestHandler.java @@ -127,7 +127,7 @@ class SnmpSubNextRequestHandler extends SnmpSubRequestHandler { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpSubRequestHandler.class.getName(), "run", "[" + Thread.currentThread() + - "]:an Snmp error occured during the operation", x); + "]:an Snmp error occurred during the operation", x); } } catch(Exception x) { @@ -135,7 +135,7 @@ class SnmpSubNextRequestHandler extends SnmpSubRequestHandler { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpSubRequestHandler.class.getName(), "run", "[" + Thread.currentThread() + - "]:a generic error occured during the operation", x); + "]:a generic error occurred during the operation", x); } } if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { diff --git a/jdk/src/share/classes/com/sun/jmx/snmp/daemon/SnmpSubRequestHandler.java b/jdk/src/share/classes/com/sun/jmx/snmp/daemon/SnmpSubRequestHandler.java index 0b981311358..391d528f876 100644 --- a/jdk/src/share/classes/com/sun/jmx/snmp/daemon/SnmpSubRequestHandler.java +++ b/jdk/src/share/classes/com/sun/jmx/snmp/daemon/SnmpSubRequestHandler.java @@ -231,7 +231,7 @@ class SnmpSubRequestHandler implements SnmpDefinitions, Runnable { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpSubRequestHandler.class.getName(), "run", "[" + Thread.currentThread() + - "]:an Snmp error occured during the operation", x); + "]:an Snmp error occurred during the operation", x); } } catch(Exception x) { @@ -239,7 +239,7 @@ class SnmpSubRequestHandler implements SnmpDefinitions, Runnable { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpSubRequestHandler.class.getName(), "run", "[" + Thread.currentThread() + - "]:a generic error occured during the operation", x); + "]:a generic error occurred during the operation", x); } } if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { diff --git a/jdk/src/share/classes/com/sun/tools/example/debug/gui/CommandInterpreter.java b/jdk/src/share/classes/com/sun/tools/example/debug/gui/CommandInterpreter.java index b0494c282df..1b164209c82 100644 --- a/jdk/src/share/classes/com/sun/tools/example/debug/gui/CommandInterpreter.java +++ b/jdk/src/share/classes/com/sun/tools/example/debug/gui/CommandInterpreter.java @@ -377,7 +377,7 @@ public class CommandInterpreter { env.failure("Attempt to launch main class \"" + clname + "\" failed."); } } else { - env.failure("No main class specifed and no current default defined."); + env.failure("No main class specified and no current default defined."); } } else { clname = t.nextToken(); @@ -428,7 +428,7 @@ public class CommandInterpreter { env.failure("Attempt to attach to port \"" + portName + "\" failed."); } } else { - env.failure("No port specifed and no current default defined."); + env.failure("No port specified and no current default defined."); } } else { portName = t.nextToken(); diff --git a/jdk/src/share/classes/com/sun/tools/script/shell/init.js b/jdk/src/share/classes/com/sun/tools/script/shell/init.js index ae2cdc42d95..ced3ba06367 100644 --- a/jdk/src/share/classes/com/sun/tools/script/shell/init.js +++ b/jdk/src/share/classes/com/sun/tools/script/shell/init.js @@ -806,7 +806,7 @@ function XSLTransform(inp, style, out) { out = arguments[2]; break; default: - println("XSL tranform requires 2 or 3 arguments"); + println("XSL transform requires 2 or 3 arguments"); return; } diff --git a/jdk/src/share/classes/com/sun/tools/script/shell/messages.properties b/jdk/src/share/classes/com/sun/tools/script/shell/messages.properties index 9caf20efd41..4494f73b73b 100644 --- a/jdk/src/share/classes/com/sun/tools/script/shell/messages.properties +++ b/jdk/src/share/classes/com/sun/tools/script/shell/messages.properties @@ -36,7 +36,7 @@ engine.not.found=\ script engine for language {0} can not be found engine.info=\ - Language {0} {1} implemention "{2}" {3} + Language {0} {1} implementation "{2}" {3} encoding.unsupported=\ encoding {0} is not supported diff --git a/jdk/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java b/jdk/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java index 0afd70f9423..60916ed938b 100644 --- a/jdk/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java +++ b/jdk/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java @@ -360,7 +360,7 @@ public class RequiredModelMBean MODELMBEAN_LOGGER.logp(Level.FINER, RequiredModelMBean.class.getName(), "setManagedResource(Object,String)", - "Managed Resouce Type is not supported: " + mr_type); + "Managed Resource Type is not supported: " + mr_type); } throw new InvalidTargetObjectTypeException(mr_type); } @@ -369,7 +369,7 @@ public class RequiredModelMBean MODELMBEAN_LOGGER.logp(Level.FINER, RequiredModelMBean.class.getName(), "setManagedResource(Object,String)", - "Managed Resouce is valid"); + "Managed Resource is valid"); } managedResource = mr; diff --git a/jdk/src/share/classes/javax/swing/KeyboardManager.java b/jdk/src/share/classes/javax/swing/KeyboardManager.java index 3ce79226a5f..afbd93e734e 100644 --- a/jdk/src/share/classes/javax/swing/KeyboardManager.java +++ b/jdk/src/share/classes/javax/swing/KeyboardManager.java @@ -208,7 +208,7 @@ class KeyboardManager { public boolean fireKeyboardAction(KeyEvent e, boolean pressed, Container topAncestor) { if (e.isConsumed()) { - System.out.println("Aquired pre-used event!"); + System.out.println("Acquired pre-used event!"); Thread.dumpStack(); } diff --git a/jdk/src/share/classes/javax/swing/SortingFocusTraversalPolicy.java b/jdk/src/share/classes/javax/swing/SortingFocusTraversalPolicy.java index cbdfc015a19..45b3766c33e 100644 --- a/jdk/src/share/classes/javax/swing/SortingFocusTraversalPolicy.java +++ b/jdk/src/share/classes/javax/swing/SortingFocusTraversalPolicy.java @@ -116,7 +116,7 @@ public class SortingFocusTraversalPolicy index = Collections.binarySearch(cycle, aComponent, comparator); } catch (ClassCastException e) { if (log.isLoggable(PlatformLogger.Level.FINE)) { - log.fine("### During the binary search for " + aComponent + " the exception occured: ", e); + log.fine("### During the binary search for " + aComponent + " the exception occurred: ", e); } return -1; } diff --git a/jdk/src/share/classes/javax/swing/text/AbstractDocument.java b/jdk/src/share/classes/javax/swing/text/AbstractDocument.java index 5ccd80d95e5..71e9d5d8c60 100644 --- a/jdk/src/share/classes/javax/swing/text/AbstractDocument.java +++ b/jdk/src/share/classes/javax/swing/text/AbstractDocument.java @@ -1367,7 +1367,7 @@ public abstract class AbstractDocument implements Document, Serializable { currWriter = Thread.currentThread(); numWriters = 1; } catch (InterruptedException e) { - throw new Error("Interrupted attempt to aquire write lock"); + throw new Error("Interrupted attempt to acquire write lock"); } } @@ -1409,7 +1409,7 @@ public abstract class AbstractDocument implements Document, Serializable { } numReaders += 1; } catch (InterruptedException e) { - throw new Error("Interrupted attempt to aquire read lock"); + throw new Error("Interrupted attempt to acquire read lock"); } } diff --git a/jdk/src/share/classes/sun/awt/AppContext.java b/jdk/src/share/classes/sun/awt/AppContext.java index e0f232e5c0c..b7bfc8072c2 100644 --- a/jdk/src/share/classes/sun/awt/AppContext.java +++ b/jdk/src/share/classes/sun/awt/AppContext.java @@ -430,7 +430,7 @@ public final class AppContext { try { w.dispose(); } catch (Throwable t) { - log.finer("exception occured while disposing app context", t); + log.finer("exception occurred while disposing app context", t); } } AccessController.doPrivileged(new PrivilegedAction() { diff --git a/jdk/src/share/classes/sun/management/snmp/jvminstr/JVM_MANAGEMENT_MIB_IMPL.java b/jdk/src/share/classes/sun/management/snmp/jvminstr/JVM_MANAGEMENT_MIB_IMPL.java index 37837b24db9..3a70921c109 100644 --- a/jdk/src/share/classes/sun/management/snmp/jvminstr/JVM_MANAGEMENT_MIB_IMPL.java +++ b/jdk/src/share/classes/sun/management/snmp/jvminstr/JVM_MANAGEMENT_MIB_IMPL.java @@ -188,7 +188,7 @@ public class JVM_MANAGEMENT_MIB_IMPL extends JVM_MANAGEMENT_MIB { sendTrap(trap, list); }catch(Exception e) { log.error("handleNotification", - "Exception occured : " + e); + "Exception occurred : " + e); } } } @@ -243,7 +243,7 @@ public class JVM_MANAGEMENT_MIB_IMPL extends JVM_MANAGEMENT_MIB { adaptor.snmpV2Trap(peer, trap, list, null); }catch(Exception e) { log.error("sendTrap", - "Exception occured while sending trap to [" + + "Exception occurred while sending trap to [" + target + "]. Exception : " + e); log.debug("sendTrap",e); } diff --git a/jdk/src/share/classes/sun/misc/ExtensionDependency.java b/jdk/src/share/classes/sun/misc/ExtensionDependency.java index 86f4308c9c3..f09b3ac117e 100644 --- a/jdk/src/share/classes/sun/misc/ExtensionDependency.java +++ b/jdk/src/share/classes/sun/misc/ExtensionDependency.java @@ -265,7 +265,7 @@ public class ExtensionDependency { * the jar file. *

* - * @param extensionName key in the attibute list + * @param extensionName key in the attribute list * @param attr manifest file attributes * @param file installed extension jar file to compare the requested * extension against. diff --git a/jdk/src/share/classes/sun/rmi/rmic/RMIGenerator.java b/jdk/src/share/classes/sun/rmi/rmic/RMIGenerator.java index a9649c7fca9..6b997e42647 100644 --- a/jdk/src/share/classes/sun/rmi/rmic/RMIGenerator.java +++ b/jdk/src/share/classes/sun/rmi/rmic/RMIGenerator.java @@ -1132,7 +1132,7 @@ public class RMIGenerator implements RMIConstants, Generator { throws IOException { if (types.length != names.length) { - throw new Error("paramter type and name arrays different sizes"); + throw new Error("parameter type and name arrays different sizes"); } for (int i = 0; i < types.length; i++) { @@ -1213,7 +1213,7 @@ public class RMIGenerator implements RMIConstants, Generator { throws IOException { if (types.length != names.length) { - throw new Error("paramter type and name arrays different sizes"); + throw new Error("parameter type and name arrays different sizes"); } boolean readObject = false; diff --git a/jdk/src/share/classes/sun/security/jgss/krb5/InitialToken.java b/jdk/src/share/classes/sun/security/jgss/krb5/InitialToken.java index c15ddd23529..7b34ff83914 100644 --- a/jdk/src/share/classes/sun/security/jgss/krb5/InitialToken.java +++ b/jdk/src/share/classes/sun/security/jgss/krb5/InitialToken.java @@ -192,7 +192,7 @@ abstract class InitialToken extends Krb5Token { if (krbCredMessage.length > 0x0000ffff) throw new GSSException(GSSException.FAILURE, -1, - "Incorrect messsage length"); + "Incorrect message length"); writeLittleEndian(krbCredMessage.length, temp); checksumBytes[pos++] = temp[0]; diff --git a/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java b/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java index 0312a1fbf76..1acc3a9a06b 100644 --- a/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java +++ b/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java @@ -360,7 +360,7 @@ public class SpNegoContext implements GSSContextSpi { if (internal_mech == null) { // return wth failure throw new GSSException(errorCode, -1, - "supported mechansim from server is null"); + "supported mechanism from server is null"); } // get the negotiated result @@ -911,7 +911,7 @@ public class SpNegoContext implements GSSContextSpi { return mechContext.isEstablished(); } else { if (DEBUG) { - System.out.println("The underlying mechansim context has " + + System.out.println("The underlying mechanism context has " + "not been initialized"); } return false; @@ -1024,7 +1024,7 @@ public class SpNegoContext implements GSSContextSpi { return peerName; } else { if (DEBUG) { - System.out.println("The underlying mechansim context has " + + System.out.println("The underlying mechanism context has " + "not been initialized"); } return null; @@ -1040,7 +1040,7 @@ public class SpNegoContext implements GSSContextSpi { return myName; } else { if (DEBUG) { - System.out.println("The underlying mechansim context has " + + System.out.println("The underlying mechanism context has " + "not been initialized"); } return null; diff --git a/jdk/src/share/demo/jfc/FileChooserDemo/FileChooserDemo.java b/jdk/src/share/demo/jfc/FileChooserDemo/FileChooserDemo.java index e492e09e032..24c5533f9a1 100644 --- a/jdk/src/share/demo/jfc/FileChooserDemo/FileChooserDemo.java +++ b/jdk/src/share/demo/jfc/FileChooserDemo/FileChooserDemo.java @@ -450,9 +450,9 @@ public class FileChooserDemo extends JPanel implements ActionListener { "User cancelled operation. No file was chosen."); } else if (retval == ERROR_OPTION) { JOptionPane.showMessageDialog(frame, - "An error occured. No file was chosen."); + "An error occurred. No file was chosen."); } else { - JOptionPane.showMessageDialog(frame, "Unknown operation occured."); + JOptionPane.showMessageDialog(frame, "Unknown operation occurred."); } } diff --git a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_util.c b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_util.c index 8889f740d0e..79d5250390d 100644 --- a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_util.c +++ b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_util.c @@ -598,16 +598,16 @@ void jAttributeArrayToCKAttributeArray(JNIEnv *env, jobjectArray jArray, CK_ATTR throwOutOfMemoryError(env, 0); return; } - TRACE1(", converting %d attibutes", jLength); + TRACE1(", converting %d attributes", jLength); for (i=0; i<(*ckpLength); i++) { - TRACE1(", getting %d. attibute", i); + TRACE1(", getting %d. attribute", i); jAttribute = (*env)->GetObjectArrayElement(env, jArray, i); if ((*env)->ExceptionCheck(env)) { freeCKAttributeArray(*ckpArray, i); return; } TRACE1(", jAttribute = %d", jAttribute); - TRACE1(", converting %d. attibute", i); + TRACE1(", converting %d. attribute", i); (*ckpArray)[i] = jAttributeToCKAttribute(env, jAttribute); if ((*env)->ExceptionCheck(env)) { freeCKAttributeArray(*ckpArray, i); diff --git a/jdk/src/share/sample/nio/chatserver/ClientReader.java b/jdk/src/share/sample/nio/chatserver/ClientReader.java index de7f639e81b..822125a946c 100644 --- a/jdk/src/share/sample/nio/chatserver/ClientReader.java +++ b/jdk/src/share/sample/nio/chatserver/ClientReader.java @@ -58,7 +58,7 @@ class ClientReader { } /** - * Runs a cycle of doing a beforeRead action and then inquiring a new + * Runs a cycle of doing a beforeRead action and then enqueuing a new * read on the client. Handles closed channels and errors while reading. * If the client is still connected a new round of actions are called. */ diff --git a/jdk/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java b/jdk/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java index e61273dc4d4..912a951f374 100644 --- a/jdk/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java +++ b/jdk/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java @@ -1173,7 +1173,7 @@ abstract class XDecoratedPeer extends XWindowPeer { } if (target == activeWindow && target != focusedWindow) { // Happens when an owned window is currently focused - focusLog.fine("Focus is on child window - transfering it back to the owner"); + focusLog.fine("Focus is on child window - transferring it back to the owner"); handleWindowFocusInSync(-1); return true; } diff --git a/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java b/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java index 725e66f8bec..d84712ba97c 100644 --- a/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java @@ -266,7 +266,7 @@ final class WindowsSelectorImpl extends SelectorImpl { private void checkForException() throws IOException { if (exception == null) return; - StringBuffer message = new StringBuffer("An exception occured" + + StringBuffer message = new StringBuffer("An exception occurred" + " during the execution of select(): \n"); message.append(exception); message.append('\n'); diff --git a/jdk/src/windows/classes/sun/security/krb5/internal/tools/Klist.java b/jdk/src/windows/classes/sun/security/krb5/internal/tools/Klist.java index ce0e3e7fb5d..566b0bee12c 100644 --- a/jdk/src/windows/classes/sun/security/krb5/internal/tools/Klist.java +++ b/jdk/src/windows/classes/sun/security/krb5/internal/tools/Klist.java @@ -336,7 +336,7 @@ public class Klist { System.out.println(" name\t name of credentials cache or " + " keytab with the prefix. File-based cache or " + "keytab's prefix is FILE:."); - System.out.println(" -c specifes that credential cache is to be " + + System.out.println(" -c specifies that credential cache is to be " + "listed"); System.out.println(" -k specifies that key tab is to be listed"); System.out.println(" options for credentials caches:"); diff --git a/jdk/src/windows/classes/sun/security/krb5/internal/tools/Ktab.java b/jdk/src/windows/classes/sun/security/krb5/internal/tools/Ktab.java index eeeb848e6e5..bf09016136f 100644 --- a/jdk/src/windows/classes/sun/security/krb5/internal/tools/Ktab.java +++ b/jdk/src/windows/classes/sun/security/krb5/internal/tools/Ktab.java @@ -381,12 +381,12 @@ public class Ktab { } } } catch (KrbException e) { - System.err.println("Error occured while deleting the entry. "+ + System.err.println("Error occurred while deleting the entry. "+ "Deletion failed."); e.printStackTrace(); System.exit(-1); } catch (IOException e) { - System.err.println("Error occured while deleting the entry. "+ + System.err.println("Error occurred while deleting the entry. "+ " Deletion failed."); e.printStackTrace(); System.exit(-1); From f7db4eb56b4c34653120d684d0aabd96b9af18ab Mon Sep 17 00:00:00 2001 From: Dan Xu Date: Fri, 1 Nov 2013 14:40:03 -0700 Subject: [PATCH 009/110] 8027624: com/sun/crypto/provider/KeyFactory/TestProviderLeak.java unstable again Reviewed-by: wetmore --- .../crypto/provider/KeyFactory/TestProviderLeak.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/jdk/test/com/sun/crypto/provider/KeyFactory/TestProviderLeak.java b/jdk/test/com/sun/crypto/provider/KeyFactory/TestProviderLeak.java index 04fa96a9813..83b2c690410 100644 --- a/jdk/test/com/sun/crypto/provider/KeyFactory/TestProviderLeak.java +++ b/jdk/test/com/sun/crypto/provider/KeyFactory/TestProviderLeak.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 6578538 + * @bug 6578538 8027624 * @summary com.sun.crypto.provider.SunJCE instance leak using KRB5 and * LoginContext * @author Brad Wetmore @@ -89,10 +89,6 @@ public class TestProviderLeak { } public static void main(String [] args) throws Exception { - // Eat up memory - Deque dummyData = eatupMemory(); - assert (dummyData != null); - // Prepare the test final SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1", "SunJCE"); @@ -107,6 +103,10 @@ public class TestProviderLeak { } }; + // Eat up memory + Deque dummyData = eatupMemory(); + assert (dummyData != null); + // Start testing iteration try { for (int i = 0; i <= 1000; i++) { From bb01d169de996d6a374930671d0293cdfb2a4567 Mon Sep 17 00:00:00 2001 From: Sergey Kuksenko Date: Sat, 2 Nov 2013 20:08:10 -0700 Subject: [PATCH 010/110] 8024635: Caching MethodType's descriptor string improves lambda linkage performance Better interpreted and compiled performance of operations in MethodType important to LambdaMetafactory. Reviewed-by: jrose, twisti, mchung --- .../classes/java/lang/invoke/MethodType.java | 51 ++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/jdk/src/share/classes/java/lang/invoke/MethodType.java b/jdk/src/share/classes/java/lang/invoke/MethodType.java index f8e0967c7af..781ecfc56bd 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodType.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodType.java @@ -32,6 +32,7 @@ import java.lang.ref.ReferenceQueue; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentHashMap; import sun.invoke.util.BytecodeDescriptor; @@ -98,13 +99,25 @@ class MethodType implements java.io.Serializable { private @Stable MethodTypeForm form; // erased form, plus cached data about primitives private @Stable MethodType wrapAlt; // alternative wrapped/unwrapped version private @Stable Invokers invokers; // cache of handy higher-order adapters + private @Stable String methodDescriptor; // cache for toMethodDescriptorString /** * Check the given parameters for validity and store them into the final fields. */ - private MethodType(Class rtype, Class[] ptypes) { + private MethodType(Class rtype, Class[] ptypes, boolean trusted) { checkRtype(rtype); checkPtypes(ptypes); + this.rtype = rtype; + // defensively copy the array passed in by the user + this.ptypes = trusted ? ptypes : Arrays.copyOf(ptypes, ptypes.length); + } + + /** + * Construct a temporary unchecked instance of MethodType for use only as a key to the intern table. + * Does not check the given parameters for validity, and must be discarded after it is used as a searching key. + * The parameters are reversed for this constructor, so that is is not accidentally used. + */ + private MethodType(Class[] ptypes, Class rtype) { this.rtype = rtype; this.ptypes = ptypes; } @@ -146,20 +159,21 @@ class MethodType implements java.io.Serializable { /*non-public*/ static final int MAX_MH_INVOKER_ARITY = MAX_MH_ARITY-1; // deduct one more for invoker private static void checkRtype(Class rtype) { - rtype.equals(rtype); // null check + Objects.requireNonNull(rtype); } - private static int checkPtype(Class ptype) { - ptype.getClass(); //NPE + private static void checkPtype(Class ptype) { + Objects.requireNonNull(ptype); if (ptype == void.class) throw newIllegalArgumentException("parameter type cannot be void"); - if (ptype == double.class || ptype == long.class) return 1; - return 0; } /** Return number of extra slots (count of long/double args). */ private static int checkPtypes(Class[] ptypes) { int slots = 0; for (Class ptype : ptypes) { - slots += checkPtype(ptype); + checkPtype(ptype); + if (ptype == double.class || ptype == long.class) { + slots++; + } } checkSlotCount(ptypes.length + slots); return slots; @@ -284,20 +298,16 @@ class MethodType implements java.io.Serializable { */ /*trusted*/ static MethodType makeImpl(Class rtype, Class[] ptypes, boolean trusted) { + MethodType mt = internTable.get(new MethodType(ptypes, rtype)); + if (mt != null) + return mt; if (ptypes.length == 0) { ptypes = NO_PTYPES; trusted = true; } - MethodType mt1 = new MethodType(rtype, ptypes); - MethodType mt0 = internTable.get(mt1); - if (mt0 != null) - return mt0; - if (!trusted) - // defensively copy the array passed in by the user - mt1 = new MethodType(rtype, ptypes.clone()); + mt = new MethodType(rtype, ptypes, trusted); // promote the object to the Real Thing, and reprobe - MethodTypeForm form = MethodTypeForm.findForm(mt1); - mt1.form = form; - return internTable.add(mt1); + mt.form = MethodTypeForm.findForm(mt); + return internTable.add(mt); } private static final MethodType[] objectOnlyTypes = new MethodType[20]; @@ -919,7 +929,12 @@ class MethodType implements java.io.Serializable { * @return the bytecode type descriptor representation */ public String toMethodDescriptorString() { - return BytecodeDescriptor.unparse(this); + String desc = methodDescriptor; + if (desc == null) { + desc = BytecodeDescriptor.unparse(this); + methodDescriptor = desc; + } + return desc; } /*non-public*/ static String toFieldDescriptorString(Class cls) { From bd40c9b63dbc83449356a4f7f50bb6f20f27a2ff Mon Sep 17 00:00:00 2001 From: Tristan Yan Date: Mon, 4 Nov 2013 06:58:30 -0500 Subject: [PATCH 011/110] 8025198: Intermittent test failure: java/util/concurrent/ThreadPoolExecutor/ThrowingTasks.java Reviewed-by: martin, dholmes --- jdk/makefiles/CompileLaunchers.gmk | 2 +- jdk/makefiles/lib/CoreLibraries.gmk | 2 +- jdk/src/share/bin/java.c | 54 +++++++++++++++---- .../ThreadPoolExecutor/ThrowingTasks.java | 16 +++++- 4 files changed, 61 insertions(+), 13 deletions(-) diff --git a/jdk/makefiles/CompileLaunchers.gmk b/jdk/makefiles/CompileLaunchers.gmk index af5b3583758..2de3900acd0 100644 --- a/jdk/makefiles/CompileLaunchers.gmk +++ b/jdk/makefiles/CompileLaunchers.gmk @@ -154,7 +154,7 @@ define SetupLauncher $(ORIGIN_ARG) \ $$($1_LDFLAGS), \ LDFLAGS_macosx := $(call SET_SHARED_LIBRARY_NAME,$1), \ - LDFLAGS_linux := -lpthread \ + LDFLAGS_linux := -lpthread -lrt \ $(call SET_SHARED_LIBRARY_NAME,$(LIBRARY_PREFIX)$(SHARED_LIBRARY_SUFFIX)), \ LDFLAGS_solaris := $$($1_LDFLAGS_solaris) \ $(call SET_SHARED_LIBRARY_NAME,$(LIBRARY_PREFIX)$(SHARED_LIBRARY_SUFFIX)), \ diff --git a/jdk/makefiles/lib/CoreLibraries.gmk b/jdk/makefiles/lib/CoreLibraries.gmk index 29c1d5fc08a..a631cf80cde 100644 --- a/jdk/makefiles/lib/CoreLibraries.gmk +++ b/jdk/makefiles/lib/CoreLibraries.gmk @@ -414,7 +414,7 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBJLI, \ LDFLAGS_solaris := $(call SET_SHARED_LIBRARY_ORIGIN,/..), \ LDFLAGS_macosx := -framework Cocoa -framework Security -framework ApplicationServices, \ LDFLAGS_SUFFIX_solaris := $(LIBZ) $(LIBDL) -lc, \ - LDFLAGS_SUFFIX_linux := $(LIBZ) $(LIBDL) -lc -lpthread, \ + LDFLAGS_SUFFIX_linux := $(LIBZ) $(LIBDL) -lc -lpthread -lrt, \ LDFLAGS_SUFFIX_macosx := $(LIBZ), \ LDFLAGS_SUFFIX_windows := \ -export:JLI_Launch \ diff --git a/jdk/src/share/bin/java.c b/jdk/src/share/bin/java.c index 73c532676b3..9d1b2bf0209 100644 --- a/jdk/src/share/bin/java.c +++ b/jdk/src/share/bin/java.c @@ -53,6 +53,8 @@ #include "java.h" +#include + /* * A NOTE TO DEVELOPERS: For performance reasons it is important that * the program image remain relatively small until after SelectVersion @@ -167,6 +169,26 @@ static jlong threadStackSize = 0; /* stack size of the new thread */ static jlong maxHeapSize = 0; /* max heap size */ static jlong initialHeapSize = 0; /* inital heap size */ +static jlong timestamps[256]; +static char* descriptors[256]; +static int ts_index = 0; + +static void stamp(char* info) { + struct timespec tp; + clock_gettime(CLOCK_MONOTONIC, &tp); + timestamps[ts_index] = ((jlong)tp.tv_sec) * (1000 * 1000 * 1000) + tp.tv_nsec; + descriptors[ts_index++] = info; +} + +static void report_times() { + printf("[0] %s\n", descriptors[0]); + int i; + for (i = 1; i < ts_index; i++) { + jlong elapsed = timestamps[i] - timestamps[i-1]; + printf("[%d] elapsed us: %.3g - Next: %s\n", i, (elapsed/1000.0), descriptors[i]); + } +} + /* * Entry point. */ @@ -184,6 +206,7 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */ jint ergo /* ergonomics class policy */ ) { + stamp("Entered JLI_Launch"); int mode = LM_UNKNOWN; char *what = NULL; char *cpath = 0; @@ -203,6 +226,7 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */ _wc_enabled = cpwildcard; _ergo_policy = ergo; +stamp("InitLauncher"); InitLauncher(javaw); DumpState(); if (JLI_IsTraceLauncher()) { @@ -231,8 +255,9 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */ * (Note: This side effect has been disabled. See comment on * bugid 5030265 below.) */ +stamp("SelectVersion"); SelectVersion(argc, argv, &main_class); - +stamp("CreateExecutionEnvironment"); CreateExecutionEnvironment(&argc, &argv, jrepath, sizeof(jrepath), jvmpath, sizeof(jvmpath), @@ -244,11 +269,11 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */ if (JLI_IsTraceLauncher()) { start = CounterGet(); } - +stamp("LoadJavaVM"); if (!LoadJavaVM(jvmpath, &ifn)) { return(6); } - +stamp("Arg processing"); if (JLI_IsTraceLauncher()) { end = CounterGet(); } @@ -295,8 +320,10 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */ /* set the -Dsun.java.launcher.* platform properties */ SetJavaLauncherPlatformProps(); - - return JVMInit(&ifn, threadStackSize, argc, argv, mode, what, ret); +stamp("JVMInit"); + int res = JVMInit(&ifn, threadStackSize, argc, argv, mode, what, ret); +stamp("initial thread DONE"); + return res; } /* * Always detach the main thread so that it appears to have ended when @@ -348,6 +375,7 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */ int JNICALL JavaMain(void * _args) { +stamp("JavaMain"); JavaMainArgs *args = (JavaMainArgs *)_args; int argc = args->argc; char **argv = args->argv; @@ -363,11 +391,12 @@ JavaMain(void * _args) jobjectArray mainArgs; int ret = 0; jlong start, end; - +stamp("RegisterThread"); RegisterThread(); /* Initialize the virtual machine */ start = CounterGet(); +stamp("InitializeJVM"); if (!InitializeJVM(&vm, &env, &ifn)) { JLI_ReportErrorMessage(JVM_ERROR1); exit(1); @@ -436,6 +465,7 @@ JavaMain(void * _args) * This method also correctly handles launching existing JavaFX * applications that may or may not have a Main-Class manifest entry. */ +stamp("LoadMainClass"); mainClass = LoadMainClass(env, mode, what); CHECK_EXCEPTION_NULL_LEAVE(mainClass); /* @@ -444,6 +474,7 @@ JavaMain(void * _args) * applications own main class but rather a helper class. To keep things * consistent in the UI we need to track and report the application main class. */ +stamp("GetApplicationClass"); appClass = GetApplicationClass(env); NULL_CHECK_RETURN_VALUE(appClass, -1); /* @@ -453,6 +484,7 @@ JavaMain(void * _args) * instead of mainClass as that may be a launcher or helper class instead * of the application class. */ +stamp("PostJVMInit"); PostJVMInit(env, appClass, vm); /* * The LoadMainClass not only loads the main class, it will also ensure @@ -460,17 +492,20 @@ JavaMain(void * _args) * is not required. The main method is invoked here so that extraneous java * stacks are not in the application stack trace. */ +stamp("Get main method"); mainID = (*env)->GetStaticMethodID(env, mainClass, "main", "([Ljava/lang/String;)V"); CHECK_EXCEPTION_NULL_LEAVE(mainID); - +stamp("CreateApplicationArgs"); /* Build platform specific argument array */ mainArgs = CreateApplicationArgs(env, argv, argc); CHECK_EXCEPTION_NULL_LEAVE(mainArgs); /* Invoke main method. */ +stamp("Invoke main method"); (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs); - +stamp("main complete"); +report_times(); /* * The launcher's exit code (in the absence of calls to * System.exit) will be non-zero if main threw an exception. @@ -1875,6 +1910,7 @@ ContinueInNewThread(InvocationFunctions* ifn, jlong threadStackSize, int argc, char **argv, int mode, char *what, int ret) { +stamp("ContinueInNewThread"); /* * If user doesn't specify stack size, check if VM has a preference. @@ -1900,7 +1936,7 @@ ContinueInNewThread(InvocationFunctions* ifn, jlong threadStackSize, args.mode = mode; args.what = what; args.ifn = *ifn; - +stamp("ContinueInNewThread0"); rslt = ContinueInNewThread0(JavaMain, threadStackSize, (void*)&args); /* If the caller has deemed there is an error we * simply return that, otherwise we return the value of diff --git a/jdk/test/java/util/concurrent/ThreadPoolExecutor/ThrowingTasks.java b/jdk/test/java/util/concurrent/ThreadPoolExecutor/ThrowingTasks.java index 1394a4c38ed..47c28540f24 100644 --- a/jdk/test/java/util/concurrent/ThreadPoolExecutor/ThrowingTasks.java +++ b/jdk/test/java/util/concurrent/ThreadPoolExecutor/ThrowingTasks.java @@ -33,6 +33,7 @@ import java.security.*; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; +import java.util.concurrent.locks.ReentrantLock; public class ThrowingTasks { static final Random rnd = new Random(); @@ -156,6 +157,7 @@ public class ThrowingTasks { } static class CheckingExecutor extends ThreadPoolExecutor { + private final ReentrantLock lock = new ReentrantLock(); CheckingExecutor() { super(10, 10, 1L, TimeUnit.HOURS, @@ -163,10 +165,20 @@ public class ThrowingTasks { tf); } @Override protected void beforeExecute(Thread t, Runnable r) { - allStarted.countDown(); - if (allStarted.getCount() < getCorePoolSize()) + final boolean lessThanCorePoolSize; + // Add a lock to sync allStarted.countDown() and + // allStarted.getCount() < getCorePoolSize() + lock.lock(); + try { + allStarted.countDown(); + lessThanCorePoolSize = allStarted.getCount() < getCorePoolSize(); + } finally { + lock.unlock(); + } + if (lessThanCorePoolSize) { try { allContinue.await(); } catch (InterruptedException x) { unexpected(x); } + } beforeExecuteCount.getAndIncrement(); check(! isTerminated()); ((Flaky)r).beforeExecute.run(); From c43c119a472b40b5a990a7e2135b3cfb637c6ab4 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Mon, 4 Nov 2013 07:39:48 -0500 Subject: [PATCH 012/110] 8027755: Anti-delta incorrect push for 8025198 Reviewed-by: alanb --- jdk/makefiles/CompileLaunchers.gmk | 2 +- jdk/makefiles/lib/CoreLibraries.gmk | 2 +- jdk/src/share/bin/java.c | 54 +++++------------------------ 3 files changed, 11 insertions(+), 47 deletions(-) diff --git a/jdk/makefiles/CompileLaunchers.gmk b/jdk/makefiles/CompileLaunchers.gmk index 2de3900acd0..af5b3583758 100644 --- a/jdk/makefiles/CompileLaunchers.gmk +++ b/jdk/makefiles/CompileLaunchers.gmk @@ -154,7 +154,7 @@ define SetupLauncher $(ORIGIN_ARG) \ $$($1_LDFLAGS), \ LDFLAGS_macosx := $(call SET_SHARED_LIBRARY_NAME,$1), \ - LDFLAGS_linux := -lpthread -lrt \ + LDFLAGS_linux := -lpthread \ $(call SET_SHARED_LIBRARY_NAME,$(LIBRARY_PREFIX)$(SHARED_LIBRARY_SUFFIX)), \ LDFLAGS_solaris := $$($1_LDFLAGS_solaris) \ $(call SET_SHARED_LIBRARY_NAME,$(LIBRARY_PREFIX)$(SHARED_LIBRARY_SUFFIX)), \ diff --git a/jdk/makefiles/lib/CoreLibraries.gmk b/jdk/makefiles/lib/CoreLibraries.gmk index a631cf80cde..29c1d5fc08a 100644 --- a/jdk/makefiles/lib/CoreLibraries.gmk +++ b/jdk/makefiles/lib/CoreLibraries.gmk @@ -414,7 +414,7 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBJLI, \ LDFLAGS_solaris := $(call SET_SHARED_LIBRARY_ORIGIN,/..), \ LDFLAGS_macosx := -framework Cocoa -framework Security -framework ApplicationServices, \ LDFLAGS_SUFFIX_solaris := $(LIBZ) $(LIBDL) -lc, \ - LDFLAGS_SUFFIX_linux := $(LIBZ) $(LIBDL) -lc -lpthread -lrt, \ + LDFLAGS_SUFFIX_linux := $(LIBZ) $(LIBDL) -lc -lpthread, \ LDFLAGS_SUFFIX_macosx := $(LIBZ), \ LDFLAGS_SUFFIX_windows := \ -export:JLI_Launch \ diff --git a/jdk/src/share/bin/java.c b/jdk/src/share/bin/java.c index 9d1b2bf0209..73c532676b3 100644 --- a/jdk/src/share/bin/java.c +++ b/jdk/src/share/bin/java.c @@ -53,8 +53,6 @@ #include "java.h" -#include - /* * A NOTE TO DEVELOPERS: For performance reasons it is important that * the program image remain relatively small until after SelectVersion @@ -169,26 +167,6 @@ static jlong threadStackSize = 0; /* stack size of the new thread */ static jlong maxHeapSize = 0; /* max heap size */ static jlong initialHeapSize = 0; /* inital heap size */ -static jlong timestamps[256]; -static char* descriptors[256]; -static int ts_index = 0; - -static void stamp(char* info) { - struct timespec tp; - clock_gettime(CLOCK_MONOTONIC, &tp); - timestamps[ts_index] = ((jlong)tp.tv_sec) * (1000 * 1000 * 1000) + tp.tv_nsec; - descriptors[ts_index++] = info; -} - -static void report_times() { - printf("[0] %s\n", descriptors[0]); - int i; - for (i = 1; i < ts_index; i++) { - jlong elapsed = timestamps[i] - timestamps[i-1]; - printf("[%d] elapsed us: %.3g - Next: %s\n", i, (elapsed/1000.0), descriptors[i]); - } -} - /* * Entry point. */ @@ -206,7 +184,6 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */ jint ergo /* ergonomics class policy */ ) { - stamp("Entered JLI_Launch"); int mode = LM_UNKNOWN; char *what = NULL; char *cpath = 0; @@ -226,7 +203,6 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */ _wc_enabled = cpwildcard; _ergo_policy = ergo; -stamp("InitLauncher"); InitLauncher(javaw); DumpState(); if (JLI_IsTraceLauncher()) { @@ -255,9 +231,8 @@ stamp("InitLauncher"); * (Note: This side effect has been disabled. See comment on * bugid 5030265 below.) */ -stamp("SelectVersion"); SelectVersion(argc, argv, &main_class); -stamp("CreateExecutionEnvironment"); + CreateExecutionEnvironment(&argc, &argv, jrepath, sizeof(jrepath), jvmpath, sizeof(jvmpath), @@ -269,11 +244,11 @@ stamp("CreateExecutionEnvironment"); if (JLI_IsTraceLauncher()) { start = CounterGet(); } -stamp("LoadJavaVM"); + if (!LoadJavaVM(jvmpath, &ifn)) { return(6); } -stamp("Arg processing"); + if (JLI_IsTraceLauncher()) { end = CounterGet(); } @@ -320,10 +295,8 @@ stamp("Arg processing"); /* set the -Dsun.java.launcher.* platform properties */ SetJavaLauncherPlatformProps(); -stamp("JVMInit"); - int res = JVMInit(&ifn, threadStackSize, argc, argv, mode, what, ret); -stamp("initial thread DONE"); - return res; + + return JVMInit(&ifn, threadStackSize, argc, argv, mode, what, ret); } /* * Always detach the main thread so that it appears to have ended when @@ -375,7 +348,6 @@ stamp("initial thread DONE"); int JNICALL JavaMain(void * _args) { -stamp("JavaMain"); JavaMainArgs *args = (JavaMainArgs *)_args; int argc = args->argc; char **argv = args->argv; @@ -391,12 +363,11 @@ stamp("JavaMain"); jobjectArray mainArgs; int ret = 0; jlong start, end; -stamp("RegisterThread"); + RegisterThread(); /* Initialize the virtual machine */ start = CounterGet(); -stamp("InitializeJVM"); if (!InitializeJVM(&vm, &env, &ifn)) { JLI_ReportErrorMessage(JVM_ERROR1); exit(1); @@ -465,7 +436,6 @@ stamp("InitializeJVM"); * This method also correctly handles launching existing JavaFX * applications that may or may not have a Main-Class manifest entry. */ -stamp("LoadMainClass"); mainClass = LoadMainClass(env, mode, what); CHECK_EXCEPTION_NULL_LEAVE(mainClass); /* @@ -474,7 +444,6 @@ stamp("LoadMainClass"); * applications own main class but rather a helper class. To keep things * consistent in the UI we need to track and report the application main class. */ -stamp("GetApplicationClass"); appClass = GetApplicationClass(env); NULL_CHECK_RETURN_VALUE(appClass, -1); /* @@ -484,7 +453,6 @@ stamp("GetApplicationClass"); * instead of mainClass as that may be a launcher or helper class instead * of the application class. */ -stamp("PostJVMInit"); PostJVMInit(env, appClass, vm); /* * The LoadMainClass not only loads the main class, it will also ensure @@ -492,20 +460,17 @@ stamp("PostJVMInit"); * is not required. The main method is invoked here so that extraneous java * stacks are not in the application stack trace. */ -stamp("Get main method"); mainID = (*env)->GetStaticMethodID(env, mainClass, "main", "([Ljava/lang/String;)V"); CHECK_EXCEPTION_NULL_LEAVE(mainID); -stamp("CreateApplicationArgs"); + /* Build platform specific argument array */ mainArgs = CreateApplicationArgs(env, argv, argc); CHECK_EXCEPTION_NULL_LEAVE(mainArgs); /* Invoke main method. */ -stamp("Invoke main method"); (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs); -stamp("main complete"); -report_times(); + /* * The launcher's exit code (in the absence of calls to * System.exit) will be non-zero if main threw an exception. @@ -1910,7 +1875,6 @@ ContinueInNewThread(InvocationFunctions* ifn, jlong threadStackSize, int argc, char **argv, int mode, char *what, int ret) { -stamp("ContinueInNewThread"); /* * If user doesn't specify stack size, check if VM has a preference. @@ -1936,7 +1900,7 @@ stamp("ContinueInNewThread"); args.mode = mode; args.what = what; args.ifn = *ifn; -stamp("ContinueInNewThread0"); + rslt = ContinueInNewThread0(JavaMain, threadStackSize, (void*)&args); /* If the caller has deemed there is an error we * simply return that, otherwise we return the value of From 8c97f82aae76084c8c6f1d57ef56605907caa296 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Mon, 4 Nov 2013 08:05:02 -0800 Subject: [PATCH 013/110] 8027625: test/java/math/BigInteger/ExtremeShiftingTests.java needs @run tag to specify heap size Add @run tag to specify heap size Reviewed-by: alanb, dxu --- jdk/test/java/math/BigInteger/ExtremeShiftingTests.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/test/java/math/BigInteger/ExtremeShiftingTests.java b/jdk/test/java/math/BigInteger/ExtremeShiftingTests.java index 4c39a6097fd..5ddc07e887c 100644 --- a/jdk/test/java/math/BigInteger/ExtremeShiftingTests.java +++ b/jdk/test/java/math/BigInteger/ExtremeShiftingTests.java @@ -25,6 +25,7 @@ * @test * @bug 6371401 * @summary Tests of shiftLeft and shiftRight on Integer.MIN_VALUE + * @run main/othervm -Xmx512m ExtremeShiftingTests * @author Joseph D. Darcy */ import java.math.BigInteger; From 2d8325d24451e286631d2d2fbcd2696756ebc924 Mon Sep 17 00:00:00 2001 From: Michael McMahon Date: Mon, 4 Nov 2013 17:47:59 +0000 Subject: [PATCH 014/110] 8027687: The constructors of URLPermission class do not behave as described in javad Reviewed-by: chegar, mduigou --- .../share/classes/java/net/HostPortrange.java | 36 +++++++++++++++++-- .../share/classes/java/net/URLPermission.java | 5 ++- .../net/URLPermission/URLPermissionTest.java | 13 ++++++- 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/jdk/src/share/classes/java/net/HostPortrange.java b/jdk/src/share/classes/java/net/HostPortrange.java index fc5e3d98a20..3c924d8bfc0 100644 --- a/jdk/src/share/classes/java/net/HostPortrange.java +++ b/jdk/src/share/classes/java/net/HostPortrange.java @@ -114,7 +114,7 @@ class HostPortrange { if (hoststr.equals("*")) { hoststr = ""; } else if (hoststr.startsWith("*.")) { - hoststr = hoststr.substring(1).toLowerCase(); // leave the '.' ? + hoststr = toLowerCase(hoststr.substring(1)); } else { throw new IllegalArgumentException("invalid host wildcard specification"); } @@ -147,7 +147,7 @@ class HostPortrange { hoststr = sb.toString(); } else { // regular domain name - hoststr = hoststr.toLowerCase(); + hoststr = toLowerCase(hoststr); } } } @@ -161,6 +161,38 @@ class HostPortrange { } } + static final int CASE_DIFF = 'A' - 'a'; + + /** + * Convert to lower case, and check that all chars are ascii + * alphanumeric, '-' or '.' only. + */ + static String toLowerCase(String s) { + int len = s.length(); + StringBuilder sb = null; + + for (int i=0; i= 'a' && c <= 'z') || (c == '.')) { + if (sb != null) + sb.append(c); + } else if ((c >= '0' && c <= '9') || (c == '-')) { + if (sb != null) + sb.append(c); + } else if (c >= 'A' && c <= 'Z') { + if (sb == null) { + sb = new StringBuilder(len); + sb.append(s, 0, i); + } + sb.append((char)(c - CASE_DIFF)); + } else { + throw new IllegalArgumentException("Invalid characters in hostname"); + } + } + return sb == null ? s : sb.toString(); + } + + public boolean literal() { return literal; } diff --git a/jdk/src/share/classes/java/net/URLPermission.java b/jdk/src/share/classes/java/net/URLPermission.java index 7ad56a1c20f..13472a9e5ab 100644 --- a/jdk/src/share/classes/java/net/URLPermission.java +++ b/jdk/src/share/classes/java/net/URLPermission.java @@ -426,7 +426,10 @@ public final class URLPermission extends Permission { this.ssp = url.substring(delim + 1); if (!ssp.startsWith("//")) { - this.authority = new Authority(scheme, ssp.toLowerCase()); + if (!ssp.equals("*")) { + throw new IllegalArgumentException("invalid URL string"); + } + this.authority = new Authority(scheme, "*"); return; } String authpath = ssp.substring(2); diff --git a/jdk/test/java/net/URLPermission/URLPermissionTest.java b/jdk/test/java/net/URLPermission/URLPermissionTest.java index 3bf862b6dc9..948e9dabb13 100644 --- a/jdk/test/java/net/URLPermission/URLPermissionTest.java +++ b/jdk/test/java/net/URLPermission/URLPermissionTest.java @@ -186,6 +186,14 @@ public class URLPermissionTest { imtest("http:*", "https://www.foo.com/a/b/c", false), imtest("http:*", "http://www.foo.com/a/b/c", true), imtest("http:*", "http://foo/bar", true), + imtest("http://WWW.foO.cOM/a/b/*", "http://wwW.foo.com/a/b/c", true), + imtest("http://wWw.fOo.cOm/a/b/*", "http://Www.foo.com/a/b/*", true), + imtest("http://www.FOO.com/", "http://www.foo.COM/", true), + imtest("http://66ww-w.F-O012O.com/", "http://66ww-w.f-o012o.COM/",true), + imtest("http://xn--ire-9la.com/", "http://xn--ire-9la.COM/", true), + imtest("http://x/", "http://X/", true), + imtest("http://x/", "http://x/", true), + imtest("http://X/", "http://X/", true), imtest("http://foo/bar", "https://foo/bar", false) }; @@ -194,9 +202,12 @@ public class URLPermissionTest { static Test[] exceptionTests = { extest("http://1.2.3.4.5/a/b/c"), extest("http://www.*.com"), - //extest("http://www.foo.com:1-X"), extest("http://[foo.com]:99"), extest("http://[fec0::X]:99"), + extest("http:\\www.foo.com"), + extest("http://w_09ww.foo.com"), + extest("http://w&09ww.foo.com/p"), + extest("http://www+foo.com"), extest("http:") }; From ee1006e3bd0f49054996f387b8ec20361716fa2d Mon Sep 17 00:00:00 2001 From: Robert Field Date: Mon, 4 Nov 2013 10:12:18 -0800 Subject: [PATCH 015/110] 7194897: JSR 292: Cannot create more than 16 instances of an anonymous class 8027681: Lambda serialization fails once reflection proxy generation kicks in Co-authored-by: Joel Borggren-Franck Co-authored-by: Brian Goetz Reviewed-by: ksrini, briangoetz, jfranck --- .../NativeConstructorAccessorImpl.java | 9 ++- .../sun/reflect/NativeMethodAccessorImpl.java | 9 ++- .../classes/sun/reflect/misc/ReflectUtil.java | 11 +++- .../lambda/RepetitiveLambdaSerialization.java | 53 ++++++++++++++++ .../lang/invoke/SerializedLambdaTest.java | 12 ++-- .../ManyNewInstanceAnonTest.java | 62 +++++++++++++++++++ 6 files changed, 147 insertions(+), 9 deletions(-) create mode 100644 jdk/test/java/lang/invoke/lambda/RepetitiveLambdaSerialization.java create mode 100644 jdk/test/sun/reflect/AnonymousNewInstance/ManyNewInstanceAnonTest.java diff --git a/jdk/src/share/classes/sun/reflect/NativeConstructorAccessorImpl.java b/jdk/src/share/classes/sun/reflect/NativeConstructorAccessorImpl.java index 4f91ddc4460..d56c3caab08 100644 --- a/jdk/src/share/classes/sun/reflect/NativeConstructorAccessorImpl.java +++ b/jdk/src/share/classes/sun/reflect/NativeConstructorAccessorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package sun.reflect; import java.lang.reflect.*; +import sun.reflect.misc.ReflectUtil; /** Used only for the first few invocations of a Constructor; afterward, switches to bytecode-based implementation */ @@ -44,7 +45,11 @@ class NativeConstructorAccessorImpl extends ConstructorAccessorImpl { IllegalArgumentException, InvocationTargetException { - if (++numInvocations > ReflectionFactory.inflationThreshold()) { + // We can't inflate a constructor belonging to a vm-anonymous class + // because that kind of class can't be referred to by name, hence can't + // be found from the generated bytecode. + if (++numInvocations > ReflectionFactory.inflationThreshold() + && !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())) { ConstructorAccessorImpl acc = (ConstructorAccessorImpl) new MethodAccessorGenerator(). generateConstructor(c.getDeclaringClass(), diff --git a/jdk/src/share/classes/sun/reflect/NativeMethodAccessorImpl.java b/jdk/src/share/classes/sun/reflect/NativeMethodAccessorImpl.java index 93f186b7b49..b1d39e7c965 100644 --- a/jdk/src/share/classes/sun/reflect/NativeMethodAccessorImpl.java +++ b/jdk/src/share/classes/sun/reflect/NativeMethodAccessorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package sun.reflect; import java.lang.reflect.*; +import sun.reflect.misc.ReflectUtil; /** Used only for the first few invocations of a Method; afterward, switches to bytecode-based implementation */ @@ -42,7 +43,11 @@ class NativeMethodAccessorImpl extends MethodAccessorImpl { public Object invoke(Object obj, Object[] args) throws IllegalArgumentException, InvocationTargetException { - if (++numInvocations > ReflectionFactory.inflationThreshold()) { + // We can't inflate methods belonging to vm-anonymous classes because + // that kind of class can't be referred to by name, hence can't be + // found from the generated bytecode. + if (++numInvocations > ReflectionFactory.inflationThreshold() + && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) { MethodAccessorImpl acc = (MethodAccessorImpl) new MethodAccessorGenerator(). generateMethod(method.getDeclaringClass(), diff --git a/jdk/src/share/classes/sun/reflect/misc/ReflectUtil.java b/jdk/src/share/classes/sun/reflect/misc/ReflectUtil.java index 1f871e8de02..4316d422c39 100644 --- a/jdk/src/share/classes/sun/reflect/misc/ReflectUtil.java +++ b/jdk/src/share/classes/sun/reflect/misc/ReflectUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -298,4 +298,13 @@ public final class ReflectUtil { } return false; } + + /** + * Checks if {@code Class cls} is a VM-anonymous class + * as defined by {@link sun.misc.Unsafe#defineAnonymousClass} + * (not to be confused with a Java Language anonymous inner class). + */ + public static boolean isVMAnonymousClass(Class cls) { + return cls.getSimpleName().contains("/"); + } } diff --git a/jdk/test/java/lang/invoke/lambda/RepetitiveLambdaSerialization.java b/jdk/test/java/lang/invoke/lambda/RepetitiveLambdaSerialization.java new file mode 100644 index 00000000000..5c57615a307 --- /dev/null +++ b/jdk/test/java/lang/invoke/lambda/RepetitiveLambdaSerialization.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8027681 + * @summary Lambda serialization fails once reflection proxy generation kicks in + * @author Robert Field + * @run main/othervm RepetitiveLambdaSerialization + */ + +import java.io.*; + +public class RepetitiveLambdaSerialization { + + static final int REPS = 20; + + public static void main(String[] args) throws Exception { + LSI ls = z -> "[" + z + "]"; + for (int i = 0; i < REPS; ++i) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutput out = new ObjectOutputStream(baos); + out.writeObject(ls); + out.flush(); + out.close(); + } + System.out.println("Passed."); + } +} + +interface LSI extends Serializable { + String convert(String x); +} diff --git a/jdk/test/java/util/stream/test/org/openjdk/tests/java/lang/invoke/SerializedLambdaTest.java b/jdk/test/java/util/stream/test/org/openjdk/tests/java/lang/invoke/SerializedLambdaTest.java index 8f01dada86f..fdbd689ad36 100644 --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/lang/invoke/SerializedLambdaTest.java +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/lang/invoke/SerializedLambdaTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,14 +56,18 @@ import static org.testng.Assert.fail; */ @Test public class SerializedLambdaTest { + public static final int REPS = 50; + @SuppressWarnings("unchecked") private void assertSerial(T p, Consumer asserter) throws IOException, ClassNotFoundException { asserter.accept(p); - byte[] bytes = serialize(p); - assertTrue(bytes.length > 0); + for (int i=0; i 0); - asserter.accept((T) deserialize(bytes)); + asserter.accept((T) deserialize(bytes)); + } } private void assertNotSerial(Predicate p, Consumer> asserter) diff --git a/jdk/test/sun/reflect/AnonymousNewInstance/ManyNewInstanceAnonTest.java b/jdk/test/sun/reflect/AnonymousNewInstance/ManyNewInstanceAnonTest.java new file mode 100644 index 00000000000..b931b8a65f8 --- /dev/null +++ b/jdk/test/sun/reflect/AnonymousNewInstance/ManyNewInstanceAnonTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 7194897 + * @summary JSR 292: Cannot create more than 16 instances of an anonymous class + * @author Robert Field + * @library /lib/testlibrary + * @compile -XDignore.symbol.file ManyNewInstanceAnonTest.java + * @run main ClassFileInstaller ManyNewInstanceAnonTest + * @run main/othervm -Xbootclasspath/a:. -Xverify:all ManyNewInstanceAnonTest + */ +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import sun.misc.Unsafe; + +public class ManyNewInstanceAnonTest { + + static final int REPS = 20; + static final Class klass = ManyNewInstanceAnonTest.class; + + public static void main(String[] args) throws Exception { + Class c = Unsafe.getUnsafe().defineAnonymousClass(klass, readClassFile(), null); + for (int i = 0; i < REPS; ++i) { + System.out.printf("%d: %s\n", i, c.newInstance()); + } + System.out.println("Passed."); + } + + private static byte[] readClassFile() throws Exception { + try (InputStream in = klass.getResourceAsStream(klass.getSimpleName() + ".class"); + ByteArrayOutputStream out = new ByteArrayOutputStream()) + { + int b; + while ((b = in.read()) != -1) { + out.write(b); + } + return out.toByteArray(); + } + } +} From 79b1f94594b1743ed2f45251b63123c4ae60f1ba Mon Sep 17 00:00:00 2001 From: Andreas Lundblad Date: Mon, 4 Nov 2013 15:21:47 +0100 Subject: [PATCH 016/110] 8016725: TEST_BUG: java/lang/reflect/Method/DefaultMethodModeling.java failing intermittently Moved DefaultMethodModeling.java to its own directory to avoid conflicts with Equals.java. Reviewed-by: darcy --- .../Method/{ => defaultMethodModeling}/DefaultMethodModeling.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename jdk/test/java/lang/reflect/Method/{ => defaultMethodModeling}/DefaultMethodModeling.java (100%) diff --git a/jdk/test/java/lang/reflect/Method/DefaultMethodModeling.java b/jdk/test/java/lang/reflect/Method/defaultMethodModeling/DefaultMethodModeling.java similarity index 100% rename from jdk/test/java/lang/reflect/Method/DefaultMethodModeling.java rename to jdk/test/java/lang/reflect/Method/defaultMethodModeling/DefaultMethodModeling.java From 3fdca184336549a0dcc7a20a96348bcbd61a72aa Mon Sep 17 00:00:00 2001 From: Dan Xu Date: Mon, 4 Nov 2013 15:48:08 -0800 Subject: [PATCH 017/110] 8027612: java/io/File/MaxPathLength.java fails intermittently in the clean-up stage Reviewed-by: chegar --- jdk/test/java/io/File/MaxPathLength.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/jdk/test/java/io/File/MaxPathLength.java b/jdk/test/java/io/File/MaxPathLength.java index 9fd6183f36d..cdda0471446 100644 --- a/jdk/test/java/io/File/MaxPathLength.java +++ b/jdk/test/java/io/File/MaxPathLength.java @@ -28,6 +28,8 @@ import java.io.*; import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.DirectoryNotEmptyException; public class MaxPathLength { private static String sep = File.separator; @@ -182,7 +184,18 @@ public class MaxPathLength { } finally { // Clean up for (int i = 0; i < max; i++) { - Files.deleteIfExists((new File(created[i])).toPath()); + Path p = (new File(created[i])).toPath(); + try { + Files.deleteIfExists(p); + // Test if the file is really deleted and wait for 1 second at most + for (int j = 0; j < 10 && Files.exists(p); j++) { + Thread.sleep(100); + } + } catch (DirectoryNotEmptyException ex) { + // Give up the clean-up, let jtreg handle it. + System.err.println("Dir, " + p + ", is not empty"); + break; + } } } } From fe6f3e2439db3d75d114c98cf661e8ecb32824fc Mon Sep 17 00:00:00 2001 From: Paul Sandoz Date: Tue, 5 Nov 2013 12:08:12 +0100 Subject: [PATCH 018/110] 8027712: DistinctOpTest fails for unordered test Reviewed-by: henryjen, alanb --- .../openjdk/tests/java/util/stream/DistinctOpTest.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/DistinctOpTest.java b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/DistinctOpTest.java index 7d26925a1f2..69432cfedf6 100644 --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/DistinctOpTest.java +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/DistinctOpTest.java @@ -54,10 +54,14 @@ public class DistinctOpTest extends OpTestCase { // These tests should short-circuit, otherwise will fail with a time-out // or an OOME - Integer one = Stream.iterate(1, i -> i + 1).unordered().parallel().distinct().findAny().get(); - assertEquals(one.intValue(), 1); + // Note that since the streams are unordered and any element is requested + // (a non-deterministic process) the only assertion that can be made is + // that an element should be found - Optional oi = ThreadLocalRandom.current().ints().boxed().parallel().distinct().findAny(); + Optional oi = Stream.iterate(1, i -> i + 1).unordered().parallel().distinct().findAny(); + assertTrue(oi.isPresent()); + + oi = ThreadLocalRandom.current().ints().boxed().parallel().distinct().findAny(); assertTrue(oi.isPresent()); } From 33be168ccb7c6d033fce9cbe541f4c118811aa46 Mon Sep 17 00:00:00 2001 From: Joe Wang Date: Tue, 5 Nov 2013 11:18:20 -0800 Subject: [PATCH 019/110] 8027860: [TEST_BUG] File not closed in javax/xml/jaxp/parsers/8022548/XOMParserTest.java Reviewed-by: alanb --- .../jaxp/parsers/8022548/XOMParserTest.java | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/jdk/test/javax/xml/jaxp/parsers/8022548/XOMParserTest.java b/jdk/test/javax/xml/jaxp/parsers/8022548/XOMParserTest.java index ba12d0ddc86..15915d04912 100644 --- a/jdk/test/javax/xml/jaxp/parsers/8022548/XOMParserTest.java +++ b/jdk/test/javax/xml/jaxp/parsers/8022548/XOMParserTest.java @@ -22,7 +22,8 @@ */ /** - * @test @bug 8022548 + * @test + * @bug 8022548 * @summary test that a parser can use DTDConfiguration * @run main XOMParserTest */ @@ -60,30 +61,27 @@ public class XOMParserTest extends TestBase { } public final void testTransform() { + String inFilename = filePath + "/JDK8022548.xml"; + String xslFilename = filePath + "/JDK8022548.xsl"; + String outFilename = "JDK8022548.out"; - try { + try (InputStream xslInput = new FileInputStream(xslFilename); + InputStream xmlInput = new FileInputStream(inFilename); + OutputStream out = new FileOutputStream(outFilename); + ) { - String inFilename = filePath + "/JDK8022548.xml"; - String xslFilename = filePath + "/JDK8022548.xsl"; - String outFilename = "JDK8022548.out"; StringWriter sw = new StringWriter(); // Create transformer factory TransformerFactory factory = TransformerFactory.newInstance(); - // set the translet name -// factory.setAttribute("translet-name", "myTranslet"); - - // set the destination directory -// factory.setAttribute("destination-directory", "c:\\temp"); -// factory.setAttribute("generate-translet", Boolean.TRUE); // Use the factory to create a template containing the xsl file - Templates template = factory.newTemplates(new StreamSource(new FileInputStream(xslFilename))); + Templates template = factory.newTemplates(new StreamSource(xslInput)); // Use the template to create a transformer Transformer xformer = template.newTransformer(); // Prepare the input and output files - Source source = new StreamSource(new FileInputStream(inFilename)); - Result result = new StreamResult(new FileOutputStream(outFilename)); + Source source = new StreamSource(xmlInput); + Result result = new StreamResult(outFilename); //Result result = new StreamResult(sw); // Apply the xsl file to the source file and write the result to the output file xformer.transform(source, result); From 1b7f902c51a23227550663bbebbe4e9a0591d56b Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Tue, 5 Nov 2013 17:33:26 -0800 Subject: [PATCH 020/110] 8022208: Intermittent test failures in java/lang/Thread/ThreadStateTest.java 6944188: ThreadMXBean/ThreadStateTest.java fails intermittently Reviewed-by: dholmes, chegar --- .../lang/Thread/ThreadStateController.java | 340 ++++++++++++++ .../java/lang/Thread/ThreadStateTest.java | 304 ++----------- .../ThreadMXBean/ThreadMXBeanStateTest.java | 230 ++++++++++ .../ThreadMXBean/ThreadStateTest.java | 424 ------------------ 4 files changed, 597 insertions(+), 701 deletions(-) create mode 100644 jdk/test/java/lang/Thread/ThreadStateController.java create mode 100644 jdk/test/java/lang/management/ThreadMXBean/ThreadMXBeanStateTest.java delete mode 100644 jdk/test/java/lang/management/ThreadMXBean/ThreadStateTest.java diff --git a/jdk/test/java/lang/Thread/ThreadStateController.java b/jdk/test/java/lang/Thread/ThreadStateController.java new file mode 100644 index 00000000000..2d876b0ec41 --- /dev/null +++ b/jdk/test/java/lang/Thread/ThreadStateController.java @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.concurrent.Phaser; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.LockSupport; + +/** + * ThreadStateController allows a thread to request this thread to transition + * to a specific thread state. The {@linkplain #transitionTo request} is + * a blocking call that the calling thread will wait until this thread is about + * going to the new state. Only one request of state transition at a time + * is supported (the Phaser expects only parties of 2 to arrive and advance + * to next phase). + */ +public class ThreadStateController extends Thread { + // used to achieve waiting states + private final Object lock; + public ThreadStateController(String name, Object lock) { + super(name); + this.lock = lock; + } + + public void checkThreadState(Thread.State expected) { + // maximum number of retries when checking for thread state. + final int MAX_RETRY = 500; + + // wait for the thread to transition to the expected state. + // There is a small window between the thread checking the state + // and the thread actual entering that state. + Thread.State state; + int retryCount=0; + while ((state = getState()) != expected && retryCount < MAX_RETRY) { + pause(10); + retryCount++; + } + + if (state == null) { + throw new RuntimeException(getName() + " expected to have " + + expected + " but got null."); + } + + if (state != expected) { + throw new RuntimeException(String.format("%s expected in %s state but got %s " + + "(iterations %d interrupted %d)%n", + getName(), expected, state, iterations.get(), interrupted.get())); + } + } + + public static void pause(long ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + // Phaser to sync between the main thread putting + // this thread into various states + private final Phaser phaser = new Phaser(2); + private volatile int newState = S_RUNNABLE; + private volatile int state = 0; + private boolean done = false; + + private static final int S_RUNNABLE = 1; + private static final int S_BLOCKED = 2; + private static final int S_WAITING = 3; + private static final int S_TIMED_WAITING = 4; + private static final int S_PARKED = 5; + private static final int S_TIMED_PARKED = 6; + private static final int S_SLEEPING = 7; + private static final int S_TERMINATE = 8; + + // for debugging + private AtomicInteger iterations = new AtomicInteger(); + private AtomicInteger interrupted = new AtomicInteger(); + public void run() { + // this thread has started + while (!done) { + // state transition + int nextState = state; + if (newState != state) { + nextState = newState; + iterations.set(0); + interrupted.set(0); + } + iterations.incrementAndGet(); + switch (nextState) { + case S_RUNNABLE: { + stateChange(nextState); + double sum = 0; + for (int i = 0; i < 1000; i++) { + double r = Math.random(); + double x = Math.pow(3, r); + sum += x - r; + } + break; + } + case S_BLOCKED: { + System.out.format("%d: %s is going to block (interations %d)%n", + getId(), getName(), iterations.get()); + stateChange(nextState); + // going to block on lock + synchronized (lock) { + System.out.format("%d: %s acquired the lock (interations %d)%n", + getId(), getName(), iterations.get()); + try { + // this thread has escaped the BLOCKED state + // release the lock and a short wait before continue + lock.wait(10); + } catch (InterruptedException e) { + // ignore + interrupted.incrementAndGet(); + } + } + break; + } + case S_WAITING: { + synchronized (lock) { + System.out.format("%d: %s is going to waiting (interations %d interrupted %d)%n", + getId(), getName(), iterations.get(), interrupted.get()); + try { + stateChange(nextState); + lock.wait(); + System.out.format("%d: %s wakes up from waiting (interations %d interrupted %d)%n", + getId(), getName(), iterations.get(), interrupted.get()); + } catch (InterruptedException e) { + // ignore + interrupted.incrementAndGet(); + } + } + break; + } + case S_TIMED_WAITING: { + synchronized (lock) { + System.out.format("%d: %s is going to timed waiting (interations %d interrupted %d)%n", + getId(), getName(), iterations.get(), interrupted.get()); + try { + stateChange(nextState); + lock.wait(10000); + System.out.format("%d: %s wakes up from timed waiting (interations %d interrupted %d)%n", + getId(), getName(), iterations.get(), interrupted.get()); + } catch (InterruptedException e) { + // ignore + interrupted.incrementAndGet(); + } + } + break; + } + case S_PARKED: { + System.out.format("%d: %s is going to park (interations %d)%n", + getId(), getName(), iterations.get()); + stateChange(nextState); + LockSupport.park(); + break; + } + case S_TIMED_PARKED: { + System.out.format("%d: %s is going to timed park (interations %d)%n", + getId(), getName(), iterations.get()); + long deadline = System.currentTimeMillis() + 10000*1000; + stateChange(nextState); + LockSupport.parkUntil(deadline); + break; + } + case S_SLEEPING: { + System.out.format("%d: %s is going to sleep (interations %d interrupted %d)%n", + getId(), getName(), iterations.get(), interrupted.get()); + try { + stateChange(nextState); + Thread.sleep(1000000); + } catch (InterruptedException e) { + // finish sleeping + interrupted.incrementAndGet(); + } + break; + } + case S_TERMINATE: { + done = true; + stateChange(nextState); + break; + } + default: + break; + } + } + } + + /** + * Change the state if it matches newState. + */ + private void stateChange(int nextState) { + // no state change + if (state == nextState) + return; + + // transition to the new state + if (newState == nextState) { + state = nextState; + phaser.arrive(); + System.out.format("%d: state change: %s %s%n", + getId(), toStateName(nextState), phaserToString(phaser)); + return; + } + + // should never reach here + throw new RuntimeException("current " + state + " next " + nextState + + " new state " + newState); + } + + /** + * Blocks until this thread transitions to the given state + */ + public void transitionTo(Thread.State tstate) throws InterruptedException { + switch (tstate) { + case RUNNABLE: + nextState(S_RUNNABLE); + break; + case BLOCKED: + nextState(S_BLOCKED); + break; + case WAITING: + nextState(S_WAITING); + break; + case TIMED_WAITING: + nextState(S_TIMED_WAITING); + break; + case TERMINATED: + nextState(S_TERMINATE); + break; + default: + break; + } + } + + /** + * Blocks until this thread transitions to sleeping + */ + public void transitionToSleep() throws InterruptedException { + nextState(S_SLEEPING); + } + + /** + * Blocks until this thread transitions to park or timed park + */ + public void transitionToPark(boolean timed) throws InterruptedException { + nextState(timed ? S_TIMED_PARKED : S_PARKED); + } + + private void nextState(int s) throws InterruptedException { + final long id = Thread.currentThread().getId(); + System.out.format("%d: wait until the thread transitions to %s %s%n", + id, toStateName(s), phaserToString(phaser)); + this.newState = s; + int phase = phaser.arrive(); + System.out.format("%d: awaiting party arrive %s %s%n", + id, toStateName(s), phaserToString(phaser)); + for (;;) { + // when this thread has changed its state before it waits or parks + // on a lock, a potential race might happen if it misses the notify + // or unpark. Hence await for the phaser to advance with timeout + // to cope with this race condition. + switch (state) { + case S_WAITING: + case S_TIMED_WAITING: + synchronized (lock) { + lock.notify(); + } + break; + case S_PARKED: + case S_TIMED_PARKED: + LockSupport.unpark(this); + break; + case S_SLEEPING: + this.interrupt(); + break; + case S_BLOCKED: + default: + break; + } + try { + phaser.awaitAdvanceInterruptibly(phase, 100, TimeUnit.MILLISECONDS); + System.out.format("%d: arrived at %s %s%n", + id, toStateName(s), phaserToString(phaser)); + return; + } catch (TimeoutException ex) { + // this thread hasn't arrived at this phase + System.out.format("%d: Timeout: %s%n", id, phaser); + } + } + } + private String phaserToString(Phaser p) { + return "[phase = " + p.getPhase() + + " parties = " + p.getRegisteredParties() + + " arrived = " + p.getArrivedParties() + "]"; + } + private String toStateName(int state) { + switch (state) { + case S_RUNNABLE: + return "runnable"; + case S_WAITING: + return "waiting"; + case S_TIMED_WAITING: + return "timed waiting"; + case S_PARKED: + return "parked"; + case S_TIMED_PARKED: + return "timed parked"; + case S_SLEEPING: + return "sleeping"; + case S_BLOCKED: + return "blocked"; + case S_TERMINATE: + return "terminated"; + default: + return "unknown " + state; + } + } +} diff --git a/jdk/test/java/lang/Thread/ThreadStateTest.java b/jdk/test/java/lang/Thread/ThreadStateTest.java index c4fa18850b2..b73421eb4c0 100644 --- a/jdk/test/java/lang/Thread/ThreadStateTest.java +++ b/jdk/test/java/lang/Thread/ThreadStateTest.java @@ -21,77 +21,64 @@ * questions. */ +import static java.lang.Thread.State.*; + /* * @test - * @bug 5014783 + * @bug 5014783 8022208 * @summary Basic unit test of thread states returned by * Thread.getState(). * * @author Mandy Chung - * - * @build ThreadStateTest + * @build ThreadStateTest ThreadStateController * @run main ThreadStateTest */ -import java.util.concurrent.locks.LockSupport; -import java.util.concurrent.Phaser; - public class ThreadStateTest { - // maximum number of retries when checking for thread state. - static final int MAX_RETRY = 500; - private static boolean testFailed = false; // used to achieve waiting states - static final Object globalLock = new Object(); + private static final Object globalLock = new Object(); - public static void main(String[] argv) { + public static void main(String[] argv) throws Exception { // Call Thread.getState to force all initialization done // before test verification begins. Thread.currentThread().getState(); - MyThread myThread = new MyThread("MyThread"); + ThreadStateController thread = new ThreadStateController("StateChanger", globalLock); + thread.setDaemon(true); // before myThread starts - checkThreadState(myThread, Thread.State.NEW); + thread.checkThreadState(NEW); - myThread.start(); - myThread.waitUntilStarted(); - checkThreadState(myThread, Thread.State.RUNNABLE); + thread.start(); + thread.transitionTo(RUNNABLE); + thread.checkThreadState(RUNNABLE); synchronized (globalLock) { - myThread.goBlocked(); - checkThreadState(myThread, Thread.State.BLOCKED); + thread.transitionTo(BLOCKED); + thread.checkThreadState(BLOCKED); } - myThread.goWaiting(); - checkThreadState(myThread, Thread.State.WAITING); + thread.transitionTo(WAITING); + thread.checkThreadState(WAITING); - myThread.goTimedWaiting(); - checkThreadState(myThread, Thread.State.TIMED_WAITING); + thread.transitionTo(TIMED_WAITING); + thread.checkThreadState(TIMED_WAITING); + thread.transitionToPark(true /* timed park*/); + thread.checkThreadState(TIMED_WAITING); - /* - *********** park and parkUntil seems not working - * ignore this case for now. - * Bug ID 5062095 - *********************************************** + thread.transitionToPark(false /* indefinite park */); + thread.checkThreadState(WAITING); - myThread.goParked(); - checkThreadState(myThread, Thread.State.WAITING); + thread.transitionToSleep(); + thread.checkThreadState(TIMED_WAITING); - myThread.goTimedParked(); - checkThreadState(myThread, Thread.State.TIMED_WAITING); - */ - - - myThread.goSleeping(); - checkThreadState(myThread, Thread.State.TIMED_WAITING); - - myThread.terminate(); - checkThreadState(myThread, Thread.State.TERMINATED); + thread.transitionTo(TERMINATED); + thread.checkThreadState(TERMINATED); try { - myThread.join(); + thread.join(); } catch (InterruptedException e) { e.printStackTrace(); System.out.println("Unexpected exception."); @@ -102,241 +89,4 @@ public class ThreadStateTest { throw new RuntimeException("TEST FAILED."); System.out.println("Test passed."); } - - private static void checkThreadState(Thread t, Thread.State expected) { - // wait for the thread to transition to the expected state. - // There is a small window between the thread checking the state - // and the thread actual entering that state. - Thread.State state; - int retryCount=0; - while ((state = t.getState()) != expected && retryCount < MAX_RETRY) { - if (state != Thread.State.RUNNABLE) { - throw new RuntimeException("Thread not in expected state yet," + - " but it should at least be RUNNABLE"); - } - goSleep(10); - retryCount++; - } - - System.out.println("Checking thread state " + state); - if (state == null) { - throw new RuntimeException(t.getName() + " expected to have " + - expected + " but got null."); - } - - if (state != expected) { - throw new RuntimeException(t.getName() + " expected to have " + - expected + " but got " + state); - } - } - - private static void goSleep(long ms) { - try { - Thread.sleep(ms); - } catch (InterruptedException e) { - e.printStackTrace(); - System.out.println("Unexpected exception."); - testFailed = true; - } - } - - static class MyThread extends Thread { - // Phaser to sync between the main thread putting - // this thread into various states - private Phaser phaser = new Phaser(2); - - MyThread(String name) { - super(name); - } - - private final int RUNNABLE = 0; - private final int BLOCKED = 1; - private final int WAITING = 2; - private final int TIMED_WAITING = 3; - private final int PARKED = 4; - private final int TIMED_PARKED = 5; - private final int SLEEPING = 6; - private final int TERMINATE = 7; - - private volatile int state = RUNNABLE; - - private boolean done = false; - public void run() { - // Signal main thread to continue. - phaser.arriveAndAwaitAdvance(); - - while (!done) { - switch (state) { - case RUNNABLE: { - double sum = 0; - for (int i = 0; i < 1000; i++) { - double r = Math.random(); - double x = Math.pow(3, r); - sum += x - r; - } - break; - } - case BLOCKED: { - // signal main thread. - phaser.arrive(); - System.out.println(" myThread is going to block."); - synchronized (globalLock) { - // finish blocking - state = RUNNABLE; - } - break; - } - case WAITING: { - synchronized (globalLock) { - // signal main thread. - phaser.arrive(); - System.out.println(" myThread is going to wait."); - try { - globalLock.wait(); - } catch (InterruptedException e) { - // ignore - } - } - break; - } - case TIMED_WAITING: { - synchronized (globalLock) { - // signal main thread. - phaser.arrive(); - System.out.println(" myThread is going to timed wait."); - try { - globalLock.wait(10000); - } catch (InterruptedException e) { - // ignore - } - } - break; - } - case PARKED: { - // signal main thread. - phaser.arrive(); - System.out.println(" myThread is going to park."); - LockSupport.park(); - // give a chance for the main thread to block - goSleep(10); - break; - } - case TIMED_PARKED: { - // signal main thread. - phaser.arrive(); - System.out.println(" myThread is going to timed park."); - long deadline = System.currentTimeMillis() + 10000*1000; - LockSupport.parkUntil(deadline); - - // give a chance for the main thread to block - goSleep(10); - break; - } - case SLEEPING: { - // signal main thread. - phaser.arrive(); - System.out.println(" myThread is going to sleep."); - try { - Thread.sleep(1000000); - } catch (InterruptedException e) { - // finish sleeping - } - break; - } - case TERMINATE: { - done = true; - // signal main thread. - phaser.arrive(); - break; - } - default: - break; - } - } - } - - public void waitUntilStarted() { - // wait for MyThread. - phaser.arriveAndAwaitAdvance(); - } - - public void goBlocked() { - System.out.println("Waiting myThread to go blocked."); - setState(BLOCKED); - // wait for MyThread to get to a point just before being blocked - phaser.arriveAndAwaitAdvance(); - } - - public void goWaiting() { - System.out.println("Waiting myThread to go waiting."); - setState(WAITING); - // wait for MyThread to get to just before wait on object. - phaser.arriveAndAwaitAdvance(); - } - - public void goTimedWaiting() { - System.out.println("Waiting myThread to go timed waiting."); - setState(TIMED_WAITING); - // wait for MyThread to get to just before timed wait call. - phaser.arriveAndAwaitAdvance(); - } - - public void goParked() { - System.out.println("Waiting myThread to go parked."); - setState(PARKED); - // wait for MyThread to get to just before parked. - phaser.arriveAndAwaitAdvance(); - } - - public void goTimedParked() { - System.out.println("Waiting myThread to go timed parked."); - setState(TIMED_PARKED); - // wait for MyThread to get to just before timed park. - phaser.arriveAndAwaitAdvance(); - } - - public void goSleeping() { - System.out.println("Waiting myThread to go sleeping."); - setState(SLEEPING); - // wait for MyThread to get to just before sleeping - phaser.arriveAndAwaitAdvance(); - } - - public void terminate() { - System.out.println("Waiting myThread to terminate."); - setState(TERMINATE); - // wait for MyThread to get to just before terminate - phaser.arriveAndAwaitAdvance(); - } - - private void setState(int newState) { - switch (state) { - case BLOCKED: - while (state == BLOCKED) { - goSleep(10); - } - state = newState; - break; - case WAITING: - case TIMED_WAITING: - state = newState; - synchronized (globalLock) { - globalLock.notify(); - } - break; - case PARKED: - case TIMED_PARKED: - state = newState; - LockSupport.unpark(this); - break; - case SLEEPING: - state = newState; - this.interrupt(); - break; - default: - state = newState; - break; - } - } - } } diff --git a/jdk/test/java/lang/management/ThreadMXBean/ThreadMXBeanStateTest.java b/jdk/test/java/lang/management/ThreadMXBean/ThreadMXBeanStateTest.java new file mode 100644 index 00000000000..dc4fe3d1016 --- /dev/null +++ b/jdk/test/java/lang/management/ThreadMXBean/ThreadMXBeanStateTest.java @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2003, 2006, 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 4967283 5080203 8022208 + * @summary Basic unit test of thread states returned by + * ThreadMXBean.getThreadInfo.getThreadState(). + * It also tests lock information returned by ThreadInfo. + * + * @author Mandy Chung + * + * @library ../../Thread + * @build ThreadMXBeanStateTest ThreadStateController + * @run main ThreadMXBeanStateTest + */ + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadMXBean; +import java.lang.management.ThreadInfo; +import static java.lang.Thread.State.*; + +public class ThreadMXBeanStateTest { + private static final ThreadMXBean tm = ManagementFactory.getThreadMXBean(); + + static class Lock { + private String name; + Lock(String name) { + this.name = name; + } + public String toString() { + return name; + } + } + private static Lock globalLock = new Lock("my lock"); + + public static void main(String[] argv) throws Exception { + // Force thread state initialization now before the test + // verification begins. + Thread.currentThread().getState(); + ThreadStateController thread = new ThreadStateController("StateChanger", globalLock); + thread.setDaemon(true); + + // before myThread starts + thread.checkThreadState(NEW); + + thread.start(); + thread.transitionTo(RUNNABLE); + thread.checkThreadState(RUNNABLE); + checkLockInfo(thread, RUNNABLE, null, null); + + thread.suspend(); + ThreadStateController.pause(10); + thread.checkThreadState(RUNNABLE); + checkSuspendedThreadState(thread, RUNNABLE); + thread.resume(); + + synchronized (globalLock) { + thread.transitionTo(BLOCKED); + thread.checkThreadState(BLOCKED); + checkLockInfo(thread, BLOCKED, + globalLock, Thread.currentThread()); + } + + thread.transitionTo(WAITING); + thread.checkThreadState(WAITING); + checkLockInfo(thread, Thread.State.WAITING, + globalLock, null); + + thread.transitionTo(TIMED_WAITING); + thread.checkThreadState(TIMED_WAITING); + checkLockInfo(thread, TIMED_WAITING, + globalLock, null); + + + thread.transitionToPark(true /* timed park */); + thread.checkThreadState(TIMED_WAITING); + checkLockInfo(thread, TIMED_WAITING, null, null); + + thread.transitionToPark(false /* indefinite park */); + thread.checkThreadState(WAITING); + checkLockInfo(thread, WAITING, null, null); + + thread.transitionToSleep(); + thread.checkThreadState(TIMED_WAITING); + checkLockInfo(thread, TIMED_WAITING, null, null); + + thread.transitionTo(TERMINATED); + thread.checkThreadState(TERMINATED); + + try { + thread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + System.out.println("TEST FAILED: Unexpected exception."); + throw new RuntimeException(e); + } + System.out.println("Test passed."); + } + + private static void checkSuspendedThreadState(ThreadStateController t, Thread.State state) { + ThreadInfo info = getThreadInfo(t, state); + if (info == null) { + throw new RuntimeException(t.getName() + + " expected to have ThreadInfo " + + " but got null."); + } + + if (info.getThreadState() != state) { + throw new RuntimeException(t.getName() + " expected to be in " + + state + " state but got " + info.getThreadState()); + } + + if (!info.isSuspended()) { + throw new RuntimeException(t.getName() + " expected to be suspended " + + " but isSuspended() returns " + info.isSuspended()); + } + } + + private static String getLockName(Object lock) { + if (lock == null) return null; + + return lock.getClass().getName() + '@' + + Integer.toHexString(System.identityHashCode(lock)); + } + + // maximum number of retries when checking for thread state. + private static final int MAX_RETRY = 500; + private static ThreadInfo getThreadInfo(ThreadStateController t, Thread.State expected) { + // wait for the thread to transition to the expected state. + // There is a small window between the thread checking the state + // and the thread actual entering that state. + int retryCount=0; + ThreadInfo info = tm.getThreadInfo(t.getId()); + while (info.getThreadState() != expected && retryCount < MAX_RETRY) { + ThreadStateController.pause(10); + retryCount++; + info = tm.getThreadInfo(t.getId()); + } + return info; + } + + private static void checkLockInfo(ThreadStateController t, Thread.State state, + Object lock, Thread owner) { + ThreadInfo info = getThreadInfo(t, state); + if (info == null) { + throw new RuntimeException(t.getName() + + " expected to have ThreadInfo " + + " but got null."); + } + + if (info.getThreadState() != state) { + throw new RuntimeException(t.getName() + " expected to be in " + + state + " state but got " + info.getThreadState()); + } + + if (lock == null && info.getLockName() != null) { + throw new RuntimeException(t.getName() + + " expected not to be blocked on any lock" + + " but got " + info.getLockName()); + } + String expectedLockName = getLockName(lock); + if (lock != null && info.getLockName() == null) { + throw new RuntimeException(t.getName() + + " expected to be blocked on lock [" + expectedLockName + + "] but got null."); + } + + if (lock != null && !expectedLockName.equals(info.getLockName())) { + throw new RuntimeException(t.getName() + + " expected to be blocked on lock [" + expectedLockName + + "] but got [" + info.getLockName() + "]."); + } + + if (owner == null && info.getLockOwnerName() != null) { + throw new RuntimeException("Lock owner is expected " + + " to be null but got " + info.getLockOwnerName()); + } + + if (owner != null && info.getLockOwnerName() == null) { + throw new RuntimeException("Lock owner is expected to be " + + owner.getName() + + " but got null."); + } + if (owner != null && !info.getLockOwnerName().equals(owner.getName())) { + throw new RuntimeException("Lock owner is expected to be " + + owner.getName() + + " but got " + owner.getName()); + } + if (owner == null && info.getLockOwnerId() != -1) { + throw new RuntimeException("Lock owner is expected " + + " to be -1 but got " + info.getLockOwnerId()); + } + + if (owner != null && info.getLockOwnerId() <= 0) { + throw new RuntimeException("Lock owner is expected to be " + + owner.getName() + "(id = " + owner.getId() + + ") but got " + info.getLockOwnerId()); + } + if (owner != null && info.getLockOwnerId() != owner.getId()) { + throw new RuntimeException("Lock owner is expected to be " + + owner.getName() + "(id = " + owner.getId() + + ") but got " + info.getLockOwnerId()); + } + if (info.isSuspended()) { + throw new RuntimeException(t.getName() + + " isSuspended() returns " + info.isSuspended()); + } + } +} diff --git a/jdk/test/java/lang/management/ThreadMXBean/ThreadStateTest.java b/jdk/test/java/lang/management/ThreadMXBean/ThreadStateTest.java deleted file mode 100644 index 1b767e46225..00000000000 --- a/jdk/test/java/lang/management/ThreadMXBean/ThreadStateTest.java +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright (c) 2003, 2006, 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 4967283 5080203 - * @summary Basic unit test of thread states returned by - * ThreadMXBean.getThreadInfo.getThreadState(). - * It also tests lock information returned by ThreadInfo. - * - * @author Mandy Chung - * - * @build ThreadExecutionSynchronizer Utils - * @run main ThreadStateTest - */ - -import java.lang.management.ManagementFactory; -import java.lang.management.ThreadMXBean; -import java.lang.management.ThreadInfo; - -import java.util.concurrent.locks.LockSupport; - -public class ThreadStateTest { - private static final ThreadMXBean tm = ManagementFactory.getThreadMXBean(); - - static class Lock { - private String name; - Lock(String name) { - this.name = name; - } - public String toString() { - return name; - } - } - private static Lock globalLock = new Lock("my lock"); - - public static void main(String[] argv) { - // Force thread state initialization now before the test - // verification begins. - Thread.currentThread().getState(); - - MyThread myThread = new MyThread("MyThread"); - - // before myThread starts - // Utils.checkThreadState(myThread, Thread.State.NEW); - - myThread.start(); - myThread.waitUntilStarted(); - Utils.checkThreadState(myThread, Thread.State.RUNNABLE); - checkLockInfo(myThread, Thread.State.RUNNABLE, null, null); - - myThread.suspend(); - Utils.goSleep(10); - checkSuspendedThreadState(myThread, Thread.State.RUNNABLE); - myThread.resume(); - - synchronized (globalLock) { - myThread.goBlocked(); - Utils.checkThreadState(myThread, Thread.State.BLOCKED); - checkLockInfo(myThread, Thread.State.BLOCKED, - globalLock, Thread.currentThread()); - } - - myThread.goWaiting(); - Utils.checkThreadState(myThread, Thread.State.WAITING); - checkLockInfo(myThread, Thread.State.WAITING, - globalLock, null); - - myThread.goTimedWaiting(); - Utils.checkThreadState(myThread, Thread.State.TIMED_WAITING); - checkLockInfo(myThread, Thread.State.TIMED_WAITING, - globalLock, null); - - - - /* - *********** parkUntil seems not working - * ignore this park case for now. - - Bug ID : 5062095 - *********************************************** - myThread.goParked(); - Utils.checkThreadState(myThread, Thread.State.WAITING); - checkLockInfo(myThread, Thread.State.WAITING, null, null); - - myThread.goTimedParked(); - Utils.checkThreadState(myThread, Thread.State.TIMED_WAITING); - checkLockInfo(myThread, Thread.State.TIMED_WAITING, null, null); - - */ - - myThread.goSleeping(); - Utils.checkThreadState(myThread, Thread.State.TIMED_WAITING); - checkLockInfo(myThread, Thread.State.TIMED_WAITING, null, null); - - - myThread.terminate(); - // Utils.checkThreadState(myThread, ThreadState.TERMINATED); - - try { - myThread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - System.out.println("TEST FAILED: Unexpected exception."); - throw new RuntimeException(e); - } - System.out.println("Test passed."); - } - - private static void checkSuspendedThreadState(Thread t, Thread.State state) { - ThreadInfo info = tm.getThreadInfo(t.getId()); - if (info == null) { - throw new RuntimeException(t.getName() + - " expected to have ThreadInfo " + - " but got null."); - } - - if (info.getThreadState() != state) { - throw new RuntimeException(t.getName() + " expected to be in " + - state + " state but got " + info.getThreadState()); - } - - if (!info.isSuspended()) { - throw new RuntimeException(t.getName() + " expected to be suspended " + - " but isSuspended() returns " + info.isSuspended()); - } - Utils.checkThreadState(t, state); - } - - private static String getLockName(Object lock) { - if (lock == null) return null; - - return lock.getClass().getName() + '@' + - Integer.toHexString(System.identityHashCode(lock)); - } - - private static void checkLockInfo(Thread t, Thread.State state, Object lock, Thread owner) { - ThreadInfo info = tm.getThreadInfo(t.getId()); - if (info == null) { - throw new RuntimeException(t.getName() + - " expected to have ThreadInfo " + - " but got null."); - } - - if (info.getThreadState() != state) { - throw new RuntimeException(t.getName() + " expected to be in " + - state + " state but got " + info.getThreadState()); - } - - if (lock == null && info.getLockName() != null) { - throw new RuntimeException(t.getName() + - " expected not to be blocked on any lock" + - " but got " + info.getLockName()); - } - String expectedLockName = getLockName(lock); - if (lock != null && info.getLockName() == null) { - throw new RuntimeException(t.getName() + - " expected to be blocked on lock [" + expectedLockName + - "] but got null."); - } - - if (lock != null && !expectedLockName.equals(info.getLockName())) { - throw new RuntimeException(t.getName() + - " expected to be blocked on lock [" + expectedLockName + - "] but got [" + info.getLockName() + "]."); - } - - if (owner == null && info.getLockOwnerName() != null) { - throw new RuntimeException("Lock owner is expected " + - " to be null but got " + info.getLockOwnerName()); - } - - if (owner != null && info.getLockOwnerName() == null) { - throw new RuntimeException("Lock owner is expected to be " + - owner.getName() + - " but got null."); - } - if (owner != null && !info.getLockOwnerName().equals(owner.getName())) { - throw new RuntimeException("Lock owner is expected to be " + - owner.getName() + - " but got " + owner.getName()); - } - if (owner == null && info.getLockOwnerId() != -1) { - throw new RuntimeException("Lock owner is expected " + - " to be -1 but got " + info.getLockOwnerId()); - } - - if (owner != null && info.getLockOwnerId() <= 0) { - throw new RuntimeException("Lock owner is expected to be " + - owner.getName() + "(id = " + owner.getId() + - ") but got " + info.getLockOwnerId()); - } - if (owner != null && info.getLockOwnerId() != owner.getId()) { - throw new RuntimeException("Lock owner is expected to be " + - owner.getName() + "(id = " + owner.getId() + - ") but got " + info.getLockOwnerId()); - } - if (info.isSuspended()) { - throw new RuntimeException(t.getName() + - " isSuspended() returns " + info.isSuspended()); - } - } - - static class MyThread extends Thread { - private ThreadExecutionSynchronizer thrsync = new ThreadExecutionSynchronizer(); - - MyThread(String name) { - super(name); - } - - private final int RUNNABLE = 0; - private final int BLOCKED = 1; - private final int WAITING = 2; - private final int TIMED_WAITING = 3; - private final int PARKED = 4; - private final int TIMED_PARKED = 5; - private final int SLEEPING = 6; - private final int TERMINATE = 7; - private int state = RUNNABLE; - - private boolean done = false; - public void run() { - // Signal main thread to continue. - thrsync.signal(); - while (!done) { - switch (state) { - case RUNNABLE: { - double sum = 0; - for (int i = 0; i < 1000; i++) { - double r = Math.random(); - double x = Math.pow(3, r); - sum += x - r; - } - break; - } - case BLOCKED: { - // signal main thread. - thrsync.signal(); - System.out.println(" myThread is going to block."); - synchronized (globalLock) { - // finish blocking - state = RUNNABLE; - } - break; - } - case WAITING: { - synchronized (globalLock) { - // signal main thread. - thrsync.signal(); - System.out.println(" myThread is going to wait."); - try { - globalLock.wait(); - } catch (InterruptedException e) { - // ignore - } - } - break; - } - case TIMED_WAITING: { - synchronized (globalLock) { - // signal main thread. - thrsync.signal(); - System.out.println(" myThread is going to timed wait."); - try { - globalLock.wait(10000); - } catch (InterruptedException e) { - // ignore - } - } - break; - } - case PARKED: { - // signal main thread. - thrsync.signal(); - System.out.println(" myThread is going to park."); - LockSupport.park(); - // give a chance for the main thread to block - System.out.println(" myThread is going to park."); - Utils.goSleep(10); - break; - } - case TIMED_PARKED: { - // signal main thread. - thrsync.signal(); - System.out.println(" myThread is going to timed park."); - long deadline = System.currentTimeMillis() + 10000*1000; - LockSupport.parkUntil(deadline); - - // give a chance for the main thread to block - Utils.goSleep(10); - break; - } - case SLEEPING: { - // signal main thread. - thrsync.signal(); - System.out.println(" myThread is going to sleep."); - try { - Thread.sleep(1000000); - } catch (InterruptedException e) { - // finish sleeping - interrupted(); - } - break; - } - case TERMINATE: { - done = true; - // signal main thread. - thrsync.signal(); - break; - } - default: - break; - } - } - } - public void waitUntilStarted() { - // wait for MyThread. - thrsync.waitForSignal(); - Utils.goSleep(10); - } - - public void goBlocked() { - System.out.println("Waiting myThread to go blocked."); - setState(BLOCKED); - // wait for MyThread to get blocked - thrsync.waitForSignal(); - Utils.goSleep(20); - } - - public void goWaiting() { - System.out.println("Waiting myThread to go waiting."); - setState(WAITING); - // wait for MyThread to wait on object. - thrsync.waitForSignal(); - Utils.goSleep(20); - } - public void goTimedWaiting() { - System.out.println("Waiting myThread to go timed waiting."); - setState(TIMED_WAITING); - // wait for MyThread timed wait call. - thrsync.waitForSignal(); - Utils.goSleep(20); - } - public void goParked() { - System.out.println("Waiting myThread to go parked."); - setState(PARKED); - // wait for MyThread state change to PARKED. - thrsync.waitForSignal(); - Utils.goSleep(20); - } - public void goTimedParked() { - System.out.println("Waiting myThread to go timed parked."); - setState(TIMED_PARKED); - // wait for MyThread. - thrsync.waitForSignal(); - Utils.goSleep(20); - } - - public void goSleeping() { - System.out.println("Waiting myThread to go sleeping."); - setState(SLEEPING); - // wait for MyThread. - thrsync.waitForSignal(); - Utils.goSleep(20); - } - public void terminate() { - System.out.println("Waiting myThread to terminate."); - setState(TERMINATE); - // wait for MyThread. - thrsync.waitForSignal(); - Utils.goSleep(20); - } - - private void setState(int newState) { - switch (state) { - case BLOCKED: - while (state == BLOCKED) { - Utils.goSleep(20); - } - state = newState; - break; - case WAITING: - case TIMED_WAITING: - state = newState; - synchronized (globalLock) { - globalLock.notify(); - } - break; - case PARKED: - case TIMED_PARKED: - state = newState; - LockSupport.unpark(this); - break; - case SLEEPING: - state = newState; - this.interrupt(); - break; - default: - state = newState; - break; - } - } - } -} From 4f0480aaeb20f7a776917008275972f03014d5eb Mon Sep 17 00:00:00 2001 From: Mike Duigou Date: Tue, 5 Nov 2013 19:44:41 -0800 Subject: [PATCH 021/110] 8021309: replace test/Makefile jdk_* targets with jtreg groups 8015068: Use jtreg -exclude for handling problemList.txt exclusions Reviewed-by: jjg, smarks, chegar, alanb, dholmes --- jdk/.hgignore | 1 + jdk/test/Makefile | 471 ++++++---------------------------------------- 2 files changed, 63 insertions(+), 409 deletions(-) diff --git a/jdk/.hgignore b/jdk/.hgignore index e849b9e6d1f..d8754b13e1f 100644 --- a/jdk/.hgignore +++ b/jdk/.hgignore @@ -1,5 +1,6 @@ ^build/ ^dist/ +^testoutput/ /nbproject/private/ ^make/netbeans/.*/build/ ^make/netbeans/.*/dist/ diff --git a/jdk/test/Makefile b/jdk/test/Makefile index c4a9b93bec6..9a9092df16b 100644 --- a/jdk/test/Makefile +++ b/jdk/test/Makefile @@ -27,6 +27,8 @@ # Makefile to run various jdk tests # +.DEFAULT : all + # Empty these to get rid of some default rules .SUFFIXES: .SUFFIXES: .java @@ -55,150 +57,19 @@ UNIQ = uniq WC = wc ZIP = zip -# Get OS name from uname -UNAME_S := $(shell $(UNAME) -s) +# Get OS name from uname (Cygwin inexplicably adds _NT-5.1) +UNAME_S := $(shell $(UNAME) -s | $(CUT) -f1 -d_) # Commands to run on paths to make mixed paths for java on windows -GETMIXEDPATH=$(ECHO) - -# Location of developer shared files -SLASH_JAVA = /java - -# Platform specific settings -ifeq ($(UNAME_S), SunOS) - OS_NAME = solaris - OS_ARCH := $(shell $(UNAME) -p) - OS_VERSION := $(shell $(UNAME) -r) -endif -ifeq ($(UNAME_S), Linux) - OS_NAME = linux - OS_ARCH := $(shell $(UNAME) -m) - # Check for unknown arch, try uname -p if uname -m says unknown - ifeq ($(OS_ARCH),unknown) - OS_ARCH := $(shell $(UNAME) -p) - endif - OS_VERSION := $(shell $(UNAME) -r) -endif -ifeq ($(UNAME_S), Darwin) - OS_NAME = macosx - OS_ARCH := $(shell $(UNAME) -m) - # Check for unknown arch, try uname -p if uname -m says unknown - ifeq ($(OS_ARCH),unknown) - OS_ARCH := $(shell $(UNAME) -p) - endif - OS_VERSION := $(shell $(UNAME) -r) -endif -ifeq ($(OS_NAME),) - OS_NAME = windows - # GNU Make or MKS overrides $(PROCESSOR_ARCHITECTURE) to always - # return "x86". Use the first word of $(PROCESSOR_IDENTIFIER) instead. - ifeq ($(PROCESSOR_IDENTIFIER),) - PROC_ARCH:=$(shell $(UNAME) -m) - else - PROC_ARCH:=$(word 1, $(PROCESSOR_IDENTIFIER)) - endif - OS_ARCH:=$(PROC_ARCH) +ifeq ($(UNAME_S), CYGWIN) + # Location of developer shared files SLASH_JAVA = J: - EXESUFFIX = .exe - # These need to be different depending on MKS or CYGWIN - ifeq ($(findstring cygdrive,$(shell ($(CD) C:/ && $(PWD)))), ) - GETMIXEDPATH = dosname -s - OS_VERSION := $(shell $(UNAME) -r) - else - GETMIXEDPATH = cygpath -m -s - OS_VERSION := $(shell $(UNAME) -s | $(CUT) -d'-' -f2) - endif -endif - -# Only want major and minor numbers from os version -OS_VERSION := $(shell $(ECHO) "$(OS_VERSION)" | $(CUT) -d'.' -f1,2) - -# Name to use for x86_64 arch (historically amd64, but should change someday) -OS_ARCH_X64_NAME:=amd64 -#OS_ARCH_X64_NAME:=x64 - -# Alternate arch names (in case this arch is known by a second name) -# PROBLEM_LISTS may use either name. -OS_ARCH2-amd64:=x64 -#OS_ARCH2-x64:=amd64 - -# Try and use the arch names consistently -OS_ARCH:=$(patsubst x64,$(OS_ARCH_X64_NAME),$(OS_ARCH)) -OS_ARCH:=$(patsubst X64,$(OS_ARCH_X64_NAME),$(OS_ARCH)) -OS_ARCH:=$(patsubst AMD64,$(OS_ARCH_X64_NAME),$(OS_ARCH)) -OS_ARCH:=$(patsubst amd64,$(OS_ARCH_X64_NAME),$(OS_ARCH)) -OS_ARCH:=$(patsubst x86_64,$(OS_ARCH_X64_NAME),$(OS_ARCH)) -OS_ARCH:=$(patsubst 8664,$(OS_ARCH_X64_NAME),$(OS_ARCH)) -OS_ARCH:=$(patsubst EM64T,$(OS_ARCH_X64_NAME),$(OS_ARCH)) -OS_ARCH:=$(patsubst em64t,$(OS_ARCH_X64_NAME),$(OS_ARCH)) -OS_ARCH:=$(patsubst intel64,$(OS_ARCH_X64_NAME),$(OS_ARCH)) -OS_ARCH:=$(patsubst Intel64,$(OS_ARCH_X64_NAME),$(OS_ARCH)) -OS_ARCH:=$(patsubst INTEL64,$(OS_ARCH_X64_NAME),$(OS_ARCH)) -OS_ARCH:=$(patsubst IA64,ia64,$(OS_ARCH)) -OS_ARCH:=$(patsubst X86,i586,$(OS_ARCH)) -OS_ARCH:=$(patsubst x86,i586,$(OS_ARCH)) -OS_ARCH:=$(patsubst i386,i586,$(OS_ARCH)) -OS_ARCH:=$(patsubst i486,i586,$(OS_ARCH)) -OS_ARCH:=$(patsubst i686,i586,$(OS_ARCH)) -OS_ARCH:=$(patsubst 386,i586,$(OS_ARCH)) -OS_ARCH:=$(patsubst 486,i586,$(OS_ARCH)) -OS_ARCH:=$(patsubst 586,i586,$(OS_ARCH)) -OS_ARCH:=$(patsubst 686,i586,$(OS_ARCH)) - -# Default ARCH_DATA_MODEL settings -ARCH_DATA_MODEL-i586 = 32 -ARCH_DATA_MODEL-$(OS_ARCH_X64_NAME) = 64 -ARCH_DATA_MODEL-ia64 = 64 -ARCH_DATA_MODEL-sparc = 32 -ARCH_DATA_MODEL-sparcv9 = 64 - -# If ARCH_DATA_MODEL is not defined, try and pick a reasonable default -ifndef ARCH_DATA_MODEL - ARCH_DATA_MODEL:=$(ARCH_DATA_MODEL-$(OS_ARCH)) -endif -ifndef ARCH_DATA_MODEL - ARCH_DATA_MODEL=32 -endif - -# Platform directory name -PLATFORM_OS = $(OS_NAME)-$(OS_ARCH) - -# Check ARCH_DATA_MODEL, adjust OS_ARCH accordingly on solaris -ARCH_DATA_MODEL_ERROR= \ - ARCH_DATA_MODEL=$(ARCH_DATA_MODEL) cannot be used with $(PLATFORM_OS) -ifeq ($(ARCH_DATA_MODEL),64) - ifeq ($(PLATFORM_OS),solaris-i586) - OS_ARCH=$(OS_ARCH_X64_NAME) - endif - ifeq ($(PLATFORM_OS),solaris-sparc) - OS_ARCH=sparcv9 - endif - ifeq ($(OS_ARCH),i586) - x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") - endif - ifeq ($(OS_ARCH),sparc) - x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") - endif + GETMIXEDPATH = cygpath -m -s else - ifeq ($(ARCH_DATA_MODEL),32) - ifeq ($(OS_ARCH),$(OS_ARCH_X64_NAME)) - x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") - endif - ifeq ($(OS_ARCH),ia64) - x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") - endif - ifeq ($(OS_ARCH),sparcv9) - x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") - endif - else - x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") - endif -endif + # Location of developer shared files + SLASH_JAVA = /java -# Alternate OS_ARCH name (defaults to OS_ARCH) -OS_ARCH2:=$(OS_ARCH2-$(OS_ARCH)) -ifeq ($(OS_ARCH2),) - OS_ARCH2:=$(OS_ARCH) + GETMIXEDPATH=$(ECHO) endif # Root of this test area (important to use full paths in some places) @@ -206,17 +77,18 @@ TEST_ROOT := $(shell $(PWD)) # Root of all test results ifdef ALT_OUTPUTDIR - ABS_OUTPUTDIR = $(ALT_OUTPUTDIR) + ABS_OUTPUTDIR = $(shell $(CD) $(ALT_OUTPUTDIR) && $(PWD)) else - ABS_OUTPUTDIR = $(TEST_ROOT)/../build/$(PLATFORM_OS) + ABS_OUTPUTDIR = $(shell $(CD) $(TEST_ROOT)/.. && $(PWD)) endif + ABS_PLATFORM_BUILD_ROOT = $(ABS_OUTPUTDIR) ABS_TEST_OUTPUT_DIR := $(ABS_PLATFORM_BUILD_ROOT)/testoutput/$(UNIQUE_DIR) # Expect JPRT to set PRODUCT_HOME (the product or jdk in this case to test) ifndef PRODUCT_HOME # Try to use j2sdk-image if it exists - ABS_JDK_IMAGE = $(ABS_PLATFORM_BUILD_ROOT)/j2sdk-image + ABS_JDK_IMAGE = $(ABS_PLATFORM_BUILD_ROOT)/images/j2sdk-image PRODUCT_HOME := \ $(shell \ if [ -d $(ABS_JDK_IMAGE) ] ; then \ @@ -240,30 +112,11 @@ ifdef JPRT_PRODUCT_VM_ARGS JAVA_VM_ARGS = $(JPRT_PRODUCT_VM_ARGS) endif -# Check JAVA_ARGS arguments based on ARCH_DATA_MODEL etc. -ifeq ($(OS_NAME),solaris) - D64_ERROR_MESSAGE=Mismatch between ARCH_DATA_MODEL=$(ARCH_DATA_MODEL) and use of -d64 in JAVA_ARGS=$(JAVA_ARGS) - ifeq ($(ARCH_DATA_MODEL),32) - ifneq ($(findstring -d64,$(JAVA_ARGS)),) - x:=$(warning "WARNING: $(D64_ERROR_MESSAGE)") - endif - endif - ifeq ($(ARCH_DATA_MODEL),64) - ifeq ($(findstring -d64,$(JAVA_ARGS)),) - x:=$(warning "WARNING: $(D64_ERROR_MESSAGE)") - endif - endif -endif - -# Macro to run make and set the shared library permissions -define SharedLibraryPermissions -$(MAKE) SHARED_LIBRARY_DIR=$1 UNIQUE_DIR=$@ shared_library_permissions -endef - # Expect JPRT to set JPRT_ARCHIVE_BUNDLE (path to zip bundle for results) -ARCHIVE_BUNDLE = $(ABS_TEST_OUTPUT_DIR)/ARCHIVE_BUNDLE.zip ifdef JPRT_ARCHIVE_BUNDLE ARCHIVE_BUNDLE = $(JPRT_ARCHIVE_BUNDLE) +else + ARCHIVE_BUNDLE = $(ABS_TEST_OUTPUT_DIR)/ARCHIVE_BUNDLE.zip endif # How to create the test bundle (pass or fail, we want to create this) @@ -272,13 +125,15 @@ ZIP_UP_RESULTS = ( $(MKDIR) -p `$(DIRNAME) $(ARCHIVE_BUNDLE)` \ && $(CD) $(ABS_TEST_OUTPUT_DIR) \ && $(CHMOD) -R a+r . \ && $(ZIP) -q -r $(ARCHIVE_BUNDLE) . ) -SUMMARY_TXT = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/JTreport/text/summary.txt + +# important results files +SUMMARY_TXT = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)/JTreport/text/summary.txt") STATS_TXT_NAME = Stats.txt -STATS_TXT = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/$(STATS_TXT_NAME) -RUNLIST = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/runlist.txt -PASSLIST = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/passlist.txt -FAILLIST = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/faillist.txt -EXITCODE = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/exitcode.txt +STATS_TXT = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)/$(STATS_TXT_NAME)") +RUNLIST = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)/runlist.txt") +PASSLIST = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)/passlist.txt") +FAILLIST = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)/faillist.txt") +EXITCODE = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)/exitcode.txt") TESTEXIT = \ if [ ! -s $(EXITCODE) ] ; then \ @@ -316,8 +171,8 @@ BUNDLE_UP_AND_EXIT = \ runc="`$(CAT) $(RUNLIST) | $(WC) -l | $(AWK) '{print $$1;}'`"; \ passc="`$(CAT) $(PASSLIST) | $(WC) -l | $(AWK) '{print $$1;}'`"; \ failc="`$(CAT) $(FAILLIST) | $(WC) -l | $(AWK) '{print $$1;}'`"; \ - exclc="`$(CAT) $(EXCLUDELIST) | $(WC) -l | $(AWK) '{print $$1;}'`"; \ - $(ECHO) "TEST STATS: name=$(UNIQUE_DIR) run=$${runc} pass=$${passc} fail=$${failc} excluded=$${exclc}" \ + exclc="FIXME CODETOOLS-7900176"; \ + $(ECHO) "TEST STATS: name=$(UNIQUE_DIR) run=$${runc} pass=$${passc} fail=$${failc}" \ >> $(STATS_TXT); \ else \ $(ECHO) "Missing file: $${_summary}" >> $(STATS_TXT); \ @@ -336,9 +191,24 @@ all: jdk_default @$(ECHO) "Testing completed successfully" # Prep for output +# Change execute permissions on shared library files. +# Files in repositories should never have execute permissions, but +# there are some tests that have pre-built shared libraries, and these +# windows dll files must have execute permission. Adding execute +# permission may happen automatically on windows when using certain +# versions of mercurial but it cannot be guaranteed. And blindly +# adding execute permission might be seen as a mercurial 'change', so +# we avoid adding execute permission to repository files. But testing +# from a plain source tree needs the chmod a+rx. Applying the chmod to +# all shared libraries not just dll files. And with CYGWIN and sshd +# service, you may need CYGWIN=ntsec for this to work. prep: @$(MKDIR) -p $(ABS_TEST_OUTPUT_DIR) @$(MKDIR) -p `$(DIRNAME) $(ARCHIVE_BUNDLE)` + @if [ ! -d $(TEST_ROOT)/../.hg ] ; then \ + $(FIND) $(TEST_ROOT) \( -name \*.dll -o -name \*.DLL -o -name \*.so \) \ + -exec $(CHMOD) a+rx {} \; ; \ + fi # Cleanup clean: @@ -357,50 +227,21 @@ ifndef JT_HOME endif endif -# Expect JPRT to set TESTDIRS to the jtreg test dirs -ifndef TESTDIRS - TESTDIRS = demo -endif - -# Some tests annoy me and fail frequently -PROBLEM_LIST=ProblemList.txt -PROBLEM_LISTS=$(PROBLEM_LIST) $(wildcard closed/$(PROBLEM_LIST)) -EXCLUDELIST=$(ABS_TEST_OUTPUT_DIR)/excludelist.txt +# Problematic tests to be excluded +PROBLEM_LISTS=$(call MixedDirs,$(wildcard ProblemList.txt closed/ProblemList.txt)) # Create exclude list for this platform and arch ifdef NO_EXCLUDES -$(EXCLUDELIST): $(PROBLEM_LISTS) $(TEST_DEPENDENCIES) - @$(ECHO) "NOTHING_EXCLUDED" > $@ + JTREG_EXCLUSIONS = else -$(EXCLUDELIST): $(PROBLEM_LISTS) $(TEST_DEPENDENCIES) - @$(RM) $@ $@.temp1 $@.temp2 - @(($(CAT) $(PROBLEM_LISTS) | $(EGREP) -- '$(OS_NAME)-all' ) ;\ - ($(CAT) $(PROBLEM_LISTS) | $(EGREP) -- '$(PLATFORM_OS)' ) ;\ - ($(CAT) $(PROBLEM_LISTS) | $(EGREP) -- '$(OS_NAME)-$(OS_ARCH2)' ) ;\ - ($(CAT) $(PROBLEM_LISTS) | $(EGREP) -- '$(OS_NAME)-$(OS_VERSION)') ;\ - ($(CAT) $(PROBLEM_LISTS) | $(EGREP) -- 'generic-$(OS_ARCH)' ) ;\ - ($(CAT) $(PROBLEM_LISTS) | $(EGREP) -- 'generic-$(OS_ARCH2)' ) ;\ - ($(CAT) $(PROBLEM_LISTS) | $(EGREP) -- 'generic-all' ) ;\ - ($(ECHO) "#") ;\ - ) | $(SED) -e 's@^[\ ]*@@' \ - | $(EGREP) -v '^#' > $@.temp1 - @for tdir in $(TESTDIRS) SOLARIS_10_SH_BUG_NO_EMPTY_FORS ; do \ - ( ( $(CAT) $@.temp1 | $(EGREP) "^$${tdir}" ) ; $(ECHO) "#" ) >> $@.temp2 ; \ - done - @$(ECHO) "# at least one line" >> $@.temp2 - @( $(EGREP) -v '^#' $@.temp2 ; true ) > $@ - @$(ECHO) "Excluding list contains `$(EXPAND) $@ | $(WC) -l` items" + JTREG_EXCLUSIONS = $(PROBLEM_LISTS:%=-exclude:%) endif -# Select list of directories that exist -define TestDirs -$(foreach i,$1,$(wildcard ${i})) $(foreach i,$1,$(wildcard closed/${i})) -endef -# Running batches of tests with or without agentvm -define RunBatch -$(ECHO) "Running tests: $?" -$(MAKE) TEST_DEPENDENCIES="$?" TESTDIRS="$?" UNIQUE_DIR=$@ jtreg_tests +# convert list of directories to dos paths +define MixedDirs +$(foreach i,$1,$(shell $(GETMIXEDPATH) "${i}")) endef + define SummaryInfo $(ECHO) "########################################################" $(CAT) $(?:%=$(ABS_TEST_OUTPUT_DIR)/%/$(STATS_TXT_NAME)) @@ -409,178 +250,11 @@ endef # ------------------------------------------------------------------ -# Batches of tests (somewhat arbitrary assigments to jdk_* targets) -# NOTE: These *do not* run the same tests as make/jprt.properties -JDK_DEFAULT_TARGETS = -JDK_ALL_TARGETS = - -JDK_ALL_TARGETS += jdk_awt -jdk_awt: $(call TestDirs, com/sun/awt java/awt sun/awt \ - javax/imageio javax/print sun/pisces) - $(call RunBatch) - -JDK_ALL_TARGETS += jdk_beans1 -JDK_DEFAULT_TARGETS += jdk_beans1 -jdk_beans1: $(call TestDirs, \ - java/beans/beancontext java/beans/PropertyChangeSupport \ - java/beans/Introspector java/beans/Performance \ - java/beans/VetoableChangeSupport java/beans/Statement) - $(call RunBatch) - -JDK_ALL_TARGETS += jdk_beans2 -jdk_beans2: $(call TestDirs, \ - java/beans/Beans java/beans/EventHandler java/beans/XMLDecoder \ - java/beans/PropertyEditor) - $(call RunBatch) - -JDK_ALL_TARGETS += jdk_beans3 -jdk_beans3: $(call TestDirs, java/beans/XMLEncoder) - $(call RunBatch) - -# All beans tests -jdk_beans: jdk_beans1 jdk_beans2 jdk_beans3 - @$(SummaryInfo) - -JDK_ALL_TARGETS += jdk_io -JDK_DEFAULT_TARGETS += jdk_io -jdk_io: $(call TestDirs, java/io) - $(call RunBatch) - -JDK_ALL_TARGETS += jdk_lang -JDK_DEFAULT_TARGETS += jdk_lang -jdk_lang: $(call TestDirs, java/lang sun/invoke sun/misc sun/reflect vm) - $(call RunBatch) - -JDK_ALL_TARGETS += jdk_jmx -jdk_jmx: $(call TestDirs, javax/management com/sun/jmx) - $(call RunBatch) - -JDK_ALL_TARGETS += jdk_management -jdk_management: $(call TestDirs, com/sun/management sun/management) - $(call RunBatch) - -JDK_ALL_TARGETS += jdk_math -JDK_DEFAULT_TARGETS += jdk_math -jdk_math: $(call TestDirs, java/math) - $(call RunBatch) - -JDK_DEFAULT_TARGETS += jdk_time -jdk_time: $(call TestDirs, java/time) - $(call RunBatch) - -JDK_ALL_TARGETS += jdk_other -JDK_DEFAULT_TARGETS += jdk_other -jdk_other: $(call TestDirs, \ - demo/jvmti demo/zipfs sample \ - javax/naming com/sun/jndi \ - javax/script \ - java/sql javax/sql \ - javax/smartcardio \ - javax/xml/jaxp \ - javax/xml/soap \ - javax/xml/ws com/sun/internal/ws com/sun/org/glassfish \ - jdk/asm \ - jdk/lambda \ - com/sun/org/apache/xerces \ - com/sun/corba \ - com/sun/tracing \ - sun/usagetracker \ - misc) - $(call RunBatch) - -JDK_ALL_TARGETS += jdk_net -JDK_DEFAULT_TARGETS += jdk_net -jdk_net: $(call TestDirs, com/sun/net java/net sun/net com/oracle/net) - $(call RunBatch) - -jdk_nio: $(call TestDirs, java/nio sun/nio com/oracle/nio) - $(call SharedLibraryPermissions,java/nio/channels) - $(call RunBatch) - -jdk_sctp: $(call TestDirs, com/sun/nio/sctp) - $(call RunBatch) - -JDK_ALL_TARGETS += jdk_rmi -jdk_rmi: $(call TestDirs, java/rmi sun/rmi javax/rmi/ssl) - $(call RunBatch) - -JDK_ALL_TARGETS += jdk_security1 -JDK_DEFAULT_TARGETS += jdk_security1 -jdk_security1: $(call TestDirs, java/security) - $(call RunBatch) - -JDK_ALL_TARGETS += jdk_security2 -jdk_security2: $(call TestDirs, javax/crypto javax/xml/crypto com/sun/crypto) - $(call RunBatch) - -JDK_ALL_TARGETS += jdk_security3 -jdk_security3: $(call TestDirs, com/sun/security lib/security javax/security \ - sun/security com/sun/org/apache/xml/internal/security \ - com/oracle/security) - $(call SharedLibraryPermissions,sun/security) - $(call RunBatch) - -# All security tests -jdk_security: jdk_security1 jdk_security2 jdk_security3 - @$(SummaryInfo) - -JDK_ALL_TARGETS += jdk_sound -jdk_sound: $(call TestDirs, javax/sound) - $(call RunBatch) - -JDK_ALL_TARGETS += jdk_swing -jdk_swing: $(call TestDirs, javax/swing sun/java2d \ - demo/jfc com/sun/java/swing) - $(call RunBatch) - -JDK_ALL_TARGETS += jdk_text -JDK_DEFAULT_TARGETS += jdk_text -jdk_text: $(call TestDirs, java/text sun/text) - $(call RunBatch) - -JDK_ALL_TARGETS += jdk_jdi -jdk_jdi: $(call TestDirs, com/sun/jdi) - $(call RunBatch) - -JDK_ALL_TARGETS += jdk_tools -jdk_tools: $(call TestDirs, com/sun/tools sun/jvmstat sun/tools tools) - $(call SharedLibraryPermissions,tools/launcher) - $(call RunBatch) - -ifdef OPENJDK -jdk_jfr: -else -JDK_ALL_TARGETS += jdk_jfr -jdk_jfr: $(call TestDirs, com/oracle/jfr) - $(call RunBatch) -endif - -JDK_ALL_TARGETS += jdk_util -JDK_DEFAULT_TARGETS += jdk_util -jdk_util: $(call TestDirs, java/util sun/util) - $(call RunBatch) - -# ------------------------------------------------------------------ - -# Run default tests -# note that this *does not* have the same meaning as jprt.properties :: jprt.make.rule.default.test.targets -jdk_default: $(JDK_DEFAULT_TARGETS) - @$(SummaryInfo) - -# Run core tests -# please keep this in sync with jdk/make/jprt.properties :: jprt.make.rule.core.test.targets -jdk_core: jdk_lang jdk_math jdk_util jdk_io jdk_net jdk_nio \ - jdk_security1 jdk_security2 jdk_security3 jdk_rmi \ - jdk_management jdk_jmx jdk_text jdk_tools jdk_jfr jdk_other - @$(SummaryInfo) - -# Run all tests -# note that this *does not* have the same meaning as jprt.properties :: jprt.make.rule.all.test.targets -jdk_all: $(JDK_ALL_TARGETS) - @$(SummaryInfo) - -# These are all phony targets -PHONY_LIST += $(JDK_ALL_TARGETS) jdk_default jdk_core jdk_all +jdk_%: + $(ECHO) "Running tests: $@" + for each in $@; do \ + $(MAKE) -j 1 TEST_SELECTION=":$$each" UNIQUE_DIR=$$each jtreg_tests; \ + done # ------------------------------------------------------------------ @@ -625,44 +299,23 @@ JTREG_TEST_OPTIONS += $(JTREG_TESTVM_MEMORY_OPTION) $(JTREG): $(JT_HOME) # Run jtreg -jtreg_tests: prep $(PRODUCT_HOME) $(JTREG) $(EXCLUDELIST) - @$(EXPAND) $(EXCLUDELIST) \ - | $(CUT) -d' ' -f1 \ - | $(SED) -e 's@^@Excluding: @' +jtreg_tests: prep $(PRODUCT_HOME) $(JTREG) ( \ ( JT_HOME=$(shell $(GETMIXEDPATH) "$(JT_HOME)"); \ export JT_HOME; \ $(shell $(GETMIXEDPATH) "$(JTREG)") \ $(JTREG_BASIC_OPTIONS) \ - -r:$(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/JTreport \ - -w:$(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/JTwork \ + -r:$(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)/JTreport") \ + -w:$(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)/JTwork") \ -jdk:$(shell $(GETMIXEDPATH) "$(PRODUCT_HOME)") \ - -exclude:$(shell $(GETMIXEDPATH) "$(EXCLUDELIST)") \ + $(JTREG_EXCLUSIONS) \ $(JTREG_TEST_OPTIONS) \ - $(TESTDIRS) \ - ) ; $(BUNDLE_UP_AND_EXIT) \ + $(TEST_SELECTION) \ + ) ; \ + $(BUNDLE_UP_AND_EXIT) \ ) 2>&1 | $(TEE) $(ABS_TEST_OUTPUT_DIR)/output.txt ; $(TESTEXIT) -# Rule that may change execute permissions on shared library files. -# Files in repositories should never have execute permissions, but there -# are some tests that have pre-built shared libraries, and these windows -# dll files must have execute permission. Adding execute permission -# may happen automatically on windows when using certain versions of mercurial -# but it cannot be guaranteed. And blindly adding execute permission might -# be seen as a mercurial 'change', so we avoid adding execute permission to -# repository files. But testing from a plain source tree needs the chmod a+rx. -# Used on select directories and applying the chmod to all shared libraries -# not just dll files. On windows, this may not work with MKS if the files -# were installed with CYGWIN unzip or untar (MKS chmod may not do anything). -# And with CYGWIN and sshd service, you may need CYGWIN=ntsec for this to work. -# -shared_library_permissions: $(SHARED_LIBRARY_DIR) - if [ ! -d $(TEST_ROOT)/../.hg ] ; then \ - $(FIND) $< \( -name \*.dll -o -name \*.DLL -o -name \*.so \) \ - -exec $(CHMOD) a+rx {} \; ; \ - fi - -PHONY_LIST += jtreg_tests shared_library_permissions +PHONY_LIST += jtreg_tests ################################################################ From 5eb7e21cc91150c46e0c890d2422c0951166f41f Mon Sep 17 00:00:00 2001 From: Anthony Juckel Date: Wed, 6 Nov 2013 13:25:24 -0800 Subject: [PATCH 022/110] 8025698: (fs) Typo in exception thrown by encode() in UnixPath.java Reviewed-by: dxu, mduigou, henryjen, weijun --- jdk/src/solaris/classes/sun/nio/fs/UnixPath.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java b/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java index aa04538cb20..1142b4c775b 100644 --- a/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java @@ -145,7 +145,7 @@ class UnixPath } if (error) { throw new InvalidPathException(input, - "Malformed input or input contains unmappable chacraters"); + "Malformed input or input contains unmappable characters"); } // trim result to actual length if required From 23d71ee6eed0f727935ad51f8b150e185c293cb7 Mon Sep 17 00:00:00 2001 From: Eric Bruneton Date: Wed, 6 Nov 2013 11:22:15 -0800 Subject: [PATCH 023/110] 8027227: [asm] generate CONSTANT_InterfaceMethodref for invoke{special/static) of non-abstract methods on ifaces Co-authored-by: Remi Forax Co-authored-by: John Rose Co-authored-by: Paul Sandoz Reviewed-by: ksrini, lagergren --- .../org/objectweb/asm/ByteVector.java | 8 +- .../org/objectweb/asm/ClassReader.java | 23 ++--- .../org/objectweb/asm/ClassWriter.java | 23 ++++- .../internal/org/objectweb/asm/Handle.java | 13 ++- .../org/objectweb/asm/MethodVisitor.java | 65 +++++++++--- .../org/objectweb/asm/MethodWriter.java | 98 +++++++++++++++---- .../objectweb/asm/commons/AdviceAdapter.java | 23 ++++- .../asm/commons/AnalyzerAdapter.java | 28 +++++- .../asm/commons/CodeSizeEvaluator.java | 23 ++++- .../asm/commons/GeneratorAdapter.java | 17 ++-- .../asm/commons/InstructionAdapter.java | 94 ++++++++++++++++-- .../asm/commons/JSRInlinerAdapter.java | 16 +++ .../asm/commons/LocalVariablesSorter.java | 6 ++ .../asm/commons/RemappingMethodAdapter.java | 39 +++++++- .../commons/RemappingSignatureAdapter.java | 6 +- .../asm/commons/SerialVersionUIDAdder.java | 9 +- .../asm/commons/StaticInitMerger.java | 3 +- .../asm/commons/TryCatchBlockSorter.java | 1 - .../objectweb/asm/tree/AnnotationNode.java | 5 + .../org/objectweb/asm/tree/ClassNode.java | 6 ++ .../org/objectweb/asm/tree/FieldNode.java | 8 +- .../objectweb/asm/tree/MethodInsnNode.java | 35 ++++++- .../org/objectweb/asm/tree/MethodNode.java | 38 ++++++- .../asm/tree/TypeAnnotationNode.java | 5 + .../objectweb/asm/tree/analysis/Frame.java | 9 ++ .../org/objectweb/asm/util/ASMifier.java | 41 +++++++- .../objectweb/asm/util/CheckClassAdapter.java | 17 +++- .../objectweb/asm/util/CheckFieldAdapter.java | 5 + .../asm/util/CheckMethodAdapter.java | 71 +++++++++++--- .../org/objectweb/asm/util/Printer.java | 29 +++++- .../org/objectweb/asm/util/Textifier.java | 28 ++++++ .../asm/util/TraceMethodVisitor.java | 26 ++++- .../internal/org/objectweb/asm/version.txt | 12 +-- 33 files changed, 711 insertions(+), 119 deletions(-) diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ByteVector.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ByteVector.java index 0d3472bcac1..89eb6d4b640 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ByteVector.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ByteVector.java @@ -233,11 +233,14 @@ public class ByteVector { * automatically enlarged if necessary. * * @param s - * a String. + * a String whose UTF8 encoded length must be less than 65536. * @return this byte vector. */ public ByteVector putUTF8(final String s) { int charLength = s.length(); + if (charLength > 65535) { + throw new IllegalArgumentException(); + } int len = length; if (len + 2 + charLength > data.length) { enlarge(2 + charLength); @@ -267,6 +270,9 @@ public class ByteVector { byteLength += 2; } } + if (byteLength > 65535) { + throw new IllegalArgumentException(); + } data[length] = (byte) (byteLength >>> 8); data[length + 1] = (byte) byteLength; if (length + 2 + byteLength > data.length) { diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java index 8cbc2d2c199..4f842157ac3 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java @@ -1266,7 +1266,7 @@ public class ClassReader { u += 2; // generates the first (implicit) stack map frame - if (FRAMES && (stackMap != 0 || unzip)) { + if (FRAMES && stackMap != 0) { /* * for the first explicit frame the offset is not offset_delta + 1 * but only offset_delta; setting the implicit frame offset to -1 @@ -1283,8 +1283,6 @@ public class ClassReader { if (unzip) { getImplicitFrame(context); } - } - if (FRAMES && stackMap != 0) { /* * Finds labels for UNINITIALIZED frame types. Instead of decoding * each element of the stack map table, we look for 3 consecutive @@ -1322,17 +1320,19 @@ public class ClassReader { } } - // visits the frame(s) for this offset, if any + // visits the frame for this offset, if any while (FRAMES && frame != null && (frame.offset == offset || frame.offset == -1)) { // if there is a frame for this offset, makes the visitor visit // it, and reads the next frame if there is one. - if (!zip || unzip) { - mv.visitFrame(Opcodes.F_NEW, frame.localCount, frame.local, - frame.stackCount, frame.stack); - } else if (frame.offset != -1) { - mv.visitFrame(frame.mode, frame.localDiff, frame.local, - frame.stackCount, frame.stack); + if (frame.offset != -1) { + if (!zip || unzip) { + mv.visitFrame(Opcodes.F_NEW, frame.localCount, + frame.local, frame.stackCount, frame.stack); + } else { + mv.visitFrame(frame.mode, frame.localDiff, frame.local, + frame.stackCount, frame.stack); + } } if (frameCount > 0) { stackMap = readFrame(stackMap, zip, unzip, frame); @@ -1434,6 +1434,7 @@ public class ClassReader { case ClassWriter.FIELDORMETH_INSN: case ClassWriter.ITFMETH_INSN: { int cpIndex = items[readUnsignedShort(u + 1)]; + boolean itf = b[cpIndex - 1] == ClassWriter.IMETH; String iowner = readClass(cpIndex, c); cpIndex = items[readUnsignedShort(cpIndex + 2)]; String iname = readUTF8(cpIndex, c); @@ -1441,7 +1442,7 @@ public class ClassReader { if (opcode < Opcodes.INVOKEVIRTUAL) { mv.visitFieldInsn(opcode, iowner, iname, idesc); } else { - mv.visitMethodInsn(opcode, iowner, iname, idesc); + mv.visitMethodInsn(opcode, iowner, iname, idesc, itf); } if (opcode == Opcodes.INVOKEINTERFACE) { u += 5; diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java index d5d8fa48903..ab9dcd0dce4 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java @@ -516,12 +516,12 @@ public class ClassWriter extends ClassVisitor { * true if the maximum stack size and number of local variables * must be automatically computed. */ - private final boolean computeMaxs; + private boolean computeMaxs; /** * true if the stack map frames must be recomputed from scratch. */ - private final boolean computeFrames; + private boolean computeFrames; /** * true if the stack map tables of this class are invalid. The @@ -988,9 +988,22 @@ public class ClassWriter extends ClassVisitor { attrs.put(this, null, 0, -1, -1, out); } if (invalidFrames) { - ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); - new ClassReader(out.data).accept(cw, ClassReader.SKIP_FRAMES); - return cw.toByteArray(); + anns = null; + ianns = null; + attrs = null; + innerClassesCount = 0; + innerClasses = null; + bootstrapMethodsCount = 0; + bootstrapMethods = null; + firstField = null; + lastField = null; + firstMethod = null; + lastMethod = null; + computeMaxs = false; + computeFrames = true; + invalidFrames = false; + new ClassReader(out.data).accept(this, ClassReader.SKIP_FRAMES); + return toByteArray(); } return out.data; } diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Handle.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Handle.java index f262f9a09a0..e8b2859b05d 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Handle.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Handle.java @@ -78,7 +78,8 @@ public final class Handle { final int tag; /** - * The internal name of the field or method designed by this handle. + * The internal name of the class that owns the field or method designated + * by this handle. */ final String owner; @@ -105,8 +106,8 @@ public final class Handle { * {@link Opcodes#H_NEWINVOKESPECIAL} or * {@link Opcodes#H_INVOKEINTERFACE}. * @param owner - * the internal name of the field or method designed by this - * handle. + * the internal name of the class that owns the field or method + * designated by this handle. * @param name * the name of the field or method designated by this handle. * @param desc @@ -135,9 +136,11 @@ public final class Handle { } /** - * Returns the internal name of the field or method designed by this handle. + * Returns the internal name of the class that owns the field or method + * designated by this handle. * - * @return the internal name of the field or method designed by this handle. + * @return the internal name of the class that owns the field or method + * designated by this handle. */ public String getOwner() { return owner; diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java index f21519e962c..0bb1a05b805 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java @@ -68,11 +68,11 @@ package jdk.internal.org.objectweb.asm; * visitTryCatchBlock | visitTryCatchBlockAnnotation | * visitLocalVariable | visitLocalVariableAnnotation | * visitLineNumber )* visitMaxs ] visitEnd. In - * addition, the visitXInsn and visitLabel - * methods must be called in the sequential order of the bytecode instructions - * of the visited code, visitInsnAnnotation must be called after - * the annotated instruction, visitTryCatchBlock must be called - * before the labels passed as arguments have been visited, + * addition, the visitXInsn and visitLabel methods must + * be called in the sequential order of the bytecode instructions of the visited + * code, visitInsnAnnotation must be called after the annotated + * instruction, visitTryCatchBlock must be called before the + * labels passed as arguments have been visited, * visitTryCatchBlockAnnotation must be called after the * corresponding try catch block has been visited, and the * visitLocalVariable, visitLocalVariableAnnotation and @@ -274,13 +274,9 @@ public abstract class MethodVisitor { * compressed form (all frames must use the same format, i.e. you must not * mix expanded and compressed frames within a single method): *
    - *
  • In expanded form, all frames must have the F_NEW type, and a first - * frame corresponding to the method signature must be explicitly visited - * before the first instruction.
  • + *
  • In expanded form, all frames must have the F_NEW type.
  • *
  • In compressed form, frames are basically "deltas" from the state of - * the previous frame (the first frame, corresponding to the method's - * parameters and access flags, is implicit in this form, and must not be - * visited): + * the previous frame: *
      *
    • {@link Opcodes#F_SAME} representing frame with exactly the same * locals as the previous frame and with the empty stack.
    • @@ -296,8 +292,14 @@ public abstract class MethodVisitor { * same as the locals in the previous frame, except that the last 1-3 locals * are absent and with the empty stack (nLocals is 1, 2 or 3). *
    • {@link Opcodes#F_FULL} representing complete frame data.
    • - *
  • *
+ * + * + *
+ * In both cases the first frame, corresponding to the method's parameters + * and access flags, is implicit and must not be visited. Also, it is + * illegal to visit two or more frames for the same code location (i.e., at + * least one instruction must be visited between two calls to visitFrame). * * @param type * the type of this stack map frame. Must be @@ -466,13 +468,52 @@ public abstract class MethodVisitor { * @param desc * the method's descriptor (see {@link Type Type}). */ + @Deprecated public void visitMethodInsn(int opcode, String owner, String name, String desc) { + if (api >= Opcodes.ASM5) { + boolean itf = opcode == Opcodes.INVOKEINTERFACE; + visitMethodInsn(opcode, owner, name, desc, itf); + return; + } if (mv != null) { mv.visitMethodInsn(opcode, owner, name, desc); } } + /** + * Visits a method instruction. A method instruction is an instruction that + * invokes a method. + * + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or + * INVOKEINTERFACE. + * @param owner + * the internal name of the method's owner class (see + * {@link Type#getInternalName() getInternalName}). + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link Type Type}). + * @param itf + * if the method's owner class is an interface. + */ + public void visitMethodInsn(int opcode, String owner, String name, + String desc, boolean itf) { + if (api < Opcodes.ASM5) { + if (itf != (opcode == Opcodes.INVOKEINTERFACE)) { + throw new IllegalArgumentException( + "INVOKESPECIAL/STATIC on interfaces require ASM 5"); + } + visitMethodInsn(opcode, owner, name, desc); + return; + } + if (mv != null) { + mv.visitMethodInsn(opcode, owner, name, desc, itf); + } + } + /** * Visits an invokedynamic instruction. * diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java index f59abfa7a3a..81a82804d6e 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java @@ -71,7 +71,7 @@ class MethodWriter extends MethodVisitor { /** * Pseudo access flag used to denote constructors. */ - static final int ACC_CONSTRUCTOR = 262144; + static final int ACC_CONSTRUCTOR = 0x80000; /** * Frame has exactly the same locals as the previous stack map frame and @@ -297,11 +297,6 @@ class MethodWriter extends MethodVisitor { */ private int[] previousFrame; - /** - * Index of the next element to be added in {@link #frame}. - */ - private int frameIndex; - /** * The current stack map frame. The first element contains the offset of the * instruction to which the frame corresponds, the second element is the @@ -496,6 +491,9 @@ class MethodWriter extends MethodVisitor { cw.lastMethod = this; this.cw = cw; this.access = access; + if ("".equals(name)) { + this.access |= ACC_CONSTRUCTOR; + } this.name = cw.newUTF8(name); this.desc = cw.newUTF8(desc); this.descriptor = desc; @@ -511,9 +509,6 @@ class MethodWriter extends MethodVisitor { } this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING); if (computeMaxs || computeFrames) { - if (computeFrames && "".equals(name)) { - this.access |= ACC_CONSTRUCTOR; - } // updates maxLocals int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2; if ((access & Opcodes.ACC_STATIC) != 0) { @@ -649,8 +644,11 @@ class MethodWriter extends MethodVisitor { } if (type == Opcodes.F_NEW) { + if (previousFrame == null) { + visitImplicitFirstFrame(); + } currentLocals = nLocal; - startFrame(code.length, nLocal, nStack); + int frameIndex = startFrame(code.length, nLocal, nStack); for (int i = 0; i < nLocal; ++i) { if (local[i] instanceof String) { frame[frameIndex++] = Frame.OBJECT @@ -914,9 +912,8 @@ class MethodWriter extends MethodVisitor { @Override public void visitMethodInsn(final int opcode, final String owner, - final String name, final String desc) { + final String name, final String desc, final boolean itf) { lastCodeOffset = code.length; - boolean itf = opcode == Opcodes.INVOKEINTERFACE; Item i = cw.newMethodItem(owner, name, desc, itf); int argSize = i.intVal; // Label currentBlock = this.currentBlock; @@ -954,7 +951,7 @@ class MethodWriter extends MethodVisitor { } } // adds the instruction to the bytecode of the method - if (itf) { + if (opcode == Opcodes.INVOKEINTERFACE) { if (argSize == 0) { argSize = Type.getArgumentsAndReturnSizes(desc); i.intVal = argSize; @@ -1528,8 +1525,8 @@ class MethodWriter extends MethodVisitor { } code.data[end] = (byte) Opcodes.ATHROW; // emits a frame for this unreachable block - startFrame(start, 0, 1); - frame[frameIndex++] = Frame.OBJECT + int frameIndex = startFrame(start, 0, 1); + frame[frameIndex] = Frame.OBJECT | cw.addType("java/lang/Throwable"); endFrame(); // removes the start-end range from the exception @@ -1756,7 +1753,7 @@ class MethodWriter extends MethodVisitor { } } // visits the frame and its content - startFrame(f.owner.position, nLocal, nStack); + int frameIndex = startFrame(f.owner.position, nLocal, nStack); for (i = 0; nLocal > 0; ++i, --nLocal) { t = locals[i]; frame[frameIndex++] = t; @@ -1774,6 +1771,67 @@ class MethodWriter extends MethodVisitor { endFrame(); } + /** + * Visit the implicit first frame of this method. + */ + private void visitImplicitFirstFrame() { + // There can be at most descriptor.length() + 1 locals + int frameIndex = startFrame(0, descriptor.length() + 1, 0); + if ((access & Opcodes.ACC_STATIC) == 0) { + if ((access & ACC_CONSTRUCTOR) == 0) { + frame[frameIndex++] = Frame.OBJECT | cw.addType(cw.thisName); + } else { + frame[frameIndex++] = 6; // Opcodes.UNINITIALIZED_THIS; + } + } + int i = 1; + loop: while (true) { + int j = i; + switch (descriptor.charAt(i++)) { + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + frame[frameIndex++] = 1; // Opcodes.INTEGER; + break; + case 'F': + frame[frameIndex++] = 2; // Opcodes.FLOAT; + break; + case 'J': + frame[frameIndex++] = 4; // Opcodes.LONG; + break; + case 'D': + frame[frameIndex++] = 3; // Opcodes.DOUBLE; + break; + case '[': + while (descriptor.charAt(i) == '[') { + ++i; + } + if (descriptor.charAt(i) == 'L') { + ++i; + while (descriptor.charAt(i) != ';') { + ++i; + } + } + frame[frameIndex++] = Frame.OBJECT + | cw.addType(descriptor.substring(j, ++i)); + break; + case 'L': + while (descriptor.charAt(i) != ';') { + ++i; + } + frame[frameIndex++] = Frame.OBJECT + | cw.addType(descriptor.substring(j + 1, i++)); + break; + default: + break loop; + } + } + frame[1] = frameIndex - 3; + endFrame(); + } + /** * Starts the visit of a stack map frame. * @@ -1783,8 +1841,9 @@ class MethodWriter extends MethodVisitor { * the number of local variables in the frame. * @param nStack * the number of stack elements in the frame. + * @return the index of the next element to be written in this frame. */ - private void startFrame(final int offset, final int nLocal, final int nStack) { + private int startFrame(final int offset, final int nLocal, final int nStack) { int n = 3 + nLocal + nStack; if (frame == null || frame.length < n) { frame = new int[n]; @@ -1792,7 +1851,7 @@ class MethodWriter extends MethodVisitor { frame[0] = offset; frame[1] = nLocal; frame[2] = nStack; - frameIndex = 3; + return 3; } /** @@ -2110,7 +2169,8 @@ class MethodWriter extends MethodVisitor { */ final void put(final ByteVector out) { final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC; - int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE + int mask = ACC_CONSTRUCTOR | Opcodes.ACC_DEPRECATED + | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR); out.putShort(access & ~mask).putShort(name).putShort(desc); if (classReaderOffset != 0) { diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java index c7d51d45b91..c07917784df 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java @@ -442,10 +442,31 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes } } + @Deprecated @Override public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) { - mv.visitMethodInsn(opcode, owner, name, desc); + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, + opcode == Opcodes.INVOKEINTERFACE); + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, itf); + } + + private void doVisitMethodInsn(int opcode, final String owner, + final String name, final String desc, final boolean itf) { + mv.visitMethodInsn(opcode, owner, name, desc, itf); if (constructor) { Type[] types = Type.getArgumentTypes(desc); for (int i = 0; i < types.length; i++) { diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/AnalyzerAdapter.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/AnalyzerAdapter.java index 1371250da0a..e914d45134e 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/AnalyzerAdapter.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/AnalyzerAdapter.java @@ -165,10 +165,15 @@ public class AnalyzerAdapter extends MethodVisitor { * @param mv * the method visitor to which this adapter delegates calls. May * be null. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public AnalyzerAdapter(final String owner, final int access, final String name, final String desc, final MethodVisitor mv) { this(Opcodes.ASM5, owner, access, name, desc, mv); + if (getClass() != AnalyzerAdapter.class) { + throw new IllegalStateException(); + } } /** @@ -331,11 +336,32 @@ public class AnalyzerAdapter extends MethodVisitor { execute(opcode, 0, desc); } + @Deprecated @Override public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) { + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, + opcode == Opcodes.INVOKEINTERFACE); + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, itf); + } + + private void doVisitMethodInsn(int opcode, final String owner, + final String name, final String desc, final boolean itf) { if (mv != null) { - mv.visitMethodInsn(opcode, owner, name, desc); + mv.visitMethodInsn(opcode, owner, name, desc, itf); } if (this.locals == null) { labels = null; diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/CodeSizeEvaluator.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/CodeSizeEvaluator.java index a04a643d18b..0a41b2b8af6 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/CodeSizeEvaluator.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/CodeSizeEvaluator.java @@ -149,9 +149,30 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes { } } + @Deprecated @Override public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) { + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, + opcode == Opcodes.INVOKEINTERFACE); + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, itf); + } + + private void doVisitMethodInsn(int opcode, final String owner, + final String name, final String desc, final boolean itf) { if (opcode == INVOKEINTERFACE) { minSize += 5; maxSize += 5; @@ -160,7 +181,7 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes { maxSize += 3; } if (mv != null) { - mv.visitMethodInsn(opcode, owner, name, desc); + mv.visitMethodInsn(opcode, owner, name, desc, itf); } } diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/GeneratorAdapter.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/GeneratorAdapter.java index 7e30acbbe72..786a5b5365a 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/GeneratorAdapter.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/GeneratorAdapter.java @@ -284,10 +284,15 @@ public class GeneratorAdapter extends LocalVariablesSorter { * the method's name. * @param desc * the method's descriptor (see {@link Type Type}). + * @throws IllegalStateException + * If a subclass calls this constructor. */ public GeneratorAdapter(final MethodVisitor mv, final int access, final String name, final String desc) { this(Opcodes.ASM5, mv, access, name, desc); + if (getClass() != GeneratorAdapter.class) { + throw new IllegalStateException(); + } } /** @@ -1400,11 +1405,11 @@ public class GeneratorAdapter extends LocalVariablesSorter { * the method to be invoked. */ private void invokeInsn(final int opcode, final Type type, - final Method method) { + final Method method, final boolean itf) { String owner = type.getSort() == Type.ARRAY ? type.getDescriptor() : type.getInternalName(); mv.visitMethodInsn(opcode, owner, method.getName(), - method.getDescriptor()); + method.getDescriptor(), itf); } /** @@ -1416,7 +1421,7 @@ public class GeneratorAdapter extends LocalVariablesSorter { * the method to be invoked. */ public void invokeVirtual(final Type owner, final Method method) { - invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method); + invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method, false); } /** @@ -1428,7 +1433,7 @@ public class GeneratorAdapter extends LocalVariablesSorter { * the constructor to be invoked. */ public void invokeConstructor(final Type type, final Method method) { - invokeInsn(Opcodes.INVOKESPECIAL, type, method); + invokeInsn(Opcodes.INVOKESPECIAL, type, method, false); } /** @@ -1440,7 +1445,7 @@ public class GeneratorAdapter extends LocalVariablesSorter { * the method to be invoked. */ public void invokeStatic(final Type owner, final Method method) { - invokeInsn(Opcodes.INVOKESTATIC, owner, method); + invokeInsn(Opcodes.INVOKESTATIC, owner, method, false); } /** @@ -1452,7 +1457,7 @@ public class GeneratorAdapter extends LocalVariablesSorter { * the method to be invoked. */ public void invokeInterface(final Type owner, final Method method) { - invokeInsn(Opcodes.INVOKEINTERFACE, owner, method); + invokeInsn(Opcodes.INVOKEINTERFACE, owner, method, true); } /** diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java index 912b622db13..4ece2dba90d 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java @@ -82,9 +82,14 @@ public class InstructionAdapter extends MethodVisitor { * * @param mv * the method visitor to which this adapter delegates calls. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public InstructionAdapter(final MethodVisitor mv) { this(Opcodes.ASM5, mv); + if (getClass() != InstructionAdapter.class) { + throw new IllegalStateException(); + } } /** @@ -536,18 +541,39 @@ public class InstructionAdapter extends MethodVisitor { } } + @Deprecated @Override public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) { + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, + opcode == Opcodes.INVOKEINTERFACE); + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, itf); + } + + private void doVisitMethodInsn(int opcode, final String owner, + final String name, final String desc, final boolean itf) { switch (opcode) { case Opcodes.INVOKESPECIAL: - invokespecial(owner, name, desc); + invokespecial(owner, name, desc, itf); break; case Opcodes.INVOKEVIRTUAL: - invokevirtual(owner, name, desc); + invokevirtual(owner, name, desc, itf); break; case Opcodes.INVOKESTATIC: - invokestatic(owner, name, desc); + invokestatic(owner, name, desc, itf); break; case Opcodes.INVOKEINTERFACE: invokeinterface(owner, name, desc); @@ -1014,24 +1040,78 @@ public class InstructionAdapter extends MethodVisitor { mv.visitFieldInsn(Opcodes.PUTFIELD, owner, name, desc); } + @Deprecated public void invokevirtual(final String owner, final String name, final String desc) { + if (api >= Opcodes.ASM5) { + invokevirtual(owner, name, desc, false); + return; + } mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc); } + public void invokevirtual(final String owner, final String name, + final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + if (itf) { + throw new IllegalArgumentException( + "INVOKEVIRTUAL on interfaces require ASM 5"); + } + invokevirtual(owner, name, desc); + return; + } + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, itf); + } + + @Deprecated public void invokespecial(final String owner, final String name, final String desc) { - mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc); + if (api >= Opcodes.ASM5) { + invokespecial(owner, name, desc, false); + return; + } + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, false); + } + + public void invokespecial(final String owner, final String name, + final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + if (itf) { + throw new IllegalArgumentException( + "INVOKESPECIAL on interfaces require ASM 5"); + } + invokespecial(owner, name, desc); + return; + } + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, itf); + } + + @Deprecated + public void invokestatic(final String owner, final String name, + final String desc) { + if (api < Opcodes.ASM5) { + invokestatic(owner, name, desc, false); + return; + } + mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, false); } public void invokestatic(final String owner, final String name, - final String desc) { - mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc); + final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + if (itf) { + throw new IllegalArgumentException( + "INVOKESTATIC on interfaces require ASM 5"); + } + invokestatic(owner, name, desc); + return; + } + mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, itf); } public void invokeinterface(final String owner, final String name, final String desc) { - mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, desc); + mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, desc, true); } public void invokedynamic(String name, String desc, Handle bsm, diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/JSRInlinerAdapter.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/JSRInlinerAdapter.java index 1a255b7096f..e0514114e51 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/JSRInlinerAdapter.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/JSRInlinerAdapter.java @@ -136,11 +136,16 @@ public class JSRInlinerAdapter extends MethodNode implements Opcodes { * the internal names of the method's exception classes (see * {@link Type#getInternalName() getInternalName}). May be * null. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public JSRInlinerAdapter(final MethodVisitor mv, final int access, final String name, final String desc, final String signature, final String[] exceptions) { this(Opcodes.ASM5, mv, access, name, desc, signature, exceptions); + if (getClass() != JSRInlinerAdapter.class) { + throw new IllegalStateException(); + } } /** @@ -381,6 +386,17 @@ public class JSRInlinerAdapter extends MethodNode implements Opcodes { // Use tail recursion here in the form of an outer while loop to // avoid our stack growing needlessly: index++; + + // We implicitly assumed above that execution can always fall + // through to the next instruction after a JSR. But a subroutine may + // never return, in which case the code after the JSR is unreachable + // and can be anything. In particular, it can seem to fall off the + // end of the method, so we must handle this case here (we could + // instead detect whether execution can return or not from a JSR, + // but this is more complicated). + if (index >= instructions.size()) { + return; + } } } diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java index 0353c499382..5d02c53768d 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java @@ -120,10 +120,15 @@ public class LocalVariablesSorter extends MethodVisitor { * the method's descriptor (see {@link Type Type}). * @param mv * the method visitor to which this adapter delegates calls. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public LocalVariablesSorter(final int access, final String desc, final MethodVisitor mv) { this(Opcodes.ASM5, access, desc, mv); + if (getClass() != LocalVariablesSorter.class) { + throw new IllegalStateException(); + } } /** @@ -323,6 +328,7 @@ public class LocalVariablesSorter extends MethodVisitor { int local = newLocalMapping(type); setLocalType(local, type); setFrameLocal(local, t); + changed = true; return local; } diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java index 319d9dedc7e..d5493a1b1b5 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java @@ -148,12 +148,41 @@ public class RemappingMethodAdapter extends LocalVariablesSorter { remapper.mapDesc(desc)); } + @Deprecated @Override - public void visitMethodInsn(int opcode, String owner, String name, - String desc) { - super.visitMethodInsn(opcode, remapper.mapType(owner), - remapper.mapMethodName(owner, name, desc), - remapper.mapMethodDesc(desc)); + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc) { + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, + opcode == Opcodes.INVOKEINTERFACE); + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, itf); + } + + private void doVisitMethodInsn(int opcode, String owner, String name, + String desc, boolean itf) { + // Calling super.visitMethodInsn requires to call the correct version + // depending on this.api (otherwise infinite loops can occur). To + // simplify and to make it easier to automatically remove the backward + // compatibility code, we inline the code of the overridden method here. + // IMPORTANT: THIS ASSUMES THAT visitMethodInsn IS NOT OVERRIDDEN IN + // LocalVariableSorter. + if (mv != null) { + mv.visitMethodInsn(opcode, remapper.mapType(owner), + remapper.mapMethodName(owner, name, desc), + remapper.mapMethodDesc(desc), itf); + } } @Override diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java index 458ee69b1ff..3b8ab02a3f1 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java @@ -95,10 +95,12 @@ public class RemappingSignatureAdapter extends SignatureVisitor { @Override public void visitInnerClassType(String name) { + String remappedOuter = remapper.mapType(className) + '$'; className = className + '$' + name; String remappedName = remapper.mapType(className); - v.visitInnerClassType(remappedName.substring(remappedName - .lastIndexOf('$') + 1)); + int index = remappedName.startsWith(remappedOuter) ? remappedOuter + .length() : remappedName.lastIndexOf('$') + 1; + v.visitInnerClassType(remappedName.substring(index)); } @Override diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java index 4050d0ce402..de8915125ff 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java @@ -195,9 +195,14 @@ public class SerialVersionUIDAdder extends ClassVisitor { * @param cv * a {@link ClassVisitor} to which this visitor will delegate * calls. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public SerialVersionUIDAdder(final ClassVisitor cv) { this(Opcodes.ASM5, cv); + if (getClass() != SerialVersionUIDAdder.class) { + throw new IllegalStateException(); + } } /** @@ -218,7 +223,7 @@ public class SerialVersionUIDAdder extends ClassVisitor { } // ------------------------------------------------------------------------ - // Overriden methods + // Overridden methods // ------------------------------------------------------------------------ /* @@ -234,7 +239,7 @@ public class SerialVersionUIDAdder extends ClassVisitor { if (computeSVUID) { this.name = name; this.access = access; - this.interfaces = interfaces; + this.interfaces = Arrays.copyOf(interfaces, interfaces.length); } super.visit(version, access, name, signature, superName, interfaces); diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/StaticInitMerger.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/StaticInitMerger.java index 3514d090787..2f2f3b6ddcb 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/StaticInitMerger.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/StaticInitMerger.java @@ -107,7 +107,8 @@ public class StaticInitMerger extends ClassVisitor { if (clinit == null) { clinit = cv.visitMethod(a, name, desc, null, null); } - clinit.visitMethodInsn(Opcodes.INVOKESTATIC, this.name, n, desc); + clinit.visitMethodInsn(Opcodes.INVOKESTATIC, this.name, n, desc, + false); } else { mv = cv.visitMethod(access, name, desc, signature, exceptions); } diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/TryCatchBlockSorter.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/TryCatchBlockSorter.java index 0b2be355877..39c2bf37904 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/TryCatchBlockSorter.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/TryCatchBlockSorter.java @@ -66,7 +66,6 @@ import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.org.objectweb.asm.tree.MethodNode; import jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode; -import jdk.internal.org.objectweb.asm.tree.TypeAnnotationNode; /** * A {@link MethodVisitor} adapter to sort the exception handlers. The handlers diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/AnnotationNode.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/AnnotationNode.java index 57b88f1b11f..b67ea38591a 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/AnnotationNode.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/AnnotationNode.java @@ -96,9 +96,14 @@ public class AnnotationNode extends AnnotationVisitor { * * @param desc * the class descriptor of the annotation class. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public AnnotationNode(final String desc) { this(Opcodes.ASM5, desc); + if (getClass() != AnnotationNode.class) { + throw new IllegalStateException(); + } } /** diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/ClassNode.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/ClassNode.java index cb70518aa93..39334641754 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/ClassNode.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/ClassNode.java @@ -216,9 +216,15 @@ public class ClassNode extends ClassVisitor { * Constructs a new {@link ClassNode}. Subclasses must not use this * constructor. Instead, they must use the {@link #ClassNode(int)} * version. + * + * @throws IllegalStateException + * If a subclass calls this constructor. */ public ClassNode() { this(Opcodes.ASM5); + if (getClass() != ClassNode.class) { + throw new IllegalStateException(); + } } /** diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/FieldNode.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/FieldNode.java index a155d2c1b80..cc79a5815cb 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/FieldNode.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/FieldNode.java @@ -168,16 +168,20 @@ public class FieldNode extends FieldVisitor { * null if the field does not have an initial value, * must be an {@link Integer}, a {@link Float}, a {@link Long}, a * {@link Double} or a {@link String}. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public FieldNode(final int access, final String name, final String desc, final String signature, final Object value) { this(Opcodes.ASM5, access, name, desc, signature, value); + if (getClass() != FieldNode.class) { + throw new IllegalStateException(); + } } /** * Constructs a new {@link FieldNode}. Subclasses must not use this - * constructor. Instead, they must use the - * {@link #FieldNode(int, int, String, String, String, Object)} version. + * constructor. * * @param api * the ASM API version implemented by this visitor. Must be one diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/MethodInsnNode.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/MethodInsnNode.java index 6f6d5dc4453..2f61df3b517 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/MethodInsnNode.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/MethodInsnNode.java @@ -61,6 +61,7 @@ package jdk.internal.org.objectweb.asm.tree; import java.util.Map; import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; /** * A node that represents a method instruction. A method instruction is an @@ -86,6 +87,11 @@ public class MethodInsnNode extends AbstractInsnNode { */ public String desc; + /** + * If the method's owner class if an interface. + */ + public boolean itf; + /** * Constructs a new {@link MethodInsnNode}. * @@ -102,12 +108,37 @@ public class MethodInsnNode extends AbstractInsnNode { * @param desc * the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}). */ + @Deprecated public MethodInsnNode(final int opcode, final String owner, final String name, final String desc) { + this(opcode, owner, name, desc, opcode == Opcodes.INVOKEINTERFACE); + } + + /** + * Constructs a new {@link MethodInsnNode}. + * + * @param opcode + * the opcode of the type instruction to be constructed. This + * opcode must be INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or + * INVOKEINTERFACE. + * @param owner + * the internal name of the method's owner class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() + * getInternalName}). + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}). + * @param itf + * if the method's owner class is an interface. + */ + public MethodInsnNode(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { super(opcode); this.owner = owner; this.name = name; this.desc = desc; + this.itf = itf; } /** @@ -128,11 +159,11 @@ public class MethodInsnNode extends AbstractInsnNode { @Override public void accept(final MethodVisitor mv) { - mv.visitMethodInsn(opcode, owner, name, desc); + mv.visitMethodInsn(opcode, owner, name, desc, itf); } @Override public AbstractInsnNode clone(final Map labels) { - return new MethodInsnNode(opcode, owner, name, desc); + return new MethodInsnNode(opcode, owner, name, desc, itf); } } diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/MethodNode.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/MethodNode.java index 072d549265c..dfd58a0fe1f 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/MethodNode.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/MethodNode.java @@ -71,7 +71,6 @@ import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.org.objectweb.asm.Type; import jdk.internal.org.objectweb.asm.TypePath; -import jdk.internal.org.objectweb.asm.TypeReference; /** * A node that represents a method. @@ -245,9 +244,15 @@ public class MethodNode extends MethodVisitor { * Constructs an uninitialized {@link MethodNode}. Subclasses must not * use this constructor. Instead, they must use the * {@link #MethodNode(int)} version. + * + * @throws IllegalStateException + * If a subclass calls this constructor. */ public MethodNode() { this(Opcodes.ASM5); + if (getClass() != MethodNode.class) { + throw new IllegalStateException(); + } } /** @@ -281,10 +286,15 @@ public class MethodNode extends MethodVisitor { * the internal names of the method's exception classes (see * {@link Type#getInternalName() getInternalName}). May be * null. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public MethodNode(final int access, final String name, final String desc, final String signature, final String[] exceptions) { this(Opcodes.ASM5, access, name, desc, signature, exceptions); + if (getClass() != MethodNode.class) { + throw new IllegalStateException(); + } } /** @@ -461,12 +471,27 @@ public class MethodNode extends MethodVisitor { instructions.add(new FieldInsnNode(opcode, owner, name, desc)); } + @Deprecated @Override - public void visitMethodInsn(final int opcode, final String owner, - final String name, final String desc) { + public void visitMethodInsn(int opcode, String owner, String name, + String desc) { + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc); + return; + } instructions.add(new MethodInsnNode(opcode, owner, name, desc)); } + @Override + public void visitMethodInsn(int opcode, String owner, String name, + String desc, boolean itf) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + instructions.add(new MethodInsnNode(opcode, owner, name, desc, itf)); + } + @Override public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { @@ -696,6 +721,12 @@ public class MethodNode extends MethodVisitor { && insn.invisibleTypeAnnotations.size() > 0) { throw new RuntimeException(); } + if (insn instanceof MethodInsnNode) { + boolean itf = ((MethodInsnNode) insn).itf; + if (itf != (insn.opcode == Opcodes.INVOKEINTERFACE)) { + throw new RuntimeException(); + } + } } if (visibleLocalVariableAnnotations != null && visibleLocalVariableAnnotations.size() > 0) { @@ -705,7 +736,6 @@ public class MethodNode extends MethodVisitor { && invisibleLocalVariableAnnotations.size() > 0) { throw new RuntimeException(); } - } } diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/TypeAnnotationNode.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/TypeAnnotationNode.java index c9e21d8c5be..641dca1c17d 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/TypeAnnotationNode.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/TypeAnnotationNode.java @@ -94,10 +94,15 @@ public class TypeAnnotationNode extends AnnotationNode { * null if the annotation targets 'typeRef' as a whole. * @param desc * the class descriptor of the annotation class. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public TypeAnnotationNode(final int typeRef, final TypePath typePath, final String desc) { this(Opcodes.ASM5, typeRef, typePath, desc); + if (getClass() != TypeAnnotationNode.class) { + throw new IllegalStateException(); + } } /** diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/analysis/Frame.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/analysis/Frame.java index 2d9434fc22e..f6b8db3ddfb 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/analysis/Frame.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/tree/analysis/Frame.java @@ -162,6 +162,15 @@ public class Frame { return locals; } + /** + * Returns the maximum stack size of this frame. + * + * @return the maximum stack size of this frame. + */ + public int getMaxStackSize() { + return values.length - locals; + } + /** * Returns the value of the given local variable. * diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/util/ASMifier.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/util/ASMifier.java index 6b6bd4dc6bb..a9487e16f5e 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/util/ASMifier.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/util/ASMifier.java @@ -113,9 +113,15 @@ public class ASMifier extends Printer { * Constructs a new {@link ASMifier}. Subclasses must not use this * constructor. Instead, they must use the * {@link #ASMifier(int, String, int)} version. + * + * @throws IllegalStateException + * If a subclass calls this constructor. */ public ASMifier() { this(Opcodes.ASM5, "cw", 0); + if (getClass() != ASMifier.class) { + throw new IllegalStateException(); + } } /** @@ -483,8 +489,9 @@ public class ASMifier extends Printer { @Override public void visitParameter(String parameterName, int access) { buf.setLength(0); - buf.append(name).append(".visitParameter(").append(parameterName) - .append(", "); + buf.append(name).append(".visitParameter("); + appendString(buf, parameterName); + buf.append(", "); appendAccess(access); text.add(buf.append(");\n").toString()); } @@ -639,9 +646,30 @@ public class ASMifier extends Printer { text.add(buf.toString()); } + @Deprecated @Override public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) { + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, + opcode == Opcodes.INVOKEINTERFACE); + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, itf); + } + + private void doVisitMethodInsn(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { buf.setLength(0); buf.append(this.name).append(".visitMethodInsn(") .append(OPCODES[opcode]).append(", "); @@ -650,6 +678,8 @@ public class ASMifier extends Printer { appendConstant(name); buf.append(", "); appendConstant(desc); + buf.append(", "); + buf.append(itf ? "true" : "false"); buf.append(");\n"); text.add(buf.toString()); } @@ -1076,6 +1106,13 @@ public class ASMifier extends Printer { buf.append("ACC_DEPRECATED"); first = false; } + if ((access & Opcodes.ACC_MANDATED) != 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_MANDATED"); + first = false; + } if (first) { buf.append('0'); } diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/util/CheckClassAdapter.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/util/CheckClassAdapter.java index ad29ab964a7..5105db7f9c2 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/util/CheckClassAdapter.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/util/CheckClassAdapter.java @@ -246,7 +246,7 @@ public class CheckClassAdapter extends ClassVisitor { List interfaces = new ArrayList(); for (Iterator i = cn.interfaces.iterator(); i.hasNext();) { - interfaces.add(Type.getObjectType(i.next().toString())); + interfaces.add(Type.getObjectType(i.next())); } for (int i = 0; i < methods.size(); ++i) { @@ -359,9 +359,14 @@ public class CheckClassAdapter extends ClassVisitor { * false to not perform any data flow check (see * {@link CheckMethodAdapter}). This option requires valid * maxLocals and maxStack values. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public CheckClassAdapter(final ClassVisitor cv, final boolean checkDataFlow) { this(Opcodes.ASM5, cv, checkDataFlow); + if (getClass() != CheckClassAdapter.class) { + throw new IllegalStateException(); + } } /** @@ -471,7 +476,15 @@ public class CheckClassAdapter extends ClassVisitor { CheckMethodAdapter.checkInternalName(outerName, "outer class name"); } if (innerName != null) { - CheckMethodAdapter.checkIdentifier(innerName, "inner class name"); + int start = 0; + while (start < innerName.length() + && Character.isDigit(innerName.charAt(start))) { + start++; + } + if (start == 0 || start < innerName.length()) { + CheckMethodAdapter.checkIdentifier(innerName, start, -1, + "inner class name"); + } } checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/util/CheckFieldAdapter.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/util/CheckFieldAdapter.java index b09559c0d8a..e0857bf06b3 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/util/CheckFieldAdapter.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/util/CheckFieldAdapter.java @@ -79,9 +79,14 @@ public class CheckFieldAdapter extends FieldVisitor { * * @param fv * the field visitor to which this adapter must delegate calls. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public CheckFieldAdapter(final FieldVisitor fv) { this(Opcodes.ASM5, fv); + if (getClass() != CheckFieldAdapter.class) { + throw new IllegalStateException(); + } } /** diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java index b59709890f4..0716debae62 100644 --- a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java @@ -142,11 +142,6 @@ public class CheckMethodAdapter extends MethodVisitor { */ private Set