From 968deb7658481da8c001e4ec94802dab8292cbf4 Mon Sep 17 00:00:00 2001 From: Antonios Printezis Date: Mon, 28 Jun 2010 14:13:18 -0400 Subject: [PATCH 01/52] 6962569: assembler_sparc.cpp:1969: assert(false) failed: error Array_overlap_test() fails when the address range crosses the MSB boundary. Thanks to Tom and Vladimir for their help on this one. Reviewed-by: kvn, never, iveresov --- hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp b/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp index 65404a44d66..99a7eebf4c4 100644 --- a/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp @@ -1007,9 +1007,9 @@ class StubGenerator: public StubCodeGenerator { __ brx(Assembler::lessEqualUnsigned, false, Assembler::pt, (*NOLp)); __ delayed()->cmp(to_from, byte_count); if (NOLp == NULL) - __ brx(Assembler::greaterEqual, false, Assembler::pt, no_overlap_target); + __ brx(Assembler::greaterEqualUnsigned, false, Assembler::pt, no_overlap_target); else - __ brx(Assembler::greaterEqual, false, Assembler::pt, (*NOLp)); + __ brx(Assembler::greaterEqualUnsigned, false, Assembler::pt, (*NOLp)); __ delayed()->nop(); } From dfc84e8c89a01342c3b1c706f974ed448617e68c Mon Sep 17 00:00:00 2001 From: Antonios Printezis Date: Mon, 28 Jun 2010 14:13:17 -0400 Subject: [PATCH 02/52] 6944166: G1: explicit GCs are not always handled correctly G1 was not handling explicit GCs correctly in many ways. It does now. See the CR for the list of improvements contained in this changeset. Reviewed-by: iveresov, ysr, johnc --- .../concurrentMarkSweep/vmCMSOperations.cpp | 5 + .../g1/concurrentMarkThread.cpp | 6 + .../gc_implementation/g1/g1CollectedHeap.cpp | 129 ++++++++++++++---- .../gc_implementation/g1/g1CollectedHeap.hpp | 49 +++++-- .../g1/g1CollectorPolicy.cpp | 52 ++++--- .../g1/g1CollectorPolicy.hpp | 16 ++- .../gc_implementation/g1/vm_operations_g1.cpp | 59 +++++++- .../gc_implementation/g1/vm_operations_g1.hpp | 35 +++-- .../vm/gc_implementation/includeDB_gc_g1 | 2 + .../shared/vmGCOperations.hpp | 4 +- hotspot/src/share/vm/gc_interface/gcCause.cpp | 3 + hotspot/src/share/vm/runtime/mutexLocker.cpp | 2 + 12 files changed, 291 insertions(+), 71 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp index bcded9b04a8..bf5188ba74c 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp @@ -234,6 +234,11 @@ void VM_GenCollectFullConcurrent::doit_epilogue() { GenCollectedHeap* gch = GenCollectedHeap::heap(); if (_gc_cause != GCCause::_gc_locker && gch->total_full_collections_completed() <= _full_gc_count_before) { + // maybe we should change the condition to test _gc_cause == + // GCCause::_java_lang_system_gc, instead of + // _gc_cause != GCCause::_gc_locker + assert(_gc_cause == GCCause::_java_lang_system_gc, + "the only way to get here if this was a System.gc()-induced GC"); assert(ExplicitGCInvokesConcurrent, "Error"); // Now, wait for witnessing concurrent gc cycle to complete, // but do so in native mode, because we want to lock the diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp index 8ecced2375b..88d9e01d0ab 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp @@ -266,6 +266,12 @@ void ConcurrentMarkThread::run() { _cm->clearNextBitmap(); _sts.leave(); } + + // Update the number of full collections that have been + // completed. This will also notify the FullGCCount_lock in case a + // Java thread is waiting for a full GC to happen (e.g., it + // called System.gc() with +ExplicitGCInvokesConcurrent). + g1->increment_full_collections_completed(true /* outer */); } assert(_should_terminate, "just checking"); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index b242e78ee7e..79622015207 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -809,7 +809,8 @@ public: } }; -void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs, +void G1CollectedHeap::do_collection(bool explicit_gc, + bool clear_all_soft_refs, size_t word_size) { if (GC_locker::check_active_before_gc()) { return; // GC is disabled (e.g. JNI GetXXXCritical operation) @@ -821,10 +822,6 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs, Universe::print_heap_before_gc(); } - if (full && DisableExplicitGC) { - return; - } - assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); assert(Thread::current() == VMThread::vm_thread(), "should be in vm thread"); @@ -837,9 +834,11 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs, IsGCActiveMark x; // Timing + bool system_gc = (gc_cause() == GCCause::_java_lang_system_gc); + assert(!system_gc || explicit_gc, "invariant"); gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - TraceTime t(full ? "Full GC (System.gc())" : "Full GC", + TraceTime t(system_gc ? "Full GC (System.gc())" : "Full GC", PrintGC, true, gclog_or_tty); TraceMemoryManagerStats tms(true /* fullGC */); @@ -944,7 +943,7 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs, heap_region_iterate(&rs_clear); // Resize the heap if necessary. - resize_if_necessary_after_full_collection(full ? 0 : word_size); + resize_if_necessary_after_full_collection(explicit_gc ? 0 : word_size); if (_cg1r->use_cache()) { _cg1r->clear_and_record_card_counts(); @@ -1009,13 +1008,18 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs, "young list should be empty at this point"); } + // Update the number of full collections that have been completed. + increment_full_collections_completed(false /* outer */); + if (PrintHeapAtGC) { Universe::print_heap_after_gc(); } } void G1CollectedHeap::do_full_collection(bool clear_all_soft_refs) { - do_collection(true, clear_all_soft_refs, 0); + do_collection(true, /* explicit_gc */ + clear_all_soft_refs, + 0 /* word_size */); } // This code is mostly copied from TenuredGeneration. @@ -1331,6 +1335,7 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : _young_list(new YoungList(this)), _gc_time_stamp(0), _surviving_young_words(NULL), + _full_collections_completed(0), _in_cset_fast_test(NULL), _in_cset_fast_test_base(NULL), _dirty_cards_region_list(NULL) { @@ -1689,6 +1694,51 @@ size_t G1CollectedHeap::unsafe_max_alloc() { return car->free(); } +bool G1CollectedHeap::should_do_concurrent_full_gc(GCCause::Cause cause) { + return + ((cause == GCCause::_gc_locker && GCLockerInvokesConcurrent) || + (cause == GCCause::_java_lang_system_gc && ExplicitGCInvokesConcurrent)); +} + +void G1CollectedHeap::increment_full_collections_completed(bool outer) { + MonitorLockerEx x(FullGCCount_lock, Mutex::_no_safepoint_check_flag); + + // We have already incremented _total_full_collections at the start + // of the GC, so total_full_collections() represents how many full + // collections have been started. + unsigned int full_collections_started = total_full_collections(); + + // Given that this method is called at the end of a Full GC or of a + // concurrent cycle, and those can be nested (i.e., a Full GC can + // interrupt a concurrent cycle), the number of full collections + // completed should be either one (in the case where there was no + // nesting) or two (when a Full GC interrupted a concurrent cycle) + // behind the number of full collections started. + + // This is the case for the inner caller, i.e. a Full GC. + assert(outer || + (full_collections_started == _full_collections_completed + 1) || + (full_collections_started == _full_collections_completed + 2), + err_msg("for inner caller: full_collections_started = %u " + "is inconsistent with _full_collections_completed = %u", + full_collections_started, _full_collections_completed)); + + // This is the case for the outer caller, i.e. the concurrent cycle. + assert(!outer || + (full_collections_started == _full_collections_completed + 1), + err_msg("for outer caller: full_collections_started = %u " + "is inconsistent with _full_collections_completed = %u", + full_collections_started, _full_collections_completed)); + + _full_collections_completed += 1; + + // This notify_all() will ensure that a thread that called + // System.gc() with (with ExplicitGCInvokesConcurrent set or not) + // and it's waiting for a full GC to finish will be woken up. It is + // waiting in VM_G1IncCollectionPause::doit_epilogue(). + FullGCCount_lock->notify_all(); +} + void G1CollectedHeap::collect_as_vm_thread(GCCause::Cause cause) { assert(Thread::current()->is_VM_thread(), "Precondition#1"); assert(Heap_lock->is_locked(), "Precondition#2"); @@ -1709,25 +1759,41 @@ void G1CollectedHeap::collect(GCCause::Cause cause) { // The caller doesn't have the Heap_lock assert(!Heap_lock->owned_by_self(), "this thread should not own the Heap_lock"); - int gc_count_before; + unsigned int gc_count_before; + unsigned int full_gc_count_before; { MutexLocker ml(Heap_lock); // Read the GC count while holding the Heap_lock gc_count_before = SharedHeap::heap()->total_collections(); + full_gc_count_before = SharedHeap::heap()->total_full_collections(); // Don't want to do a GC until cleanup is completed. wait_for_cleanup_complete(); - } // We give up heap lock; VMThread::execute gets it back below - switch (cause) { - case GCCause::_scavenge_alot: { - // Do an incremental pause, which might sometimes be abandoned. - VM_G1IncCollectionPause op(gc_count_before, cause); + + // We give up heap lock; VMThread::execute gets it back below + } + + if (should_do_concurrent_full_gc(cause)) { + // Schedule an initial-mark evacuation pause that will start a + // concurrent cycle. + VM_G1IncCollectionPause op(gc_count_before, + true, /* should_initiate_conc_mark */ + g1_policy()->max_pause_time_ms(), + cause); + VMThread::execute(&op); + } else { + if (cause == GCCause::_gc_locker + DEBUG_ONLY(|| cause == GCCause::_scavenge_alot)) { + + // Schedule a standard evacuation pause. + VM_G1IncCollectionPause op(gc_count_before, + false, /* should_initiate_conc_mark */ + g1_policy()->max_pause_time_ms(), + cause); VMThread::execute(&op); - break; - } - default: { - // In all other cases, we currently do a full gc. - VM_G1CollectFull op(gc_count_before, cause); + } else { + // Schedule a Full GC. + VM_G1CollectFull op(gc_count_before, full_gc_count_before, cause); VMThread::execute(&op); } } @@ -1989,6 +2055,11 @@ void G1CollectedHeap::collection_set_iterate(HeapRegionClosure* cl) { void G1CollectedHeap::collection_set_iterate_from(HeapRegion* r, HeapRegionClosure *cl) { + if (r == NULL) { + // The CSet is empty so there's nothing to do. + return; + } + assert(r->in_collection_set(), "Start region must be a member of the collection set."); HeapRegion* cur = r; @@ -2481,11 +2552,13 @@ void G1CollectedHeap::gc_epilogue(bool full /* Ignored */) { } void G1CollectedHeap::do_collection_pause() { + assert(Heap_lock->owned_by_self(), "we assume we'reholding the Heap_lock"); + // Read the GC count while holding the Heap_lock // we need to do this _before_ wait_for_cleanup_complete(), to // ensure that we do not give up the heap lock and potentially // pick up the wrong count - int gc_count_before = SharedHeap::heap()->total_collections(); + unsigned int gc_count_before = SharedHeap::heap()->total_collections(); // Don't want to do a GC pause while cleanup is being completed! wait_for_cleanup_complete(); @@ -2493,7 +2566,10 @@ void G1CollectedHeap::do_collection_pause() { g1_policy()->record_stop_world_start(); { MutexUnlocker mu(Heap_lock); // give up heap lock, execute gets it back - VM_G1IncCollectionPause op(gc_count_before); + VM_G1IncCollectionPause op(gc_count_before, + false, /* should_initiate_conc_mark */ + g1_policy()->max_pause_time_ms(), + GCCause::_g1_inc_collection_pause); VMThread::execute(&op); } } @@ -2612,7 +2688,7 @@ struct PrepareForRSScanningClosure : public HeapRegionClosure { }; void -G1CollectedHeap::do_collection_pause_at_safepoint() { +G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { if (GC_locker::check_active_before_gc()) { return; // GC is disabled (e.g. JNI GetXXXCritical operation) } @@ -2637,8 +2713,12 @@ G1CollectedHeap::do_collection_pause_at_safepoint() { else strcat(verbose_str, "(partial)"); } - if (g1_policy()->during_initial_mark_pause()) + if (g1_policy()->during_initial_mark_pause()) { strcat(verbose_str, " (initial-mark)"); + // We are about to start a marking cycle, so we increment the + // full collection counter. + increment_total_full_collections(); + } // if PrintGCDetails is on, we'll print long statistics information // in the collector policy code, so let's not print this as the output @@ -2661,7 +2741,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint() { "young list should be well formed"); } - bool abandoned = false; { // Call to jvmpi::post_class_unload_events must occur outside of active GC IsGCActiveMark x; @@ -2743,7 +2822,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint() { // Now choose the CS. We may abandon a pause if we find no // region that will fit in the MMU pause. - bool abandoned = g1_policy()->choose_collection_set(); + bool abandoned = g1_policy()->choose_collection_set(target_pause_time_ms); // Nothing to do if we were unable to choose a collection set. if (!abandoned) { diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index 38b44e72c75..74606c18bdf 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -277,6 +277,18 @@ private: void update_surviving_young_words(size_t* surv_young_words); void cleanup_surviving_young_words(); + // It decides whether an explicit GC should start a concurrent cycle + // instead of doing a STW GC. Currently, a concurrent cycle is + // explicitly started if: + // (a) cause == _gc_locker and +GCLockerInvokesConcurrent, or + // (b) cause == _java_lang_system_gc and +ExplicitGCInvokesConcurrent. + bool should_do_concurrent_full_gc(GCCause::Cause cause); + + // Keeps track of how many "full collections" (i.e., Full GCs or + // concurrent cycles) we have completed. The number of them we have + // started is maintained in _total_full_collections in CollectedHeap. + volatile unsigned int _full_collections_completed; + protected: // Returns "true" iff none of the gc alloc regions have any allocations @@ -356,13 +368,14 @@ protected: // GC pause. void retire_alloc_region(HeapRegion* alloc_region, bool par); - // Helper function for two callbacks below. - // "full", if true, indicates that the GC is for a System.gc() request, - // and should collect the entire heap. If "clear_all_soft_refs" is true, - // all soft references are cleared during the GC. If "full" is false, - // "word_size" describes the allocation that the GC should - // attempt (at least) to satisfy. - void do_collection(bool full, bool clear_all_soft_refs, + // - if explicit_gc is true, the GC is for a System.gc() or a heap + // inspection request and should collect the entire heap + // - if clear_all_soft_refs is true, all soft references are cleared + // during the GC + // - if explicit_gc is false, word_size describes the allocation that + // the GC should attempt (at least) to satisfy + void do_collection(bool explicit_gc, + bool clear_all_soft_refs, size_t word_size); // Callback from VM_G1CollectFull operation. @@ -431,6 +444,26 @@ public: _in_cset_fast_test_length * sizeof(bool)); } + // This is called at the end of either a concurrent cycle or a Full + // GC to update the number of full collections completed. Those two + // can happen in a nested fashion, i.e., we start a concurrent + // cycle, a Full GC happens half-way through it which ends first, + // and then the cycle notices that a Full GC happened and ends + // too. The outer parameter is a boolean to help us do a bit tighter + // consistency checking in the method. If outer is false, the caller + // is the inner caller in the nesting (i.e., the Full GC). If outer + // is true, the caller is the outer caller in this nesting (i.e., + // the concurrent cycle). Further nesting is not currently + // supported. The end of the this call also notifies the + // FullGCCount_lock in case a Java thread is waiting for a full GC + // to happen (e.g., it called System.gc() with + // +ExplicitGCInvokesConcurrent). + void increment_full_collections_completed(bool outer); + + unsigned int full_collections_completed() { + return _full_collections_completed; + } + protected: // Shrink the garbage-first heap by at most the given size (in bytes!). @@ -444,7 +477,7 @@ protected: // The guts of the incremental collection pause, executed by the vm // thread. - virtual void do_collection_pause_at_safepoint(); + virtual void do_collection_pause_at_safepoint(double target_pause_time_ms); // Actually do the work of evacuating the collection set. virtual void evacuate_collection_set(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp index 1eeba34217c..0cb73eb0c6b 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp @@ -154,7 +154,6 @@ G1CollectorPolicy::G1CollectorPolicy() : _known_garbage_bytes(0), _young_gc_eff_seq(new TruncatedSeq(TruncatedSeqLength)), - _target_pause_time_ms(-1.0), _recent_prev_end_times_for_all_gcs_sec(new TruncatedSeq(NumPrevPausesForHeuristics)), @@ -1635,8 +1634,6 @@ void G1CollectorPolicy::record_collection_pause_end(bool abandoned) { double update_rs_time_goal_ms = _mmu_tracker->max_gc_time() * MILLIUNITS * G1RSetUpdatingPauseTimePercent / 100.0; adjust_concurrent_refinement(update_rs_time, update_rs_processed_buffers, update_rs_time_goal_ms); // - - _target_pause_time_ms = -1.0; } // @@ -2366,7 +2363,6 @@ G1CollectorPolicy_BestRegionsFirst::should_do_collection_pause(size_t if (reached_target_length) { assert( young_list_length > 0 && _g1->young_list()->length() > 0, "invariant" ); - _target_pause_time_ms = max_pause_time_ms; return true; } } else { @@ -2398,6 +2394,17 @@ bool G1CollectorPolicy_BestRegionsFirst::assertMarkedBytesDataOK() { } #endif +bool +G1CollectorPolicy::force_initial_mark_if_outside_cycle() { + bool during_cycle = _g1->concurrent_mark()->cmThread()->during_cycle(); + if (!during_cycle) { + set_initiate_conc_mark_if_possible(); + return true; + } else { + return false; + } +} + void G1CollectorPolicy::decide_on_conc_mark_initiation() { // We are about to decide on whether this pause will be an @@ -2864,7 +2871,8 @@ void G1CollectorPolicy::print_collection_set(HeapRegion* list_head, outputStream #endif // !PRODUCT bool -G1CollectorPolicy_BestRegionsFirst::choose_collection_set() { +G1CollectorPolicy_BestRegionsFirst::choose_collection_set( + double target_pause_time_ms) { // Set this here - in case we're not doing young collections. double non_young_start_time_sec = os::elapsedTime(); @@ -2877,26 +2885,19 @@ G1CollectorPolicy_BestRegionsFirst::choose_collection_set() { start_recording_regions(); - guarantee(_target_pause_time_ms > -1.0 - NOT_PRODUCT(|| Universe::heap()->gc_cause() == GCCause::_scavenge_alot), - "_target_pause_time_ms should have been set!"); -#ifndef PRODUCT - if (_target_pause_time_ms <= -1.0) { - assert(ScavengeALot && Universe::heap()->gc_cause() == GCCause::_scavenge_alot, "Error"); - _target_pause_time_ms = _mmu_tracker->max_gc_time() * 1000.0; - } -#endif - assert(_collection_set == NULL, "Precondition"); + guarantee(target_pause_time_ms > 0.0, + err_msg("target_pause_time_ms = %1.6lf should be positive", + target_pause_time_ms)); + guarantee(_collection_set == NULL, "Precondition"); double base_time_ms = predict_base_elapsed_time_ms(_pending_cards); double predicted_pause_time_ms = base_time_ms; - double target_time_ms = _target_pause_time_ms; - double time_remaining_ms = target_time_ms - base_time_ms; + double time_remaining_ms = target_pause_time_ms - base_time_ms; // the 10% and 50% values are arbitrary... - if (time_remaining_ms < 0.10*target_time_ms) { - time_remaining_ms = 0.50 * target_time_ms; + if (time_remaining_ms < 0.10 * target_pause_time_ms) { + time_remaining_ms = 0.50 * target_pause_time_ms; _within_target = false; } else { _within_target = true; @@ -3059,7 +3060,18 @@ choose_collection_set_end: _recorded_non_young_cset_choice_time_ms = (non_young_end_time_sec - non_young_start_time_sec) * 1000.0; - return abandon_collection; + // Here we are supposed to return whether the pause should be + // abandoned or not (i.e., whether the collection set is empty or + // not). However, this introduces a subtle issue when a pause is + // initiated explicitly with System.gc() and + // +ExplicitGCInvokesConcurrent (see Comment #2 in CR 6944166), it's + // supposed to start a marking cycle, and it's abandoned. So, by + // returning false here we are telling the caller never to consider + // a pause to be abandoned. We'll actually remove all the code + // associated with abandoned pauses as part of CR 6963209, but we are + // just disabling them this way for the moment to avoid increasing + // further the amount of changes for CR 6944166. + return false; } void G1CollectorPolicy_BestRegionsFirst::record_full_collection_end() { diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp index b6f885d4534..61dbee6c09e 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp @@ -199,8 +199,6 @@ protected: size_t _young_cset_length; bool _last_young_gc_full; - double _target_pause_time_ms; - unsigned _full_young_pause_num; unsigned _partial_young_pause_num; @@ -526,6 +524,10 @@ public: return _mmu_tracker; } + double max_pause_time_ms() { + return _mmu_tracker->max_gc_time() * 1000.0; + } + double predict_init_time_ms() { return get_new_prediction(_concurrent_mark_init_times_ms); } @@ -1008,7 +1010,7 @@ public: // Choose a new collection set. Marks the chosen regions as being // "in_collection_set", and links them together. The head and number of // the collection set are available via access methods. - virtual bool choose_collection_set() = 0; + virtual bool choose_collection_set(double target_pause_time_ms) = 0; // The head of the list (via "next_in_collection_set()") representing the // current collection set. @@ -1077,6 +1079,12 @@ public: void set_during_initial_mark_pause() { _during_initial_mark_pause = true; } void clear_during_initial_mark_pause(){ _during_initial_mark_pause = false; } + // This sets the initiate_conc_mark_if_possible() flag to start a + // new cycle, as long as we are not already in one. It's best if it + // is called during a safepoint when the test whether a cycle is in + // progress or not is stable. + bool force_initial_mark_if_outside_cycle(); + // This is called at the very beginning of an evacuation pause (it // has to be the first thing that the pause does). If // initiate_conc_mark_if_possible() is true, and the concurrent @@ -1259,7 +1267,7 @@ class G1CollectorPolicy_BestRegionsFirst: public G1CollectorPolicy { // If the estimated is less then desirable, resize if possible. void expand_if_possible(size_t numRegions); - virtual bool choose_collection_set(); + virtual bool choose_collection_set(double target_pause_time_ms); virtual void record_collection_pause_start(double start_time_sec, size_t start_used); virtual void record_concurrent_mark_cleanup_end(size_t freed_bytes, diff --git a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp index 02370cadc18..575e6781786 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp @@ -42,8 +42,65 @@ void VM_G1CollectFull::doit() { void VM_G1IncCollectionPause::doit() { JvmtiGCForAllocationMarker jgcm; G1CollectedHeap* g1h = G1CollectedHeap::heap(); + assert(!_should_initiate_conc_mark || + ((_gc_cause == GCCause::_gc_locker && GCLockerInvokesConcurrent) || + (_gc_cause == GCCause::_java_lang_system_gc && ExplicitGCInvokesConcurrent)), + "only a GC locker or a System.gc() induced GC should start a cycle"); + GCCauseSetter x(g1h, _gc_cause); - g1h->do_collection_pause_at_safepoint(); + if (_should_initiate_conc_mark) { + // It's safer to read full_collections_completed() here, given + // that noone else will be updating it concurrently. Since we'll + // only need it if we're initiating a marking cycle, no point in + // setting it earlier. + _full_collections_completed_before = g1h->full_collections_completed(); + + // At this point we are supposed to start a concurrent cycle. We + // will do so if one is not already in progress. + bool res = g1h->g1_policy()->force_initial_mark_if_outside_cycle(); + } + g1h->do_collection_pause_at_safepoint(_target_pause_time_ms); +} + +void VM_G1IncCollectionPause::doit_epilogue() { + VM_GC_Operation::doit_epilogue(); + + // If the pause was initiated by a System.gc() and + // +ExplicitGCInvokesConcurrent, we have to wait here for the cycle + // that just started (or maybe one that was already in progress) to + // finish. + if (_gc_cause == GCCause::_java_lang_system_gc && + _should_initiate_conc_mark) { + assert(ExplicitGCInvokesConcurrent, + "the only way to be here is if ExplicitGCInvokesConcurrent is set"); + + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + + // In the doit() method we saved g1h->full_collections_completed() + // in the _full_collections_completed_before field. We have to + // wait until we observe that g1h->full_collections_completed() + // has increased by at least one. This can happen if a) we started + // a cycle and it completes, b) a cycle already in progress + // completes, or c) a Full GC happens. + + // If the condition has already been reached, there's no point in + // actually taking the lock and doing the wait. + if (g1h->full_collections_completed() <= + _full_collections_completed_before) { + // The following is largely copied from CMS + + Thread* thr = Thread::current(); + assert(thr->is_Java_thread(), "invariant"); + JavaThread* jt = (JavaThread*)thr; + ThreadToNativeFromVM native(jt); + + MutexLockerEx x(FullGCCount_lock, Mutex::_no_safepoint_check_flag); + while (g1h->full_collections_completed() <= + _full_collections_completed_before) { + FullGCCount_lock->wait(Mutex::_no_safepoint_check_flag); + } + } + } } void VM_CGC_Operation::doit() { diff --git a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.hpp b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.hpp index 3368c300eaf..d05beac9ea1 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.hpp @@ -31,13 +31,12 @@ // - VM_G1PopRegionCollectionPause class VM_G1CollectFull: public VM_GC_Operation { - private: public: - VM_G1CollectFull(int gc_count_before, - GCCause::Cause gc_cause) - : VM_GC_Operation(gc_count_before) - { - _gc_cause = gc_cause; + VM_G1CollectFull(unsigned int gc_count_before, + unsigned int full_gc_count_before, + GCCause::Cause cause) + : VM_GC_Operation(gc_count_before, full_gc_count_before) { + _gc_cause = cause; } ~VM_G1CollectFull() {} virtual VMOp_Type type() const { return VMOp_G1CollectFull; } @@ -67,12 +66,28 @@ class VM_G1CollectForAllocation: public VM_GC_Operation { }; class VM_G1IncCollectionPause: public VM_GC_Operation { - public: - VM_G1IncCollectionPause(int gc_count_before, - GCCause::Cause gc_cause = GCCause::_g1_inc_collection_pause) : - VM_GC_Operation(gc_count_before) { _gc_cause = gc_cause; } +private: + bool _should_initiate_conc_mark; + double _target_pause_time_ms; + unsigned int _full_collections_completed_before; +public: + VM_G1IncCollectionPause(unsigned int gc_count_before, + bool should_initiate_conc_mark, + double target_pause_time_ms, + GCCause::Cause cause) + : VM_GC_Operation(gc_count_before), + _full_collections_completed_before(0), + _should_initiate_conc_mark(should_initiate_conc_mark), + _target_pause_time_ms(target_pause_time_ms) { + guarantee(target_pause_time_ms > 0.0, + err_msg("target_pause_time_ms = %1.6lf should be positive", + target_pause_time_ms)); + + _gc_cause = cause; + } virtual VMOp_Type type() const { return VMOp_G1IncCollectionPause; } virtual void doit(); + virtual void doit_epilogue(); virtual const char* name() const { return "garbage-first incremental collection pause"; } diff --git a/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 b/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 index dd271e1d1d8..13e3464ed8f 100644 --- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 +++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 @@ -367,4 +367,6 @@ vm_operations_g1.hpp vmGCOperations.hpp vm_operations_g1.cpp vm_operations_g1.hpp vm_operations_g1.cpp g1CollectedHeap.inline.hpp +vm_operations_g1.cpp g1CollectorPolicy.hpp +vm_operations_g1.cpp interfaceSupport.hpp vm_operations_g1.cpp isGCActiveMark.hpp diff --git a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp index d70d78ab92f..b3a202902a5 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp @@ -86,9 +86,7 @@ class VM_GC_Operation: public VM_Operation { _gc_locked = false; - if (full) { - _full_gc_count_before = full_gc_count_before; - } + _full_gc_count_before = full_gc_count_before; // In ParallelScavengeHeap::mem_allocate() collections can be // executed within a loop and _all_soft_refs_clear can be set // true after they have been cleared by a collection and another diff --git a/hotspot/src/share/vm/gc_interface/gcCause.cpp b/hotspot/src/share/vm/gc_interface/gcCause.cpp index 19822c92777..e96f55a86ee 100644 --- a/hotspot/src/share/vm/gc_interface/gcCause.cpp +++ b/hotspot/src/share/vm/gc_interface/gcCause.cpp @@ -78,6 +78,9 @@ const char* GCCause::to_string(GCCause::Cause cause) { case _old_generation_too_full_to_scavenge: return "Old Generation Too Full To Scavenge"; + case _g1_inc_collection_pause: + return "G1 Evacuation Pause"; + case _last_ditch_collection: return "Last ditch collection"; diff --git a/hotspot/src/share/vm/runtime/mutexLocker.cpp b/hotspot/src/share/vm/runtime/mutexLocker.cpp index 71cbc771856..93f1e2feea0 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp @@ -159,6 +159,8 @@ void mutex_init() { def(STS_init_lock , Mutex, leaf, true ); if (UseConcMarkSweepGC) { def(iCMS_lock , Monitor, special, true ); // CMS incremental mode start/stop notification + } + if (UseConcMarkSweepGC || UseG1GC) { def(FullGCCount_lock , Monitor, leaf, true ); // in support of ExplicitGCInvokesConcurrent } if (UseG1GC) { From c3da61922777228c2f117b446e29befbcd06c131 Mon Sep 17 00:00:00 2001 From: Peter Zhelezniakov Date: Tue, 13 Jul 2010 17:26:34 +0400 Subject: [PATCH 03/52] 6462562: InternationalFormatter inserts text incorrectly 6578432: Currency format instance does not work with Swing's NumberFormatter Reviewed-by: rupashka --- .../javax/swing/text/DefaultFormatter.java | 4 +- .../swing/text/InternationalFormatter.java | 78 +--- .../JFormattedTextField/Test6462562.java | 360 ++++++++++++++++++ 3 files changed, 380 insertions(+), 62 deletions(-) create mode 100644 jdk/test/javax/swing/JFormattedTextField/Test6462562.java diff --git a/jdk/src/share/classes/javax/swing/text/DefaultFormatter.java b/jdk/src/share/classes/javax/swing/text/DefaultFormatter.java index d6e47c5fdf9..75c3481678e 100644 --- a/jdk/src/share/classes/javax/swing/text/DefaultFormatter.java +++ b/jdk/src/share/classes/javax/swing/text/DefaultFormatter.java @@ -570,7 +570,9 @@ public class DefaultFormatter extends JFormattedTextField.AbstractFormatter direction = -1; } - if (getOverwriteMode() && rh.text != null) { + if (getOverwriteMode() && rh.text != null && + getFormattedTextField().getSelectedText() == null) + { rh.length = Math.min(Math.max(rh.length, rh.text.length()), rh.fb.getDocument().getLength() - rh.offset); } diff --git a/jdk/src/share/classes/javax/swing/text/InternationalFormatter.java b/jdk/src/share/classes/javax/swing/text/InternationalFormatter.java index c511b20e281..b49fed2e3ce 100644 --- a/jdk/src/share/classes/javax/swing/text/InternationalFormatter.java +++ b/jdk/src/share/classes/javax/swing/text/InternationalFormatter.java @@ -622,18 +622,8 @@ public class InternationalFormatter extends DefaultFormatter { /** * Overriden in an attempt to honor the literals. - *

- * If we do - * not allow invalid values and are in overwrite mode, this does the - * following for each character in the replacement range: - *

    - *
  1. If the character is a literal, add it to the string to replace - * with. If there is text to insert and it doesn't match the - * literal, then insert the literal in the the middle of the insert - * text. This allows you to either paste in literals or not and - * get the same behavior. - *
  2. If there is no text to insert, replace it with ' '. - *
+ *

If we do not allow invalid values and are in overwrite mode, this + * {@code rh.length} is corrected as to preserve trailing literals. * If not in overwrite mode, and there is text to insert it is * inserted at the next non literal index going forward. If there * is only text to remove, it is removed from the next non literal @@ -643,61 +633,27 @@ public class InternationalFormatter extends DefaultFormatter { if (!getAllowsInvalid()) { String text = rh.text; int tl = (text != null) ? text.length() : 0; + JTextComponent c = getFormattedTextField(); - if (tl == 0 && rh.length == 1 && getFormattedTextField(). - getSelectionStart() != rh.offset) { + if (tl == 0 && rh.length == 1 && c.getSelectionStart() != rh.offset) { // Backspace, adjust to actually delete next non-literal. rh.offset = getNextNonliteralIndex(rh.offset, -1); - } - if (getOverwriteMode()) { - StringBuffer replace = null; + } else if (getOverwriteMode()) { + int pos = rh.offset; + int textPos = pos; + boolean overflown = false; - for (int counter = 0, textIndex = 0, - max = Math.max(tl, rh.length); counter < max; - counter++) { - if (isLiteral(rh.offset + counter)) { - if (replace != null) { - replace.append(getLiteral(rh.offset + - counter)); - } - if (textIndex < tl && text.charAt(textIndex) == - getLiteral(rh.offset + counter)) { - textIndex++; - } - else if (textIndex == 0) { - rh.offset++; - rh.length--; - counter--; - max--; - } - else if (replace == null) { - replace = new StringBuffer(max); - replace.append(text.substring(0, textIndex)); - replace.append(getLiteral(rh.offset + - counter)); - } - } - else if (textIndex < tl) { - if (replace != null) { - replace.append(text.charAt(textIndex)); - } - textIndex++; - } - else { - // Nothing to replace it with, assume ' ' - if (replace == null) { - replace = new StringBuffer(max); - if (textIndex > 0) { - replace.append(text.substring(0, textIndex)); - } - } - if (replace != null) { - replace.append(' '); - } + for (int i = 0; i < rh.length; i++) { + while (isLiteral(pos)) pos++; + if (pos >= string.length()) { + pos = textPos; + overflown = true; + break; } + textPos = ++pos; } - if (replace != null) { - rh.text = replace.toString(); + if (overflown || c.getSelectedText() == null) { + rh.length = pos - rh.offset; } } else if (tl > 0) { diff --git a/jdk/test/javax/swing/JFormattedTextField/Test6462562.java b/jdk/test/javax/swing/JFormattedTextField/Test6462562.java new file mode 100644 index 00000000000..0696a016fba --- /dev/null +++ b/jdk/test/javax/swing/JFormattedTextField/Test6462562.java @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @bug 6462562 + @summary Tests text input into JFormattedTextField + with an InternationalFormatter + @author Peter Zhelezniakov + @run main Test6462562 +*/ + +import java.awt.event.ActionEvent; +import java.text.DateFormat; +import java.text.NumberFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import javax.swing.Action; +import javax.swing.JFormattedTextField; +import javax.swing.SwingUtilities; +import javax.swing.text.Caret; +import javax.swing.text.DateFormatter; +import javax.swing.text.DefaultEditorKit; +import javax.swing.text.InternationalFormatter; +import javax.swing.text.NumberFormatter; + + +public class Test6462562 +{ + static final String BACKSPACE = new String("backspace"); + static final String DELETE = new String("delete"); + + boolean failed = false; + + void test() { + testPercentFormat(); + testCurrencyFormat(); + testIntegerFormat(); + testDateFormat(); + + if (failed) { + throw new RuntimeException("Some testcases failed, see output above"); + } + System.err.println("(-; All testcases passed ;-)"); + } + + TestFormattedTextField create(NumberFormat format) { + format.setMaximumFractionDigits(0); + NumberFormatter fmt = new NumberFormatter(format); + return new TestFormattedTextField(fmt); + } + + TestFormattedTextField create(DateFormat format) { + DateFormatter fmt = new DateFormatter(format); + return new TestFormattedTextField(fmt); + } + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + new Test6462562().test(); + } + }); + } + + class TestFormattedTextField extends JFormattedTextField + { + final Action backspace; + final Action delete; + final Action insert; + + final ActionEvent dummyEvent; + + public TestFormattedTextField(InternationalFormatter fmt) { + super(fmt); + fmt.setAllowsInvalid(false); + fmt.setOverwriteMode(true); + + backspace = getActionMap().get(DefaultEditorKit.deletePrevCharAction); + delete = getActionMap().get(DefaultEditorKit.deleteNextCharAction); + insert = getActionMap().get(DefaultEditorKit.insertContentAction); + dummyEvent = new ActionEvent(this, 0, null); + } + + public boolean test(int pos, int selectionLength, String todo, Object expectedResult) { + Object v0 = getValue(); + + Caret caret = getCaret(); + caret.setDot(pos); + if (selectionLength > 0) { + caret.moveDot(pos + selectionLength); + } + + String desc = todo; + if (todo == BACKSPACE) { + backspace.actionPerformed(dummyEvent); + } else if (todo == DELETE) { + delete.actionPerformed(dummyEvent); + } else { + desc = "insert('" + todo + "')"; + insert.actionPerformed(new ActionEvent(this, 0, todo)); + } + + try { + commitEdit(); + } catch (ParseException e) { + e.printStackTrace(); + failed = true; + return false; + } + + Object v1 = getValue(); + if (! v1.equals(expectedResult)) { + System.err.printf("Failure: value='%s', mark=%d, dot=%d, action=%s\n", + v0, pos, pos + selectionLength, desc); + System.err.printf(" Result: '%s', expected: '%s'\n", v1, expectedResult); + failed = true; + return false; + } + return true; + } + } + + void testPercentFormat() { + NumberFormat format = NumberFormat.getPercentInstance(Locale.US); + TestFormattedTextField ftf = create(format); + ftf.setValue(.34); + + System.err.println("Testing NumberFormat.getPercentInstance(Locale.US)"); + + // test inserting individual characters + ftf.test(0, 0, "1", .14); + ftf.test(2, 0, "2", 1.42); + ftf.test(1, 0, "0", 1.02); + + // test inserting several characters at once - e.g. from clipboard + ftf.test(0, 0, "1024", 10.24); + ftf.test(3, 0, "333", 103.33); + ftf.test(6, 0, "77", 10333.77); + ftf.test(4, 0, "99", 10399.77); + ftf.test(6, 0, "00", 10390.07); + + // test inserting strings that contain some formatting + ftf.test(0, 0, "2,2", 2290.07); + ftf.test(2, 0, "2,2", 222.27); + ftf.test(4, 0, "2,2", 222.22); + ftf.test(6, 0, "33,33", 2222233.33); + + // test delete + ftf.test(0, 0, DELETE, 222233.33); + ftf.test(10, 0, DELETE, 222233.33); + ftf.test(5, 0, DELETE, 22223.33); + ftf.test(6, 0, DELETE, 2222.33); + + // test backspace + ftf.test(0, 0, BACKSPACE, 2222.33); + ftf.test(7, 0, BACKSPACE, 222.23); + ftf.test(4, 0, BACKSPACE, 22.23); + ftf.test(2, 0, BACKSPACE, 2.23); + + // test replacing selection + ftf.test(0, 1, "555", 555.23); + ftf.test(4, 2, "555", 5555.55); + ftf.test(2, 3, "1", 551.55); + ftf.test(3, 2, "6", 55.65); + ftf.test(4, 2, "12", 556.12); + ftf.test(3, 4, "0", 5.5); + ftf.test(0, 3, "111222333444555", 1112223334445.55); + + // test deleting selection + ftf.test(0, 2, DELETE, 12223334445.55); + ftf.test(0, 3, BACKSPACE, 223334445.55); + ftf.test(12, 2, DELETE, 2233344.45); + ftf.test(9, 2, BACKSPACE, 22333.44); + ftf.test(4, 3, DELETE, 223.44); + ftf.test(1, 2, BACKSPACE, 23.44); + ftf.test(3, 3, DELETE, .23); + ftf.test(1, 2, BACKSPACE, .02); + } + + void testCurrencyFormat() { + NumberFormat format = NumberFormat.getCurrencyInstance(Locale.US); + TestFormattedTextField ftf = create(format); + ftf.setValue(56L); + + System.err.println("Testing NumberFormat.getCurrencyInstance(Locale.US)"); + + // test inserting individual characters + ftf.test(1, 0, "1", 16L); + ftf.test(3, 0, "2", 162L); + ftf.test(2, 0, "0", 102L); + + // test inserting several characters at once - e.g. from clipboard + ftf.test(1, 0, "1024", 1024L); + ftf.test(4, 0, "333", 10333L); + ftf.test(7, 0, "77", 1033377L); + ftf.test(5, 0, "99", 1039977L); + ftf.test(7, 0, "00", 1039007L); + + // test inserting strings that contain some formatting + ftf.test(1, 0, "2,2", 229007L); + ftf.test(3, 0, "2,2", 22227L); + ftf.test(4, 0, "2,2", 2222L); + ftf.test(6, 0, "33,33", 22223333L); + + // test delete + ftf.test(1, 0, DELETE, 2223333L); + ftf.test(10, 0, DELETE, 2223333L); + ftf.test(5, 0, DELETE, 222333L); + ftf.test(5, 0, DELETE, 22233L); + + // test backspace + ftf.test(1, 0, BACKSPACE, 22233L); + ftf.test(7, 0, BACKSPACE, 2223L); + ftf.test(4, 0, BACKSPACE, 223L); + ftf.test(2, 0, BACKSPACE, 23L); + + // test replacing selection + ftf.test(1, 1, "555", 5553L); + ftf.test(4, 2, "555", 55555L); + ftf.test(2, 3, "1", 5155L); + ftf.test(3, 2, "6", 565L); + ftf.test(1, 3, "111222333444555", 111222333444555L); + + // test deleting selection + ftf.test(1, 2, DELETE, 1222333444555L); + ftf.test(1, 3, BACKSPACE, 22333444555L); + ftf.test(13, 2, DELETE, 223334445L); + ftf.test(10, 2, BACKSPACE, 2233344L); + ftf.test(4, 4, DELETE, 2244L); + ftf.test(1, 4, BACKSPACE, 4L); + } + + void testIntegerFormat() { + NumberFormat format = NumberFormat.getIntegerInstance(Locale.US); + TestFormattedTextField ftf = create(format); + ftf.setValue(56L); + + System.err.println("Testing NumberFormat.getIntegerInstance(Locale.US)"); + + // test inserting individual characters + ftf.test(0, 0, "1", 16L); + ftf.test(2, 0, "2", 162L); + ftf.test(1, 0, "0", 102L); + + // test inserting several characters at once - e.g. from clipboard + ftf.test(0, 0, "1024", 1024L); + ftf.test(3, 0, "333", 10333L); + ftf.test(6, 0, "77", 1033377L); + ftf.test(4, 0, "99", 1039977L); + ftf.test(6, 0, "00", 1039007L); + + // test inserting strings that contain some formatting + ftf.test(0, 0, "2,2", 229007L); + ftf.test(2, 0, "2,2", 22227L); + ftf.test(3, 0, "2,2", 2222L); + ftf.test(5, 0, "33,33", 22223333L); + + // test delete + ftf.test(0, 0, DELETE, 2223333L); + ftf.test(9, 0, DELETE, 2223333L); + ftf.test(4, 0, DELETE, 222333L); + ftf.test(4, 0, DELETE, 22233L); + + // test backspace + ftf.test(0, 0, BACKSPACE, 22233L); + ftf.test(6, 0, BACKSPACE, 2223L); + ftf.test(2, 0, BACKSPACE, 223L); + ftf.test(2, 0, BACKSPACE, 23L); + + // test replacing selection + ftf.test(0, 1, "555", 5553L); + ftf.test(3, 2, "555", 55555L); + ftf.test(1, 3, "1", 5155L); + ftf.test(2, 2, "6", 565L); + ftf.test(0, 3, "111222333444555", 111222333444555L); + + // test deleting selection + ftf.test(0, 2, DELETE, 1222333444555L); + ftf.test(0, 3, BACKSPACE, 22333444555L); + ftf.test(12, 2, DELETE, 223334445L); + ftf.test(9, 2, BACKSPACE, 2233344L); + ftf.test(3, 4, DELETE, 2244L); + ftf.test(0, 4, BACKSPACE, 4L); + } + + Date date(DateFormat format, String spec) { + try { + return format.parse(spec); + } catch (ParseException e) { + throw new Error("Error in test"); + } + } + + void testDateFormat() { + DateFormat format = new SimpleDateFormat("MM/dd/yyyy", Locale.US); + TestFormattedTextField ftf = create(format); + ftf.setValue(date(format, "12/05/2005")); + + System.err.println("Testing SimpleDateFormat(\"MM/dd/yyyy\", Locale.US)"); + + // test inserting individual characters + ftf.test(0, 0, "0", date(format, "02/05/2005")); + ftf.test(4, 0, "4", date(format, "02/04/2005")); + ftf.test(6, 0, "1", date(format, "02/04/1005")); + ftf.test(9, 0, "9", date(format, "02/04/1009")); + + // test inserting several characters at once - e.g. from clipboard + ftf.test(0, 0, "11", date(format, "11/04/1009")); + ftf.test(3, 0, "23", date(format, "11/23/1009")); + ftf.test(6, 0, "191", date(format, "11/23/1919")); + + // test delete + ftf.test(0, 0, DELETE, date(format, "01/23/1919")); + ftf.test(3, 0, DELETE, date(format, "01/03/1919")); + ftf.test(10, 0, DELETE, date(format, "01/03/1919")); + ftf.test(1, 0, DELETE, date(format, "12/03/1918")); + ftf.test(4, 0, DELETE, date(format, "11/30/1918")); + + // test backspace + ftf.test(0, 0, BACKSPACE, date(format, "11/30/1918")); + ftf.test(1, 0, BACKSPACE, date(format, "01/30/1918")); + ftf.test(4, 0, BACKSPACE, date(format, "12/31/1917")); + ftf.test(10, 0, BACKSPACE, date(format, "12/31/0191")); + ftf.test(3, 0, BACKSPACE, date(format, "01/31/0191")); + ftf.test(5, 0, BACKSPACE, date(format, "01/03/0191")); + + // test replacing selection + ftf.test(0, 1, "1", date(format, "11/03/0191")); + ftf.test(3, 1, "2", date(format, "11/23/0191")); + ftf.test(6, 2, "20", date(format, "11/23/2091")); + + // test deleting selection + ftf.test(0, 1, BACKSPACE, date(format, "01/23/2091")); + ftf.test(3, 1, DELETE, date(format, "01/03/2091")); + ftf.test(6, 2, BACKSPACE, date(format, "01/03/0091")); + ftf.test(8, 1, DELETE, date(format, "01/03/0001")); + } +} From ec05f75ccd971c2b8e83e974b1c4abb629498092 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Tue, 13 Jul 2010 19:14:09 -0700 Subject: [PATCH 04/52] 6966732: replace use of static Log.getLocalizedString with non-static alternative where possible Reviewed-by: darcy --- .../com/sun/tools/javac/jvm/ClassReader.java | 4 +-- .../com/sun/tools/javac/jvm/ClassWriter.java | 2 +- .../sun/tools/javac/main/JavaCompiler.java | 12 +++---- .../JavacProcessingEnvironment.java | 35 ++++++++----------- .../classes/com/sun/tools/javac/util/Log.java | 29 +++++++++++++-- 5 files changed, 50 insertions(+), 32 deletions(-) diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java index d16dc1d2ce8..09d5d7c5b2f 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -2628,7 +2628,7 @@ public class ClassReader implements Completer { * @param arg An argument for substitution into the output string. */ private void printVerbose(String key, CharSequence arg) { - Log.printLines(log.noticeWriter, Log.getLocalizedString("verbose." + key, arg)); + log.printNoteLines("verbose." + key, arg); } /** Output for "-checkclassfile" option. @@ -2636,7 +2636,7 @@ public class ClassReader implements Completer { * @param arg An argument for substitution into the output string. */ private void printCCF(String key, Object arg) { - Log.printLines(log.noticeWriter, Log.getLocalizedString(key, arg)); + log.printNoteLines(key, arg); } diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java index 687d5344323..e0af0d914f9 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java @@ -1604,7 +1604,7 @@ public class ClassWriter extends ClassFile { try { writeClassFile(out, c); if (verbose) - log.errWriter.println(Log.getLocalizedString("verbose.wrote.file", outFile)); + log.printErrLines("verbose.wrote.file", outFile); out.close(); out = null; } finally { diff --git a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java index d65aca9cdb8..86ce0da81cd 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -1105,7 +1105,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter { return env; if (verboseCompilePolicy) - Log.printLines(log.noticeWriter, "[attribute " + env.enclClass.sym + "]"); + printNote("[attribute " + env.enclClass.sym + "]"); if (verbose) printVerbose("checking.attribution", env.enclClass.sym); @@ -1527,19 +1527,19 @@ public class JavaCompiler implements ClassReader.SourceCompleter { * @param arg An argument for substitution into the output string. */ protected void printVerbose(String key, Object arg) { - Log.printLines(log.noticeWriter, Log.getLocalizedString("verbose." + key, arg)); + log.printNoteLines("verbose." + key, arg); } /** Print numbers of errors and warnings. */ protected void printCount(String kind, int count) { if (count != 0) { - String text; + String key; if (count == 1) - text = Log.getLocalizedString("count." + kind, String.valueOf(count)); + key = "count." + kind; else - text = Log.getLocalizedString("count." + kind + ".plural", String.valueOf(count)); - Log.printLines(log.errWriter, text); + key = "count." + kind + ".plural"; + log.printErrLines(key, String.valueOf(count)); log.errWriter.flush(); } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java index 2f605fdc528..800a1a21e1b 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java +++ b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java @@ -654,9 +654,6 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea Set annotationsPresent, List topLevelClasses, List packageInfoFiles) { - // Writer for -XprintRounds and -XprintProcessorInfo data - PrintWriter xout = context.get(Log.outKey); - Map unmatchedAnnotations = new HashMap(annotationsPresent.size()); @@ -708,10 +705,10 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea ps.removeSupportedOptions(unmatchedProcessorOptions); if (printProcessorInfo || verbose) { - xout.println(Log.getLocalizedString("x.print.processor.info", - ps.processor.getClass().getName(), - matchedNames.toString(), - processingResult)); + log.printNoteLines("x.print.processor.info", + ps.processor.getClass().getName(), + matchedNames.toString(), + processingResult); } if (processingResult) { @@ -795,8 +792,6 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea throws IOException { log = Log.instance(context); - // Writer for -XprintRounds and -XprintProcessorInfo data - PrintWriter xout = context.get(Log.outKey); TaskListener taskListener = context.get(TaskListener.class); JavaCompiler compiler = JavaCompiler.instance(context); @@ -839,7 +834,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea this.context = currentContext; roundNumber++; - printRoundInfo(xout, roundNumber, topLevelClasses, annotationsPresent, false); + printRoundInfo(roundNumber, topLevelClasses, annotationsPresent, false); if (taskListener != null) taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND)); @@ -908,7 +903,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea break runAround; // No new files } } - roots = runLastRound(xout, roundNumber, errorStatus, compiler, roots, taskListener); + roots = runLastRound(roundNumber, errorStatus, compiler, roots, taskListener); // Set error status for any files compiled and generated in // the last round if (log.unrecoverableError) @@ -982,8 +977,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea } // Call the last round of annotation processing - private List runLastRound(PrintWriter xout, - int roundNumber, + private List runLastRound(int roundNumber, boolean errorStatus, JavaCompiler compiler, List roots, @@ -991,7 +985,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea roundNumber++; List noTopLevelClasses = List.nil(); Set noAnnotations = Collections.emptySet(); - printRoundInfo(xout, roundNumber, noTopLevelClasses, noAnnotations, true); + printRoundInfo(roundNumber, noTopLevelClasses, noAnnotations, true); Set emptyRootElements = Collections.emptySet(); // immutable RoundEnvironment renv = new JavacRoundEnvironment(true, @@ -1032,17 +1026,16 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea } } - private void printRoundInfo(PrintWriter xout, - int roundNumber, + private void printRoundInfo(int roundNumber, List topLevelClasses, Set annotationsPresent, boolean lastRound) { if (printRounds || verbose) { - xout.println(Log.getLocalizedString("x.print.rounds", - roundNumber, - "{" + topLevelClasses.toString(", ") + "}", - annotationsPresent, - lastRound)); + log.printNoteLines("x.print.rounds", + roundNumber, + "{" + topLevelClasses.toString(", ") + "}", + annotationsPresent, + lastRound); } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/util/Log.java b/langtools/src/share/classes/com/sun/tools/javac/util/Log.java index 6fcc4b0fbcb..66d5e947ab2 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/util/Log.java +++ b/langtools/src/share/classes/com/sun/tools/javac/util/Log.java @@ -269,7 +269,7 @@ public class Log extends AbstractLog { */ public void prompt() { if (promptOnError) { - System.err.println(getLocalizedString("resume.abort")); + System.err.println(localize("resume.abort")); char ch; try { while (true) { @@ -317,8 +317,23 @@ public class Log extends AbstractLog { if (msg.length() != 0) writer.println(msg); } + /** Print the text of a message to the errWriter stream, + * translating newlines appropriately for the platform. + */ + public void printErrLines(String key, Object... args) { + printLines(errWriter, localize(key, args)); + } + + + /** Print the text of a message to the noticeWriter stream, + * translating newlines appropriately for the platform. + */ + public void printNoteLines(String key, Object... args) { + printLines(noticeWriter, localize(key, args)); + } + protected void directError(String key, Object... args) { - printLines(errWriter, getLocalizedString(key, args)); + printErrLines(key, args); errWriter.flush(); } @@ -426,6 +441,8 @@ public class Log extends AbstractLog { } /** Find a localized string in the resource bundle. + * Because this method is static, it ignores the locale. + * Use localize(key, args) when possible. * @param key The key for the localized string. * @param args Fields to substitute into the string. */ @@ -433,6 +450,14 @@ public class Log extends AbstractLog { return JavacMessages.getDefaultLocalizedString("compiler.misc." + key, args); } + /** Find a localized string in the resource bundle. + * @param key The key for the localized string. + * @param args Fields to substitute into the string. + */ + public String localize(String key, Object... args) { + return messages.getLocalizedString("compiler.misc." + key, args); + } + /*************************************************************************** * raw error messages without internationalization; used for experimentation * and quick prototyping From 5db54afdeaad361d29feca7f7b66a050cb26d565 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Tue, 13 Jul 2010 19:17:55 -0700 Subject: [PATCH 05/52] 6968434: test CheckResourceKeys fails on control builds Reviewed-by: darcy --- .../tools/javac/diags/CheckResourceKeys.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/langtools/test/tools/javac/diags/CheckResourceKeys.java b/langtools/test/tools/javac/diags/CheckResourceKeys.java index 7b60ae68af4..32ef8ed4a4a 100644 --- a/langtools/test/tools/javac/diags/CheckResourceKeys.java +++ b/langtools/test/tools/javac/diags/CheckResourceKeys.java @@ -294,6 +294,7 @@ public class CheckResourceKeys { Set results = new TreeSet(); JavaCompiler c = ToolProvider.getSystemJavaCompiler(); JavaFileManager fm = c.getStandardFileManager(null, null, null); + JavaFileManager.Location javacLoc = findJavacLocation(fm); String[] pkgs = { "javax.annotation.processing", "javax.lang.model", @@ -302,7 +303,7 @@ public class CheckResourceKeys { "com.sun.tools.javac" }; for (String pkg: pkgs) { - for (JavaFileObject fo: fm.list(StandardLocation.PLATFORM_CLASS_PATH, + for (JavaFileObject fo: fm.list(javacLoc, pkg, EnumSet.of(JavaFileObject.Kind.CLASS), true)) { String name = fo.getName(); // ignore resource files, and files which are not really part of javac @@ -316,6 +317,23 @@ public class CheckResourceKeys { return results; } + // depending on how the test is run, javac may be on bootclasspath or classpath + JavaFileManager.Location findJavacLocation(JavaFileManager fm) { + JavaFileManager.Location[] locns = + { StandardLocation.PLATFORM_CLASS_PATH, StandardLocation.CLASS_PATH }; + try { + for (JavaFileManager.Location l: locns) { + JavaFileObject fo = fm.getJavaFileForInput(l, + "com.sun.tools.javac.Main", JavaFileObject.Kind.CLASS); + if (fo != null) + return l; + } + } catch (IOException e) { + throw new Error(e); + } + throw new IllegalStateException("Cannot find javac"); + } + /** * Get the set of strings from a class file. * Only strings that look like they might be a resource key are returned. From a1e7efde4abf16e5e06a3e1384c663146eb35398 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Tue, 13 Jul 2010 19:20:48 -0700 Subject: [PATCH 06/52] 6968789: incorrect text in "diamond not supported" message Reviewed-by: darcy --- .../classes/com/sun/tools/javac/resources/compiler.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties index dec8126dd43..8fee222ad64 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -1263,7 +1263,7 @@ compiler.err.enums.not.supported.in.source=\ compiler.err.diamond.not.supported.in.source=\ diamond operator is not supported in -source {0}\n\ -(use -source 7 or higher to enable multi-catch statement) +(use -source 7 or higher to enable diamond operator) compiler.err.multicatch.not.supported.in.source=\ multi-catch statement is not supported in -source {0}\n\ From aa93fd77012f7d1f02c33690683f59bc3679b898 Mon Sep 17 00:00:00 2001 From: Mahmood Ali Date: Thu, 15 Jul 2010 16:31:02 +0100 Subject: [PATCH 07/52] 6967002: JDK7 b99 javac compilation error (java.lang.AssertionError) Bug in JavacParser related to parsing of type annotations in varargs position Reviewed-by: jjg --- .../sun/tools/javac/parser/JavacParser.java | 8 +++-- .../typeAnnotations/6967002/T6967002.java | 35 +++++++++++++++++++ .../typeAnnotations/6967002/T6967002.out | 8 +++++ 3 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 langtools/test/tools/javac/typeAnnotations/6967002/T6967002.java create mode 100644 langtools/test/tools/javac/typeAnnotations/6967002/T6967002.out diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java index 01ab573d00e..32ae4d52a19 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -1151,8 +1151,12 @@ public class JavacParser implements Parser { t = toP(F.at(pos).Select(t, ident())); break; case ELLIPSIS: - assert this.permitTypeAnnotationsPushBack; - typeAnnotationsPushedBack = annos; + if (this.permitTypeAnnotationsPushBack) { + this.typeAnnotationsPushedBack = annos; + } else if (annos.nonEmpty()) { + // Don't return here -- error recovery attempt + illegal(annos.head.pos); + } break loop; default: break loop; diff --git a/langtools/test/tools/javac/typeAnnotations/6967002/T6967002.java b/langtools/test/tools/javac/typeAnnotations/6967002/T6967002.java new file mode 100644 index 00000000000..317cf34199e --- /dev/null +++ b/langtools/test/tools/javac/typeAnnotations/6967002/T6967002.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6967002 + * @summary JDK7 b99 javac compilation error (java.lang.AssertionError) + * @author Maurizio Cimadamore + * @compile/fail/ref=T6967002.out -XDrawDiagnostics T6967002.java + */ +class Test { + private static void m(byte[] octets) { + return m(octets..., ?); + } +} diff --git a/langtools/test/tools/javac/typeAnnotations/6967002/T6967002.out b/langtools/test/tools/javac/typeAnnotations/6967002/T6967002.out new file mode 100644 index 00000000000..18b75307f04 --- /dev/null +++ b/langtools/test/tools/javac/typeAnnotations/6967002/T6967002.out @@ -0,0 +1,8 @@ +T6967002.java:33:22: compiler.err.expected: ')' +T6967002.java:33:25: compiler.err.illegal.start.of.expr +T6967002.java:33:28: compiler.err.illegal.start.of.expr +T6967002.java:33:29: compiler.err.illegal.start.of.expr +T6967002.java:33:27: compiler.err.not.stmt +T6967002.java:33:30: compiler.err.expected: ';' +T6967002.java:35:2: compiler.err.premature.eof +7 errors From 9c273720d69c69bb1fff7b0247a64cfee0742048 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Thu, 15 Jul 2010 16:31:56 +0100 Subject: [PATCH 08/52] 6964669: javac reports error on miranda methods Synthetic name clash check should not apply to miranda methods Reviewed-by: jjg --- .../com/sun/tools/javac/comp/Check.java | 1 + .../tools/javac/miranda/6964669/T6964669.java | 29 +++++++++++++++++++ .../tools/javac/miranda/6964669/pkg/A.java | 26 +++++++++++++++++ .../tools/javac/miranda/6964669/pkg/B.java | 28 ++++++++++++++++++ .../tools/javac/miranda/6964669/pkg/C.java | 28 ++++++++++++++++++ 5 files changed, 112 insertions(+) create mode 100644 langtools/test/tools/javac/miranda/6964669/T6964669.java create mode 100644 langtools/test/tools/javac/miranda/6964669/pkg/A.java create mode 100644 langtools/test/tools/javac/miranda/6964669/pkg/B.java create mode 100644 langtools/test/tools/javac/miranda/6964669/pkg/C.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java index 09bf0bf0865..3b9999c1794 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java @@ -1853,6 +1853,7 @@ public class Check { types.isSameType(types.erasure(sym.type), types.erasure(e.sym.type)) && sym != e.sym && (sym.flags() & Flags.SYNTHETIC) != (e.sym.flags() & Flags.SYNTHETIC) && + (sym.flags() & IPROXY) == 0 && (e.sym.flags() & IPROXY) == 0 && (sym.flags() & BRIDGE) == 0 && (e.sym.flags() & BRIDGE) == 0) { syntheticError(pos, (e.sym.flags() & SYNTHETIC) == 0 ? e.sym : sym); return; diff --git a/langtools/test/tools/javac/miranda/6964669/T6964669.java b/langtools/test/tools/javac/miranda/6964669/T6964669.java new file mode 100644 index 00000000000..6023b179338 --- /dev/null +++ b/langtools/test/tools/javac/miranda/6964669/T6964669.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6964669 + * @summary javac reports error on miranda methods + * @compile -source 1.2 -target 1.1 pkg/A.java pkg/B.java pkg/C.java + */ diff --git a/langtools/test/tools/javac/miranda/6964669/pkg/A.java b/langtools/test/tools/javac/miranda/6964669/pkg/A.java new file mode 100644 index 00000000000..71ee85449f7 --- /dev/null +++ b/langtools/test/tools/javac/miranda/6964669/pkg/A.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pkg; + +public abstract class A implements C {} diff --git a/langtools/test/tools/javac/miranda/6964669/pkg/B.java b/langtools/test/tools/javac/miranda/6964669/pkg/B.java new file mode 100644 index 00000000000..efafcfe1364 --- /dev/null +++ b/langtools/test/tools/javac/miranda/6964669/pkg/B.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pkg; + +public class B extends A { + public void a() {} +} diff --git a/langtools/test/tools/javac/miranda/6964669/pkg/C.java b/langtools/test/tools/javac/miranda/6964669/pkg/C.java new file mode 100644 index 00000000000..9508349c0fd --- /dev/null +++ b/langtools/test/tools/javac/miranda/6964669/pkg/C.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pkg; + +public interface C { + public void a(); +} From a4e41493406de39a5a1ba8565d94a569a9e59880 Mon Sep 17 00:00:00 2001 From: John R Rose Date: Thu, 15 Jul 2010 18:40:45 -0700 Subject: [PATCH 09/52] 6964498: JSR 292 invokedynamic sites need local bootstrap methods Add JVM_CONSTANT_InvokeDynamic records to constant pool to determine per-instruction BSMs. Reviewed-by: twisti --- .../sun/jvm/hotspot/oops/ConstantPool.java | 14 ++++ .../jvm/hotspot/runtime/ClassConstants.java | 1 + .../jvm/hotspot/tools/jcore/ClassWriter.java | 21 ++++-- .../ui/classbrowser/HTMLGenerator.java | 5 ++ .../jvm/hotspot/utilities/ConstantTag.java | 2 + .../share/vm/classfile/classFileParser.cpp | 36 +++++++++- .../share/vm/classfile/systemDictionary.cpp | 65 ++++++++++++++++--- .../share/vm/classfile/systemDictionary.hpp | 5 +- hotspot/src/share/vm/classfile/verifier.cpp | 3 +- .../share/vm/interpreter/bytecodeTracer.cpp | 17 ++++- .../vm/interpreter/interpreterRuntime.cpp | 25 +++---- .../src/share/vm/interpreter/linkResolver.cpp | 24 ++++++- .../src/share/vm/interpreter/linkResolver.hpp | 1 + hotspot/src/share/vm/interpreter/rewriter.cpp | 27 ++++++++ hotspot/src/share/vm/interpreter/rewriter.hpp | 17 +++++ .../src/share/vm/oops/constantPoolKlass.cpp | 4 ++ hotspot/src/share/vm/oops/constantPoolOop.cpp | 39 ++++++++++- hotspot/src/share/vm/oops/constantPoolOop.hpp | 15 +++++ hotspot/src/share/vm/oops/cpCacheOop.cpp | 45 +++++++++++-- hotspot/src/share/vm/oops/cpCacheOop.hpp | 5 ++ hotspot/src/share/vm/prims/jvm.h | 3 +- hotspot/src/share/vm/prims/methodHandles.cpp | 4 ++ hotspot/src/share/vm/runtime/globals.hpp | 3 + .../src/share/vm/utilities/constantTag.cpp | 2 + .../src/share/vm/utilities/constantTag.hpp | 3 +- 25 files changed, 340 insertions(+), 46 deletions(-) diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java index 58e199089ef..27872450487 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java @@ -297,6 +297,7 @@ public class ConstantPool extends Oop implements ClassConstants { case JVM_CONSTANT_NameAndType: return "JVM_CONSTANT_NameAndType"; case JVM_CONSTANT_MethodHandle: return "JVM_CONSTANT_MethodHandle"; case JVM_CONSTANT_MethodType: return "JVM_CONSTANT_MethodType"; + case JVM_CONSTANT_InvokeDynamic: return "JVM_CONSTANT_InvokeDynamic"; case JVM_CONSTANT_Invalid: return "JVM_CONSTANT_Invalid"; case JVM_CONSTANT_UnresolvedClass: return "JVM_CONSTANT_UnresolvedClass"; case JVM_CONSTANT_UnresolvedClassInError: return "JVM_CONSTANT_UnresolvedClassInError"; @@ -355,6 +356,7 @@ public class ConstantPool extends Oop implements ClassConstants { case JVM_CONSTANT_NameAndType: case JVM_CONSTANT_MethodHandle: case JVM_CONSTANT_MethodType: + case JVM_CONSTANT_InvokeDynamic: visitor.doInt(new IntField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true); break; } @@ -517,6 +519,18 @@ public class ConstantPool extends Oop implements ClassConstants { + ", type = " + signatureIndex); break; } + + case JVM_CONSTANT_InvokeDynamic: { + dos.writeByte(cpConstType); + int value = getIntAt(ci); + short bootstrapMethodIndex = (short) extractLowShortFromInt(value); + short nameAndTypeIndex = (short) extractHighShortFromInt(value); + dos.writeShort(bootstrapMethodIndex); + dos.writeShort(nameAndTypeIndex); + if (DEBUG) debugMessage("CP[" + ci + "] = indy BSM = " + bootstrapMethodIndex + + ", N&T = " + nameAndTypeIndex); + break; + } default: throw new InternalError("unknown tag: " + cpConstType); } // switch diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java index 889e9dc08b7..ff7db309fe9 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java @@ -42,6 +42,7 @@ public interface ClassConstants public static final int JVM_CONSTANT_NameAndType = 12; public static final int JVM_CONSTANT_MethodHandle = 15; public static final int JVM_CONSTANT_MethodType = 16; + public static final int JVM_CONSTANT_InvokeDynamic = 17; // JVM_CONSTANT_MethodHandle subtypes public static final int JVM_REF_getField = 1; diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java index 99ffaedc8eb..31f37a5df46 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java @@ -303,12 +303,12 @@ public class ClassWriter implements /* imports */ ClassConstants case JVM_CONSTANT_MethodHandle: { dos.writeByte(cpConstType); int value = cpool.getIntAt(ci); - short refIndex = (short) extractHighShortFromInt(value); - byte refKind = (byte) extractLowShortFromInt(value); - dos.writeByte(refKind); - dos.writeShort(refIndex); - if (DEBUG) debugMessage("CP[" + ci + "] = MH index = " + refIndex - + ", kind = " + refKind); + short bootstrapMethodIndex = (short) extractLowShortFromInt(value); + short nameAndTypeIndex = (short) extractHighShortFromInt(value); + dos.writeShort(bootstrapMethodIndex); + dos.writeShort(nameAndTypeIndex); + if (DEBUG) debugMessage("CP[" + ci + "] = indy BSM = " + + bootstrapMethodIndex + ", N&T = " + nameAndTypeIndex); break; } @@ -321,6 +321,15 @@ public class ClassWriter implements /* imports */ ClassConstants break; } + case JVM_CONSTANT_InvokeDynamic: { + dos.writeByte(cpConstType); + int value = cpool.getIntAt(ci); + short refIndex = (short) value; + dos.writeShort(refIndex); + if (DEBUG) debugMessage("CP[" + ci + "] = MT index = " + refIndex); + break; + } + default: throw new InternalError("Unknown tag: " + cpConstType); } // switch diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java index 8ef0d8c4d42..d594404f414 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java @@ -582,6 +582,11 @@ public class HTMLGenerator implements /* imports */ ClassConstants { buf.cell(Integer.toString(cpool.getIntAt(index))); break; + case JVM_CONSTANT_InvokeDynamic: + buf.cell("JVM_CONSTANT_InvokeDynamic"); + buf.cell(genLowHighShort(cpool.getIntAt(index))); + break; + default: throw new InternalError("unknown tag: " + ctag); } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java index 2a710c2a002..3f2baf3d9cc 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java @@ -40,6 +40,7 @@ public class ConstantTag { private static int JVM_CONSTANT_NameAndType = 12; private static int JVM_CONSTANT_MethodHandle = 15; // JSR 292 private static int JVM_CONSTANT_MethodType = 16; // JSR 292 + private static int JVM_CONSTANT_InvokeDynamic = 17; // JSR 292 private static int JVM_CONSTANT_Invalid = 0; // For bad value initialization private static int JVM_CONSTANT_UnresolvedClass = 100; // Temporary tag until actual use private static int JVM_CONSTANT_ClassIndex = 101; // Temporary tag while constructing constant pool @@ -78,6 +79,7 @@ public class ConstantTag { public boolean isUtf8() { return tag == JVM_CONSTANT_Utf8; } public boolean isMethodHandle() { return tag == JVM_CONSTANT_MethodHandle; } public boolean isMethodType() { return tag == JVM_CONSTANT_MethodType; } + public boolean isInvokeDynamic() { return tag == JVM_CONSTANT_InvokeDynamic; } public boolean isInvalid() { return tag == JVM_CONSTANT_Invalid; } diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index 73fd78c7b98..f9c1d637c83 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -122,7 +122,7 @@ void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int len if (!EnableMethodHandles || _major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) { classfile_parse_error( - (!EnableInvokeDynamic ? + (!EnableMethodHandles ? "This JVM does not support constant tag %u in class file %s" : "Class file version does not support constant tag %u in class file %s"), tag, CHECK); @@ -140,6 +140,22 @@ void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int len ShouldNotReachHere(); } break; + case JVM_CONSTANT_InvokeDynamic : + { + if (!EnableInvokeDynamic || + _major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) { + classfile_parse_error( + (!EnableInvokeDynamic ? + "This JVM does not support constant tag %u in class file %s" : + "Class file version does not support constant tag %u in class file %s"), + tag, CHECK); + } + cfs->guarantee_more(5, CHECK); // bsm_index, name_and_type_index, tag/access_flags + u2 bootstrap_method_index = cfs->get_u2_fast(); + u2 name_and_type_index = cfs->get_u2_fast(); + cp->invoke_dynamic_at_put(index, bootstrap_method_index, name_and_type_index); + } + break; case JVM_CONSTANT_Integer : { cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags @@ -414,6 +430,24 @@ constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) { ref_index, CHECK_(nullHandle)); } break; + case JVM_CONSTANT_InvokeDynamic : + { + int bootstrap_method_ref_index = cp->invoke_dynamic_bootstrap_method_ref_index_at(index); + int name_and_type_ref_index = cp->invoke_dynamic_name_and_type_ref_index_at(index); + check_property((bootstrap_method_ref_index == 0 && AllowTransitionalJSR292) + || + (valid_cp_range(bootstrap_method_ref_index, length) && + cp->tag_at(bootstrap_method_ref_index).is_method_handle()), + "Invalid constant pool index %u in class file %s", + bootstrap_method_ref_index, + CHECK_(nullHandle)); + check_property(valid_cp_range(name_and_type_ref_index, length) && + cp->tag_at(name_and_type_ref_index).is_name_and_type(), + "Invalid constant pool index %u in class file %s", + name_and_type_ref_index, + CHECK_(nullHandle)); + break; + } default: fatal(err_msg("bad constant pool tag value %u", cp->tag_at(index).value())); diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp index 40c81427afe..fefe4d67c96 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp @@ -2507,6 +2507,10 @@ Handle SystemDictionary::make_dynamic_call_site(Handle bootstrap_method, int caller_bci, TRAPS) { Handle empty; + guarantee(bootstrap_method.not_null() && + java_dyn_MethodHandle::is_instance(bootstrap_method()), + "caller must supply a valid BSM"); + Handle caller_mname = MethodHandles::new_MemberName(CHECK_(empty)); MethodHandles::init_MemberName(caller_mname(), caller_method()); @@ -2537,20 +2541,61 @@ Handle SystemDictionary::make_dynamic_call_site(Handle bootstrap_method, return call_site_oop; } -Handle SystemDictionary::find_bootstrap_method(KlassHandle caller, TRAPS) { +Handle SystemDictionary::find_bootstrap_method(methodHandle caller_method, int caller_bci, + int cache_index, TRAPS) { Handle empty; - if (!caller->oop_is_instance()) return empty; - instanceKlassHandle ik(THREAD, caller()); + constantPoolHandle pool; + { + klassOop caller = caller_method->method_holder(); + if (!Klass::cast(caller)->oop_is_instance()) return empty; + pool = constantPoolHandle(THREAD, instanceKlass::cast(caller)->constants()); + } - oop boot_method_oop = ik->bootstrap_method(); - if (boot_method_oop != NULL) { - if (TraceMethodHandles) { - tty->print_cr("bootstrap method for "PTR_FORMAT" cached as "PTR_FORMAT":", ik(), boot_method_oop); + int constant_pool_index = pool->cache()->entry_at(cache_index)->constant_pool_index(); + constantTag tag = pool->tag_at(constant_pool_index); + + if (tag.is_invoke_dynamic()) { + // JVM_CONSTANT_InvokeDynamic is an ordered pair of [bootm, name&type] + // The bootm, being a JVM_CONSTANT_MethodHandle, has its own cache entry. + int bsm_index = pool->invoke_dynamic_bootstrap_method_ref_index_at(constant_pool_index); + if (bsm_index != 0) { + int bsm_index_in_cache = pool->cache()->entry_at(cache_index)->bootstrap_method_index_in_cache(); + DEBUG_ONLY(int bsm_index_2 = pool->cache()->entry_at(bsm_index_in_cache)->constant_pool_index()); + assert(bsm_index == bsm_index_2, "BSM constant lifted to cache"); + if (TraceMethodHandles) { + tty->print_cr("resolving bootstrap method for "PTR_FORMAT" at %d at cache[%d]CP[%d]...", + (intptr_t) caller_method(), caller_bci, cache_index, constant_pool_index); + } + oop bsm_oop = pool->resolve_cached_constant_at(bsm_index_in_cache, CHECK_(empty)); + if (TraceMethodHandles) { + tty->print_cr("bootstrap method for "PTR_FORMAT" at %d retrieved as "PTR_FORMAT":", + (intptr_t) caller_method(), caller_bci, (intptr_t) bsm_oop); + } + assert(bsm_oop->is_oop() + && java_dyn_MethodHandle::is_instance(bsm_oop), "must be sane"); + return Handle(THREAD, bsm_oop); } - assert(boot_method_oop->is_oop() - && java_dyn_MethodHandle::is_instance(boot_method_oop), "must be sane"); - return Handle(THREAD, boot_method_oop); + // else null BSM; fall through + } else if (tag.is_name_and_type()) { + // JSR 292 EDR does not have JVM_CONSTANT_InvokeDynamic + // a bare name&type defaults its BSM to null, so fall through... + } else { + ShouldNotReachHere(); // verifier does not allow this + } + + // Fall through to pick up the per-class bootstrap method. + // This mechanism may go away in the PFD. + assert(AllowTransitionalJSR292, "else the verifier should have stopped us already"); + oop bsm_oop = instanceKlass::cast(caller_method->method_holder())->bootstrap_method(); + if (bsm_oop != NULL) { + if (TraceMethodHandles) { + tty->print_cr("bootstrap method for "PTR_FORMAT" registered as "PTR_FORMAT":", + (intptr_t) caller_method(), (intptr_t) bsm_oop); + } + assert(bsm_oop->is_oop() + && java_dyn_MethodHandle::is_instance(bsm_oop), "must be sane"); + return Handle(THREAD, bsm_oop); } return empty; diff --git a/hotspot/src/share/vm/classfile/systemDictionary.hpp b/hotspot/src/share/vm/classfile/systemDictionary.hpp index 56de18c42aa..11bf2257992 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp @@ -492,7 +492,10 @@ public: TRAPS); // coordinate with Java about bootstrap methods - static Handle find_bootstrap_method(KlassHandle caller, TRAPS); + static Handle find_bootstrap_method(methodHandle caller_method, + int caller_bci, // N.B. must be an invokedynamic + int cache_index, // must be corresponding main_entry + TRAPS); // Utility for printing loader "name" as part of tracing constraints static const char* loader_name(oop loader) { diff --git a/hotspot/src/share/vm/classfile/verifier.cpp b/hotspot/src/share/vm/classfile/verifier.cpp index 603d4ec3c25..10072bd2e59 100644 --- a/hotspot/src/share/vm/classfile/verifier.cpp +++ b/hotspot/src/share/vm/classfile/verifier.cpp @@ -1913,7 +1913,8 @@ void ClassVerifier::verify_invoke_instructions( unsigned int types = (opcode == Bytecodes::_invokeinterface ? 1 << JVM_CONSTANT_InterfaceMethodref : opcode == Bytecodes::_invokedynamic - ? 1 << JVM_CONSTANT_NameAndType + ? (1 << JVM_CONSTANT_NameAndType + |1 << JVM_CONSTANT_InvokeDynamic) : 1 << JVM_CONSTANT_Methodref); verify_cp_type(index, cp, types, CHECK_VERIFY(this)); diff --git a/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp b/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp index 6fa807a4d86..1a5cadb4cc4 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp @@ -328,24 +328,35 @@ void BytecodePrinter::print_field_or_method(int orig_i, int i, outputStream* st) constantPoolOop constants = method()->constants(); constantTag tag = constants->tag_at(i); - int nt_index = -1; + bool has_klass = true; switch (tag.value()) { case JVM_CONSTANT_InterfaceMethodref: case JVM_CONSTANT_Methodref: case JVM_CONSTANT_Fieldref: + break; case JVM_CONSTANT_NameAndType: + case JVM_CONSTANT_InvokeDynamic: + has_klass = false; break; default: st->print_cr(" bad tag=%d at %d", tag.value(), i); return; } - symbolOop klass = constants->klass_name_at(constants->uncached_klass_ref_index_at(i)); symbolOop name = constants->uncached_name_ref_at(i); symbolOop signature = constants->uncached_signature_ref_at(i); const char* sep = (tag.is_field() ? "/" : ""); - st->print_cr(" %d <%s.%s%s%s> ", i, klass->as_C_string(), name->as_C_string(), sep, signature->as_C_string()); + if (has_klass) { + symbolOop klass = constants->klass_name_at(constants->uncached_klass_ref_index_at(i)); + st->print_cr(" %d <%s.%s%s%s> ", i, klass->as_C_string(), name->as_C_string(), sep, signature->as_C_string()); + } else { + if (tag.is_invoke_dynamic()) { + int bsm = constants->invoke_dynamic_bootstrap_method_ref_index_at(i); + st->print(" bsm=%d", bsm); + } + st->print_cr(" %d <%s%s%s>", i, name->as_C_string(), sep, signature->as_C_string()); + } } diff --git a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp index 2880a9ec2f9..c156bbb3792 100644 --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp @@ -702,10 +702,6 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) { methodHandle caller_method(thread, method(thread)); - // first find the bootstrap method - KlassHandle caller_klass(thread, caller_method->method_holder()); - Handle bootm = SystemDictionary::find_bootstrap_method(caller_klass, CHECK); - constantPoolHandle pool(thread, caller_method->constants()); pool->set_invokedynamic(); // mark header to flag active call sites @@ -726,7 +722,7 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) { CallInfo info; LinkResolver::resolve_invoke(info, Handle(), pool, site_index, bytecode, CHECK); - // The main entry corresponds to a JVM_CONSTANT_NameAndType, and serves + // The main entry corresponds to a JVM_CONSTANT_InvokeDynamic, and serves // as a common reference point for all invokedynamic call sites with // that exact call descriptor. We will link it in the CP cache exactly // as if it were an invokevirtual of MethodHandle.invoke. @@ -734,23 +730,30 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) { bytecode, info.resolved_method(), info.vtable_index()); - assert(pool->cache()->entry_at(main_index)->is_vfinal(), "f2 must be a methodOop"); } // The method (f2 entry) of the main entry is the MH.invoke for the // invokedynamic target call signature. - intptr_t f2_value = pool->cache()->entry_at(main_index)->f2(); - methodHandle signature_invoker(THREAD, (methodOop) f2_value); + oop f1_value = pool->cache()->entry_at(main_index)->f1(); + methodHandle signature_invoker(THREAD, (methodOop) f1_value); assert(signature_invoker.not_null() && signature_invoker->is_method() && signature_invoker->is_method_handle_invoke(), "correct result from LinkResolver::resolve_invokedynamic"); + Handle bootm = SystemDictionary::find_bootstrap_method(caller_method, caller_bci, + main_index, CHECK); + if (bootm.is_null()) { + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), + "no bootstrap method found for invokedynamic"); + } + + // Short circuit if CallSite has been bound already: + if (!pool->cache()->secondary_entry_at(site_index)->is_f1_null()) + return; + symbolHandle call_site_name(THREAD, pool->name_ref_at(site_index)); Handle info; // NYI: Other metadata from a new kind of CP entry. (Annotations?) - // this is the index which gets stored on the CallSite object (as "callerPosition"): - int call_site_position = constantPoolCacheOopDesc::decode_secondary_index(site_index); - Handle call_site = SystemDictionary::make_dynamic_call_site(bootm, // Callee information: diff --git a/hotspot/src/share/vm/interpreter/linkResolver.cpp b/hotspot/src/share/vm/interpreter/linkResolver.cpp index 1c444a954ca..4a3669403f1 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp @@ -67,6 +67,15 @@ void CallInfo::set_virtual(KlassHandle resolved_klass, KlassHandle selected_klas set_common(resolved_klass, selected_klass, resolved_method, selected_method, vtable_index, CHECK); } +void CallInfo::set_dynamic(methodHandle resolved_method, TRAPS) { + assert(resolved_method->is_method_handle_invoke(), ""); + KlassHandle resolved_klass = SystemDictionaryHandles::MethodHandle_klass(); + assert(resolved_klass == resolved_method->method_holder(), ""); + int vtable_index = methodOopDesc::nonvirtual_vtable_index; + assert(resolved_method->vtable_index() == vtable_index, ""); + set_common(resolved_klass, KlassHandle(), resolved_method, resolved_method, vtable_index, CHECK); +} + void CallInfo::set_common(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index, TRAPS) { assert(resolved_method->signature() == selected_method->signature(), "signatures must correspond"); _resolved_klass = resolved_klass; @@ -176,9 +185,20 @@ void LinkResolver::lookup_implicit_method(methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, KlassHandle current_klass, TRAPS) { - if (EnableMethodHandles && MethodHandles::enabled() && + if (EnableMethodHandles && klass() == SystemDictionary::MethodHandle_klass() && methodOopDesc::is_method_handle_invoke_name(name())) { + if (!MethodHandles::enabled()) { + // Make sure the Java part of the runtime has been booted up. + klassOop natives = SystemDictionary::MethodHandleNatives_klass(); + if (natives == NULL || instanceKlass::cast(natives)->is_not_initialized()) { + SystemDictionary::resolve_or_fail(vmSymbolHandles::sun_dyn_MethodHandleNatives(), + Handle(), + Handle(), + true, + CHECK); + } + } methodOop result_oop = SystemDictionary::find_method_handle_invoke(name, signature, current_klass, @@ -1065,7 +1085,7 @@ void LinkResolver::resolve_invokedynamic(CallInfo& result, constantPoolHandle po if (resolved_method.is_null()) { THROW(vmSymbols::java_lang_InternalError()); } - result.set_virtual(resolved_klass, KlassHandle(), resolved_method, resolved_method, resolved_method->vtable_index(), CHECK); + result.set_dynamic(resolved_method, CHECK); } //------------------------------------------------------------------------------------------------------------------------ diff --git a/hotspot/src/share/vm/interpreter/linkResolver.hpp b/hotspot/src/share/vm/interpreter/linkResolver.hpp index c39ea8f41db..f98db15a441 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.hpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.hpp @@ -73,6 +73,7 @@ class CallInfo: public LinkInfo { void set_static( KlassHandle resolved_klass, methodHandle resolved_method , TRAPS); void set_interface(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method , TRAPS); void set_virtual( KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index, TRAPS); + void set_dynamic( methodHandle resolved_method, TRAPS); void set_common( KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index, TRAPS); friend class LinkResolver; diff --git a/hotspot/src/share/vm/interpreter/rewriter.cpp b/hotspot/src/share/vm/interpreter/rewriter.cpp index 00afdf63a14..558e3138be5 100644 --- a/hotspot/src/share/vm/interpreter/rewriter.cpp +++ b/hotspot/src/share/vm/interpreter/rewriter.cpp @@ -32,14 +32,17 @@ void Rewriter::compute_index_maps() { const int length = _pool->length(); init_cp_map(length); + jint tag_mask = 0; for (int i = 0; i < length; i++) { int tag = _pool->tag_at(i).value(); + tag_mask |= (1 << tag); switch (tag) { case JVM_CONSTANT_InterfaceMethodref: case JVM_CONSTANT_Fieldref : // fall through case JVM_CONSTANT_Methodref : // fall through case JVM_CONSTANT_MethodHandle : // fall through case JVM_CONSTANT_MethodType : // fall through + case JVM_CONSTANT_InvokeDynamic : // fall through add_cp_cache_entry(i); break; } @@ -47,6 +50,8 @@ void Rewriter::compute_index_maps() { guarantee((int)_cp_cache_map.length()-1 <= (int)((u2)-1), "all cp cache indexes fit in a u2"); + + _have_invoke_dynamic = ((tag_mask & (1 << JVM_CONSTANT_InvokeDynamic)) != 0); } @@ -59,6 +64,28 @@ void Rewriter::make_constant_pool_cache(TRAPS) { constantPoolCacheOop cache = oopFactory::new_constantPoolCache(length, methodOopDesc::IsUnsafeConc, CHECK); cache->initialize(_cp_cache_map); + + // Don't bother to the next pass if there is no JVM_CONSTANT_InvokeDynamic. + if (_have_invoke_dynamic) { + for (int i = 0; i < length; i++) { + int pool_index = cp_cache_entry_pool_index(i); + if (pool_index >= 0 && + _pool->tag_at(pool_index).is_invoke_dynamic()) { + int bsm_index = _pool->invoke_dynamic_bootstrap_method_ref_index_at(pool_index); + if (bsm_index != 0) { + assert(_pool->tag_at(bsm_index).is_method_handle(), "must be a MH constant"); + // There is a CP cache entry holding the BSM for these calls. + int bsm_cache_index = cp_entry_to_cp_cache(bsm_index); + cache->entry_at(i)->initialize_bootstrap_method_index_in_cache(bsm_cache_index); + } else { + // There is no CP cache entry holding the BSM for these calls. + // We will need to look for a class-global BSM, later. + guarantee(AllowTransitionalJSR292, ""); + } + } + } + } + _pool->set_cache(cache); cache->set_constant_pool(_pool()); } diff --git a/hotspot/src/share/vm/interpreter/rewriter.hpp b/hotspot/src/share/vm/interpreter/rewriter.hpp index 91ad08a2b95..1f772a640a2 100644 --- a/hotspot/src/share/vm/interpreter/rewriter.hpp +++ b/hotspot/src/share/vm/interpreter/rewriter.hpp @@ -32,6 +32,7 @@ class Rewriter: public StackObj { objArrayHandle _methods; intArray _cp_map; intStack _cp_cache_map; + bool _have_invoke_dynamic; void init_cp_map(int length) { _cp_map.initialize(length, -1); @@ -56,6 +57,22 @@ class Rewriter: public StackObj { return cache_index; } + // Access the contents of _cp_cache_map to determine CP cache layout. + int cp_cache_entry_pool_index(int cache_index) { + int cp_index = _cp_cache_map[cache_index]; + if ((cp_index & _secondary_entry_tag) != 0) + return -1; + else + return cp_index; + } + int cp_cache_secondary_entry_main_index(int cache_index) { + int cp_index = _cp_cache_map[cache_index]; + if ((cp_index & _secondary_entry_tag) == 0) + return -1; + else + return (cp_index - _secondary_entry_tag); + } + // All the work goes in here: Rewriter(instanceKlassHandle klass, constantPoolHandle cpool, objArrayHandle methods, TRAPS); diff --git a/hotspot/src/share/vm/oops/constantPoolKlass.cpp b/hotspot/src/share/vm/oops/constantPoolKlass.cpp index ab00023b60f..dd4cb287c4a 100644 --- a/hotspot/src/share/vm/oops/constantPoolKlass.cpp +++ b/hotspot/src/share/vm/oops/constantPoolKlass.cpp @@ -379,6 +379,10 @@ void constantPoolKlass::oop_print_on(oop obj, outputStream* st) { case JVM_CONSTANT_MethodType : st->print("signature_index=%d", cp->method_type_index_at(index)); break; + case JVM_CONSTANT_InvokeDynamic : + st->print("bootstrap_method_index=%d", cp->invoke_dynamic_bootstrap_method_ref_index_at(index)); + st->print(" name_and_type_index=%d", cp->invoke_dynamic_name_and_type_ref_index_at(index)); + break; default: ShouldNotReachHere(); break; diff --git a/hotspot/src/share/vm/oops/constantPoolOop.cpp b/hotspot/src/share/vm/oops/constantPoolOop.cpp index 4915a4543dd..62e2f64dc79 100644 --- a/hotspot/src/share/vm/oops/constantPoolOop.cpp +++ b/hotspot/src/share/vm/oops/constantPoolOop.cpp @@ -264,10 +264,15 @@ symbolOop constantPoolOopDesc::impl_signature_ref_at(int which, bool uncached) { int constantPoolOopDesc::impl_name_and_type_ref_index_at(int which, bool uncached) { int i = which; if (!uncached && cache() != NULL) { - if (constantPoolCacheOopDesc::is_secondary_index(which)) + if (constantPoolCacheOopDesc::is_secondary_index(which)) { // Invokedynamic indexes are always processed in native order // so there is no question of reading a native u2 in Java order here. - return cache()->main_entry_at(which)->constant_pool_index(); + int pool_index = cache()->main_entry_at(which)->constant_pool_index(); + if (tag_at(pool_index).is_invoke_dynamic()) + pool_index = invoke_dynamic_name_and_type_ref_index_at(pool_index); + assert(tag_at(pool_index).is_name_and_type(), ""); + return pool_index; + } // change byte-ordering and go via cache i = remap_instruction_operand_from_cache(which); } else { @@ -830,6 +835,19 @@ bool constantPoolOopDesc::compare_entry_to(int index1, constantPoolHandle cp2, } } break; + case JVM_CONSTANT_InvokeDynamic: + { + int k1 = invoke_dynamic_bootstrap_method_ref_index_at(index1); + int k2 = cp2->invoke_dynamic_bootstrap_method_ref_index_at(index2); + if (k1 == k2) { + int i1 = invoke_dynamic_name_and_type_ref_index_at(index1); + int i2 = cp2->invoke_dynamic_name_and_type_ref_index_at(index2); + if (i1 == i2) { + return true; + } + } + } break; + case JVM_CONSTANT_UnresolvedString: { symbolOop s1 = unresolved_string_at(index1); @@ -1016,6 +1034,13 @@ void constantPoolOopDesc::copy_entry_to(int from_i, constantPoolHandle to_cp, to_cp->method_handle_index_at_put(to_i, k1, k2); } break; + case JVM_CONSTANT_InvokeDynamic: + { + int k1 = invoke_dynamic_bootstrap_method_ref_index_at(from_i); + int k2 = invoke_dynamic_name_and_type_ref_index_at(from_i); + to_cp->invoke_dynamic_at_put(to_i, k1, k2); + } break; + // Invalid is used as the tag for the second constant pool entry // occupied by JVM_CONSTANT_Double or JVM_CONSTANT_Long. It should // not be seen by itself. @@ -1231,6 +1256,7 @@ jint constantPoolOopDesc::cpool_entry_size(jint idx) { case JVM_CONSTANT_Methodref: case JVM_CONSTANT_InterfaceMethodref: case JVM_CONSTANT_NameAndType: + case JVM_CONSTANT_InvokeDynamic: return 5; case JVM_CONSTANT_Long: @@ -1444,6 +1470,15 @@ int constantPoolOopDesc::copy_cpool_bytes(int cpool_size, DBG(printf("JVM_CONSTANT_MethodType: %hd", idx1)); break; } + case JVM_CONSTANT_InvokeDynamic: { + *bytes = JVM_CONSTANT_InvokeDynamic; + idx1 = invoke_dynamic_bootstrap_method_ref_index_at(idx); + idx2 = invoke_dynamic_name_and_type_ref_index_at(idx); + Bytes::put_Java_u2((address) (bytes+1), idx1); + Bytes::put_Java_u2((address) (bytes+3), idx2); + DBG(printf("JVM_CONSTANT_InvokeDynamic: %hd %hd", idx1, idx2)); + break; + } } DBG(printf("\n")); bytes += ent_size; diff --git a/hotspot/src/share/vm/oops/constantPoolOop.hpp b/hotspot/src/share/vm/oops/constantPoolOop.hpp index 3ea9087636d..8b5889b45ee 100644 --- a/hotspot/src/share/vm/oops/constantPoolOop.hpp +++ b/hotspot/src/share/vm/oops/constantPoolOop.hpp @@ -156,6 +156,11 @@ class constantPoolOopDesc : public oopDesc { *int_at_addr(which) = ref_index; } + void invoke_dynamic_at_put(int which, int bootstrap_method_index, int name_and_type_index) { + tag_at_put(which, JVM_CONSTANT_InvokeDynamic); + *int_at_addr(which) = ((jint) name_and_type_index<<16) | bootstrap_method_index; + } + // Temporary until actual use void unresolved_string_at_put(int which, symbolOop s) { *obj_at_addr(which) = NULL; @@ -396,6 +401,16 @@ class constantPoolOopDesc : public oopDesc { int sym = method_type_index_at(which); return symbol_at(sym); } + int invoke_dynamic_bootstrap_method_ref_index_at(int which) { + assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool"); + jint ref_index = *int_at_addr(which); + return extract_low_short_from_int(ref_index); + } + int invoke_dynamic_name_and_type_ref_index_at(int which) { + assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool"); + jint ref_index = *int_at_addr(which); + return extract_high_short_from_int(ref_index); + } // The following methods (name/signature/klass_ref_at, klass_ref_at_noresolve, // name_and_type_ref_index_at) all expect to be passed indices obtained diff --git a/hotspot/src/share/vm/oops/cpCacheOop.cpp b/hotspot/src/share/vm/oops/cpCacheOop.cpp index f9533c5bd79..8542cf5eaa5 100644 --- a/hotspot/src/share/vm/oops/cpCacheOop.cpp +++ b/hotspot/src/share/vm/oops/cpCacheOop.cpp @@ -134,7 +134,7 @@ int ConstantPoolCacheEntry::field_index() const { void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code, methodHandle method, int vtable_index) { - + assert(!is_secondary_entry(), ""); assert(method->interpreter_entry() != NULL, "should have been set at this point"); assert(!method->is_obsolete(), "attempt to write obsolete method to cpCache"); bool change_to_virtual = (invoke_code == Bytecodes::_invokeinterface); @@ -142,7 +142,6 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code, int byte_no = -1; bool needs_vfinal_flag = false; switch (invoke_code) { - case Bytecodes::_invokedynamic: case Bytecodes::_invokevirtual: case Bytecodes::_invokeinterface: { if (method->can_be_statically_bound()) { @@ -155,6 +154,23 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code, byte_no = 2; break; } + + case Bytecodes::_invokedynamic: // similar to _invokevirtual + if (TraceInvokeDynamic) { + tty->print_cr("InvokeDynamic set_method%s method="PTR_FORMAT" index=%d", + (is_secondary_entry() ? " secondary" : ""), + (intptr_t)method(), vtable_index); + method->print(); + this->print(tty, 0); + } + assert(method->can_be_statically_bound(), "must be a MH invoker method"); + assert(AllowTransitionalJSR292 || _f2 >= constantPoolOopDesc::CPCACHE_INDEX_TAG, "BSM index initialized"); + set_f1(method()); + needs_vfinal_flag = false; // _f2 is not an oop + assert(!is_vfinal(), "f2 not an oop"); + byte_no = 1; // just a formality + break; + case Bytecodes::_invokespecial: // Preserve the value of the vfinal flag on invokevirtual bytecode // which may be shared with this constant pool cache entry. @@ -209,6 +225,7 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code, void ConstantPoolCacheEntry::set_interface_call(methodHandle method, int index) { + assert(!is_secondary_entry(), ""); klassOop interf = method->method_holder(); assert(instanceKlass::cast(interf)->is_interface(), "must be an interface"); set_f1(interf); @@ -218,8 +235,23 @@ void ConstantPoolCacheEntry::set_interface_call(methodHandle method, int index) } +void ConstantPoolCacheEntry::initialize_bootstrap_method_index_in_cache(int bsm_cache_index) { + assert(!is_secondary_entry(), "only for JVM_CONSTANT_InvokeDynamic main entry"); + assert(_f2 == 0, "initialize once"); + assert(bsm_cache_index == (int)(u2)bsm_cache_index, "oob"); + set_f2(bsm_cache_index + constantPoolOopDesc::CPCACHE_INDEX_TAG); +} + +int ConstantPoolCacheEntry::bootstrap_method_index_in_cache() { + assert(!is_secondary_entry(), "only for JVM_CONSTANT_InvokeDynamic main entry"); + intptr_t bsm_cache_index = (intptr_t) _f2 - constantPoolOopDesc::CPCACHE_INDEX_TAG; + assert(bsm_cache_index == (intptr_t)(u2)bsm_cache_index, "oob"); + return (int) bsm_cache_index; +} + void ConstantPoolCacheEntry::set_dynamic_call(Handle call_site, methodHandle signature_invoker) { + assert(is_secondary_entry(), ""); int param_size = signature_invoker->size_of_parameters(); assert(param_size >= 1, "method argument size must include MH.this"); param_size -= 1; // do not count MH.this; it is not stacked for invokedynamic @@ -227,7 +259,6 @@ void ConstantPoolCacheEntry::set_dynamic_call(Handle call_site, // racing threads might be trying to install their own favorites set_f1(call_site()); } - //set_f2(0); bool is_final = true; assert(signature_invoker->is_final_method(), "is_final"); set_flags(as_flags(as_TosState(signature_invoker->result_type()), is_final, false, false, false, true) | param_size); @@ -417,14 +448,14 @@ void ConstantPoolCacheEntry::print(outputStream* st, int index) const { // print separator if (index == 0) tty->print_cr(" -------------"); // print entry - tty->print_cr("%3d (%08x) ", index, this); + tty->print("%3d ("PTR_FORMAT") ", index, (intptr_t)this); if (is_secondary_entry()) tty->print_cr("[%5d|secondary]", main_entry_index()); else tty->print_cr("[%02x|%02x|%5d]", bytecode_2(), bytecode_1(), constant_pool_index()); - tty->print_cr(" [ %08x]", (address)(oop)_f1); - tty->print_cr(" [ %08x]", _f2); - tty->print_cr(" [ %08x]", _flags); + tty->print_cr(" [ "PTR_FORMAT"]", (intptr_t)(oop)_f1); + tty->print_cr(" [ "PTR_FORMAT"]", (intptr_t)_f2); + tty->print_cr(" [ "PTR_FORMAT"]", (intptr_t)_flags); tty->print_cr(" -------------"); } diff --git a/hotspot/src/share/vm/oops/cpCacheOop.hpp b/hotspot/src/share/vm/oops/cpCacheOop.hpp index 0759815697c..4253413b06d 100644 --- a/hotspot/src/share/vm/oops/cpCacheOop.hpp +++ b/hotspot/src/share/vm/oops/cpCacheOop.hpp @@ -185,6 +185,10 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { methodHandle signature_invoker // determines signature information ); + // For JVM_CONSTANT_InvokeDynamic cache entries: + void initialize_bootstrap_method_index_in_cache(int bsm_cache_index); + int bootstrap_method_index_in_cache(); + void set_parameter_size(int value) { assert(parameter_size() == 0 || parameter_size() == value, "size must not change"); @@ -234,6 +238,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { Bytecodes::Code bytecode_1() const { return Bytecodes::cast((_indices >> 16) & 0xFF); } Bytecodes::Code bytecode_2() const { return Bytecodes::cast((_indices >> 24) & 0xFF); } volatile oop f1() const { return _f1; } + bool is_f1_null() const { return (oop)_f1 == NULL; } // classifies a CPC entry as unbound intx f2() const { return _f2; } int field_index() const; int parameter_size() const { return _flags & 0xFF; } diff --git a/hotspot/src/share/vm/prims/jvm.h b/hotspot/src/share/vm/prims/jvm.h index 1445a32d65a..bd982910111 100644 --- a/hotspot/src/share/vm/prims/jvm.h +++ b/hotspot/src/share/vm/prims/jvm.h @@ -1046,7 +1046,8 @@ enum { JVM_CONSTANT_InterfaceMethodref, JVM_CONSTANT_NameAndType, JVM_CONSTANT_MethodHandle = 15, // JSR 292 - JVM_CONSTANT_MethodType = 16 // JSR 292 + JVM_CONSTANT_MethodType = 16, // JSR 292 + JVM_CONSTANT_InvokeDynamic = 17 // JSR 292 }; /* JVM_CONSTANT_MethodHandle subtypes */ diff --git a/hotspot/src/share/vm/prims/methodHandles.cpp b/hotspot/src/share/vm/prims/methodHandles.cpp index f084b5af82f..7b3acfda1e1 100644 --- a/hotspot/src/share/vm/prims/methodHandles.cpp +++ b/hotspot/src/share/vm/prims/methodHandles.cpp @@ -2475,6 +2475,10 @@ JVM_END JVM_ENTRY(void, MHI_registerBootstrap(JNIEnv *env, jobject igcls, jclass caller_jh, jobject bsm_jh)) { instanceKlassHandle ik = MethodHandles::resolve_instance_klass(caller_jh, THREAD); + if (!AllowTransitionalJSR292) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "registerBootstrapMethod is only supported in JSR 292 EDR"); + } ik->link_class(CHECK); if (!java_dyn_MethodHandle::is_instance(JNIHandles::resolve(bsm_jh))) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "method handle"); diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index d4f84c4450e..daf5b6b6ba5 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -3517,6 +3517,9 @@ class CommandLineFlags { experimental(bool, EnableInvokeDynamic, false, \ "recognize the invokedynamic instruction") \ \ + experimental(bool, AllowTransitionalJSR292, true, \ + "recognize pre-PFD formats of invokedynamic") \ + \ develop(bool, TraceInvokeDynamic, false, \ "trace internal invoke dynamic operations") \ \ diff --git a/hotspot/src/share/vm/utilities/constantTag.cpp b/hotspot/src/share/vm/utilities/constantTag.cpp index f6fb94a63c9..4d0bfe89bfb 100644 --- a/hotspot/src/share/vm/utilities/constantTag.cpp +++ b/hotspot/src/share/vm/utilities/constantTag.cpp @@ -91,6 +91,8 @@ const char* constantTag::internal_name() const { return "MethodHandle"; case JVM_CONSTANT_MethodType : return "MethodType"; + case JVM_CONSTANT_InvokeDynamic : + return "InvokeDynamic"; case JVM_CONSTANT_Object : return "Object"; case JVM_CONSTANT_Utf8 : diff --git a/hotspot/src/share/vm/utilities/constantTag.hpp b/hotspot/src/share/vm/utilities/constantTag.hpp index 97a9fe99104..39e335039e7 100644 --- a/hotspot/src/share/vm/utilities/constantTag.hpp +++ b/hotspot/src/share/vm/utilities/constantTag.hpp @@ -80,13 +80,14 @@ class constantTag VALUE_OBJ_CLASS_SPEC { bool is_method_type() const { return _tag == JVM_CONSTANT_MethodType; } bool is_method_handle() const { return _tag == JVM_CONSTANT_MethodHandle; } + bool is_invoke_dynamic() const { return _tag == JVM_CONSTANT_InvokeDynamic; } constantTag() { _tag = JVM_CONSTANT_Invalid; } constantTag(jbyte tag) { assert((tag >= 0 && tag <= JVM_CONSTANT_NameAndType) || - (tag >= JVM_CONSTANT_MethodHandle && tag <= JVM_CONSTANT_MethodType) || + (tag >= JVM_CONSTANT_MethodHandle && tag <= JVM_CONSTANT_InvokeDynamic) || (tag >= JVM_CONSTANT_InternalMin && tag <= JVM_CONSTANT_InternalMax), "Invalid constant tag"); _tag = tag; } From 7e34622217de977e79bb5b0c77a3a11da70960fe Mon Sep 17 00:00:00 2001 From: John R Rose Date: Fri, 16 Jul 2010 18:14:19 -0700 Subject: [PATCH 10/52] 6969574: invokedynamic call sites deoptimize instead of executing Reviewed-by: kvn --- hotspot/src/share/vm/ci/ciEnv.cpp | 4 ++-- hotspot/src/share/vm/ci/ciMethod.cpp | 23 ++++++------------- hotspot/src/share/vm/oops/cpCacheOop.cpp | 2 +- hotspot/src/share/vm/oops/cpCacheOop.hpp | 1 + hotspot/src/share/vm/oops/methodOop.cpp | 12 +++++++--- .../src/share/vm/prims/methodHandleWalk.cpp | 9 +++++++- 6 files changed, 28 insertions(+), 23 deletions(-) diff --git a/hotspot/src/share/vm/ci/ciEnv.cpp b/hotspot/src/share/vm/ci/ciEnv.cpp index a21d79a2352..de1fb564d76 100644 --- a/hotspot/src/share/vm/ci/ciEnv.cpp +++ b/hotspot/src/share/vm/ci/ciEnv.cpp @@ -728,8 +728,8 @@ ciMethod* ciEnv::get_fake_invokedynamic_method_impl(constantPoolHandle cpool, } // Get the invoker methodOop from the constant pool. - intptr_t f2_value = cpool->cache()->main_entry_at(index)->f2(); - methodOop signature_invoker = methodOop(f2_value); + oop f1_value = cpool->cache()->main_entry_at(index)->f1(); + methodOop signature_invoker = methodOop(f1_value); assert(signature_invoker != NULL && signature_invoker->is_method() && signature_invoker->is_method_handle_invoke(), "correct result from LinkResolver::resolve_invokedynamic"); diff --git a/hotspot/src/share/vm/ci/ciMethod.cpp b/hotspot/src/share/vm/ci/ciMethod.cpp index 22fc4f5fb78..f8c784f2ffe 100644 --- a/hotspot/src/share/vm/ci/ciMethod.cpp +++ b/hotspot/src/share/vm/ci/ciMethod.cpp @@ -694,30 +694,21 @@ int ciMethod::scale_count(int count, float prof_factor) { // ------------------------------------------------------------------ // ciMethod::is_method_handle_invoke // -// Return true if the method is a MethodHandle target. +// Return true if the method is an instance of one of the two +// signature-polymorphic MethodHandle methods, invokeExact or invokeGeneric. bool ciMethod::is_method_handle_invoke() const { - bool flag = (holder()->name() == ciSymbol::java_dyn_MethodHandle() && - methodOopDesc::is_method_handle_invoke_name(name()->sid())); -#ifdef ASSERT - if (is_loaded()) { - bool flag2 = ((flags().as_int() & JVM_MH_INVOKE_BITS) == JVM_MH_INVOKE_BITS); - { - VM_ENTRY_MARK; - bool flag3 = get_methodOop()->is_method_handle_invoke(); - assert(flag2 == flag3, "consistent"); - assert(flag == flag3, "consistent"); - } - } -#endif //ASSERT - return flag; + if (!is_loaded()) return false; + VM_ENTRY_MARK; + return get_methodOop()->is_method_handle_invoke(); } // ------------------------------------------------------------------ // ciMethod::is_method_handle_adapter // // Return true if the method is a generated MethodHandle adapter. +// These are built by MethodHandleCompiler. bool ciMethod::is_method_handle_adapter() const { - check_is_loaded(); + if (!is_loaded()) return false; VM_ENTRY_MARK; return get_methodOop()->is_method_handle_adapter(); } diff --git a/hotspot/src/share/vm/oops/cpCacheOop.cpp b/hotspot/src/share/vm/oops/cpCacheOop.cpp index 8542cf5eaa5..eb27f1658ab 100644 --- a/hotspot/src/share/vm/oops/cpCacheOop.cpp +++ b/hotspot/src/share/vm/oops/cpCacheOop.cpp @@ -168,7 +168,7 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code, set_f1(method()); needs_vfinal_flag = false; // _f2 is not an oop assert(!is_vfinal(), "f2 not an oop"); - byte_no = 1; // just a formality + byte_no = 1; // coordinate this with bytecode_number & is_resolved break; case Bytecodes::_invokespecial: diff --git a/hotspot/src/share/vm/oops/cpCacheOop.hpp b/hotspot/src/share/vm/oops/cpCacheOop.hpp index 4253413b06d..68460717fe0 100644 --- a/hotspot/src/share/vm/oops/cpCacheOop.hpp +++ b/hotspot/src/share/vm/oops/cpCacheOop.hpp @@ -211,6 +211,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC { case Bytecodes::_getfield : // fall through case Bytecodes::_invokespecial : // fall through case Bytecodes::_invokestatic : // fall through + case Bytecodes::_invokedynamic : // fall through case Bytecodes::_invokeinterface : return 1; case Bytecodes::_putstatic : // fall through case Bytecodes::_putfield : // fall through diff --git a/hotspot/src/share/vm/oops/methodOop.cpp b/hotspot/src/share/vm/oops/methodOop.cpp index 75a9d23dc72..ec32108d2a6 100644 --- a/hotspot/src/share/vm/oops/methodOop.cpp +++ b/hotspot/src/share/vm/oops/methodOop.cpp @@ -851,9 +851,15 @@ jint* methodOopDesc::method_type_offsets_chain() { // MethodHandleCompiler. // Must be consistent with MethodHandleCompiler::get_method_oop(). bool methodOopDesc::is_method_handle_adapter() const { - return (is_method_handle_invoke_name(name()) && - is_synthetic() && - MethodHandleCompiler::klass_is_method_handle_adapter_holder(method_holder())); + if (is_synthetic() && + !is_native() && // has code from MethodHandleCompiler + is_method_handle_invoke_name(name()) && + MethodHandleCompiler::klass_is_method_handle_adapter_holder(method_holder())) { + assert(!is_method_handle_invoke(), "disjoint"); + return true; + } else { + return false; + } } methodHandle methodOopDesc::make_invoke_method(KlassHandle holder, diff --git a/hotspot/src/share/vm/prims/methodHandleWalk.cpp b/hotspot/src/share/vm/prims/methodHandleWalk.cpp index f41f63a16a0..6a82f4b2436 100644 --- a/hotspot/src/share/vm/prims/methodHandleWalk.cpp +++ b/hotspot/src/share/vm/prims/methodHandleWalk.cpp @@ -738,6 +738,12 @@ void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) { // bi case Bytecodes::_ldc: + assert(Bytecodes::format_bits(op, false) == (Bytecodes::_fmt_b|Bytecodes::_fmt_has_k), "wrong bytecode format"); + assert((char) index == index, "index does not fit in 8-bit"); + _bytecode.push(op); + _bytecode.push(index); + break; + case Bytecodes::_iload: case Bytecodes::_lload: case Bytecodes::_fload: @@ -754,7 +760,8 @@ void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) { _bytecode.push(index); break; - // bii + // bkk + case Bytecodes::_ldc_w: case Bytecodes::_ldc2_w: case Bytecodes::_checkcast: assert(Bytecodes::format_bits(op, false) == Bytecodes::_fmt_bkk, "wrong bytecode format"); From 985efdc4759d06cdf422f9e6b2f26148640b8fa8 Mon Sep 17 00:00:00 2001 From: Tom Ball Date: Fri, 16 Jul 2010 19:35:24 -0700 Subject: [PATCH 11/52] 6911256: Project Coin: Support Automatic Resource Management (ARM) blocks in the compiler 6964740: Project Coin: More tests for ARM compiler changes 6965277: Project Coin: Correctness issues in ARM implementation 6967065: add -Xlint warning category for Automatic Resource Management (ARM) Reviewed-by: jjb, darcy, mcimadamore, jjg, briangoetz --- langtools/make/build.properties | 3 +- .../classes/com/sun/source/tree/TryTree.java | 1 + .../com/sun/source/util/TreeScanner.java | 3 +- .../com/sun/tools/javac/code/Lint.java | 7 +- .../com/sun/tools/javac/code/Source.java | 3 + .../com/sun/tools/javac/code/Symbol.java | 9 +- .../com/sun/tools/javac/code/Symtab.java | 10 + .../com/sun/tools/javac/comp/Attr.java | 60 +- .../com/sun/tools/javac/comp/Check.java | 6 +- .../com/sun/tools/javac/comp/Flow.java | 52 +- .../com/sun/tools/javac/comp/Lower.java | 148 ++++ .../com/sun/tools/javac/comp/TransTypes.java | 8 + .../com/sun/tools/javac/jvm/CRTable.java | 1 + .../sun/tools/javac/parser/JavacParser.java | 62 +- .../tools/javac/resources/compiler.properties | 14 + .../com/sun/tools/javac/tree/JCTree.java | 15 +- .../com/sun/tools/javac/tree/Pretty.java | 13 + .../com/sun/tools/javac/tree/TreeCopier.java | 3 +- .../com/sun/tools/javac/tree/TreeMaker.java | 9 +- .../com/sun/tools/javac/tree/TreeScanner.java | 1 + .../sun/tools/javac/tree/TreeTranslator.java | 1 + .../com/sun/tools/javac/util/Names.java | 5 + .../tools/javac/TryWithResources/ArmLint.java | 55 ++ .../tools/javac/TryWithResources/ArmLint.out | 3 + .../tools/javac/TryWithResources/BadTwr.java | 36 + .../tools/javac/TryWithResources/BadTwr.out | 5 + .../javac/TryWithResources/BadTwrSyntax.java | 22 + .../javac/TryWithResources/BadTwrSyntax.out | 2 + .../TryWithResources/DuplicateResource.java | 65 ++ .../DuplicateResourceDecl.java | 20 + .../DuplicateResourceDecl.out | 2 + .../javac/TryWithResources/ImplicitFinal.java | 27 + .../javac/TryWithResources/ImplicitFinal.out | 2 + .../javac/TryWithResources/PlainTry.java | 15 + .../tools/javac/TryWithResources/PlainTry.out | 2 + .../javac/TryWithResources/PlainTry6.out | 2 + .../TryWithResources/ResourceOutsideTry.java | 23 + .../TryWithResources/ResourceOutsideTry.out | 3 + .../TryWithResources/ResourceTypeVar.java | 43 + .../tools/javac/TryWithResources/TwrFlow.java | 39 + .../tools/javac/TryWithResources/TwrFlow.out | 5 + .../javac/TryWithResources/TwrInference.java | 43 + .../TryWithResources/TwrIntersection.java | 47 ++ .../TryWithResources/TwrIntersection02.java | 37 + .../TryWithResources/TwrIntersection02.out | 3 + .../javac/TryWithResources/TwrMultiCatch.java | 81 ++ .../TryWithResources/TwrOnNonResource.java | 42 + .../TryWithResources/TwrOnNonResource.out | 7 + .../javac/TryWithResources/TwrTests.java | 742 ++++++++++++++++++ .../javac/TryWithResources/WeirdTwr.java | 48 ++ .../model/element/TestResourceVariable.java | 113 +++ 51 files changed, 1950 insertions(+), 18 deletions(-) create mode 100644 langtools/test/tools/javac/TryWithResources/ArmLint.java create mode 100644 langtools/test/tools/javac/TryWithResources/ArmLint.out create mode 100644 langtools/test/tools/javac/TryWithResources/BadTwr.java create mode 100644 langtools/test/tools/javac/TryWithResources/BadTwr.out create mode 100644 langtools/test/tools/javac/TryWithResources/BadTwrSyntax.java create mode 100644 langtools/test/tools/javac/TryWithResources/BadTwrSyntax.out create mode 100644 langtools/test/tools/javac/TryWithResources/DuplicateResource.java create mode 100644 langtools/test/tools/javac/TryWithResources/DuplicateResourceDecl.java create mode 100644 langtools/test/tools/javac/TryWithResources/DuplicateResourceDecl.out create mode 100644 langtools/test/tools/javac/TryWithResources/ImplicitFinal.java create mode 100644 langtools/test/tools/javac/TryWithResources/ImplicitFinal.out create mode 100644 langtools/test/tools/javac/TryWithResources/PlainTry.java create mode 100644 langtools/test/tools/javac/TryWithResources/PlainTry.out create mode 100644 langtools/test/tools/javac/TryWithResources/PlainTry6.out create mode 100644 langtools/test/tools/javac/TryWithResources/ResourceOutsideTry.java create mode 100644 langtools/test/tools/javac/TryWithResources/ResourceOutsideTry.out create mode 100644 langtools/test/tools/javac/TryWithResources/ResourceTypeVar.java create mode 100644 langtools/test/tools/javac/TryWithResources/TwrFlow.java create mode 100644 langtools/test/tools/javac/TryWithResources/TwrFlow.out create mode 100644 langtools/test/tools/javac/TryWithResources/TwrInference.java create mode 100644 langtools/test/tools/javac/TryWithResources/TwrIntersection.java create mode 100644 langtools/test/tools/javac/TryWithResources/TwrIntersection02.java create mode 100644 langtools/test/tools/javac/TryWithResources/TwrIntersection02.out create mode 100644 langtools/test/tools/javac/TryWithResources/TwrMultiCatch.java create mode 100644 langtools/test/tools/javac/TryWithResources/TwrOnNonResource.java create mode 100644 langtools/test/tools/javac/TryWithResources/TwrOnNonResource.out create mode 100644 langtools/test/tools/javac/TryWithResources/TwrTests.java create mode 100644 langtools/test/tools/javac/TryWithResources/WeirdTwr.java create mode 100644 langtools/test/tools/javac/processing/model/element/TestResourceVariable.java diff --git a/langtools/make/build.properties b/langtools/make/build.properties index f9a87321d41..4ba6256f053 100644 --- a/langtools/make/build.properties +++ b/langtools/make/build.properties @@ -107,7 +107,8 @@ javac.includes = \ javax/annotation/processing/ \ javax/lang/model/ \ javax/tools/ \ - com/sun/source/ com/sun/tools/javac/ + com/sun/source/ \ + com/sun/tools/javac/ javac.tests = \ tools/javac diff --git a/langtools/src/share/classes/com/sun/source/tree/TryTree.java b/langtools/src/share/classes/com/sun/source/tree/TryTree.java index 8eeedb095d9..6e31bee66b0 100644 --- a/langtools/src/share/classes/com/sun/source/tree/TryTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/TryTree.java @@ -49,4 +49,5 @@ public interface TryTree extends StatementTree { BlockTree getBlock(); List getCatches(); BlockTree getFinallyBlock(); + List getResources(); } diff --git a/langtools/src/share/classes/com/sun/source/util/TreeScanner.java b/langtools/src/share/classes/com/sun/source/util/TreeScanner.java index d4448fb6d25..dbb2d303809 100644 --- a/langtools/src/share/classes/com/sun/source/util/TreeScanner.java +++ b/langtools/src/share/classes/com/sun/source/util/TreeScanner.java @@ -209,7 +209,8 @@ public class TreeScanner implements TreeVisitor { } public R visitTry(TryTree node, P p) { - R r = scan(node.getBlock(), p); + R r = scan(node.getResources(), p); + r = scanAndReduce(node.getBlock(), p, r); r = scanAndReduce(node.getCatches(), p, r); r = scanAndReduce(node.getFinallyBlock(), p, r); return r; diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Lint.java b/langtools/src/share/classes/com/sun/tools/javac/code/Lint.java index c02c5bb9e55..319865950f9 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Lint.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Lint.java @@ -208,7 +208,12 @@ public class Lint /** * Warn about potentially unsafe vararg methods */ - VARARGS("varargs"); + VARARGS("varargs"), + + /** + * Warn about arm resources + */ + ARM("arm"); LintCategory(String option) { this(option, false); diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java index bce1513d22a..5dbd6f4fd16 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java @@ -159,6 +159,9 @@ public enum Source { public boolean enforceMandatoryWarnings() { return compareTo(JDK1_5) >= 0; } + public boolean allowTryWithResources() { + return compareTo(JDK1_7) >= 0; + } public boolean allowTypeAnnotations() { return compareTo(JDK1_7) >= 0; } diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java index 2c75a0cd1f9..9faa4b06f74 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java @@ -993,12 +993,17 @@ public abstract class Symbol implements Element { return data == ElementKind.EXCEPTION_PARAMETER; } + public boolean isResourceVariable() { + return data == ElementKind.RESOURCE_VARIABLE; + } + public Object getConstValue() { // TODO: Consider if getConstValue and getConstantValue can be collapsed - if (data == ElementKind.EXCEPTION_PARAMETER) { + if (data == ElementKind.EXCEPTION_PARAMETER || + data == ElementKind.RESOURCE_VARIABLE) { return null; } else if (data instanceof Callable) { - // In this case, this is final a variable, with an as + // In this case, this is a final variable, with an as // yet unevaluated initializer. Callable eval = (Callable)data; data = null; // to make sure we don't evaluate this twice. diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java b/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java index 947691e3522..1d037c29ba7 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java @@ -148,6 +148,7 @@ public class Symtab { public final Type inheritedType; public final Type proprietaryType; public final Type systemType; + public final Type autoCloseableType; /** The symbol representing the length field of an array. */ @@ -159,6 +160,9 @@ public class Symtab { /** The symbol representing the final finalize method on enums */ public final MethodSymbol enumFinalFinalize; + /** The symbol representing the close method on TWR AutoCloseable type */ + public final MethodSymbol autoCloseableClose; + /** The predefined type that belongs to a tag. */ public final Type[] typeOfTag = new Type[TypeTags.TypeTagCount]; @@ -444,6 +448,12 @@ public class Symtab { suppressWarningsType = enterClass("java.lang.SuppressWarnings"); inheritedType = enterClass("java.lang.annotation.Inherited"); systemType = enterClass("java.lang.System"); + autoCloseableType = enterClass("java.lang.AutoCloseable"); + autoCloseableClose = new MethodSymbol(PUBLIC, + names.close, + new MethodType(List.nil(), voidType, + List.of(exceptionType), methodClass), + autoCloseableType.tsym); synthesizeEmptyInterfaceIfMissing(cloneableType); synthesizeEmptyInterfaceIfMissing(serializableType); diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java index ca63b46b55e..1c28ba75c2f 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java @@ -192,7 +192,7 @@ public class Attr extends JCTree.Visitor { Type check(JCTree tree, Type owntype, int ownkind, int pkind, Type pt) { if (owntype.tag != ERROR && pt.tag != METHOD && pt.tag != FORALL) { if ((ownkind & ~pkind) == 0) { - owntype = chk.checkType(tree.pos(), owntype, pt); + owntype = chk.checkType(tree.pos(), owntype, pt, errKey); } else { log.error(tree.pos(), "unexpected.type", kindNames(pkind), @@ -239,7 +239,11 @@ public class Attr extends JCTree.Visitor { !((base == null || (base.getTag() == JCTree.IDENT && TreeInfo.name(base) == names._this)) && isAssignableAsBlankFinal(v, env)))) { - log.error(pos, "cant.assign.val.to.final.var", v); + if (v.isResourceVariable()) { //TWR resource + log.error(pos, "twr.resource.may.not.be.assigned", v); + } else { + log.error(pos, "cant.assign.val.to.final.var", v); + } } } @@ -372,6 +376,10 @@ public class Attr extends JCTree.Visitor { */ Type pt; + /** Visitor argument: the error key to be generated when a type error occurs + */ + String errKey; + /** Visitor result: the computed type. */ Type result; @@ -385,13 +393,19 @@ public class Attr extends JCTree.Visitor { * @param pt The prototype visitor argument. */ Type attribTree(JCTree tree, Env env, int pkind, Type pt) { + return attribTree(tree, env, pkind, pt, "incompatible.types"); + } + + Type attribTree(JCTree tree, Env env, int pkind, Type pt, String errKey) { Env prevEnv = this.env; int prevPkind = this.pkind; Type prevPt = this.pt; + String prevErrKey = this.errKey; try { this.env = env; this.pkind = pkind; this.pt = pt; + this.errKey = errKey; tree.accept(this); if (tree == breakTree) throw new BreakAttr(env); @@ -403,6 +417,7 @@ public class Attr extends JCTree.Visitor { this.env = prevEnv; this.pkind = prevPkind; this.pt = prevPt; + this.errKey = prevErrKey; } } @@ -412,6 +427,10 @@ public class Attr extends JCTree.Visitor { return attribTree(tree, env, VAL, pt.tag != ERROR ? pt : Type.noType); } + public Type attribExpr(JCTree tree, Env env, Type pt, String key) { + return attribTree(tree, env, VAL, pt.tag != ERROR ? pt : Type.noType, key); + } + /** Derived visitor method: attribute an expression tree with * no constraints on the computed type. */ @@ -976,14 +995,34 @@ public class Attr extends JCTree.Visitor { } public void visitTry(JCTry tree) { + // Create a new local environment with a local + Env localEnv = env.dup(tree, env.info.dup(env.info.scope.dup())); + boolean isTryWithResource = tree.resources.nonEmpty(); + // Create a nested environment for attributing the try block if needed + Env tryEnv = isTryWithResource ? + env.dup(tree, localEnv.info.dup(localEnv.info.scope.dup())) : + localEnv; + // Attribute resource declarations + for (JCTree resource : tree.resources) { + if (resource.getTag() == JCTree.VARDEF) { + attribStat(resource, tryEnv); + chk.checkType(resource, resource.type, syms.autoCloseableType, "twr.not.applicable.to.type"); + VarSymbol var = (VarSymbol)TreeInfo.symbolFor(resource); + var.setData(ElementKind.RESOURCE_VARIABLE); + } else { + attribExpr(resource, tryEnv, syms.autoCloseableType, "twr.not.applicable.to.type"); + } + } // Attribute body - attribStat(tree.body, env.dup(tree, env.info.dup())); + attribStat(tree.body, tryEnv); + if (isTryWithResource) + tryEnv.info.scope.leave(); // Attribute catch clauses for (List l = tree.catchers; l.nonEmpty(); l = l.tail) { JCCatch c = l.head; Env catchEnv = - env.dup(c, env.info.dup(env.info.scope.dup())); + localEnv.dup(c, localEnv.info.dup(localEnv.info.scope.dup())); Type ctype = attribStat(c.param, catchEnv); if (TreeInfo.isMultiCatch(c)) { //check that multi-catch parameter is marked as final @@ -1003,7 +1042,9 @@ public class Attr extends JCTree.Visitor { } // Attribute finalizer - if (tree.finalizer != null) attribStat(tree.finalizer, env); + if (tree.finalizer != null) attribStat(tree.finalizer, localEnv); + + localEnv.info.scope.leave(); result = null; } @@ -2139,6 +2180,15 @@ public class Attr extends JCTree.Visitor { checkAssignable(tree.pos(), v, tree.selected, env); } + if (sitesym != null && + sitesym.kind == VAR && + ((VarSymbol)sitesym).isResourceVariable() && + sym.kind == MTH && + sym.overrides(syms.autoCloseableClose, sitesym.type.tsym, types, true) && + env.info.lint.isEnabled(Lint.LintCategory.ARM)) { + log.warning(tree, "twr.explicit.close.call"); + } + // Disallow selecting a type from an expression if (isType(sym) && (sitesym==null || (sitesym.kind&(TYP|PCK)) == 0)) { tree.type = check(tree.selected, pt, diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java index 3b9999c1794..a306e357277 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java @@ -393,6 +393,10 @@ public class Check { * @param req The type that was required. */ Type checkType(DiagnosticPosition pos, Type found, Type req) { + return checkType(pos, found, req, "incompatible.types"); + } + + Type checkType(DiagnosticPosition pos, Type found, Type req, String errKey) { if (req.tag == ERROR) return req; if (found.tag == FORALL) @@ -411,7 +415,7 @@ public class Check { log.error(pos, "assignment.to.extends-bound", req); return types.createErrorType(found); } - return typeError(pos, diags.fragment("incompatible.types"), found, req); + return typeError(pos, diags.fragment(errKey), found, req); } /** Instantiate polymorphic type to some prototype, unless diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java index afec481986c..d105eb97564 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java @@ -28,6 +28,8 @@ package com.sun.tools.javac.comp; import java.util.HashMap; +import java.util.Map; +import java.util.LinkedHashMap; import com.sun.tools.javac.code.*; import com.sun.tools.javac.tree.*; @@ -265,6 +267,10 @@ public class Flow extends TreeScanner { */ List caught; + /** The list of unreferenced automatic resources. + */ + Map unrefdResources; + /** Set when processing a loop body the second time for DU analysis. */ boolean loopPassTwo = false; @@ -963,6 +969,7 @@ public class Flow extends TreeScanner { public void visitTry(JCTry tree) { List caughtPrev = caught; List thrownPrev = thrown; + Map unrefdResourcesPrev = unrefdResources; thrown = List.nil(); for (List l = tree.catchers; l.nonEmpty(); l = l.tail) { List subClauses = TreeInfo.isMultiCatch(l.head) ? @@ -977,6 +984,32 @@ public class Flow extends TreeScanner { pendingExits = new ListBuffer(); Bits initsTry = inits.dup(); uninitsTry = uninits.dup(); + unrefdResources = new LinkedHashMap(); + for (JCTree resource : tree.resources) { + if (resource instanceof JCVariableDecl) { + JCVariableDecl vdecl = (JCVariableDecl) resource; + visitVarDef(vdecl); + unrefdResources.put(vdecl.sym, vdecl); + } else if (resource instanceof JCExpression) { + scanExpr((JCExpression) resource); + } else { + throw new AssertionError(tree); // parser error + } + } + for (JCTree resource : tree.resources) { + MethodSymbol topCloseMethod = (MethodSymbol)syms.autoCloseableType.tsym.members().lookup(names.close).sym; + List closeableSupertypes = resource.type.isCompound() ? + types.interfaces(resource.type).prepend(types.supertype(resource.type)) : + List.of(resource.type); + for (Type sup : closeableSupertypes) { + if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) { + MethodSymbol closeMethod = types.implementation(topCloseMethod, sup.tsym, types, true); + for (Type t : closeMethod.getThrownTypes()) { + markThrown(tree.body, t); + } + } + } + } scanStat(tree.body); List thrownInTry = thrown; thrown = thrownPrev; @@ -987,6 +1020,14 @@ public class Flow extends TreeScanner { Bits uninitsEnd = uninits; int nextadrCatch = nextadr; + if (!unrefdResources.isEmpty() && + lint.isEnabled(Lint.LintCategory.ARM)) { + for (Map.Entry e : unrefdResources.entrySet()) { + log.warning(e.getValue().pos(), + "automatic.resource.not.referenced", e.getKey()); + } + } + List caughtInTry = List.nil(); for (List l = tree.catchers; l.nonEmpty(); l = l.tail) { alive = true; @@ -1070,6 +1111,7 @@ public class Flow extends TreeScanner { while (exits.nonEmpty()) pendingExits.append(exits.next()); } uninitsTry.andSet(uninitsTryPrev).andSet(uninits); + unrefdResources = unrefdResourcesPrev; } public void visitConditional(JCConditional tree) { @@ -1293,8 +1335,16 @@ public class Flow extends TreeScanner { } public void visitIdent(JCIdent tree) { - if (tree.sym.kind == VAR) + if (tree.sym.kind == VAR) { checkInit(tree.pos(), (VarSymbol)tree.sym); + referenced(tree.sym); + } + } + + void referenced(Symbol sym) { + if (unrefdResources != null && unrefdResources.containsKey(sym)) { + unrefdResources.remove(sym); + } } public void visitTypeCast(JCTypeCast tree) { diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java index 44435b2dcfe..c5434eaf062 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java @@ -605,6 +605,23 @@ public class Lower extends TreeTranslator { s.enter(sym); } + /** Create a fresh synthetic name within a given scope - the unique name is + * obtained by appending '$' chars at the end of the name until no match + * is found. + * + * @param name base name + * @param s scope in which the name has to be unique + * @return fresh synthetic name + */ + private Name makeSyntheticName(Name name, Scope s) { + do { + name = name.append( + target.syntheticNameChar(), + names.empty); + } while (lookupSynthetic(name, s) != null); + return name; + } + /** Check whether synthetic symbols generated during lowering conflict * with user-defined symbols. * @@ -1299,6 +1316,11 @@ public class Lower extends TreeTranslator { */ Scope proxies; + /** A scope containing all unnamed resource variables/saved + * exception variables for translated TWR blocks + */ + Scope twrVars; + /** A stack containing the this$n field of the currently translated * classes (if needed) in innermost first order. * Inside a constructor, proxies and any this$n symbol are duplicated @@ -1400,6 +1422,122 @@ public class Lower extends TreeTranslator { } } + /** Optionally replace a try statement with an automatic resource + * management (ARM) block. + * @param tree The try statement to inspect. + * @return An ARM block, or the original try block if there are no + * resources to manage. + */ + JCTree makeArmTry(JCTry tree) { + make_at(tree.pos()); + twrVars = twrVars.dup(); + JCBlock armBlock = makeArmBlock(tree.resources, tree.body, 0); + if (tree.catchers.isEmpty() && tree.finalizer == null) + result = translate(armBlock); + else + result = translate(make.Try(armBlock, tree.catchers, tree.finalizer)); + twrVars = twrVars.leave(); + return result; + } + + private JCBlock makeArmBlock(List resources, JCBlock block, int depth) { + if (resources.isEmpty()) + return block; + + // Add resource declaration or expression to block statements + ListBuffer stats = new ListBuffer(); + JCTree resource = resources.head; + JCExpression expr = null; + if (resource instanceof JCVariableDecl) { + JCVariableDecl var = (JCVariableDecl) resource; + expr = make.Ident(var.sym).setType(resource.type); + stats.add(var); + } else { + assert resource instanceof JCExpression; + VarSymbol syntheticTwrVar = + new VarSymbol(SYNTHETIC | FINAL, + makeSyntheticName(names.fromString("twrVar" + + depth), twrVars), + (resource.type.tag == TypeTags.BOT) ? + syms.autoCloseableType : resource.type, + currentMethodSym); + twrVars.enter(syntheticTwrVar); + JCVariableDecl syntheticTwrVarDecl = + make.VarDef(syntheticTwrVar, (JCExpression)resource); + expr = (JCExpression)make.Ident(syntheticTwrVar); + stats.add(syntheticTwrVarDecl); + } + + // Add primaryException declaration + VarSymbol primaryException = + new VarSymbol(SYNTHETIC, + makeSyntheticName(names.fromString("primaryException" + + depth), twrVars), + syms.throwableType, + currentMethodSym); + twrVars.enter(primaryException); + JCVariableDecl primaryExceptionTreeDecl = make.VarDef(primaryException, makeNull()); + stats.add(primaryExceptionTreeDecl); + + // Create catch clause that saves exception and then rethrows it + VarSymbol param = + new VarSymbol(FINAL|SYNTHETIC, + names.fromString("t" + + target.syntheticNameChar()), + syms.throwableType, + currentMethodSym); + JCVariableDecl paramTree = make.VarDef(param, null); + JCStatement assign = make.Assignment(primaryException, make.Ident(param)); + JCStatement rethrowStat = make.Throw(make.Ident(param)); + JCBlock catchBlock = make.Block(0L, List.of(assign, rethrowStat)); + JCCatch catchClause = make.Catch(paramTree, catchBlock); + + int oldPos = make.pos; + make.at(TreeInfo.endPos(block)); + JCBlock finallyClause = makeArmFinallyClause(primaryException, expr); + make.at(oldPos); + JCTry outerTry = make.Try(makeArmBlock(resources.tail, block, depth + 1), + List.of(catchClause), + finallyClause); + stats.add(outerTry); + return make.Block(0L, stats.toList()); + } + + private JCBlock makeArmFinallyClause(Symbol primaryException, JCExpression resource) { + // primaryException.addSuppressedException(catchException); + VarSymbol catchException = + new VarSymbol(0, make.paramName(2), + syms.throwableType, + currentMethodSym); + JCStatement addSuppressionStatement = + make.Exec(makeCall(make.Ident(primaryException), + names.fromString("addSuppressedException"), + List.of(make.Ident(catchException)))); + + // try { resource.close(); } catch (e) { primaryException.addSuppressedException(e); } + JCBlock tryBlock = + make.Block(0L, List.of(makeResourceCloseInvocation(resource))); + JCVariableDecl catchExceptionDecl = make.VarDef(catchException, null); + JCBlock catchBlock = make.Block(0L, List.of(addSuppressionStatement)); + List catchClauses = List.of(make.Catch(catchExceptionDecl, catchBlock)); + JCTry tryTree = make.Try(tryBlock, catchClauses, null); + + // if (resource != null) resourceClose; + JCExpression nullCheck = makeBinary(JCTree.NE, + make.Ident(primaryException), + makeNull()); + JCIf closeIfStatement = make.If(nullCheck, + tryTree, + makeResourceCloseInvocation(resource)); + return make.Block(0L, List.of(closeIfStatement)); + } + + private JCStatement makeResourceCloseInvocation(JCExpression resource) { + // create resource.close() method invocation + JCExpression resourceClose = makeCall(resource, names.close, List.nil()); + return make.Exec(resourceClose); + } + /** Construct a tree that represents the outer instance * . Never pick the current `this'. * @param pos The source code position to be used for the tree. @@ -3405,6 +3543,15 @@ public class Lower extends TreeTranslator { result = tree; } + @Override + public void visitTry(JCTry tree) { + if (tree.resources.isEmpty()) { + super.visitTry(tree); + } else { + result = makeArmTry(tree); + } + } + /************************************************************************** * main method *************************************************************************/ @@ -3430,6 +3577,7 @@ public class Lower extends TreeTranslator { actualSymbols = new HashMap(); freevarCache = new HashMap>(); proxies = new Scope(syms.noSymbol); + twrVars = new Scope(syms.noSymbol); outerThisStack = List.nil(); accessNums = new HashMap(); accessSyms = new HashMap(); diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java b/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java index cab86ec9b96..6530e09a14d 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java @@ -535,6 +535,14 @@ public class TransTypes extends TreeTranslator { result = tree; } + public void visitTry(JCTry tree) { + tree.resources = translate(tree.resources, syms.autoCloseableType); + tree.body = translate(tree.body); + tree.catchers = translateCatchers(tree.catchers); + tree.finalizer = translate(tree.finalizer); + result = tree; + } + public void visitConditional(JCConditional tree) { tree.cond = translate(tree.cond, syms.booleanType); tree.truepart = translate(tree.truepart, erasure(tree.type)); diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/CRTable.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/CRTable.java index d49bf075ef3..e505129ef69 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/CRTable.java +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/CRTable.java @@ -325,6 +325,7 @@ implements CRTFlags { public void visitTry(JCTry tree) { SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); + sr.mergeWith(csp(tree.resources)); sr.mergeWith(csp(tree.body)); sr.mergeWith(cspCatchers(tree.catchers)); sr.mergeWith(csp(tree.finalizer)); diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java index 32ae4d52a19..1d77d5362ca 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -131,6 +131,7 @@ public class JavacParser implements Parser { this.allowForeach = source.allowForeach(); this.allowStaticImport = source.allowStaticImport(); this.allowAnnotations = source.allowAnnotations(); + this.allowTWR = source.allowTryWithResources(); this.allowDiamond = source.allowDiamond(); this.allowMulticatch = source.allowMulticatch(); this.allowTypeAnnotations = source.allowTypeAnnotations(); @@ -186,6 +187,10 @@ public class JavacParser implements Parser { */ boolean allowTypeAnnotations; + /** Switch: should we recognize automatic resource management? + */ + boolean allowTWR; + /** Switch: should we keep docComments? */ boolean keepDocComments; @@ -1846,6 +1851,7 @@ public class JavacParser implements Parser { * | WHILE ParExpression Statement * | DO Statement WHILE ParExpression ";" * | TRY Block ( Catches | [Catches] FinallyPart ) + * | TRY "(" ResourceSpecification ")" Block [Catches] [FinallyPart] * | SWITCH ParExpression "{" SwitchBlockStatementGroups "}" * | SYNCHRONIZED ParExpression Block * | RETURN [Expression] ";" @@ -1916,6 +1922,13 @@ public class JavacParser implements Parser { } case TRY: { S.nextToken(); + List resources = List.nil(); + if (S.token() == LPAREN) { + checkAutomaticResourceManagement(); + S.nextToken(); + resources = resources(); + accept(RPAREN); + } JCBlock body = block(); ListBuffer catchers = new ListBuffer(); JCBlock finalizer = null; @@ -1926,9 +1939,13 @@ public class JavacParser implements Parser { finalizer = block(); } } else { - log.error(pos, "try.without.catch.or.finally"); + if (allowTWR) { + if (resources.isEmpty()) + log.error(pos, "try.without.catch.finally.or.resource.decls"); + } else + log.error(pos, "try.without.catch.or.finally"); } - return F.at(pos).Try(body, catchers.toList(), finalizer); + return F.at(pos).Try(resources, body, catchers.toList(), finalizer); } case SWITCH: { S.nextToken(); @@ -2389,6 +2406,39 @@ public class JavacParser implements Parser { return toP(F.at(pos).VarDef(mods, name, type, null)); } + /** Resources = Resource { ";" Resources } + */ + List resources() { + ListBuffer defs = new ListBuffer(); + defs.append(resource()); + while (S.token() == SEMI) { + // All but last of multiple declarators subsume a semicolon + storeEnd(defs.elems.last(), S.endPos()); + S.nextToken(); + defs.append(resource()); + } + return defs.toList(); + } + + /** Resource = + * VariableModifiers Type VariableDeclaratorId = Expression + * | Expression + */ + JCTree resource() { + int pos = S.pos(); + if (S.token() == FINAL || S.token() == MONKEYS_AT) { + return variableDeclaratorRest(pos, optFinal(0), parseType(), + ident(), true, null); + } else { + JCExpression t = term(EXPR | TYPE); + if ((lastmode & TYPE) != 0 && S.token() == IDENTIFIER) + return variableDeclaratorRest(pos, toP(F.at(pos).Modifiers(Flags.FINAL)), t, + ident(), true, null); + else + return t; + } + } + /** CompilationUnit = [ { "@" Annotation } PACKAGE Qualident ";"] {ImportDeclaration} {TypeDeclaration} */ public JCTree.JCCompilationUnit parseCompilationUnit() { @@ -3220,6 +3270,12 @@ public class JavacParser implements Parser { if (!allowMulticatch) { log.error(S.pos(), "multicatch.not.supported.in.source", source.name); allowMulticatch = true; - } + } + } + void checkAutomaticResourceManagement() { + if (!allowTWR) { + log.error(S.pos(), "automatic.resource.management.not.supported.in.source", source.name); + allowTWR = true; + } } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties index 8fee222ad64..2e437a4f769 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -61,6 +61,8 @@ compiler.err.anon.class.impl.intf.no.typeargs=\ anonymous class implements interface; cannot have type arguments compiler.err.anon.class.impl.intf.no.qual.for.new=\ anonymous class implements interface; cannot have qualifier for new +compiler.misc.twr.not.applicable.to.type=\ + automatic resource management not applicable to variable type compiler.err.array.and.varargs=\ cannot declare both {0} and {1} in {2} compiler.err.array.dimension.missing=\ @@ -172,6 +174,8 @@ compiler.err.except.never.thrown.in.try=\ compiler.err.final.parameter.may.not.be.assigned=\ final parameter {0} may not be assigned +compiler.err.twr.resource.may.not.be.assigned=\ + automatic resource {0} may not be assigned compiler.err.multicatch.parameter.may.not.be.assigned=\ multi-catch parameter {0} may not be assigned compiler.err.multicatch.param.must.be.final=\ @@ -448,6 +452,8 @@ compiler.err.throws.not.allowed.in.intf.annotation=\ throws clause not allowed in @interface members compiler.err.try.without.catch.or.finally=\ ''try'' without ''catch'' or ''finally'' +compiler.err.try.without.catch.finally.or.resource.decls=\ + ''try'' without ''catch'', ''finally'' or resource declarations compiler.err.type.doesnt.take.params=\ type {0} does not take parameters compiler.err.type.var.cant.be.deref=\ @@ -797,6 +803,10 @@ compiler.warn.proc.unclosed.type.files=\ compiler.warn.proc.unmatched.processor.options=\ The following options were not recognized by any processor: ''{0}'' +compiler.warn.twr.explicit.close.call=\ + [arm] explicit call to close() on an automatic resource +compiler.warn.automatic.resource.not.referenced=\ + [arm] automatic resource {0} is never referenced in body of corresponding try statement compiler.warn.unchecked.assign=\ [unchecked] unchecked assignment: {0} to {1} compiler.warn.unchecked.assign.to.var=\ @@ -1217,6 +1227,10 @@ compiler.err.unsupported.underscore.lit=\ underscores in literals are not supported in -source {0}\n\ (use -source 7 or higher to enable underscores in literals) +compiler.err.automatic.resource.management.not.supported.in.source=\ + automatic resource management is not supported in -source {0}\n\ +(use -source 7 or higher to enable automatic resource management) + compiler.warn.enum.as.identifier=\ as of release 5, ''enum'' is a keyword, and may not be used as an identifier\n\ (use -source 5 or higher to use ''enum'' as a keyword) diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java index bf3f59292f2..64a991b03f7 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java @@ -1021,10 +1021,15 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { public JCBlock body; public List catchers; public JCBlock finalizer; - protected JCTry(JCBlock body, List catchers, JCBlock finalizer) { + public List resources; + protected JCTry(List resources, + JCBlock body, + List catchers, + JCBlock finalizer) { this.body = body; this.catchers = catchers; this.finalizer = finalizer; + this.resources = resources; } @Override public void accept(Visitor v) { v.visitTry(this); } @@ -1040,6 +1045,10 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitTry(this, d); } @Override + public List getResources() { + return resources; + } + @Override public int getTag() { return TRY; } @@ -2162,6 +2171,10 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { JCCase Case(JCExpression pat, List stats); JCSynchronized Synchronized(JCExpression lock, JCBlock body); JCTry Try(JCBlock body, List catchers, JCBlock finalizer); + JCTry Try(List resources, + JCBlock body, + List catchers, + JCBlock finalizer); JCCatch Catch(JCVariableDecl param, JCBlock body); JCConditional Conditional(JCExpression cond, JCExpression thenpart, diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java b/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java index 34e221ee528..66f6e56104d 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java @@ -691,6 +691,19 @@ public class Pretty extends JCTree.Visitor { public void visitTry(JCTry tree) { try { print("try "); + if (tree.resources.nonEmpty()) { + print("("); + boolean first = true; + for (JCTree var : tree.resources) { + if (!first) { + println(); + indent(); + } + printStat(var); + first = false; + } + print(") "); + } printStat(tree.body); for (List l = tree.catchers; l.nonEmpty(); l = l.tail) { printStat(l.head); diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java index e3977f66559..6abbfdbec9c 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java @@ -332,10 +332,11 @@ public class TreeCopier

implements TreeVisitor { public JCTree visitTry(TryTree node, P p) { JCTry t = (JCTry) node; + List resources = copy(t.resources, p); JCBlock body = copy(t.body, p); List catchers = copy(t.catchers, p); JCBlock finalizer = copy(t.finalizer, p); - return M.at(t.pos).Try(body, catchers, finalizer); + return M.at(t.pos).Try(resources, body, catchers, finalizer); } public JCTree visitParameterizedType(ParameterizedTypeTree node, P p) { diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java index 5ef56c86d26..eef94a62b32 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java @@ -269,7 +269,14 @@ public class TreeMaker implements JCTree.Factory { } public JCTry Try(JCBlock body, List catchers, JCBlock finalizer) { - JCTry tree = new JCTry(body, catchers, finalizer); + return Try(List.nil(), body, catchers, finalizer); + } + + public JCTry Try(List resources, + JCBlock body, + List catchers, + JCBlock finalizer) { + JCTry tree = new JCTry(resources, body, catchers, finalizer); tree.pos = pos; return tree; } diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java index d0bcfb912f1..53eb5118fb3 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java @@ -147,6 +147,7 @@ public class TreeScanner extends Visitor { } public void visitTry(JCTry tree) { + scan(tree.resources); scan(tree.body); scan(tree.catchers); scan(tree.finalizer); diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java index e08238267b8..ffb219b6a63 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java @@ -212,6 +212,7 @@ public class TreeTranslator extends JCTree.Visitor { } public void visitTry(JCTry tree) { + tree.resources = translate(tree.resources); tree.body = translate(tree.body); tree.catchers = translateCatchers(tree.catchers); tree.finalizer = translate(tree.finalizer); diff --git a/langtools/src/share/classes/com/sun/tools/javac/util/Names.java b/langtools/src/share/classes/com/sun/tools/javac/util/Names.java index 3bfa9a35743..095a7e3f0ee 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/util/Names.java +++ b/langtools/src/share/classes/com/sun/tools/javac/util/Names.java @@ -148,6 +148,8 @@ public class Names { public final Name getDeclaringClass; public final Name ex; public final Name finalize; + public final Name java_lang_AutoCloseable; + public final Name close; public final Name.Table table; @@ -263,6 +265,9 @@ public class Names { getDeclaringClass = fromString("getDeclaringClass"); ex = fromString("ex"); finalize = fromString("finalize"); + + java_lang_AutoCloseable = fromString("java.lang.AutoCloseable"); + close = fromString("close"); } protected Name.Table createTable(Options options) { diff --git a/langtools/test/tools/javac/TryWithResources/ArmLint.java b/langtools/test/tools/javac/TryWithResources/ArmLint.java new file mode 100644 index 00000000000..2a5a22392ba --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/ArmLint.java @@ -0,0 +1,55 @@ +/* + * @test /nodynamiccopyright/ + * @bug 6911256 6964740 6965277 6967065 + * @author Joseph D. Darcy + * @summary Check that -Xlint:arm warnings are generated as expected + * @compile/ref=ArmLint.out -Xlint:arm,deprecation -XDrawDiagnostics ArmLint.java + */ + +class ArmLint implements AutoCloseable { + private static void test1() { + try(ArmLint r1 = new ArmLint(); + ArmLint r2 = new ArmLint(); + ArmLint r3 = new ArmLint()) { + r1.close(); // The resource's close + r2.close(42); // *Not* the resource's close + // r3 not referenced + } + + } + + @SuppressWarnings("arm") + private static void test2() { + try(@SuppressWarnings("deprecation") AutoCloseable r4 = + new DeprecatedAutoCloseable()) { + // r4 not referenced + } catch(Exception e) { + ; + } + } + + /** + * The AutoCloseable method of a resource. + */ + @Override + public void close () { + return; + } + + /** + * Not the AutoCloseable method of a resource. + */ + public void close (int arg) { + return; + } +} + +@Deprecated +class DeprecatedAutoCloseable implements AutoCloseable { + public DeprecatedAutoCloseable(){super();} + + @Override + public void close () { + return; + } +} diff --git a/langtools/test/tools/javac/TryWithResources/ArmLint.out b/langtools/test/tools/javac/TryWithResources/ArmLint.out new file mode 100644 index 00000000000..f60161a5257 --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/ArmLint.out @@ -0,0 +1,3 @@ +ArmLint.java:14:15: compiler.warn.twr.explicit.close.call +ArmLint.java:13:13: compiler.warn.automatic.resource.not.referenced: r3 +2 warnings diff --git a/langtools/test/tools/javac/TryWithResources/BadTwr.java b/langtools/test/tools/javac/TryWithResources/BadTwr.java new file mode 100644 index 00000000000..71286458e4e --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/BadTwr.java @@ -0,0 +1,36 @@ +/* + * @test /nodynamiccopyright/ + * @bug 6911256 6964740 + * @author Joseph D. Darcy + * @summary Verify bad TWRs don't compile + * @compile/fail -source 6 TwrFlow.java + * @compile/fail/ref=BadTwr.out -XDrawDiagnostics BadTwr.java + */ + +public class BadTwr implements AutoCloseable { + public static void main(String... args) { + // illegal repeated name + try(BadTwr r1 = new BadTwr(); BadTwr r1 = new BadTwr()) { + System.out.println(r1.toString()); + } + + // illegal duplicate name of method argument + try(BadTwr args = new BadTwr()) { + System.out.println(args.toString()); + final BadTwr thatsIt = new BadTwr(); + thatsIt = null; + } + + try(BadTwr name = new BadTwr()) { + // illegal duplicate name of enclosing try + try(BadTwr name = new BadTwr()) { + System.out.println(name.toString()); + } + } + + } + + public void close() { + ; + } +} diff --git a/langtools/test/tools/javac/TryWithResources/BadTwr.out b/langtools/test/tools/javac/TryWithResources/BadTwr.out new file mode 100644 index 00000000000..3ed73139157 --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/BadTwr.out @@ -0,0 +1,5 @@ +BadTwr.java:13:39: compiler.err.already.defined: r1, main(java.lang.String...) +BadTwr.java:18:13: compiler.err.already.defined: args, main(java.lang.String...) +BadTwr.java:21:13: compiler.err.cant.assign.val.to.final.var: thatsIt +BadTwr.java:26:17: compiler.err.already.defined: name, main(java.lang.String...) +4 errors diff --git a/langtools/test/tools/javac/TryWithResources/BadTwrSyntax.java b/langtools/test/tools/javac/TryWithResources/BadTwrSyntax.java new file mode 100644 index 00000000000..3dbe2c4f5e8 --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/BadTwrSyntax.java @@ -0,0 +1,22 @@ +/* + * @test /nodynamiccopyright/ + * @bug 6911256 6964740 + * @author Joseph D. Darcy + * @summary Verify bad TWRs don't compile + * @compile/fail -source 6 BadTwrSyntax.java + * @compile/fail/ref=BadTwrSyntax.out -XDrawDiagnostics BadTwrSyntax.java + */ + +import java.io.IOException; +public class BadTwrSyntax implements AutoCloseable { + public static void main(String... args) throws Exception { + // illegal semicolon ending resources + try(BadTwr twrflow = new BadTwr();) { + System.out.println(twrflow.toString()); + } + } + + public void close() { + ; + } +} diff --git a/langtools/test/tools/javac/TryWithResources/BadTwrSyntax.out b/langtools/test/tools/javac/TryWithResources/BadTwrSyntax.out new file mode 100644 index 00000000000..df925e04eb9 --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/BadTwrSyntax.out @@ -0,0 +1,2 @@ +BadTwrSyntax.java:14:43: compiler.err.illegal.start.of.expr +1 error diff --git a/langtools/test/tools/javac/TryWithResources/DuplicateResource.java b/langtools/test/tools/javac/TryWithResources/DuplicateResource.java new file mode 100644 index 00000000000..ca2f554244f --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/DuplicateResource.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6911256 6964740 6965277 + * @author Maurizio Cimadamore + * @summary Check that lowered arm block does not end up creating resource twice + */ + +import java.util.ArrayList; + +public class DuplicateResource { + + static class TestResource implements AutoCloseable { + TestResource() { + resources.add(this); + } + boolean isClosed = false; + public void close() throws Exception { + isClosed = true; + } + } + + static ArrayList resources = new ArrayList(); + + public static void main(String[] args) { + try(new TestResource()) { + //do something + } catch (Exception e) { + throw new AssertionError("Shouldn't reach here", e); + } + check(); + } + + public static void check() { + if (resources.size() != 1) { + throw new AssertionError("Expected one resource, found: " + resources.size()); + } + TestResource resource = resources.get(0); + if (!resource.isClosed) { + throw new AssertionError("Resource used in ARM block has not been automatically closed"); + } + } +} diff --git a/langtools/test/tools/javac/TryWithResources/DuplicateResourceDecl.java b/langtools/test/tools/javac/TryWithResources/DuplicateResourceDecl.java new file mode 100644 index 00000000000..52b8d243eee --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/DuplicateResourceDecl.java @@ -0,0 +1,20 @@ +/* + * @test /nodynamiccopyright/ + * @bug 6911256 6964740 6965277 + * @author Maurizio Cimadamore + * @summary Check that resource variable is not accessible from catch/finally clause + * @compile/fail/ref=DuplicateResourceDecl.out -XDrawDiagnostics DuplicateResourceDecl.java + */ + +class DuplicateResourceDecl { + + public static void main(String[] args) { + try(MyResource c = new MyResource();MyResource c = new MyResource()) { + //do something + } catch (Exception e) { } + } + + static class MyResource implements AutoCloseable { + public void close() throws Exception {} + } +} diff --git a/langtools/test/tools/javac/TryWithResources/DuplicateResourceDecl.out b/langtools/test/tools/javac/TryWithResources/DuplicateResourceDecl.out new file mode 100644 index 00000000000..463b10be558 --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/DuplicateResourceDecl.out @@ -0,0 +1,2 @@ +DuplicateResourceDecl.java:12:45: compiler.err.already.defined: c, main(java.lang.String[]) +1 error diff --git a/langtools/test/tools/javac/TryWithResources/ImplicitFinal.java b/langtools/test/tools/javac/TryWithResources/ImplicitFinal.java new file mode 100644 index 00000000000..ebcf0aff3f2 --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/ImplicitFinal.java @@ -0,0 +1,27 @@ +/* + * @test /nodynamiccopyright/ + * @bug 6911256 6964740 6965277 + * @author Maurizio Cimadamore + * @summary Test that resource variables are implicitly final + * @compile/fail/ref=ImplicitFinal.out -XDrawDiagnostics ImplicitFinal.java + */ + +import java.io.IOException; + +class ImplicitFinal implements AutoCloseable { + public static void main(String... args) { + try(ImplicitFinal r = new ImplicitFinal()) { + r = null; //disallowed + } catch (IOException ioe) { // Not reachable + throw new AssertionError("Shouldn't reach here", ioe); + } + } + + + // A close method, but the class is not Closeable or + // AutoCloseable. + + public void close() throws IOException { + throw new IOException(); + } +} diff --git a/langtools/test/tools/javac/TryWithResources/ImplicitFinal.out b/langtools/test/tools/javac/TryWithResources/ImplicitFinal.out new file mode 100644 index 00000000000..0e33814b83f --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/ImplicitFinal.out @@ -0,0 +1,2 @@ +ImplicitFinal.java:14:13: compiler.err.twr.resource.may.not.be.assigned: r +1 error diff --git a/langtools/test/tools/javac/TryWithResources/PlainTry.java b/langtools/test/tools/javac/TryWithResources/PlainTry.java new file mode 100644 index 00000000000..fad4ca8c054 --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/PlainTry.java @@ -0,0 +1,15 @@ +/* + * @test /nodynamiccopyright/ + * @bug 6911256 6964740 + * @author Joseph D. Darcy + * @summary Test error messages for an unadorned try + * @compile/fail/ref=PlainTry6.out -XDrawDiagnostics -source 6 PlainTry.java + * @compile/fail/ref=PlainTry.out -XDrawDiagnostics PlainTry.java + */ +public class PlainTry { + public static void main(String... args) { + try { + ; + } + } +} diff --git a/langtools/test/tools/javac/TryWithResources/PlainTry.out b/langtools/test/tools/javac/TryWithResources/PlainTry.out new file mode 100644 index 00000000000..2751797eeb6 --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/PlainTry.out @@ -0,0 +1,2 @@ +PlainTry.java:11:9: compiler.err.try.without.catch.finally.or.resource.decls +1 error diff --git a/langtools/test/tools/javac/TryWithResources/PlainTry6.out b/langtools/test/tools/javac/TryWithResources/PlainTry6.out new file mode 100644 index 00000000000..5a8067d66fb --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/PlainTry6.out @@ -0,0 +1,2 @@ +PlainTry.java:11:9: compiler.err.try.without.catch.or.finally +1 error diff --git a/langtools/test/tools/javac/TryWithResources/ResourceOutsideTry.java b/langtools/test/tools/javac/TryWithResources/ResourceOutsideTry.java new file mode 100644 index 00000000000..16e5d3471e1 --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/ResourceOutsideTry.java @@ -0,0 +1,23 @@ +/* + * @test /nodynamiccopyright/ + * @bug 6911256 6964740 6965277 + * @author Maurizio Cimadamore + * @summary Check that resource variable is not accessible from catch/finally clause + * @compile/fail/ref=ResourceOutsideTry.out -XDrawDiagnostics ResourceOutsideTry.java + */ + +class ResourceOutsideTry { + void test() { + try(MyResource c = new MyResource()) { + //do something + } catch (Exception e) { + c.test(); + } finally { + c.test(); + } + } + static class MyResource implements AutoCloseable { + public void close() throws Exception {} + void test() {} + } +} diff --git a/langtools/test/tools/javac/TryWithResources/ResourceOutsideTry.out b/langtools/test/tools/javac/TryWithResources/ResourceOutsideTry.out new file mode 100644 index 00000000000..e043b792dec --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/ResourceOutsideTry.out @@ -0,0 +1,3 @@ +ResourceOutsideTry.java:14:13: compiler.err.cant.resolve.location: kindname.variable, c, , , kindname.class, ResourceOutsideTry +ResourceOutsideTry.java:16:13: compiler.err.cant.resolve.location: kindname.variable, c, , , kindname.class, ResourceOutsideTry +2 errors diff --git a/langtools/test/tools/javac/TryWithResources/ResourceTypeVar.java b/langtools/test/tools/javac/TryWithResources/ResourceTypeVar.java new file mode 100644 index 00000000000..2c9837318be --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/ResourceTypeVar.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6911256 6964740 6965277 + * @author Maurizio Cimadamore + * @summary Resource of a type-variable type crashes Flow + * @compile ResourceTypeVar.java + */ + +class ResourceTypeVar { + + public void test() { + try(X armflow = getX()) { + //do something + } catch (Exception e) { // Not reachable + throw new AssertionError("Shouldn't reach here", e); + } + } + + X getX() { return null; } +} diff --git a/langtools/test/tools/javac/TryWithResources/TwrFlow.java b/langtools/test/tools/javac/TryWithResources/TwrFlow.java new file mode 100644 index 00000000000..01f8b1aa2e9 --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/TwrFlow.java @@ -0,0 +1,39 @@ +/* + * @test /nodynamiccopyright/ + * @bug 6911256 6964740 + * @author Joseph D. Darcy + * @summary Test exception analysis of ARM blocks + * @compile/fail/ref=TwrFlow.out -XDrawDiagnostics TwrFlow.java + */ + +import java.io.IOException; +public class TwrFlow implements AutoCloseable { + public static void main(String... args) { + try(TwrFlow armflow = new TwrFlow()) { + System.out.println(armflow.toString()); + } catch (IOException ioe) { // Not reachable + throw new AssertionError("Shouldn't reach here", ioe); + } + // CustomCloseException should be caught or added to throws clause + + // Also check behavior on a resource expression rather than a + // declaration. + TwrFlow armflowexpr = new TwrFlow(); + try(armflowexpr) { + System.out.println(armflowexpr.toString()); + } catch (IOException ioe) { // Not reachable + throw new AssertionError("Shouldn't reach here", ioe); + } + // CustomCloseException should be caught or added to throws clause + } + + /* + * A close method, but the class is not Closeable or + * AutoCloseable. + */ + public void close() throws CustomCloseException { + throw new CustomCloseException(); + } +} + +class CustomCloseException extends Exception {} diff --git a/langtools/test/tools/javac/TryWithResources/TwrFlow.out b/langtools/test/tools/javac/TryWithResources/TwrFlow.out new file mode 100644 index 00000000000..dd0e61aebf4 --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/TwrFlow.out @@ -0,0 +1,5 @@ +TwrFlow.java:14:11: compiler.err.except.never.thrown.in.try: java.io.IOException +TwrFlow.java:24:11: compiler.err.except.never.thrown.in.try: java.io.IOException +TwrFlow.java:12:46: compiler.err.unreported.exception.need.to.catch.or.throw: CustomCloseException +TwrFlow.java:22:26: compiler.err.unreported.exception.need.to.catch.or.throw: CustomCloseException +4 errors diff --git a/langtools/test/tools/javac/TryWithResources/TwrInference.java b/langtools/test/tools/javac/TryWithResources/TwrInference.java new file mode 100644 index 00000000000..87187e43ffe --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/TwrInference.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6911256 6964740 6965277 + * @author Maurizio Cimadamore + * @summary Verify that method type-inference works as expected in TWR context + * @compile TwrInference.java + */ + +class TwrInference { + + public void test() { + try(getX()) { + //do something + } catch (Exception e) { // Not reachable + throw new AssertionError("Shouldn't reach here", e); + } + } + + X getX() { return null; } +} diff --git a/langtools/test/tools/javac/TryWithResources/TwrIntersection.java b/langtools/test/tools/javac/TryWithResources/TwrIntersection.java new file mode 100644 index 00000000000..4e3a1303736 --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/TwrIntersection.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6911256 6964740 6965277 + * @author Maurizio Cimadamore + * @summary Resource of an intersection type crashes Flow + * @compile TwrIntersection.java + */ + +interface MyCloseable extends AutoCloseable { + void close() throws java.io.IOException; +} + +class ResourceTypeVar { + + public void test() { + try(getX()) { + //do something + } catch (java.io.IOException e) { // Not reachable + throw new AssertionError("Shouldn't reach here", e); + } + } + + X getX() { return null; } +} diff --git a/langtools/test/tools/javac/TryWithResources/TwrIntersection02.java b/langtools/test/tools/javac/TryWithResources/TwrIntersection02.java new file mode 100644 index 00000000000..3cefe6b505c --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/TwrIntersection02.java @@ -0,0 +1,37 @@ +/* + * @test /nodynamiccopyright/ + * @bug 6911256 6964740 6965277 + * @author Maurizio Cimadamore + * @summary Check that resources of an intersection type forces union of exception types + * to be caught outside twr block + * @compile/fail/ref=TwrIntersection02.out -XDrawDiagnostics TwrIntersection02.java + */ + +class TwrIntersection02 { + + static class Exception1 extends Exception {} + static class Exception2 extends Exception {} + + + interface MyResource1 extends AutoCloseable { + void close() throws Exception1; + } + + interface MyResource2 extends AutoCloseable { + void close() throws Exception2; + } + + public void test1() throws Exception1 { + try(getX()) { + //do something + } + } + + public void test2() throws Exception2 { + try(getX()) { + //do something + } + } + + X getX() { return null; } +} diff --git a/langtools/test/tools/javac/TryWithResources/TwrIntersection02.out b/langtools/test/tools/javac/TryWithResources/TwrIntersection02.out new file mode 100644 index 00000000000..69a5f3f1c78 --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/TwrIntersection02.out @@ -0,0 +1,3 @@ +TwrIntersection02.java:25:21: compiler.err.unreported.exception.need.to.catch.or.throw: TwrIntersection02.Exception2 +TwrIntersection02.java:31:21: compiler.err.unreported.exception.need.to.catch.or.throw: TwrIntersection02.Exception1 +2 errors diff --git a/langtools/test/tools/javac/TryWithResources/TwrMultiCatch.java b/langtools/test/tools/javac/TryWithResources/TwrMultiCatch.java new file mode 100644 index 00000000000..8b49837d80e --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/TwrMultiCatch.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6911256 6964740 + * @author Joseph D. Darcy + * @summary Test that TWR and multi-catch play well together + * @compile TwrMultiCatch.java + * @run main TwrMultiCatch + */ + +import java.io.IOException; +public class TwrMultiCatch implements AutoCloseable { + private final Class exceptionClass; + + private TwrMultiCatch(Class exceptionClass) { + this.exceptionClass = exceptionClass; + } + + public static void main(String... args) { + test(new TwrMultiCatch(CustomCloseException1.class), + CustomCloseException1.class); + + test(new TwrMultiCatch(CustomCloseException2.class), + CustomCloseException2.class); + } + + private static void test(TwrMultiCatch twrMultiCatch, + Class expected) { + try(twrMultiCatch) { + System.out.println(twrMultiCatch.toString()); + } catch (final CustomCloseException1 | + CustomCloseException2 exception) { + if (!exception.getClass().equals(expected) ) { + throw new RuntimeException("Unexpected catch!"); + } + } + } + + public void close() throws CustomCloseException1, CustomCloseException2 { + Throwable t; + try { + t = exceptionClass.newInstance(); + } catch(ReflectiveOperationException rfe) { + throw new RuntimeException(rfe); + } + + try { + throw t; + } catch (final CustomCloseException1 | + CustomCloseException2 exception) { + throw exception; + } catch (Throwable throwable) { + throw new RuntimeException(throwable); + } + } +} + +class CustomCloseException1 extends Exception {} +class CustomCloseException2 extends Exception {} diff --git a/langtools/test/tools/javac/TryWithResources/TwrOnNonResource.java b/langtools/test/tools/javac/TryWithResources/TwrOnNonResource.java new file mode 100644 index 00000000000..5673243ae95 --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/TwrOnNonResource.java @@ -0,0 +1,42 @@ +/* + * @test /nodynamiccopyright/ + * @bug 6911256 6964740 + * @author Joseph D. Darcy + * @summary Verify invalid TWR block is not accepted. + * @compile/fail -source 6 TwrOnNonResource.java + * @compile/fail/ref=TwrOnNonResource.out -XDrawDiagnostics TwrOnNonResource.java + */ + +class TwrOnNonResource { + public static void main(String... args) { + try(TwrOnNonResource aonr = new TwrOnNonResource()) { + System.out.println(aonr.toString()); + } + try(TwrOnNonResource aonr = new TwrOnNonResource()) { + System.out.println(aonr.toString()); + } finally {;} + try(TwrOnNonResource aonr = new TwrOnNonResource()) { + System.out.println(aonr.toString()); + } catch (Exception e) {;} + + // Also check expression form + TwrOnNonResource aonr = new TwrOnNonResource(); + try(aonr) { + System.out.println(aonr.toString()); + } + try(aonr) { + System.out.println(aonr.toString()); + } finally {;} + try(aonr) { + System.out.println(aonr.toString()); + } catch (Exception e) {;} + } + + /* + * A close method, but the class is not Closeable or + * AutoCloseable. + */ + public void close() { + throw new AssertionError("I'm not Closable!"); + } +} diff --git a/langtools/test/tools/javac/TryWithResources/TwrOnNonResource.out b/langtools/test/tools/javac/TryWithResources/TwrOnNonResource.out new file mode 100644 index 00000000000..a894aff7ffb --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/TwrOnNonResource.out @@ -0,0 +1,7 @@ +TwrOnNonResource.java:12:13: compiler.err.prob.found.req: (compiler.misc.twr.not.applicable.to.type), TwrOnNonResource, java.lang.AutoCloseable +TwrOnNonResource.java:15:13: compiler.err.prob.found.req: (compiler.misc.twr.not.applicable.to.type), TwrOnNonResource, java.lang.AutoCloseable +TwrOnNonResource.java:18:13: compiler.err.prob.found.req: (compiler.misc.twr.not.applicable.to.type), TwrOnNonResource, java.lang.AutoCloseable +TwrOnNonResource.java:24:13: compiler.err.prob.found.req: (compiler.misc.twr.not.applicable.to.type), TwrOnNonResource, java.lang.AutoCloseable +TwrOnNonResource.java:27:13: compiler.err.prob.found.req: (compiler.misc.twr.not.applicable.to.type), TwrOnNonResource, java.lang.AutoCloseable +TwrOnNonResource.java:30:13: compiler.err.prob.found.req: (compiler.misc.twr.not.applicable.to.type), TwrOnNonResource, java.lang.AutoCloseable +6 errors diff --git a/langtools/test/tools/javac/TryWithResources/TwrTests.java b/langtools/test/tools/javac/TryWithResources/TwrTests.java new file mode 100644 index 00000000000..c3ca6176573 --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/TwrTests.java @@ -0,0 +1,742 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6911256 6964740 + * @summary Tests of generated TWR code. + */ + +import java.util.List; +import java.util.ArrayList; + +public class TwrTests { + public static void main(String[] args) { + testCreateFailure1(); + testCreateFailure2(); + testCreateFailure2Nested(); + testCreateFailure3(); + testCreateFailure3Nested(); + testCreateFailure4(); + testCreateFailure4Nested(); + testCreateFailure5(); + testCreateFailure5Nested(); + + testCreateSuccess1(); + testCreateSuccess2(); + testCreateSuccess2Nested(); + testCreateSuccess3(); + testCreateSuccess3Nested(); + testCreateSuccess4(); + testCreateSuccess4Nested(); + testCreateSuccess5(); + testCreateSuccess5Nested(); + } + + /* + * The following tests simulate a creation failure of every possible + * resource in an TWR block, and check to make sure that the failure + * prevents creation of subsequent resources, and that all created + * resources are properly closed, even if one or more of the close + * attempts fails. + */ + + public static void testCreateFailure1() { + int creationFailuresDetected = 0; + List closedList = new ArrayList(0); + try (Resource r0 = createResource(0, 0, 0, closedList)) { + throw new AssertionError("Resource creation succeeded"); + } catch (Resource.CreateFailException e) { + creationFailuresDetected++; + if (e.resourceId() != 0) { + throw new AssertionError("Wrong resource creation " + + e.resourceId() + " failed"); + } + } catch (Resource.CloseFailException e) { + throw new AssertionError("Unexpected CloseFailException: " + e.resourceId()); + } + checkForSingleCreationFailure(creationFailuresDetected); + checkClosedList(closedList, 0); + } + + public static void testCreateFailure2() { + for (int createFailureId = 0; createFailureId < 2; createFailureId++) { + for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) { + int creationFailuresDetected = 0; + List closedList = new ArrayList(); + try (Resource r0 = createResource(0, createFailureId, bitMap, closedList); + Resource r1 = createResource(1, createFailureId, bitMap, closedList)) { + throw new AssertionError("Entire resource creation succeeded"); + } catch (Resource.CreateFailException e) { + creationFailuresDetected++; + checkCreateFailureId(e.resourceId(), createFailureId); + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap); + } catch (Resource.CloseFailException e) { + throw new AssertionError("Secondary exception suppression failed"); + } + checkForSingleCreationFailure(creationFailuresDetected); + checkClosedList(closedList, createFailureId); + } + } + } + + public static void testCreateFailure2Nested() { + for (int createFailureId = 0; createFailureId < 2; createFailureId++) { + for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) { + int creationFailuresDetected = 0; + List closedList = new ArrayList(); + try (Resource r0 = createResource(0, createFailureId, bitMap, closedList)) { + try(Resource r1 = createResource(1, createFailureId, bitMap, closedList)) { + throw new AssertionError("Entire resource creation succeeded"); + } + } catch (Resource.CreateFailException e) { + creationFailuresDetected++; + checkCreateFailureId(e.resourceId(), createFailureId); + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap); + } catch (Resource.CloseFailException e) { + throw new AssertionError("Secondary exception suppression failed"); + } + checkForSingleCreationFailure(creationFailuresDetected); + checkClosedList(closedList, createFailureId); + } + } + } + + public static void testCreateFailure3() { + for (int createFailureId = 0; createFailureId < 3; createFailureId++) { + for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) { + int creationFailuresDetected = 0; + List closedList = new ArrayList(); + try (Resource r0 = createResource(0, createFailureId, bitMap, closedList); + Resource r1 = createResource(1, createFailureId, bitMap, closedList); + Resource r2 = createResource(2, createFailureId, bitMap, closedList)) { + throw new AssertionError("Entire resource creation succeeded"); + } catch (Resource.CreateFailException e) { + creationFailuresDetected++; + checkCreateFailureId(e.resourceId(), createFailureId); + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap); + } catch (Resource.CloseFailException e) { + throw new AssertionError("Secondary exception suppression failed:" + e); + } + checkForSingleCreationFailure(creationFailuresDetected); + checkClosedList(closedList, createFailureId); + } + } + } + + public static void testCreateFailure3Nested() { + for (int createFailureId = 0; createFailureId < 3; createFailureId++) { + for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) { + int creationFailuresDetected = 0; + List closedList = new ArrayList(); + try (Resource r0 = createResource(0, createFailureId, bitMap, closedList)) { + try (Resource r1 = createResource(1, createFailureId, bitMap, closedList)) { + try (Resource r2 = createResource(2, createFailureId, bitMap, closedList)) { + throw new AssertionError("Entire resource creation succeeded"); + } + } + } catch (Resource.CreateFailException e) { + creationFailuresDetected++; + checkCreateFailureId(e.resourceId(), createFailureId); + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap); + } catch (Resource.CloseFailException e) { + throw new AssertionError("Secondary exception suppression failed:" + e); + } + checkForSingleCreationFailure(creationFailuresDetected); + checkClosedList(closedList, createFailureId); + } + } + } + + public static void testCreateFailure4() { + for (int createFailureId = 0; createFailureId < 4; createFailureId++) { + for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) { + int creationFailuresDetected = 0; + List closedList = new ArrayList(); + try (Resource r0 = createResource(0, createFailureId, bitMap, closedList); + Resource r1 = createResource(1, createFailureId, bitMap, closedList); + Resource r2 = createResource(2, createFailureId, bitMap, closedList); + Resource r3 = createResource(3, createFailureId, bitMap, closedList)) { + throw new AssertionError("Entire resource creation succeeded"); + } catch (Resource.CreateFailException e) { + creationFailuresDetected++; + checkCreateFailureId(e.resourceId(), createFailureId); + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap); + } catch (Resource.CloseFailException e) { + throw new AssertionError("Secondary exception suppression failed:" + e); + } + checkForSingleCreationFailure(creationFailuresDetected); + checkClosedList(closedList, createFailureId); + } + } + } + + public static void testCreateFailure4Nested() { + for (int createFailureId = 0; createFailureId < 4; createFailureId++) { + for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) { + int creationFailuresDetected = 0; + List closedList = new ArrayList(); + try (Resource r0 = createResource(0, createFailureId, bitMap, closedList)) { + try (Resource r1 = createResource(1, createFailureId, bitMap, closedList)) { + try (Resource r2 = createResource(2, createFailureId, bitMap, closedList)) { + try (Resource r3 = createResource(3, createFailureId, bitMap, closedList)) { + throw new AssertionError("Entire resource creation succeeded"); + } + } + } + } catch (Resource.CreateFailException e) { + creationFailuresDetected++; + checkCreateFailureId(e.resourceId(), createFailureId); + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap); + } catch (Resource.CloseFailException e) { + throw new AssertionError("Secondary exception suppression failed:" + e); + } + checkForSingleCreationFailure(creationFailuresDetected); + checkClosedList(closedList, createFailureId); + } + } + } + + public static void testCreateFailure5() { + for (int createFailureId = 0; createFailureId < 5; createFailureId++) { + for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) { + int creationFailuresDetected = 0; + List closedList = new ArrayList(); + try (Resource r0 = createResource(0, createFailureId, bitMap, closedList); + Resource r1 = createResource(1, createFailureId, bitMap, closedList); + Resource r2 = createResource(2, createFailureId, bitMap, closedList); + Resource r3 = createResource(3, createFailureId, bitMap, closedList); + Resource r4 = createResource(4, createFailureId, bitMap, closedList)) { + throw new AssertionError("Entire resource creation succeeded"); + } catch (Resource.CreateFailException e) { + creationFailuresDetected++; + checkCreateFailureId(e.resourceId(), createFailureId); + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap); + } catch (Resource.CloseFailException e) { + throw new AssertionError("Secondary exception suppression failed:" + e); + } + checkForSingleCreationFailure(creationFailuresDetected); + checkClosedList(closedList, createFailureId); + } + } + } + + public static void testCreateFailure5Nested() { + for (int createFailureId = 0; createFailureId < 5; createFailureId++) { + for (int bitMap = 0, n = 1 << createFailureId; bitMap < n; bitMap++) { + int creationFailuresDetected = 0; + List closedList = new ArrayList(); + try (Resource r0 = createResource(0, createFailureId, bitMap, closedList)) { + try (Resource r1 = createResource(1, createFailureId, bitMap, closedList)) { + try (Resource r2 = createResource(2, createFailureId, bitMap, closedList)) { + try (Resource r3 = createResource(3, createFailureId, bitMap, closedList)) { + try (Resource r4 = createResource(4, createFailureId, bitMap, closedList)) { + throw new AssertionError("Entire resource creation succeeded"); + } + } + } + } + } catch (Resource.CreateFailException e) { + creationFailuresDetected++; + checkCreateFailureId(e.resourceId(), createFailureId); + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap); + } catch (Resource.CloseFailException e) { + throw new AssertionError("Secondary exception suppression failed:" + e); + } + checkForSingleCreationFailure(creationFailuresDetected); + checkClosedList(closedList, createFailureId); + } + } + } + + /** + * Create a resource with the specified ID. The ID must be less than createFailureId. + * A subsequent attempt to close the resource will fail iff the corresponding bit + * is set in closeFailureBitMap. When an attempt is made to close this resource, + * its ID will be added to closedList, regardless of whether the attempt succeeds. + * + * @param id the ID of this resource + * @param createFailureId the ID of the resource whose creation will fail + * @param closeFailureBitMap a bit vector describing which resources should throw an + * exception when close is attempted + * @param closedList a list on which to record resource close attempts + * @throws AssertionError if no attempt should be made to create this resource + */ + private static Resource createResource(int id, + int createFailureId, + int closeFailureBitMap, + List closedList) throws Resource.CreateFailException { + if (id > createFailureId) + throw new AssertionError("Resource " + id + " shouldn't be created"); + boolean createSucceeds = id != createFailureId; + boolean closeSucceeds = (closeFailureBitMap & (1 << id)) == 0; + return new Resource(id, createSucceeds, closeSucceeds, closedList); + } + + + /** + * Check that an observed creation failure has the expected resource ID. + * + * @param foundId the ID of the resource whose creation failed + * @param expectedId the ID of the resource whose creation should have failed + */ + private static void checkCreateFailureId(int foundId, int expectedId) { + if (foundId != expectedId) + throw new AssertionError("Wrong resource creation failed. Found ID " + + foundId + " expected " + expectedId); + } + + /** + * Check for proper suppressed exceptions in proper order. + * + * @param suppressedExceptions the suppressed exceptions array returned by + * getSuppressedExceptions() + * @bitmap a bitmap indicating which suppressed exceptions are expected. + * Bit i is set iff id should throw a CloseFailException. + */ + private static void checkSuppressedExceptions(Throwable[] suppressedExceptions, int bitMap) { + if (suppressedExceptions.length != Integer.bitCount(bitMap)) + throw new AssertionError("Expected " + Integer.bitCount(bitMap) + + " suppressed exceptions, got " + suppressedExceptions.length); + + int prevCloseFailExceptionId = Integer.MAX_VALUE; + for (Throwable t : suppressedExceptions) { + int id = ((Resource.CloseFailException) t).resourceId(); + if ((1 << id & bitMap) == 0) + throw new AssertionError("Unexpected suppressed CloseFailException: " + id); + if (id > prevCloseFailExceptionId) + throw new AssertionError("Suppressed CloseFailException" + id + + " followed " + prevCloseFailExceptionId); + } + } + + /** + * Check that exactly one resource creation failed. + * + * @param numCreationFailuresDetected the number of creation failures detected + */ + private static void checkForSingleCreationFailure(int numCreationFailuresDetected) { + if (numCreationFailuresDetected != 1) + throw new AssertionError("Wrong number of creation failures: " + + numCreationFailuresDetected); + } + + /** + * Check that a close was attempted on every resourced that was successfully opened, + * and that the close attempts occurred in the proper order. + * + * @param closedList the resource IDs of the close attempts, in the order they occurred + * @param the ID of the resource whose creation failed. Close attempts should occur + * for all previous resources, in reverse order. + */ + private static void checkClosedList(List closedList, int createFailureId) { + List expectedList = new ArrayList(createFailureId); + for (int i = createFailureId - 1; i >= 0; i--) + expectedList.add(i); + if (!closedList.equals(expectedList)) + throw new AssertionError("Closing sequence " + closedList + " != " + expectedList); + } + + /* + * The following tests simulate the creation of several resources, followed + * by success or failure of forward processing. They test that all resources + * are properly closed, even if one or more of the close attempts fails. + */ + + public static void testCreateSuccess1() { + for (int bitMap = 0, n = 1 << 1; bitMap < n; bitMap++) { + for (int failure = 0; failure < 2; failure++) { + List closedList = new ArrayList(); + try (Resource r0 = createResource(0, bitMap, closedList)) { + if (failure != 0) + throw new MyKindOfException(); + } catch (Resource.CreateFailException e) { + throw new AssertionError( + "Resource creation failed: " + e.resourceId()); + } catch (MyKindOfException e) { + if (failure == 0) + throw new AssertionError("Unexpected MyKindOfException"); + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap); + } catch (Resource.CloseFailException e) { + if (failure == 1) + throw new AssertionError("Secondary exception suppression failed"); + int id = e.resourceId(); + if (bitMap == 0) + throw new AssertionError("Unexpected CloseFailException: " + id); + int highestCloseFailBit = Integer.highestOneBit(bitMap); + if (1 << id != highestCloseFailBit) { + throw new AssertionError("CloseFailException: got id " + id + + ", expected lg(" + highestCloseFailBit +")"); + } + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit); + } + checkClosedList(closedList, 1); + } + } + } + + public static void testCreateSuccess2() { + for (int bitMap = 0, n = 1 << 2; bitMap < n; bitMap++) { + for (int failure = 0; failure < 2; failure++) { + List closedList = new ArrayList(); + try (Resource r0 = createResource(0, bitMap, closedList); + Resource r1 = createResource(1, bitMap, closedList)) { + if (failure != 0) + throw new MyKindOfException(); + } catch (Resource.CreateFailException e) { + throw new AssertionError( + "Resource creation failed: " + e.resourceId()); + } catch (MyKindOfException e) { + if (failure == 0) + throw new AssertionError("Unexpected MyKindOfException"); + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap); + } catch (Resource.CloseFailException e) { + if (failure == 1) + throw new AssertionError("Secondary exception suppression failed"); + int id = e.resourceId(); + if (bitMap == 0) + throw new AssertionError("Unexpected CloseFailException: " + id); + int highestCloseFailBit = Integer.highestOneBit(bitMap); + if (1 << id != highestCloseFailBit) { + throw new AssertionError("CloseFailException: got id " + id + + ", expected lg(" + highestCloseFailBit +")"); + } + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit); + } + checkClosedList(closedList, 2); + } + } + } + + public static void testCreateSuccess2Nested() { + for (int bitMap = 0, n = 1 << 2; bitMap < n; bitMap++) { + for (int failure = 0; failure < 2; failure++) { + List closedList = new ArrayList(); + try (Resource r0 = createResource(0, bitMap, closedList)) { + try (Resource r1 = createResource(1, bitMap, closedList)) { + if (failure != 0) + throw new MyKindOfException(); + } + } catch (Resource.CreateFailException e) { + throw new AssertionError( + "Resource creation failed: " + e.resourceId()); + } catch (MyKindOfException e) { + if (failure == 0) + throw new AssertionError("Unexpected MyKindOfException"); + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap); + } catch (Resource.CloseFailException e) { + if (failure == 1) + throw new AssertionError("Secondary exception suppression failed"); + int id = e.resourceId(); + if (bitMap == 0) + throw new AssertionError("Unexpected CloseFailException: " + id); + int highestCloseFailBit = Integer.highestOneBit(bitMap); + if (1 << id != highestCloseFailBit) { + throw new AssertionError("CloseFailException: got id " + id + + ", expected lg(" + highestCloseFailBit +")"); + } + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit); + } + checkClosedList(closedList, 2); + } + } + } + + public static void testCreateSuccess3() { + for (int bitMap = 0, n = 1 << 3; bitMap < n; bitMap++) { + for (int failure = 0; failure < 2; failure++) { + List closedList = new ArrayList(); + try (Resource r0 = createResource(0, bitMap, closedList); + Resource r1 = createResource(1, bitMap, closedList); + Resource r2 = createResource(2, bitMap, closedList)) { + if (failure != 0) + throw new MyKindOfException(); + } catch (Resource.CreateFailException e) { + throw new AssertionError( + "Resource creation failed: " + e.resourceId()); + } catch (MyKindOfException e) { + if (failure == 0) + throw new AssertionError("Unexpected MyKindOfException"); + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap); + } catch (Resource.CloseFailException e) { + if (failure == 1) + throw new AssertionError("Secondary exception suppression failed"); + int id = e.resourceId(); + if (bitMap == 0) + throw new AssertionError("Unexpected CloseFailException: " + id); + int highestCloseFailBit = Integer.highestOneBit(bitMap); + if (1 << id != highestCloseFailBit) { + throw new AssertionError("CloseFailException: got id " + id + + ", expected lg(" + highestCloseFailBit +")"); + } + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit); + } + checkClosedList(closedList, 3); + } + } + } + + public static void testCreateSuccess3Nested() { + for (int bitMap = 0, n = 1 << 3; bitMap < n; bitMap++) { + for (int failure = 0; failure < 2; failure++) { + List closedList = new ArrayList(); + try (Resource r0 = createResource(0, bitMap, closedList)) { + try (Resource r1 = createResource(1, bitMap, closedList)) { + try (Resource r2 = createResource(2, bitMap, closedList)) { + if (failure != 0) + throw new MyKindOfException(); + } + } + } catch (Resource.CreateFailException e) { + throw new AssertionError( + "Resource creation failed: " + e.resourceId()); + } catch (MyKindOfException e) { + if (failure == 0) + throw new AssertionError("Unexpected MyKindOfException"); + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap); + } catch (Resource.CloseFailException e) { + if (failure == 1) + throw new AssertionError("Secondary exception suppression failed"); + int id = e.resourceId(); + if (bitMap == 0) + throw new AssertionError("Unexpected CloseFailException: " + id); + int highestCloseFailBit = Integer.highestOneBit(bitMap); + if (1 << id != highestCloseFailBit) { + throw new AssertionError("CloseFailException: got id " + id + + ", expected lg(" + highestCloseFailBit +")"); + } + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit); + } + checkClosedList(closedList, 3); + } + } + } + + public static void testCreateSuccess4() { + for (int bitMap = 0, n = 1 << 4; bitMap < n; bitMap++) { + for (int failure = 0; failure < 2; failure++) { + List closedList = new ArrayList(); + try (Resource r0 = createResource(0, bitMap, closedList); + Resource r1 = createResource(1, bitMap, closedList); + Resource r2 = createResource(2, bitMap, closedList); + Resource r3 = createResource(3, bitMap, closedList)) { + if (failure != 0) + throw new MyKindOfException(); + } catch (Resource.CreateFailException e) { + throw new AssertionError( + "Resource creation failed: " + e.resourceId()); + } catch (MyKindOfException e) { + if (failure == 0) + throw new AssertionError("Unexpected MyKindOfException"); + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap); + } catch (Resource.CloseFailException e) { + if (failure == 1) + throw new AssertionError("Secondary exception suppression failed"); + int id = e.resourceId(); + if (bitMap == 0) + throw new AssertionError("Unexpected CloseFailException: " + id); + int highestCloseFailBit = Integer.highestOneBit(bitMap); + if (1 << id != highestCloseFailBit) { + throw new AssertionError("CloseFailException: got id " + id + + ", expected lg(" + highestCloseFailBit +")"); + } + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit); + } + checkClosedList(closedList, 4); + } + } + } + + public static void testCreateSuccess4Nested() { + for (int bitMap = 0, n = 1 << 4; bitMap < n; bitMap++) { + for (int failure = 0; failure < 2; failure++) { + List closedList = new ArrayList(); + try (Resource r0 = createResource(0, bitMap, closedList)) { + try (Resource r1 = createResource(1, bitMap, closedList)) { + try (Resource r2 = createResource(2, bitMap, closedList)) { + try (Resource r3 = createResource(3, bitMap, closedList)) { + if (failure != 0) + throw new MyKindOfException(); + } + } + } + } catch (Resource.CreateFailException e) { + throw new AssertionError( + "Resource creation failed: " + e.resourceId()); + } catch (MyKindOfException e) { + if (failure == 0) + throw new AssertionError("Unexpected MyKindOfException"); + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap); + } catch (Resource.CloseFailException e) { + if (failure == 1) + throw new AssertionError("Secondary exception suppression failed"); + int id = e.resourceId(); + if (bitMap == 0) + throw new AssertionError("Unexpected CloseFailException: " + id); + int highestCloseFailBit = Integer.highestOneBit(bitMap); + if (1 << id != highestCloseFailBit) { + throw new AssertionError("CloseFailException: got id " + id + + ", expected lg(" + highestCloseFailBit +")"); + } + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit); + } + checkClosedList(closedList, 4); + } + } + } + + public static void testCreateSuccess5() { + for (int bitMap = 0, n = 1 << 5; bitMap < n; bitMap++) { + for (int failure = 0; failure < 2; failure++) { + List closedList = new ArrayList(); + try (Resource r0 = createResource(0, bitMap, closedList); + Resource r1 = createResource(1, bitMap, closedList); + Resource r2 = createResource(2, bitMap, closedList); + Resource r3 = createResource(3, bitMap, closedList); + Resource r4 = createResource(4, bitMap, closedList)) { + if (failure != 0) + throw new MyKindOfException(); + } catch (Resource.CreateFailException e) { + throw new AssertionError("Resource creation failed: " + e.resourceId()); + } catch (MyKindOfException e) { + if (failure == 0) + throw new AssertionError("Unexpected MyKindOfException"); + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap); + } catch (Resource.CloseFailException e) { + if (failure == 1) + throw new AssertionError("Secondary exception suppression failed"); + int id = e.resourceId(); + if (bitMap == 0) + throw new AssertionError("Unexpected CloseFailException: " + id); + int highestCloseFailBit = Integer.highestOneBit(bitMap); + if (1 << id != highestCloseFailBit) { + throw new AssertionError("CloseFailException: got id " + id + + ", expected lg(" + highestCloseFailBit +")"); + } + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit); + } + checkClosedList(closedList, 5); + } + } + } + + public static void testCreateSuccess5Nested() { + for (int bitMap = 0, n = 1 << 5; bitMap < n; bitMap++) { + for (int failure = 0; failure < 2; failure++) { + List closedList = new ArrayList(); + try (Resource r0 = createResource(0, bitMap, closedList)) { + try (Resource r1 = createResource(1, bitMap, closedList)) { + try (Resource r2 = createResource(2, bitMap, closedList)) { + try (Resource r3 = createResource(3, bitMap, closedList)) { + try (Resource r4 = createResource(4, bitMap, closedList)) { + if (failure != 0) + throw new MyKindOfException(); + } + } + } + } + } catch (Resource.CreateFailException e) { + throw new AssertionError("Resource creation failed: " + e.resourceId()); + } catch (MyKindOfException e) { + if (failure == 0) + throw new AssertionError("Unexpected MyKindOfException"); + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap); + } catch (Resource.CloseFailException e) { + if (failure == 1) + throw new AssertionError("Secondary exception suppression failed"); + int id = e.resourceId(); + if (bitMap == 0) + throw new AssertionError("Unexpected CloseFailException: " + id); + int highestCloseFailBit = Integer.highestOneBit(bitMap); + if (1 << id != highestCloseFailBit) { + throw new AssertionError("CloseFailException: got id " + id + + ", expected lg(" + highestCloseFailBit +")"); + } + checkSuppressedExceptions(e.getSuppressedExceptions(), bitMap & ~highestCloseFailBit); + } + checkClosedList(closedList, 5); + } + } + } + + private static Resource createResource(int id, + int closeFailureBitMap, + List closedList) throws Resource.CreateFailException { + boolean closeSucceeds = (closeFailureBitMap & (1 << id)) == 0; + return new Resource(id, true, closeSucceeds, closedList); + } + + private static class MyKindOfException extends Exception { + } +} + +class Resource implements AutoCloseable { + /** A number identifying this resource */ + private final int resourceId; + + /** Whether the close call on this resource should succeed or fail */ + private final boolean closeSucceeds; + + /** When resource is closed, it records its ID in this list */ + private final List closedList; + + Resource(int resourceId, boolean createSucceeds, boolean closeSucceeds, + List closedList) throws CreateFailException { + if (!createSucceeds) + throw new CreateFailException(resourceId); + this.resourceId = resourceId; + this.closeSucceeds = closeSucceeds; + this.closedList = closedList; + } + + public void close() throws CloseFailException { + closedList.add(resourceId); + if (!closeSucceeds) + throw new CloseFailException(resourceId); + } + + public static class ResourceException extends RuntimeException { + private final int resourceId; + + public ResourceException(int resourceId) { + super("Resource ID = " + resourceId); + this.resourceId = resourceId; + } + + public int resourceId() { + return resourceId; + } + } + + public static class CreateFailException extends ResourceException { + public CreateFailException(int resourceId) { + super(resourceId); + } + } + + public static class CloseFailException extends ResourceException { + public CloseFailException(int resourceId) { + super(resourceId); + } + } +} diff --git a/langtools/test/tools/javac/TryWithResources/WeirdTwr.java b/langtools/test/tools/javac/TryWithResources/WeirdTwr.java new file mode 100644 index 00000000000..7092986ffd3 --- /dev/null +++ b/langtools/test/tools/javac/TryWithResources/WeirdTwr.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6911256 6964740 + * @author Joseph D. Darcy + * @summary Strange TWRs + * @compile/fail -source 6 WeirdTwr.java + * @compile WeirdTwr.java + * @run main WeirdTwr + */ + +public class WeirdTwr implements AutoCloseable { + private static int closeCount = 0; + public static void main(String... args) { + try(WeirdTwr r1 = new WeirdTwr(); WeirdTwr r2 = r1) { + if (r1 != r2) + throw new RuntimeException("Unexpected inequality."); + } + if (closeCount != 2) + throw new RuntimeException("bad closeCount" + closeCount); + } + + public void close() { + closeCount++; + } +} diff --git a/langtools/test/tools/javac/processing/model/element/TestResourceVariable.java b/langtools/test/tools/javac/processing/model/element/TestResourceVariable.java new file mode 100644 index 00000000000..45829b46e33 --- /dev/null +++ b/langtools/test/tools/javac/processing/model/element/TestResourceVariable.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6911256 6964740 + * @summary Test that the resource variable kind is appropriately set + * @author Joseph D. Darcy + * @build TestResourceVariable + * @compile/fail -processor TestResourceVariable -proc:only TestResourceVariable.java + */ + +// Bug should be filed for this misbehavior + +import java.io.*; +import javax.annotation.processing.*; +import javax.lang.model.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; +import java.util.*; +import com.sun.source.tree.*; +import com.sun.source.util.*; +import static javax.tools.Diagnostic.Kind.*; + +/** + * Using the tree API, retrieve element representations of the + * resource of an ARM block and verify their kind tags are set + * appropriately. + */ +@SupportedAnnotationTypes("*") +public class TestResourceVariable extends AbstractProcessor implements AutoCloseable { + int resourceVariableCount = 0; + + public boolean process(Set annotations, + RoundEnvironment roundEnv) { + if (!roundEnv.processingOver()) { + Trees trees = Trees.instance(processingEnv); + + for(Element rootElement : roundEnv.getRootElements()) { + TreePath treePath = trees.getPath(rootElement); + + (new ResourceVariableScanner(trees)). + scan(trees.getTree(rootElement), + treePath.getCompilationUnit()); + } + if (resourceVariableCount != 3) + throw new RuntimeException("Bad resource variable count " + + resourceVariableCount); + } + return true; + } + + @Override + public void close() {} + + private void test1() { + try(TestResourceVariable trv = this) {} + } + + private void test2() { + try(TestResourceVariable trv1 = this; TestResourceVariable trv2 = trv1) {} + } + + class ResourceVariableScanner extends TreeScanner { + private Trees trees; + + public ResourceVariableScanner(Trees trees) { + super(); + this.trees = trees; + } + @Override + public Void visitVariable(VariableTree node, CompilationUnitTree cu) { + Element element = trees.getElement(trees.getPath(cu, node)); + if (element == null) { + System.out.println("Null variable element: " + node); + } else { + System.out.println("Name: " + element.getSimpleName() + + "\tKind: " + element.getKind()); + } + if (element != null && + element.getKind() == ElementKind.RESOURCE_VARIABLE) { + resourceVariableCount++; + } + return super.visitVariable(node, cu); + } + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } +} From daf491a814c75a35085a2f55915daac25c6438a3 Mon Sep 17 00:00:00 2001 From: John Coomes Date: Fri, 16 Jul 2010 21:33:21 -0700 Subject: [PATCH 12/52] 6962947: shared TaskQueue statistics Reviewed-by: tonyp, ysr --- .../concurrentMarkSweepGeneration.cpp | 13 +-- .../parNew/parNewGeneration.cpp | 7 +- .../parNew/parNewGeneration.hpp | 12 +-- .../parNew/parOopClosures.hpp | 5 +- .../parallelScavenge/psPromotionManager.cpp | 92 +++++++++---------- .../parallelScavenge/psPromotionManager.hpp | 65 +++---------- .../psPromotionManager.inline.hpp | 10 +- .../parallelScavenge/psTasks.cpp | 9 +- .../share/vm/utilities/globalDefinitions.hpp | 31 ++++++- hotspot/src/share/vm/utilities/taskqueue.cpp | 42 +++++++++ hotspot/src/share/vm/utilities/taskqueue.hpp | 87 +++++++++++++++++- 11 files changed, 236 insertions(+), 137 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index 0aa08ec3018..1fac91a5466 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -664,19 +664,14 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen, return; } - // XXX use a global constant instead of 64! - typedef struct OopTaskQueuePadded { - OopTaskQueue work_queue; - char pad[64 - sizeof(OopTaskQueue)]; // prevent false sharing - } OopTaskQueuePadded; - + typedef Padded PaddedOopTaskQueue; for (i = 0; i < num_queues; i++) { - OopTaskQueuePadded *q_padded = new OopTaskQueuePadded(); - if (q_padded == NULL) { + PaddedOopTaskQueue *q = new PaddedOopTaskQueue(); + if (q == NULL) { warning("work_queue allocation failure."); return; } - _task_queues->register_queue(i, &q_padded->work_queue); + _task_queues->register_queue(i, q); } for (i = 0; i < num_queues; i++) { _task_queues->queue(i)->initialize(); diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp index 250d244d25a..dc655aed136 100644 --- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp @@ -539,10 +539,9 @@ ParNewGeneration(ReservedSpace rs, size_t initial_byte_size, int level) guarantee(_task_queues != NULL, "task_queues allocation failure."); for (uint i1 = 0; i1 < ParallelGCThreads; i1++) { - ObjToScanQueuePadded *q_padded = new ObjToScanQueuePadded(); - guarantee(q_padded != NULL, "work_queue Allocation failure."); - - _task_queues->register_queue(i1, &q_padded->work_queue); + ObjToScanQueue *q = new ObjToScanQueue(); + guarantee(q != NULL, "work_queue Allocation failure."); + _task_queues->register_queue(i1, q); } for (uint i2 = 0; i2 < ParallelGCThreads; i2++) diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp index afbab7b99c5..8196e621372 100644 --- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp +++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,8 +33,8 @@ class ParEvacuateFollowersClosure; // but they must be here to allow ParScanClosure::do_oop_work to be defined // in genOopClosures.inline.hpp. -typedef OopTaskQueue ObjToScanQueue; -typedef OopTaskQueueSet ObjToScanQueueSet; +typedef Padded ObjToScanQueue; +typedef GenericTaskQueueSet ObjToScanQueueSet; // Enable this to get push/pop/steal stats. const int PAR_STATS_ENABLED = 0; @@ -304,12 +304,6 @@ class ParNewGeneration: public DefNewGeneration { friend class ParEvacuateFollowersClosure; private: - // XXX use a global constant instead of 64! - struct ObjToScanQueuePadded { - ObjToScanQueue work_queue; - char pad[64 - sizeof(ObjToScanQueue)]; // prevent false sharing - }; - // The per-worker-thread work queues ObjToScanQueueSet* _task_queues; diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parOopClosures.hpp b/hotspot/src/share/vm/gc_implementation/parNew/parOopClosures.hpp index f261f31b752..c6a2543d0f5 100644 --- a/hotspot/src/share/vm/gc_implementation/parNew/parOopClosures.hpp +++ b/hotspot/src/share/vm/gc_implementation/parNew/parOopClosures.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,8 @@ class ParScanThreadState; class ParNewGeneration; -typedef OopTaskQueueSet ObjToScanQueueSet; +typedef Padded ObjToScanQueue; +typedef GenericTaskQueueSet ObjToScanQueueSet; class ParallelTaskTerminator; class ParScanClosure: public OopsInGenClosure { diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp index 8453ce9185e..2da32555dee 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp @@ -90,10 +90,7 @@ void PSPromotionManager::pre_scavenge() { } void PSPromotionManager::post_scavenge() { -#if PS_PM_STATS - print_stats(); -#endif // PS_PM_STATS - + TASKQUEUE_STATS_ONLY(if (PrintGCDetails && ParallelGCVerbose) print_stats()); for (uint i = 0; i < ParallelGCThreads + 1; i++) { PSPromotionManager* manager = manager_array(i); if (UseDepthFirstScavengeOrder) { @@ -105,37 +102,58 @@ void PSPromotionManager::post_scavenge() { } } -#if PS_PM_STATS +#if TASKQUEUE_STATS +void +PSPromotionManager::print_taskqueue_stats(uint i) const { + const TaskQueueStats& stats = depth_first() ? + _claimed_stack_depth.stats : _claimed_stack_breadth.stats; + tty->print("%3u ", i); + stats.print(); + tty->cr(); +} void -PSPromotionManager::print_stats(uint i) { - tty->print_cr("---- GC Worker %2d Stats", i); - tty->print_cr(" total pushes %8d", _total_pushes); - tty->print_cr(" masked pushes %8d", _masked_pushes); - tty->print_cr(" overflow pushes %8d", _overflow_pushes); - tty->print_cr(" max overflow length %8d", _max_overflow_length); - tty->print_cr(""); - tty->print_cr(" arrays chunked %8d", _arrays_chunked); - tty->print_cr(" array chunks processed %8d", _array_chunks_processed); - tty->print_cr(""); - tty->print_cr(" total steals %8d", _total_steals); - tty->print_cr(" masked steals %8d", _masked_steals); - tty->print_cr(""); +PSPromotionManager::print_local_stats(uint i) const { + #define FMT " " SIZE_FORMAT_W(10) + tty->print_cr("%3u" FMT FMT FMT FMT, i, _masked_pushes, _masked_steals, + _arrays_chunked, _array_chunks_processed); + #undef FMT } +static const char* const pm_stats_hdr[] = { + " --------masked------- arrays array", + "thr push steal chunked chunks", + "--- ---------- ---------- ---------- ----------" +}; + void PSPromotionManager::print_stats() { - tty->print_cr("== GC Tasks Stats (%s), GC %3d", - (UseDepthFirstScavengeOrder) ? "Depth-First" : "Breadth-First", + const bool df = UseDepthFirstScavengeOrder; + tty->print_cr("== GC Task Stats (%s-First), GC %3d", df ? "Depth" : "Breadth", Universe::heap()->total_collections()); - for (uint i = 0; i < ParallelGCThreads+1; ++i) { - PSPromotionManager* manager = manager_array(i); - manager->print_stats(i); + tty->print("thr "); TaskQueueStats::print_header(1); tty->cr(); + tty->print("--- "); TaskQueueStats::print_header(2); tty->cr(); + for (uint i = 0; i < ParallelGCThreads + 1; ++i) { + manager_array(i)->print_taskqueue_stats(i); + } + + const uint hlines = sizeof(pm_stats_hdr) / sizeof(pm_stats_hdr[0]); + for (uint i = 0; i < hlines; ++i) tty->print_cr(pm_stats_hdr[i]); + for (uint i = 0; i < ParallelGCThreads + 1; ++i) { + manager_array(i)->print_local_stats(i); } } -#endif // PS_PM_STATS +void +PSPromotionManager::reset_stats() { + TaskQueueStats& stats = depth_first() ? + claimed_stack_depth()->stats : claimed_stack_breadth()->stats; + stats.reset(); + _masked_pushes = _masked_steals = 0; + _arrays_chunked = _array_chunks_processed = 0; +} +#endif // TASKQUEUE_STATS PSPromotionManager::PSPromotionManager() { ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); @@ -189,16 +207,7 @@ void PSPromotionManager::reset() { _prefetch_queue.clear(); -#if PS_PM_STATS - _total_pushes = 0; - _masked_pushes = 0; - _overflow_pushes = 0; - _max_overflow_length = 0; - _arrays_chunked = 0; - _array_chunks_processed = 0; - _total_steals = 0; - _masked_steals = 0; -#endif // PS_PM_STATS + TASKQUEUE_STATS_ONLY(reset_stats()); } @@ -423,14 +432,9 @@ oop PSPromotionManager::copy_to_survivor_space(oop o, bool depth_first) { new_obj->is_objArray() && PSChunkLargeArrays) { // we'll chunk it -#if PS_PM_STATS - ++_arrays_chunked; -#endif // PS_PM_STATS oop* const masked_o = mask_chunked_array_oop(o); push_depth(masked_o); -#if PS_PM_STATS - ++_masked_pushes; -#endif // PS_PM_STATS + TASKQUEUE_STATS_ONLY(++_arrays_chunked; ++_masked_pushes); } else { // we'll just push its contents new_obj->push_contents(this); @@ -494,9 +498,7 @@ void PSPromotionManager::process_array_chunk(oop old) { assert(old->is_objArray(), "invariant"); assert(old->is_forwarded(), "invariant"); -#if PS_PM_STATS - ++_array_chunks_processed; -#endif // PS_PM_STATS + TASKQUEUE_STATS_ONLY(++_array_chunks_processed); oop const obj = old->forwardee(); @@ -508,9 +510,7 @@ void PSPromotionManager::process_array_chunk(oop old) { assert(start > 0, "invariant"); arrayOop(old)->set_length(start); push_depth(mask_chunked_array_oop(old)); -#if PS_PM_STATS - ++_masked_pushes; -#endif // PS_PM_STATS + TASKQUEUE_STATS_ONLY(++_masked_pushes); } else { // this is the final chunk for this array start = 0; diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp index 07694fc94ce..ec89b9557bb 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp @@ -42,8 +42,6 @@ class MutableSpace; class PSOldGen; class ParCompactionManager; -#define PS_PM_STATS 0 - class PSPromotionManager : public CHeapObj { friend class PSScavenge; friend class PSRefProcTaskExecutor; @@ -54,22 +52,18 @@ class PSPromotionManager : public CHeapObj { static PSOldGen* _old_gen; static MutableSpace* _young_space; -#if PS_PM_STATS - uint _total_pushes; - uint _masked_pushes; +#if TASKQUEUE_STATS + size_t _masked_pushes; + size_t _masked_steals; + size_t _arrays_chunked; + size_t _array_chunks_processed; - uint _overflow_pushes; - uint _max_overflow_length; - - uint _arrays_chunked; - uint _array_chunks_processed; - - uint _total_steals; - uint _masked_steals; - - void print_stats(uint i); + void print_taskqueue_stats(uint i) const; + void print_local_stats(uint i) const; static void print_stats(); -#endif // PS_PM_STATS + + void reset_stats(); +#endif // TASKQUEUE_STATS PSYoungPromotionLAB _young_lab; PSOldPromotionLAB _old_lab; @@ -143,42 +137,12 @@ class PSPromotionManager : public CHeapObj { template void push_depth(T* p) { assert(depth_first(), "pre-condition"); - -#if PS_PM_STATS - ++_total_pushes; - int stack_length = claimed_stack_depth()->overflow_stack()->length(); -#endif // PS_PM_STATS - claimed_stack_depth()->push(p); - -#if PS_PM_STATS - if (claimed_stack_depth()->overflow_stack()->length() != stack_length) { - ++_overflow_pushes; - if ((uint)stack_length + 1 > _max_overflow_length) { - _max_overflow_length = (uint)stack_length + 1; - } - } -#endif // PS_PM_STATS } void push_breadth(oop o) { assert(!depth_first(), "pre-condition"); - -#if PS_PM_STATS - ++_total_pushes; - int stack_length = claimed_stack_breadth()->overflow_stack()->length(); -#endif // PS_PM_STATS - claimed_stack_breadth()->push(o); - -#if PS_PM_STATS - if (claimed_stack_breadth()->overflow_stack()->length() != stack_length) { - ++_overflow_pushes; - if ((uint)stack_length + 1 > _max_overflow_length) { - _max_overflow_length = (uint)stack_length + 1; - } - } -#endif // PS_PM_STATS } protected: @@ -256,12 +220,5 @@ class PSPromotionManager : public CHeapObj { template inline void claim_or_forward_depth(T* p); template inline void claim_or_forward_breadth(T* p); -#if PS_PM_STATS - void increment_steals(oop* p = NULL) { - _total_steals += 1; - if (p != NULL && is_oop_masked(p)) { - _masked_steals += 1; - } - } -#endif // PS_PM_STATS + TASKQUEUE_STATS_ONLY(inline void record_steal(StarTask& p);) }; diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp index 213f6261401..ea81c817b30 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -124,3 +124,11 @@ inline void PSPromotionManager::process_popped_location_depth(StarTask p) { } } } + +#if TASKQUEUE_STATS +void PSPromotionManager::record_steal(StarTask& p) { + if (is_oop_masked(p)) { + ++_masked_steals; + } +} +#endif // TASKQUEUE_STATS diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp index bbff68c6b2c..6f72724bfda 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -148,9 +148,7 @@ void StealTask::do_it(GCTaskManager* manager, uint which) { while(true) { StarTask p; if (PSPromotionManager::steal_depth(which, &random_seed, p)) { -#if PS_PM_STATS - pm->increment_steals(p); -#endif // PS_PM_STATS + TASKQUEUE_STATS_ONLY(pm->record_steal(p)); pm->process_popped_location_depth(p); pm->drain_stacks_depth(true); } else { @@ -163,9 +161,6 @@ void StealTask::do_it(GCTaskManager* manager, uint which) { while(true) { oop obj; if (PSPromotionManager::steal_breadth(which, &random_seed, obj)) { -#if PS_PM_STATS - pm->increment_steals(); -#endif // PS_PM_STATS obj->copy_contents(pm); pm->drain_stacks_breadth(true); } else { diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp index a5a8ae403d2..97d96c21f12 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -345,6 +345,35 @@ inline intptr_t align_object_offset(intptr_t offset) { return align_size_up(offset, HeapWordsPerLong); } +// The expected size in bytes of a cache line, used to pad data structures. +#define DEFAULT_CACHE_LINE_SIZE 64 + +// Bytes needed to pad type to avoid cache-line sharing; alignment should be the +// expected cache line size (a power of two). The first addend avoids sharing +// when the start address is not a multiple of alignment; the second maintains +// alignment of starting addresses that happen to be a multiple. +#define PADDING_SIZE(type, alignment) \ + ((alignment) + align_size_up_(sizeof(type), alignment)) + +// Templates to create a subclass padded to avoid cache line sharing. These are +// effective only when applied to derived-most (leaf) classes. + +// When no args are passed to the base ctor. +template +class Padded: public T { +private: + char _pad_buf_[PADDING_SIZE(T, alignment)]; +}; + +// When either 0 or 1 args may be passed to the base ctor. +template +class Padded01: public T { +public: + Padded01(): T() { } + Padded01(Arg1T arg1): T(arg1) { } +private: + char _pad_buf_[PADDING_SIZE(T, alignment)]; +}; //---------------------------------------------------------------------------------------------------- // Utility macros for compilers diff --git a/hotspot/src/share/vm/utilities/taskqueue.cpp b/hotspot/src/share/vm/utilities/taskqueue.cpp index 66571581e64..7a001803d96 100644 --- a/hotspot/src/share/vm/utilities/taskqueue.cpp +++ b/hotspot/src/share/vm/utilities/taskqueue.cpp @@ -31,6 +31,48 @@ uint ParallelTaskTerminator::_total_spins = 0; uint ParallelTaskTerminator::_total_peeks = 0; #endif +#if TASKQUEUE_STATS +const char * const TaskQueueStats::_names[last_stat_id] = { + "qpush", "qpop", "qpop-s", "qattempt", "qsteal", "opush", "omax" +}; + +void TaskQueueStats::print_header(unsigned int line, outputStream* const stream, + unsigned int width) +{ + // Use a width w: 1 <= w <= max_width + const unsigned int max_width = 40; + const unsigned int w = MAX2(MIN2(width, max_width), 1U); + + if (line == 0) { // spaces equal in width to the header + const unsigned int hdr_width = w * last_stat_id + last_stat_id - 1; + stream->print("%*s", hdr_width, " "); + } else if (line == 1) { // labels + stream->print("%*s", w, _names[0]); + for (unsigned int i = 1; i < last_stat_id; ++i) { + stream->print(" %*s", w, _names[i]); + } + } else if (line == 2) { // dashed lines + char dashes[max_width + 1]; + memset(dashes, '-', w); + dashes[w] = '\0'; + stream->print("%s", dashes); + for (unsigned int i = 1; i < last_stat_id; ++i) { + stream->print(" %s", dashes); + } + } +} + +void TaskQueueStats::print(outputStream* stream, unsigned int width) const +{ + #define FMT SIZE_FORMAT_W(*) + stream->print(FMT, width, _stats[0]); + for (unsigned int i = 1; i < last_stat_id; ++i) { + stream->print(" " FMT, width, _stats[i]); + } + #undef FMT +} +#endif // TASKQUEUE_STATS + int TaskQueueSetSuper::randomParkAndMiller(int *seed0) { const int a = 16807; const int m = 2147483647; diff --git a/hotspot/src/share/vm/utilities/taskqueue.hpp b/hotspot/src/share/vm/utilities/taskqueue.hpp index 2deba1b9edb..52e89fc8027 100644 --- a/hotspot/src/share/vm/utilities/taskqueue.hpp +++ b/hotspot/src/share/vm/utilities/taskqueue.hpp @@ -22,6 +22,72 @@ * */ +// Simple TaskQueue stats that are collected by default in debug builds. + +#if !defined(TASKQUEUE_STATS) && defined(ASSERT) +#define TASKQUEUE_STATS 1 +#elif !defined(TASKQUEUE_STATS) +#define TASKQUEUE_STATS 0 +#endif + +#if TASKQUEUE_STATS +#define TASKQUEUE_STATS_ONLY(code) code +#else +#define TASKQUEUE_STATS_ONLY(code) +#endif // TASKQUEUE_STATS + +#if TASKQUEUE_STATS +class TaskQueueStats { +public: + enum StatId { + push, // number of taskqueue pushes + pop, // number of taskqueue pops + pop_slow, // subset of taskqueue pops that were done slow-path + steal_attempt, // number of taskqueue steal attempts + steal, // number of taskqueue steals + overflow, // number of overflow pushes + overflow_max_len, // max length of overflow stack + last_stat_id + }; + +public: + inline TaskQueueStats() { reset(); } + + inline void record_push() { ++_stats[push]; } + inline void record_pop() { ++_stats[pop]; } + inline void record_pop_slow() { record_pop(); ++_stats[pop_slow]; } + inline void record_steal(bool success); + inline void record_overflow(size_t new_length); + + inline size_t get(StatId id) const { return _stats[id]; } + inline const size_t* get() const { return _stats; } + + inline void reset(); + + static void print_header(unsigned int line, outputStream* const stream = tty, + unsigned int width = 10); + void print(outputStream* const stream = tty, unsigned int width = 10) const; + +private: + size_t _stats[last_stat_id]; + static const char * const _names[last_stat_id]; +}; + +void TaskQueueStats::record_steal(bool success) { + ++_stats[steal_attempt]; + if (success) ++_stats[steal]; +} + +void TaskQueueStats::record_overflow(size_t new_len) { + ++_stats[overflow]; + if (new_len > _stats[overflow_max_len]) _stats[overflow_max_len] = new_len; +} + +void TaskQueueStats::reset() { + memset(_stats, 0, sizeof(_stats)); +} +#endif // TASKQUEUE_STATS + template class TaskQueueSuper: public CHeapObj { protected: @@ -135,6 +201,8 @@ public: // Total size of queue. static const uint total_size() { return N; } + + TASKQUEUE_STATS_ONLY(TaskQueueStats stats;) }; template @@ -152,6 +220,7 @@ protected: public: using TaskQueueSuper::max_elems; using TaskQueueSuper::size; + TASKQUEUE_STATS_ONLY(using TaskQueueSuper::stats;) private: // Slow paths for push, pop_local. (pop_global has no fast path.) @@ -224,14 +293,14 @@ bool GenericTaskQueue::push_slow(E t, uint dirty_n_elems) { // g++ complains if the volatile result of the assignment is unused. const_cast(_elems[localBot] = t); OrderAccess::release_store(&_bottom, increment_index(localBot)); + TASKQUEUE_STATS_ONLY(stats.record_push()); return true; } return false; } template -bool GenericTaskQueue:: -pop_local_slow(uint localBot, Age oldAge) { +bool GenericTaskQueue::pop_local_slow(uint localBot, Age oldAge) { // This queue was observed to contain exactly one element; either this // thread will claim it, or a competing "pop_global". In either case, // the queue will be logically empty afterwards. Create a new Age value @@ -251,6 +320,7 @@ pop_local_slow(uint localBot, Age oldAge) { if (tempAge == oldAge) { // We win. assert(dirty_size(localBot, _age.top()) != N - 1, "sanity"); + TASKQUEUE_STATS_ONLY(stats.record_pop_slow()); return true; } } @@ -306,6 +376,8 @@ public: typedef GrowableArray overflow_t; typedef GenericTaskQueue taskqueue_t; + TASKQUEUE_STATS_ONLY(using taskqueue_t::stats;) + OverflowTaskQueue(); ~OverflowTaskQueue(); void initialize(); @@ -356,6 +428,7 @@ bool OverflowTaskQueue::push(E t) { if (!taskqueue_t::push(t)) { overflow_stack()->push(t); + TASKQUEUE_STATS_ONLY(stats.record_overflow(overflow_stack()->length())); } return true; } @@ -424,9 +497,13 @@ GenericTaskQueueSet::queue(uint i) { template bool GenericTaskQueueSet::steal(uint queue_num, int* seed, E& t) { - for (uint i = 0; i < 2 * _n; i++) - if (steal_best_of_2(queue_num, seed, t)) + for (uint i = 0; i < 2 * _n; i++) { + if (steal_best_of_2(queue_num, seed, t)) { + TASKQUEUE_STATS_ONLY(queue(queue_num)->stats.record_steal(true)); return true; + } + } + TASKQUEUE_STATS_ONLY(queue(queue_num)->stats.record_steal(false)); return false; } @@ -574,6 +651,7 @@ GenericTaskQueue::push(E t) { // g++ complains if the volatile result of the assignment is unused. const_cast(_elems[localBot] = t); OrderAccess::release_store(&_bottom, increment_index(localBot)); + TASKQUEUE_STATS_ONLY(stats.record_push()); return true; } else { return push_slow(t, dirty_n_elems); @@ -603,6 +681,7 @@ GenericTaskQueue::pop_local(E& t) { idx_t tp = _age.top(); // XXX if (size(localBot, tp) > 0) { assert(dirty_size(localBot, tp) != N - 1, "sanity"); + TASKQUEUE_STATS_ONLY(stats.record_pop()); return true; } else { // Otherwise, the queue contained exactly one element; we take the slow From 5c3da1ee7eecc8f6e4eafedaaa1b5304c57799c5 Mon Sep 17 00:00:00 2001 From: John Cuthbertson Date: Mon, 19 Jul 2010 11:06:34 -0700 Subject: [PATCH 13/52] 6956639: G1: assert(cached_ptr != card_ptr) failed: shouldn't be, concurrentG1Refine.cpp:307 During concurrent refinment, filter cards in young regions after it has been determined that the region has been allocated from and the young type of the region has been set. Reviewed-by: iveresov, tonyp, jcoomes --- .../g1/concurrentG1Refine.cpp | 64 ++++++++----------- .../gc_implementation/g1/g1CollectedHeap.cpp | 5 ++ .../vm/gc_implementation/g1/g1RemSet.cpp | 32 ++++++++-- .../vm/gc_implementation/g1/heapRegion.cpp | 13 +++- .../vm/gc_implementation/g1/heapRegion.hpp | 7 +- 5 files changed, 75 insertions(+), 46 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp index 7652a5f05e4..78d3d5cb2cd 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -271,21 +271,16 @@ jbyte* ConcurrentG1Refine::add_card_count(jbyte* card_ptr, int* count, bool* def if (cas_res == prev_epoch_entry) { // We successfully updated the card num value in the epoch entry count_ptr->_count = 0; // initialize counter for new card num + jbyte* old_card_ptr = card_num_2_ptr(old_card_num); // Even though the region containg the card at old_card_num was not // in the young list when old_card_num was recorded in the epoch // cache it could have been added to the free list and subsequently - // added to the young list in the intervening time. If the evicted - // card is in a young region just return the card_ptr and the evicted - // card will not be cleaned. See CR 6817995. - - jbyte* old_card_ptr = card_num_2_ptr(old_card_num); - if (is_young_card(old_card_ptr)) { - *count = 0; - // We can defer the processing of card_ptr - *defer = true; - return card_ptr; - } + // added to the young list in the intervening time. See CR 6817995. + // We do not deal with this case here - it will be handled in + // HeapRegion::oops_on_card_seq_iterate_careful after it has been + // determined that the region containing the card has been allocated + // to, and it's safe to check the young type of the region. // We do not want to defer processing of card_ptr in this case // (we need to refine old_card_ptr and card_ptr) @@ -301,22 +296,22 @@ jbyte* ConcurrentG1Refine::cache_insert(jbyte* card_ptr, bool* defer) { jbyte* cached_ptr = add_card_count(card_ptr, &count, defer); assert(cached_ptr != NULL, "bad cached card ptr"); - if (is_young_card(cached_ptr)) { - // The region containing cached_ptr has been freed during a clean up - // pause, reallocated, and tagged as young. - assert(cached_ptr != card_ptr, "shouldn't be"); + // We've just inserted a card pointer into the card count cache + // and got back the card that we just inserted or (evicted) the + // previous contents of that count slot. - // We've just inserted a new old-gen card pointer into the card count - // cache and evicted the previous contents of that count slot. - // The evicted card pointer has been determined to be in a young region - // and so cannot be the newly inserted card pointer (that will be - // in an old region). - // The count for newly inserted card will be set to zero during the - // insertion, so we don't want to defer the cleaning of the newly - // inserted card pointer. - assert(*defer == false, "deferring non-hot card"); - return NULL; - } + // The card we got back could be in a young region. When the + // returned card (if evicted) was originally inserted, we had + // determined that its containing region was not young. However + // it is possible for the region to be freed during a cleanup + // pause, then reallocated and tagged as young which will result + // in the returned card residing in a young region. + // + // We do not deal with this case here - the change from non-young + // to young could be observed at any time - it will be handled in + // HeapRegion::oops_on_card_seq_iterate_careful after it has been + // determined that the region containing the card has been allocated + // to. // The card pointer we obtained from card count cache is not hot // so do not store it in the cache; return it for immediate @@ -325,7 +320,7 @@ jbyte* ConcurrentG1Refine::cache_insert(jbyte* card_ptr, bool* defer) { return cached_ptr; } - // Otherwise, the pointer we got from the _card_counts is hot. + // Otherwise, the pointer we got from the _card_counts cache is hot. jbyte* res = NULL; MutexLockerEx x(HotCardCache_lock, Mutex::_no_safepoint_check_flag); if (_n_hot == _hot_cache_size) { @@ -338,17 +333,8 @@ jbyte* ConcurrentG1Refine::cache_insert(jbyte* card_ptr, bool* defer) { if (_hot_cache_idx == _hot_cache_size) _hot_cache_idx = 0; _n_hot++; - if (res != NULL) { - // Even though the region containg res was not in the young list - // when it was recorded in the hot cache it could have been added - // to the free list and subsequently added to the young list in - // the intervening time. If res is in a young region, return NULL - // so that res is not cleaned. See CR 6817995. - - if (is_young_card(res)) { - res = NULL; - } - } + // The card obtained from the hot card cache could be in a young + // region. See above on how this can happen. return res; } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 79622015207..658ac777f49 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -638,6 +638,11 @@ G1CollectedHeap::attempt_allocation_slow(size_t word_size, // Now retry the allocation. if (_cur_alloc_region != NULL) { + if (allocated_young_region != NULL) { + // We need to ensure that the store to top does not + // float above the setting of the young type. + OrderAccess::storestore(); + } res = _cur_alloc_region->allocate(word_size); } } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp index 5de8d9e61f6..a3a77ed186b 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -676,9 +676,27 @@ void HRInto_G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i // We must complete this write before we do any of the reads below. OrderAccess::storeload(); // And process it, being careful of unallocated portions of TLAB's. + + // The region for the current card may be a young region. The + // current card may have been a card that was evicted from the + // card cache. When the card was inserted into the cache, we had + // determined that its region was non-young. While in the cache, + // the region may have been freed during a cleanup pause, reallocated + // and tagged as young. + // + // We wish to filter out cards for such a region but the current + // thread, if we're running conucrrently, may "see" the young type + // change at any time (so an earlier "is_young" check may pass or + // fail arbitrarily). We tell the iteration code to perform this + // filtering when it has been determined that there has been an actual + // allocation in this region and making it safe to check the young type. + bool filter_young = true; + HeapWord* stop_point = r->oops_on_card_seq_iterate_careful(dirtyRegion, - &filter_then_update_rs_oop_cl); + &filter_then_update_rs_oop_cl, + filter_young); + // If stop_point is non-null, then we encountered an unallocated region // (perhaps the unfilled portion of a TLAB.) For now, we'll dirty the // card and re-enqueue: if we put off the card until a GC pause, then the @@ -789,8 +807,14 @@ void HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i) { if (r == NULL) { assert(_g1->is_in_permanent(start), "Or else where?"); } else { - guarantee(!r->is_young(), "It was evicted in the current minor cycle."); - // Process card pointer we get back from the hot card cache + // Checking whether the region we got back from the cache + // is young here is inappropriate. The region could have been + // freed, reallocated and tagged as young while in the cache. + // Hence we could see its young type change at any time. + // + // Process card pointer we get back from the hot card cache. This + // will check whether the region containing the card is young + // _after_ checking that the region has been allocated from. concurrentRefineOneCard_impl(res, worker_i); } } diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp index 74541915ef3..4e5446e1f5e 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp @@ -658,7 +658,8 @@ HeapRegion::object_iterate_mem_careful(MemRegion mr, HeapWord* HeapRegion:: oops_on_card_seq_iterate_careful(MemRegion mr, - FilterOutOfRegionClosure* cl) { + FilterOutOfRegionClosure* cl, + bool filter_young) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); // If we're within a stop-world GC, then we might look at a card in a @@ -672,6 +673,16 @@ oops_on_card_seq_iterate_careful(MemRegion mr, if (mr.is_empty()) return NULL; // Otherwise, find the obj that extends onto mr.start(). + // The intersection of the incoming mr (for the card) and the + // allocated part of the region is non-empty. This implies that + // we have actually allocated into this region. The code in + // G1CollectedHeap.cpp that allocates a new region sets the + // is_young tag on the region before allocating. Thus we + // safely know if this region is young. + if (is_young() && filter_young) { + return NULL; + } + // We used to use "block_start_careful" here. But we're actually happy // to update the BOT while we do this... HeapWord* cur = block_start(mr.start()); diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp index c8768c24267..42e96bbfb50 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp @@ -252,7 +252,7 @@ class HeapRegion: public G1OffsetTableContigSpace { // survivor }; - YoungType _young_type; + volatile YoungType _young_type; int _young_index_in_cset; SurvRateGroup* _surv_rate_group; int _age_index; @@ -726,9 +726,12 @@ class HeapRegion: public G1OffsetTableContigSpace { HeapWord* object_iterate_mem_careful(MemRegion mr, ObjectClosure* cl); + // In this version - if filter_young is true and the region + // is a young region then we skip the iteration. HeapWord* oops_on_card_seq_iterate_careful(MemRegion mr, - FilterOutOfRegionClosure* cl); + FilterOutOfRegionClosure* cl, + bool filter_young); // The region "mr" is entirely in "this", and starts and ends at block // boundaries. The caller declares that all the contained blocks are From 7eb8c115ec13d9499917b3cdae2a32519981417e Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Thu, 22 Jul 2010 11:02:54 -0700 Subject: [PATCH 14/52] 6968063: provide examples of code that generate diagnostics Reviewed-by: mcimadamore --- langtools/make/build.xml | 29 + .../test/tools/javac/diags/CheckExamples.java | 218 +++++++ langtools/test/tools/javac/diags/Example.java | 523 ++++++++++++++++ .../test/tools/javac/diags/FileManager.java | 191 ++++++ .../test/tools/javac/diags/HTMLWriter.java | 582 ++++++++++++++++++ .../tools/javac/diags/README.examples.txt | 134 ++++ .../test/tools/javac/diags/RunExamples.java | 582 ++++++++++++++++++ .../tools/javac/diags/examples.not-yet.txt | 115 ++++ .../examples/AbstractCantBeAccessed.java | 34 + .../examples/AbstractCantBeInstantiated.java | 32 + .../examples/AbstractMethodCantHaveBody.java | 28 + .../javac/diags/examples/AlreadyDefined.java | 29 + .../diags/examples/AlreadyDefinedImport.java | 29 + .../AlreadDefinedStaticImport.java | 27 + .../AlreadyDefinedStaticImport/p/E1.java | 26 + .../AlreadyDefinedStaticImport/p/E2.java | 26 + .../diags/examples/AnnoNotApplicable.java | 33 + .../diags/examples/AnnoNotValidForType.java | 31 + .../examples/AnnoValueMustBeAnnotation.java | 35 ++ .../examples/AnnoValueMustBeClassLiteral.java | 31 + .../AnnosWithoutProcessors.java | 30 + .../processors/AnnoProc.java | 38 ++ .../examples/AnnotationMissingValue.java | 31 + .../examples/AnnotationMustBeNameValue.java | 32 + .../examples/AnnotationsNotSupported.java | 28 + .../AnonClassImplInterfaceNoArgs.java | 30 + .../AnonClassImplInterfaceNoQualForNew.java | 31 + .../AnonClassImplInterfaceNoTypeArgs.java | 30 + .../javac/diags/examples/AnonymousClass.java | 33 + .../javac/diags/examples/ArrayAndVarargs.java | 29 + .../javac/diags/examples/ArrayDimMissing.java | 28 + .../javac/diags/examples/ArrayRequired.java | 29 + .../diags/examples/AssertAsIdentifier.java | 29 + .../diags/examples/AssertAsIdentifier2.java | 28 + .../diags/examples/AttrMustBeConstant.java | 31 + .../BadSourceFileHeader.java | 30 + .../BadSourceFileHeader/sourcepath/p/A.java | 28 + .../examples/BreakOutsideSwitchLoop.java | 30 + .../javac/diags/examples/CallMustBeFirst.java | 31 + .../CannotCreateArrayWithTypeArgs.java | 28 + .../diags/examples/CantApplyDiamond.java | 34 + .../diags/examples/CantAssignToFinal.java | 32 + .../tools/javac/diags/examples/CantDeref.java | 30 + .../diags/examples/CantExtendIntfAnno.java | 28 + .../javac/diags/examples/CantImplement.java | 33 + .../diags/examples/CantInheritDiffArg.java | 28 + .../diags/examples/CantRefBeforeConstr.java | 36 ++ .../javac/diags/examples/CantResolve.java | 31 + .../javac/diags/examples/CantResolveArgs.java | 35 ++ .../diags/examples/CantResolveArgsParams.java | 31 + .../diags/examples/CantResolveLocation.java | 28 + .../examples/CantResolveLocationArgs.java | 30 + .../CantResolveLocationArgsParams.java | 32 + .../examples/CantReturnValueForVoid.java | 30 + .../javac/diags/examples/CatchWithoutTry.java | 33 + .../javac/diags/examples/ClashesWith.java | 33 + .../javac/diags/examples/ClassCantWrite.java | 27 + .../diags/examples/ClassPublicInFile.java | 26 + .../examples/ConcreteInheritanceConflict.java | 31 + .../diags/examples/ConstExprRequired.java | 36 ++ .../javac/diags/examples/ConstantSVUID.java | 31 + .../diags/examples/ContinueOutsideLoop.java | 30 + .../javac/diags/examples/CountError.java | 30 + .../diags/examples/CountErrorPlural.java | 31 + .../tools/javac/diags/examples/CountWarn.java | 35 ++ .../javac/diags/examples/CountWarnPlural.java | 36 ++ .../diags/examples/CyclicAnnoElement.java | 28 + .../diags/examples/CyclicInheritance.java | 26 + .../DefaultAllowedInIntfAnnotationMember.java | 28 + .../diags/examples/DeprecatedFilename.java | 32 + .../DeprecatedFilenameAdditional.java | 37 ++ .../DeprecatedPlural/DeprecatedClass.java | 25 + .../DeprecatedPlural/DeprecatedFilename.java | 26 + .../DeprecatedPlural/DeprecatedPlural.java | 29 + .../DeprecatedClass.java | 25 + .../DeprecatedFilename.java | 26 + .../DeprecatedPlural.java | 26 + .../DeprecatedPluralAdditional.java | 30 + .../diags/examples/DiamondInvalidArg.java | 31 + .../diags/examples/DiamondInvalidArgs.java | 32 + .../diags/examples/DiamondNotSupported.java | 33 + .../examples/DirPathElementNotFound.java | 28 + .../tools/javac/diags/examples/DivZero.java | 31 + .../javac/diags/examples/DoesNotOverride.java | 30 + .../javac/diags/examples/DoesntExist.java | 26 + .../diags/examples/DotClassExpected.java | 28 + .../diags/examples/DuplicateAnnotation.java | 30 + .../DuplicateAnnotationMemberValue.java | 31 + .../diags/examples/DuplicateCaseLabel.java | 34 + .../javac/diags/examples/DuplicateClass.java | 28 + .../diags/examples/DuplicateDefaultLabel.java | 35 ++ .../javac/diags/examples/ElseWithoutIf.java | 31 + .../diags/examples/EmptyBytecodeIdent.java | 28 + .../diags/examples/EmptyCharLiteral.java | 31 + .../tools/javac/diags/examples/EmptyIf.java | 31 + .../diags/examples/EnclClassRequired.java | 30 + .../EnumAnnoValueMustBeEnumConst.java | 33 + .../diags/examples/EnumAsIdentifier.java | 29 + .../diags/examples/EnumAsIdentifier2.java | 28 + .../examples/EnumCantBeInstantiated.java | 30 + .../diags/examples/EnumConstRequired.java | 35 ++ .../diags/examples/EnumLabelUnqualified.java | 36 ++ .../javac/diags/examples/EnumNoFinalize.java | 32 + .../diags/examples/EnumNoSubclassing.java | 26 + .../examples/EnumTypesNotExtensible.java | 29 + .../diags/examples/EnumsMustBeStatic.java | 30 + .../diags/examples/EnumsNotSupported.java | 27 + .../ErrProcMessager/ErrProcMessager.java | 27 + .../ErrProcMessager/processors/AnnoProc.java | 43 ++ .../examples/ErrSyntheticNameConflict.java | 33 + .../tools/javac/diags/examples/Error.java | 40 ++ .../diags/examples/ErrorReadingFile.java | 27 + .../diags/examples/ExceptAlreadyCaught.java | 36 ++ .../diags/examples/ExceptNeverThrown.java | 35 ++ .../tools/javac/diags/examples/Expected2.java | 27 + .../tools/javac/diags/examples/Expected3.java | 26 + .../examples/FinalParamCantBeAssigned.java | 30 + .../diags/examples/FinallyCannotComplete.java | 34 + .../diags/examples/FinallyWithoutTry.java | 31 + .../diags/examples/FloatNumberTooLarge.java | 28 + .../diags/examples/FloatNumberTooSmall.java | 28 + .../diags/examples/ForeachNotApplicable.java | 32 + .../diags/examples/ForeachNotSupported.java | 33 + .../diags/examples/GenericArrayCreation.java | 30 + .../diags/examples/GenericThrowable.java | 26 + .../diags/examples/GenericsNotSupported.java | 27 + .../diags/examples/HasBeenDeprecated.java | 34 + .../diags/examples/IdentifierExpected.java | 32 + .../examples/IllegalBytecodeIdentChar.java | 28 + .../javac/diags/examples/IllegalChar.java | 28 + .../diags/examples/IllegalComboModifiers.java | 28 + .../diags/examples/IllegalEnumStaticRef.java | 29 + .../diags/examples/IllegalEscapeChar.java | 28 + .../diags/examples/IllegalForwardRef.java | 29 + .../diags/examples/IllegalInitializer.java | 28 + .../examples/IllegalLineEndInCharLit.java | 29 + .../diags/examples/IllegalNonAsciiDigit.java | 28 + .../diags/examples/IllegalQualNotIcls.java | 31 + .../javac/diags/examples/IllegalSelfRef.java | 28 + .../diags/examples/IllegalStartOfExpr.java | 28 + .../diags/examples/IllegalUnderscore.java | 28 + .../diags/examples/IllegalUnicodeEscape.java | 28 + .../ImportRequiresCanonical.java | 28 + .../ImportRequiresCanonical/p/Base.java | 28 + .../p/ExtendsBase.java | 27 + .../javac/diags/examples/ImproperSVUID.java | 31 + .../examples/ImproperTypeInnerRawParam.java | 34 + .../examples/ImproperTypeParamMissing.java | 34 + .../diags/examples/IncomparableTypes.java | 28 + .../diags/examples/IncompatibleTypes1.java | 34 + .../diags/examples/InconvertibleTypes.java | 35 ++ .../diags/examples/InexactVarargsCall.java | 35 ++ .../InferredDoNotConformToBounds.java | 35 ++ .../diags/examples/InheritFromFinal.java | 28 + .../examples/InitializerMustComplete.java | 30 + .../examples/InnerClassCantHaveStatic.java | 30 + .../diags/examples/IntNumberTooLarge.java | 28 + .../diags/examples/InterfaceExpected.java | 26 + .../diags/examples/InterfaceNotAllowed.java | 30 + .../IntfAnnotationCantHaveTypeParams.java | 26 + .../examples/IntfAnnotationMemberClash.java | 28 + .../IntfAnnotationsCantHaveParams.java | 28 + .../IntfAnnotationsCantHaveTypeParams.java | 28 + .../examples/IntfMethodCantHaveBody.java | 28 + .../diags/examples/InvalidAnnoMemberType.java | 28 + .../diags/examples/InvalidBinaryNumber.java | 31 + .../diags/examples/InvalidHexNumber.java | 29 + .../diags/examples/InvalidInferredTypes.java | 38 ++ .../diags/examples/InvalidInstanceof.java | 31 + .../diags/examples/InvalidMethodDecl.java | 28 + .../javac/diags/examples/KindnameClass.java | 31 + .../diags/examples/KindnameConstructor.java | 38 ++ .../javac/diags/examples/KindnameMethod.java | 32 + .../diags/examples/KindnameVariable.java | 32 + .../javac/diags/examples/LabelInUse.java | 37 ++ .../tools/javac/diags/examples/LocalEnum.java | 30 + .../diags/examples/LocalVarNeedsFinal.java | 35 ++ .../tools/javac/diags/examples/LongSVUID.java | 31 + .../javac/diags/examples/MalformedFpLit.java | 29 + .../MalformedSupported.java | 27 + .../processors/AnnoProc.java | 38 ++ .../diags/examples/MethodDoesNotOverride.java | 29 + .../diags/examples/MightBeAssignedInLoop.java | 33 + .../examples/MissingDeprecatedAnnotation.java | 29 + .../diags/examples/MissingMethodBody.java | 28 + .../examples/MissingReturnStatement.java | 29 + .../diags/examples/MissingReturnValue.java | 30 + .../javac/diags/examples/MissingSVUID.java | 30 + .../diags/examples/ModifierNotAllowed.java | 26 + .../examples/MulticatchCantBeAssigned.java | 38 ++ .../diags/examples/MulticatchMustBeFinal.java | 38 ++ .../examples/MulticatchNotSupported.java | 42 ++ .../diags/examples/NameClashSameErasure.java | 31 + .../NameClashSameErasureNoOverride.java | 34 + .../examples/NativeMethodCantHaveBody.java | 28 + .../examples/NeitherConditionalSubtype.java | 31 + .../diags/examples/NewNotAllowedInAnno.java | 31 + .../tools/javac/diags/examples/NoArgs.java | 32 + .../examples/NoExplicitAnnoProcRequested.java | 28 + .../diags/examples/NoInterfaceExpected.java | 26 + .../javac/diags/examples/NoInterfaceHere.java | 28 + .../javac/diags/examples/NoJavaLang.java | 28 + .../javac/diags/examples/NoSuperclass.java | 32 + .../diags/examples/NonStaticCantBeRef.java | 32 + .../NotDefAccessClassIntfCantAccess.java | 33 + .../NotDefAccessClassIntfCantAccess/p/C.java | 30 + .../NotDefPublicCantAccess.java | 28 + .../examples/NotDefPublicCantAccess/p/C.java | 26 + .../javac/diags/examples/NotEnclClass.java | 28 + .../javac/diags/examples/NotLoopLabel.java | 38 ++ .../javac/diags/examples/NotWithinBounds.java | 31 + .../test/tools/javac/diags/examples/Note.java | 33 + .../NoteProcMessager/NoteProcMessager.java | 27 + .../NoteProcMessager/processors/AnnoProc.java | 43 ++ .../diags/examples/OperatorCantBeApplied.java | 28 + .../tools/javac/diags/examples/Orphaned.java | 31 + .../diags/examples/OverrideDoesntThrow.java | 34 + .../examples/OverrideIncompatibleReturn.java | 38 ++ .../javac/diags/examples/OverrideMeth.java | 33 + .../javac/diags/examples/OverrideStatic.java | 33 + .../examples/OverrideUncheckedReturn.java | 36 ++ .../examples/OverrideUncheckedThrown.java | 34 + .../diags/examples/OverrideVarargsExtra.java | 34 + .../examples/OverrideVarargsMissing.java | 34 + .../diags/examples/OverrideWeakerAccess.java | 29 + .../javac/diags/examples/PackageAnnos.java | 29 + .../p/package-info.java | 24 + .../PackageInfoAlreadySeen/package-info.java | 26 + .../diags/examples/PathElementNotFound.java | 28 + .../diags/examples/PkgClashWithClass/p/q.java | 31 + .../examples/PkgClashWithClass/p/q/C.java | 26 + .../diags/examples/PossibleFallThrough.java | 37 ++ .../diags/examples/PossibleLossPrecision.java | 30 + .../javac/diags/examples/PrematureEOF.java | 26 + .../PrintProcessorInfo.java | 28 + .../processors/AnnoProc.java | 38 ++ .../examples/PrintRounds/PrintRounds.java | 28 + .../PrintRounds/processors/AnnoProc.java | 38 ++ .../ProcCantFindClass/ProcCantFindClass.java | 26 + .../processors/AnnoProc.java | 32 + .../ProcFileReopening/ProcFileReopening.java | 28 + .../processors/AnnoProc.java | 57 ++ .../ProcIllegalFileName.java | 28 + .../processors/AnnoProc.java | 55 ++ .../ProcIncompatibleSourceVersion.java | 27 + .../processors/AnnoProc.java | 35 ++ .../javac/diags/examples/ProcOnlyNoProcs.java | 25 + .../ProcPackageDoesNotExist.java | 26 + .../processors/AnnoProc.java | 39 ++ .../ProcTypeRecreate/ProcTypeRecreate.java | 28 + .../ProcTypeRecreate/processors/AnnoProc.java | 55 ++ .../ProcUnclosedTypeFiles.java | 27 + .../processors/AnnoProc.java | 55 ++ .../ProcUseImplicit/ProcUseImplicit.java | 30 + .../ProcUseImplicit/processors/AnnoProc.java | 54 ++ .../sourcepath/p/SomeClass.java | 26 + .../ProcUseProcOrImplicit.java | 30 + .../processors/AnnoProc.java | 54 ++ .../sourcepath/p/SomeClass.java | 26 + .../ProcessorCantInstantiate.java | 27 + .../processors/AnnoProc.java | 38 ++ .../diags/examples/ProcessorNotFound.java | 27 + .../ProcessorWrongType.java | 27 + .../processors/AnnoProc.java | 24 + .../examples/QualifiedNewStaticClass.java | 30 + .../javac/diags/examples/RawClassUse.java | 31 + .../examples/RecursiveConstrInvocation.java | 30 + .../javac/diags/examples/RedundantCast.java | 29 + .../javac/diags/examples/RefAmbiguous.java | 33 + .../examples/RepeatedAnnotationTarget.java | 29 + .../diags/examples/RepeatedInterface.java | 30 + .../diags/examples/RepeatedModifier.java | 28 + .../javac/diags/examples/ReportAccess.java | 32 + .../javac/diags/examples/ResourceClosed.java | 35 ++ .../examples/ResourceMayNotBeAssigned.java | 34 + .../examples/ResourceNotApplicableToType.java | 32 + .../diags/examples/ResourceNotReferenced.java | 34 + .../diags/examples/ReturnOutsideMethod.java | 28 + .../examples/StaticImportNotSupported.java | 29 + .../Other.java | 28 + .../StaticImportOnlyClassesAndInterfaces.java | 29 + .../examples/StaticNotQualifiedByType.java | 35 ++ .../diags/examples/StringConstRequired.java | 36 ++ .../examples/StringSwitchNotSupported.java | 35 ++ .../javac/diags/examples/SunApiFilename.java | 30 + .../examples/SunApiFilenameAdditional.java | 31 + .../examples/SunApiPlural/SunApiFilename.java | 26 + .../examples/SunApiPlural/SunApiPlural.java | 30 + .../SunApiFilename.java | 26 + .../SunApiPluralAdditional/SunApiPlural.java | 26 + .../SunApiPluralAdditional.java | 30 + .../javac/diags/examples/SunProprietary.java | 28 + .../diags/examples/SuperNotAllowedInEnum.java | 33 + .../examples/ThrowsNotAllowedInAnno.java | 28 + .../examples/TryResourceNotSupported.java | 35 ++ .../examples/TryWithoutCatchOrFinally.java | 32 + .../TryWithoutCatchOrFinallyOrResource.java | 31 + .../examples/TypeAnnotationsNotSupported.java | 33 + .../diags/examples/TypeFoundRequired.java | 32 + .../javac/diags/examples/TypeNoParams.java | 28 + .../diags/examples/TypeReqClassArray.java | 31 + .../javac/diags/examples/TypeReqRef.java | 30 + .../diags/examples/TypeVarCantBeDeref.java | 28 + .../TypeVarMayNotBeFollowedByOtherBounds.java | 28 + .../diags/examples/TypesIncompatible.java | 34 + .../javac/diags/examples/UncheckedAssign.java | 34 + .../diags/examples/UncheckedAssignToVar.java | 36 ++ .../javac/diags/examples/UncheckedCall.java | 34 + .../javac/diags/examples/UncheckedCast.java | 34 + .../javac/diags/examples/UncheckedClash.java | 36 ++ .../diags/examples/UncheckedFilename.java | 31 + .../examples/UncheckedFilenameAdditional.java | 37 ++ .../UncheckedGenericArrayCreation.java | 37 ++ .../diags/examples/UncheckedImplement.java | 36 ++ .../examples/UncheckedMethodInvocation.java | 37 ++ .../UncheckedPlural/UncheckedFilename.java | 28 + .../UncheckedPlural/UncheckedPlural.java | 31 + .../UncheckedFilename1.java | 28 + .../UncheckedFilename2.java | 28 + .../UncheckedPluralAdditional.java | 33 + .../diags/examples/UnclosedBytecodeIdent.java | 28 + .../diags/examples/UnclosedCharLiteral.java | 28 + .../javac/diags/examples/UnclosedComment.java | 30 + .../diags/examples/UnclosedStringLiteral.java | 28 + .../javac/diags/examples/UndefinedLabel.java | 35 ++ .../diags/examples/UndeterminedType1.java | 34 + .../UnmatchedProcessorOptions.java | 27 + .../processors/AnnoProc.java | 39 ++ .../javac/diags/examples/UnnamedPackage.java | 32 + .../diags/examples/UnreachableStatement.java | 31 + .../diags/examples/UnreportedException.java | 30 + ...UnreportedExceptionDefaultConstructor.java | 30 + .../examples/UnsupportedBinaryLiteral.java | 29 + .../diags/examples/UnsupportedEncoding.java | 27 + .../diags/examples/UnsupportedFpLit.java | 29 + .../UnsupportedUnderscoreLiteral.java | 29 + .../examples/VarMightAlreadyBeAssigned.java | 33 + .../VarMightNotHaveBeenInitialized.java | 32 + .../javac/diags/examples/VarargsClash.java | 34 + .../javac/diags/examples/VarargsFilename.java | 29 + .../examples/VarargsFilenameAdditional.java | 31 + .../diags/examples/VarargsImplement.java | 34 + .../examples/VarargsNonReifiableType.java | 32 + .../diags/examples/VarargsNotSupported.java | 29 + .../javac/diags/examples/VarargsOverride.java | 34 + .../VarargsPlural/VarargsFilename.java | 26 + .../examples/VarargsPlural/VarargsPlural.java | 29 + .../VarargsFilename.java | 26 + .../VarargsPlural.java | 26 + .../VarargsPluralAdditional.java | 30 + .../tools/javac/diags/examples/Verbose.java | 35 ++ .../javac/diags/examples/VoidNotAllowed.java | 32 + .../javac/diags/examples/WarnForwardRef.java | 30 + .../WarnProcMessager/WarnProcMessager.java | 27 + .../WarnProcMessager/processors/AnnoProc.java | 43 ++ .../javac/diags/examples/WarnSelfRef.java | 29 + .../examples/WarnSyntheticNameConflict.java | 34 + .../diags/examples/WarningAndWerror.java | 32 + .../javac/diags/examples/WhereCaptured.java | 41 ++ .../javac/diags/examples/WhereCaptured1.java | 42 ++ .../diags/examples/WhereIntersection.java | 43 ++ .../javac/diags/examples/WhereTypeVar.java | 36 ++ .../diags/examples/WrongNumberTypeArgs.java | 30 + 363 files changed, 13449 insertions(+) create mode 100644 langtools/test/tools/javac/diags/CheckExamples.java create mode 100644 langtools/test/tools/javac/diags/Example.java create mode 100644 langtools/test/tools/javac/diags/FileManager.java create mode 100644 langtools/test/tools/javac/diags/HTMLWriter.java create mode 100644 langtools/test/tools/javac/diags/README.examples.txt create mode 100644 langtools/test/tools/javac/diags/RunExamples.java create mode 100644 langtools/test/tools/javac/diags/examples.not-yet.txt create mode 100644 langtools/test/tools/javac/diags/examples/AbstractCantBeAccessed.java create mode 100644 langtools/test/tools/javac/diags/examples/AbstractCantBeInstantiated.java create mode 100644 langtools/test/tools/javac/diags/examples/AbstractMethodCantHaveBody.java create mode 100644 langtools/test/tools/javac/diags/examples/AlreadyDefined.java create mode 100644 langtools/test/tools/javac/diags/examples/AlreadyDefinedImport.java create mode 100644 langtools/test/tools/javac/diags/examples/AlreadyDefinedStaticImport/AlreadDefinedStaticImport.java create mode 100644 langtools/test/tools/javac/diags/examples/AlreadyDefinedStaticImport/p/E1.java create mode 100644 langtools/test/tools/javac/diags/examples/AlreadyDefinedStaticImport/p/E2.java create mode 100644 langtools/test/tools/javac/diags/examples/AnnoNotApplicable.java create mode 100644 langtools/test/tools/javac/diags/examples/AnnoNotValidForType.java create mode 100644 langtools/test/tools/javac/diags/examples/AnnoValueMustBeAnnotation.java create mode 100644 langtools/test/tools/javac/diags/examples/AnnoValueMustBeClassLiteral.java create mode 100644 langtools/test/tools/javac/diags/examples/AnnosWithoutProcessors/AnnosWithoutProcessors.java create mode 100644 langtools/test/tools/javac/diags/examples/AnnosWithoutProcessors/processors/AnnoProc.java create mode 100644 langtools/test/tools/javac/diags/examples/AnnotationMissingValue.java create mode 100644 langtools/test/tools/javac/diags/examples/AnnotationMustBeNameValue.java create mode 100644 langtools/test/tools/javac/diags/examples/AnnotationsNotSupported.java create mode 100644 langtools/test/tools/javac/diags/examples/AnonClassImplInterfaceNoArgs.java create mode 100644 langtools/test/tools/javac/diags/examples/AnonClassImplInterfaceNoQualForNew.java create mode 100644 langtools/test/tools/javac/diags/examples/AnonClassImplInterfaceNoTypeArgs.java create mode 100644 langtools/test/tools/javac/diags/examples/AnonymousClass.java create mode 100644 langtools/test/tools/javac/diags/examples/ArrayAndVarargs.java create mode 100644 langtools/test/tools/javac/diags/examples/ArrayDimMissing.java create mode 100644 langtools/test/tools/javac/diags/examples/ArrayRequired.java create mode 100644 langtools/test/tools/javac/diags/examples/AssertAsIdentifier.java create mode 100644 langtools/test/tools/javac/diags/examples/AssertAsIdentifier2.java create mode 100644 langtools/test/tools/javac/diags/examples/AttrMustBeConstant.java create mode 100644 langtools/test/tools/javac/diags/examples/BadSourceFileHeader/BadSourceFileHeader.java create mode 100644 langtools/test/tools/javac/diags/examples/BadSourceFileHeader/sourcepath/p/A.java create mode 100644 langtools/test/tools/javac/diags/examples/BreakOutsideSwitchLoop.java create mode 100644 langtools/test/tools/javac/diags/examples/CallMustBeFirst.java create mode 100644 langtools/test/tools/javac/diags/examples/CannotCreateArrayWithTypeArgs.java create mode 100644 langtools/test/tools/javac/diags/examples/CantApplyDiamond.java create mode 100644 langtools/test/tools/javac/diags/examples/CantAssignToFinal.java create mode 100644 langtools/test/tools/javac/diags/examples/CantDeref.java create mode 100644 langtools/test/tools/javac/diags/examples/CantExtendIntfAnno.java create mode 100644 langtools/test/tools/javac/diags/examples/CantImplement.java create mode 100644 langtools/test/tools/javac/diags/examples/CantInheritDiffArg.java create mode 100644 langtools/test/tools/javac/diags/examples/CantRefBeforeConstr.java create mode 100644 langtools/test/tools/javac/diags/examples/CantResolve.java create mode 100644 langtools/test/tools/javac/diags/examples/CantResolveArgs.java create mode 100644 langtools/test/tools/javac/diags/examples/CantResolveArgsParams.java create mode 100644 langtools/test/tools/javac/diags/examples/CantResolveLocation.java create mode 100644 langtools/test/tools/javac/diags/examples/CantResolveLocationArgs.java create mode 100644 langtools/test/tools/javac/diags/examples/CantResolveLocationArgsParams.java create mode 100644 langtools/test/tools/javac/diags/examples/CantReturnValueForVoid.java create mode 100644 langtools/test/tools/javac/diags/examples/CatchWithoutTry.java create mode 100644 langtools/test/tools/javac/diags/examples/ClashesWith.java create mode 100644 langtools/test/tools/javac/diags/examples/ClassCantWrite.java create mode 100644 langtools/test/tools/javac/diags/examples/ClassPublicInFile.java create mode 100644 langtools/test/tools/javac/diags/examples/ConcreteInheritanceConflict.java create mode 100644 langtools/test/tools/javac/diags/examples/ConstExprRequired.java create mode 100644 langtools/test/tools/javac/diags/examples/ConstantSVUID.java create mode 100644 langtools/test/tools/javac/diags/examples/ContinueOutsideLoop.java create mode 100644 langtools/test/tools/javac/diags/examples/CountError.java create mode 100644 langtools/test/tools/javac/diags/examples/CountErrorPlural.java create mode 100644 langtools/test/tools/javac/diags/examples/CountWarn.java create mode 100644 langtools/test/tools/javac/diags/examples/CountWarnPlural.java create mode 100644 langtools/test/tools/javac/diags/examples/CyclicAnnoElement.java create mode 100644 langtools/test/tools/javac/diags/examples/CyclicInheritance.java create mode 100644 langtools/test/tools/javac/diags/examples/DefaultAllowedInIntfAnnotationMember.java create mode 100644 langtools/test/tools/javac/diags/examples/DeprecatedFilename.java create mode 100644 langtools/test/tools/javac/diags/examples/DeprecatedFilenameAdditional.java create mode 100644 langtools/test/tools/javac/diags/examples/DeprecatedPlural/DeprecatedClass.java create mode 100644 langtools/test/tools/javac/diags/examples/DeprecatedPlural/DeprecatedFilename.java create mode 100644 langtools/test/tools/javac/diags/examples/DeprecatedPlural/DeprecatedPlural.java create mode 100644 langtools/test/tools/javac/diags/examples/DeprecatedPluralAdditional/DeprecatedClass.java create mode 100644 langtools/test/tools/javac/diags/examples/DeprecatedPluralAdditional/DeprecatedFilename.java create mode 100644 langtools/test/tools/javac/diags/examples/DeprecatedPluralAdditional/DeprecatedPlural.java create mode 100644 langtools/test/tools/javac/diags/examples/DeprecatedPluralAdditional/DeprecatedPluralAdditional.java create mode 100644 langtools/test/tools/javac/diags/examples/DiamondInvalidArg.java create mode 100644 langtools/test/tools/javac/diags/examples/DiamondInvalidArgs.java create mode 100644 langtools/test/tools/javac/diags/examples/DiamondNotSupported.java create mode 100644 langtools/test/tools/javac/diags/examples/DirPathElementNotFound.java create mode 100644 langtools/test/tools/javac/diags/examples/DivZero.java create mode 100644 langtools/test/tools/javac/diags/examples/DoesNotOverride.java create mode 100644 langtools/test/tools/javac/diags/examples/DoesntExist.java create mode 100644 langtools/test/tools/javac/diags/examples/DotClassExpected.java create mode 100644 langtools/test/tools/javac/diags/examples/DuplicateAnnotation.java create mode 100644 langtools/test/tools/javac/diags/examples/DuplicateAnnotationMemberValue.java create mode 100644 langtools/test/tools/javac/diags/examples/DuplicateCaseLabel.java create mode 100644 langtools/test/tools/javac/diags/examples/DuplicateClass.java create mode 100644 langtools/test/tools/javac/diags/examples/DuplicateDefaultLabel.java create mode 100644 langtools/test/tools/javac/diags/examples/ElseWithoutIf.java create mode 100644 langtools/test/tools/javac/diags/examples/EmptyBytecodeIdent.java create mode 100644 langtools/test/tools/javac/diags/examples/EmptyCharLiteral.java create mode 100644 langtools/test/tools/javac/diags/examples/EmptyIf.java create mode 100644 langtools/test/tools/javac/diags/examples/EnclClassRequired.java create mode 100644 langtools/test/tools/javac/diags/examples/EnumAnnoValueMustBeEnumConst.java create mode 100644 langtools/test/tools/javac/diags/examples/EnumAsIdentifier.java create mode 100644 langtools/test/tools/javac/diags/examples/EnumAsIdentifier2.java create mode 100644 langtools/test/tools/javac/diags/examples/EnumCantBeInstantiated.java create mode 100644 langtools/test/tools/javac/diags/examples/EnumConstRequired.java create mode 100644 langtools/test/tools/javac/diags/examples/EnumLabelUnqualified.java create mode 100644 langtools/test/tools/javac/diags/examples/EnumNoFinalize.java create mode 100644 langtools/test/tools/javac/diags/examples/EnumNoSubclassing.java create mode 100644 langtools/test/tools/javac/diags/examples/EnumTypesNotExtensible.java create mode 100644 langtools/test/tools/javac/diags/examples/EnumsMustBeStatic.java create mode 100644 langtools/test/tools/javac/diags/examples/EnumsNotSupported.java create mode 100644 langtools/test/tools/javac/diags/examples/ErrProcMessager/ErrProcMessager.java create mode 100644 langtools/test/tools/javac/diags/examples/ErrProcMessager/processors/AnnoProc.java create mode 100644 langtools/test/tools/javac/diags/examples/ErrSyntheticNameConflict.java create mode 100644 langtools/test/tools/javac/diags/examples/Error.java create mode 100644 langtools/test/tools/javac/diags/examples/ErrorReadingFile.java create mode 100644 langtools/test/tools/javac/diags/examples/ExceptAlreadyCaught.java create mode 100644 langtools/test/tools/javac/diags/examples/ExceptNeverThrown.java create mode 100644 langtools/test/tools/javac/diags/examples/Expected2.java create mode 100644 langtools/test/tools/javac/diags/examples/Expected3.java create mode 100644 langtools/test/tools/javac/diags/examples/FinalParamCantBeAssigned.java create mode 100644 langtools/test/tools/javac/diags/examples/FinallyCannotComplete.java create mode 100644 langtools/test/tools/javac/diags/examples/FinallyWithoutTry.java create mode 100644 langtools/test/tools/javac/diags/examples/FloatNumberTooLarge.java create mode 100644 langtools/test/tools/javac/diags/examples/FloatNumberTooSmall.java create mode 100644 langtools/test/tools/javac/diags/examples/ForeachNotApplicable.java create mode 100644 langtools/test/tools/javac/diags/examples/ForeachNotSupported.java create mode 100644 langtools/test/tools/javac/diags/examples/GenericArrayCreation.java create mode 100644 langtools/test/tools/javac/diags/examples/GenericThrowable.java create mode 100644 langtools/test/tools/javac/diags/examples/GenericsNotSupported.java create mode 100644 langtools/test/tools/javac/diags/examples/HasBeenDeprecated.java create mode 100644 langtools/test/tools/javac/diags/examples/IdentifierExpected.java create mode 100644 langtools/test/tools/javac/diags/examples/IllegalBytecodeIdentChar.java create mode 100644 langtools/test/tools/javac/diags/examples/IllegalChar.java create mode 100644 langtools/test/tools/javac/diags/examples/IllegalComboModifiers.java create mode 100644 langtools/test/tools/javac/diags/examples/IllegalEnumStaticRef.java create mode 100644 langtools/test/tools/javac/diags/examples/IllegalEscapeChar.java create mode 100644 langtools/test/tools/javac/diags/examples/IllegalForwardRef.java create mode 100644 langtools/test/tools/javac/diags/examples/IllegalInitializer.java create mode 100644 langtools/test/tools/javac/diags/examples/IllegalLineEndInCharLit.java create mode 100644 langtools/test/tools/javac/diags/examples/IllegalNonAsciiDigit.java create mode 100644 langtools/test/tools/javac/diags/examples/IllegalQualNotIcls.java create mode 100644 langtools/test/tools/javac/diags/examples/IllegalSelfRef.java create mode 100644 langtools/test/tools/javac/diags/examples/IllegalStartOfExpr.java create mode 100644 langtools/test/tools/javac/diags/examples/IllegalUnderscore.java create mode 100644 langtools/test/tools/javac/diags/examples/IllegalUnicodeEscape.java create mode 100644 langtools/test/tools/javac/diags/examples/ImportRequiresCanonical/ImportRequiresCanonical.java create mode 100644 langtools/test/tools/javac/diags/examples/ImportRequiresCanonical/p/Base.java create mode 100644 langtools/test/tools/javac/diags/examples/ImportRequiresCanonical/p/ExtendsBase.java create mode 100644 langtools/test/tools/javac/diags/examples/ImproperSVUID.java create mode 100644 langtools/test/tools/javac/diags/examples/ImproperTypeInnerRawParam.java create mode 100644 langtools/test/tools/javac/diags/examples/ImproperTypeParamMissing.java create mode 100644 langtools/test/tools/javac/diags/examples/IncomparableTypes.java create mode 100644 langtools/test/tools/javac/diags/examples/IncompatibleTypes1.java create mode 100644 langtools/test/tools/javac/diags/examples/InconvertibleTypes.java create mode 100644 langtools/test/tools/javac/diags/examples/InexactVarargsCall.java create mode 100644 langtools/test/tools/javac/diags/examples/InferredDoNotConformToBounds.java create mode 100644 langtools/test/tools/javac/diags/examples/InheritFromFinal.java create mode 100644 langtools/test/tools/javac/diags/examples/InitializerMustComplete.java create mode 100644 langtools/test/tools/javac/diags/examples/InnerClassCantHaveStatic.java create mode 100644 langtools/test/tools/javac/diags/examples/IntNumberTooLarge.java create mode 100644 langtools/test/tools/javac/diags/examples/InterfaceExpected.java create mode 100644 langtools/test/tools/javac/diags/examples/InterfaceNotAllowed.java create mode 100644 langtools/test/tools/javac/diags/examples/IntfAnnotationCantHaveTypeParams.java create mode 100644 langtools/test/tools/javac/diags/examples/IntfAnnotationMemberClash.java create mode 100644 langtools/test/tools/javac/diags/examples/IntfAnnotationsCantHaveParams.java create mode 100644 langtools/test/tools/javac/diags/examples/IntfAnnotationsCantHaveTypeParams.java create mode 100644 langtools/test/tools/javac/diags/examples/IntfMethodCantHaveBody.java create mode 100644 langtools/test/tools/javac/diags/examples/InvalidAnnoMemberType.java create mode 100644 langtools/test/tools/javac/diags/examples/InvalidBinaryNumber.java create mode 100644 langtools/test/tools/javac/diags/examples/InvalidHexNumber.java create mode 100644 langtools/test/tools/javac/diags/examples/InvalidInferredTypes.java create mode 100644 langtools/test/tools/javac/diags/examples/InvalidInstanceof.java create mode 100644 langtools/test/tools/javac/diags/examples/InvalidMethodDecl.java create mode 100644 langtools/test/tools/javac/diags/examples/KindnameClass.java create mode 100644 langtools/test/tools/javac/diags/examples/KindnameConstructor.java create mode 100644 langtools/test/tools/javac/diags/examples/KindnameMethod.java create mode 100644 langtools/test/tools/javac/diags/examples/KindnameVariable.java create mode 100644 langtools/test/tools/javac/diags/examples/LabelInUse.java create mode 100644 langtools/test/tools/javac/diags/examples/LocalEnum.java create mode 100644 langtools/test/tools/javac/diags/examples/LocalVarNeedsFinal.java create mode 100644 langtools/test/tools/javac/diags/examples/LongSVUID.java create mode 100644 langtools/test/tools/javac/diags/examples/MalformedFpLit.java create mode 100644 langtools/test/tools/javac/diags/examples/MalformedSupported/MalformedSupported.java create mode 100644 langtools/test/tools/javac/diags/examples/MalformedSupported/processors/AnnoProc.java create mode 100644 langtools/test/tools/javac/diags/examples/MethodDoesNotOverride.java create mode 100644 langtools/test/tools/javac/diags/examples/MightBeAssignedInLoop.java create mode 100644 langtools/test/tools/javac/diags/examples/MissingDeprecatedAnnotation.java create mode 100644 langtools/test/tools/javac/diags/examples/MissingMethodBody.java create mode 100644 langtools/test/tools/javac/diags/examples/MissingReturnStatement.java create mode 100644 langtools/test/tools/javac/diags/examples/MissingReturnValue.java create mode 100644 langtools/test/tools/javac/diags/examples/MissingSVUID.java create mode 100644 langtools/test/tools/javac/diags/examples/ModifierNotAllowed.java create mode 100644 langtools/test/tools/javac/diags/examples/MulticatchCantBeAssigned.java create mode 100644 langtools/test/tools/javac/diags/examples/MulticatchMustBeFinal.java create mode 100644 langtools/test/tools/javac/diags/examples/MulticatchNotSupported.java create mode 100644 langtools/test/tools/javac/diags/examples/NameClashSameErasure.java create mode 100644 langtools/test/tools/javac/diags/examples/NameClashSameErasureNoOverride.java create mode 100644 langtools/test/tools/javac/diags/examples/NativeMethodCantHaveBody.java create mode 100644 langtools/test/tools/javac/diags/examples/NeitherConditionalSubtype.java create mode 100644 langtools/test/tools/javac/diags/examples/NewNotAllowedInAnno.java create mode 100644 langtools/test/tools/javac/diags/examples/NoArgs.java create mode 100644 langtools/test/tools/javac/diags/examples/NoExplicitAnnoProcRequested.java create mode 100644 langtools/test/tools/javac/diags/examples/NoInterfaceExpected.java create mode 100644 langtools/test/tools/javac/diags/examples/NoInterfaceHere.java create mode 100644 langtools/test/tools/javac/diags/examples/NoJavaLang.java create mode 100644 langtools/test/tools/javac/diags/examples/NoSuperclass.java create mode 100644 langtools/test/tools/javac/diags/examples/NonStaticCantBeRef.java create mode 100644 langtools/test/tools/javac/diags/examples/NotDefAccessClassIntfCantAccess/NotDefAccessClassIntfCantAccess.java create mode 100644 langtools/test/tools/javac/diags/examples/NotDefAccessClassIntfCantAccess/p/C.java create mode 100644 langtools/test/tools/javac/diags/examples/NotDefPublicCantAccess/NotDefPublicCantAccess.java create mode 100644 langtools/test/tools/javac/diags/examples/NotDefPublicCantAccess/p/C.java create mode 100644 langtools/test/tools/javac/diags/examples/NotEnclClass.java create mode 100644 langtools/test/tools/javac/diags/examples/NotLoopLabel.java create mode 100644 langtools/test/tools/javac/diags/examples/NotWithinBounds.java create mode 100644 langtools/test/tools/javac/diags/examples/Note.java create mode 100644 langtools/test/tools/javac/diags/examples/NoteProcMessager/NoteProcMessager.java create mode 100644 langtools/test/tools/javac/diags/examples/NoteProcMessager/processors/AnnoProc.java create mode 100644 langtools/test/tools/javac/diags/examples/OperatorCantBeApplied.java create mode 100644 langtools/test/tools/javac/diags/examples/Orphaned.java create mode 100644 langtools/test/tools/javac/diags/examples/OverrideDoesntThrow.java create mode 100644 langtools/test/tools/javac/diags/examples/OverrideIncompatibleReturn.java create mode 100644 langtools/test/tools/javac/diags/examples/OverrideMeth.java create mode 100644 langtools/test/tools/javac/diags/examples/OverrideStatic.java create mode 100644 langtools/test/tools/javac/diags/examples/OverrideUncheckedReturn.java create mode 100644 langtools/test/tools/javac/diags/examples/OverrideUncheckedThrown.java create mode 100644 langtools/test/tools/javac/diags/examples/OverrideVarargsExtra.java create mode 100644 langtools/test/tools/javac/diags/examples/OverrideVarargsMissing.java create mode 100644 langtools/test/tools/javac/diags/examples/OverrideWeakerAccess.java create mode 100644 langtools/test/tools/javac/diags/examples/PackageAnnos.java create mode 100644 langtools/test/tools/javac/diags/examples/PackageInfoAlreadySeen/p/package-info.java create mode 100644 langtools/test/tools/javac/diags/examples/PackageInfoAlreadySeen/package-info.java create mode 100644 langtools/test/tools/javac/diags/examples/PathElementNotFound.java create mode 100644 langtools/test/tools/javac/diags/examples/PkgClashWithClass/p/q.java create mode 100644 langtools/test/tools/javac/diags/examples/PkgClashWithClass/p/q/C.java create mode 100644 langtools/test/tools/javac/diags/examples/PossibleFallThrough.java create mode 100644 langtools/test/tools/javac/diags/examples/PossibleLossPrecision.java create mode 100644 langtools/test/tools/javac/diags/examples/PrematureEOF.java create mode 100644 langtools/test/tools/javac/diags/examples/PrintProcessorInfo/PrintProcessorInfo.java create mode 100644 langtools/test/tools/javac/diags/examples/PrintProcessorInfo/processors/AnnoProc.java create mode 100644 langtools/test/tools/javac/diags/examples/PrintRounds/PrintRounds.java create mode 100644 langtools/test/tools/javac/diags/examples/PrintRounds/processors/AnnoProc.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcCantFindClass/ProcCantFindClass.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcCantFindClass/processors/AnnoProc.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcFileReopening/ProcFileReopening.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcFileReopening/processors/AnnoProc.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcIllegalFileName/ProcIllegalFileName.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcIllegalFileName/processors/AnnoProc.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcIncompatibleSourceVersion/ProcIncompatibleSourceVersion.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcIncompatibleSourceVersion/processors/AnnoProc.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcOnlyNoProcs.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcPackageDoesNotExist/ProcPackageDoesNotExist.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcPackageDoesNotExist/processors/AnnoProc.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcTypeRecreate/ProcTypeRecreate.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcTypeRecreate/processors/AnnoProc.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcUnclosedTypeFiles/ProcUnclosedTypeFiles.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcUnclosedTypeFiles/processors/AnnoProc.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcUseImplicit/ProcUseImplicit.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcUseImplicit/processors/AnnoProc.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcUseImplicit/sourcepath/p/SomeClass.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcUseProcOrImplicit/ProcUseProcOrImplicit.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcUseProcOrImplicit/processors/AnnoProc.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcUseProcOrImplicit/sourcepath/p/SomeClass.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcessorCantInstantiate/ProcessorCantInstantiate.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcessorCantInstantiate/processors/AnnoProc.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcessorNotFound.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcessorWrongType/ProcessorWrongType.java create mode 100644 langtools/test/tools/javac/diags/examples/ProcessorWrongType/processors/AnnoProc.java create mode 100644 langtools/test/tools/javac/diags/examples/QualifiedNewStaticClass.java create mode 100644 langtools/test/tools/javac/diags/examples/RawClassUse.java create mode 100644 langtools/test/tools/javac/diags/examples/RecursiveConstrInvocation.java create mode 100644 langtools/test/tools/javac/diags/examples/RedundantCast.java create mode 100644 langtools/test/tools/javac/diags/examples/RefAmbiguous.java create mode 100644 langtools/test/tools/javac/diags/examples/RepeatedAnnotationTarget.java create mode 100644 langtools/test/tools/javac/diags/examples/RepeatedInterface.java create mode 100644 langtools/test/tools/javac/diags/examples/RepeatedModifier.java create mode 100644 langtools/test/tools/javac/diags/examples/ReportAccess.java create mode 100644 langtools/test/tools/javac/diags/examples/ResourceClosed.java create mode 100644 langtools/test/tools/javac/diags/examples/ResourceMayNotBeAssigned.java create mode 100644 langtools/test/tools/javac/diags/examples/ResourceNotApplicableToType.java create mode 100644 langtools/test/tools/javac/diags/examples/ResourceNotReferenced.java create mode 100644 langtools/test/tools/javac/diags/examples/ReturnOutsideMethod.java create mode 100644 langtools/test/tools/javac/diags/examples/StaticImportNotSupported.java create mode 100644 langtools/test/tools/javac/diags/examples/StaticImportOnlyClassesAndInterfaces/Other.java create mode 100644 langtools/test/tools/javac/diags/examples/StaticImportOnlyClassesAndInterfaces/StaticImportOnlyClassesAndInterfaces.java create mode 100644 langtools/test/tools/javac/diags/examples/StaticNotQualifiedByType.java create mode 100644 langtools/test/tools/javac/diags/examples/StringConstRequired.java create mode 100644 langtools/test/tools/javac/diags/examples/StringSwitchNotSupported.java create mode 100644 langtools/test/tools/javac/diags/examples/SunApiFilename.java create mode 100644 langtools/test/tools/javac/diags/examples/SunApiFilenameAdditional.java create mode 100644 langtools/test/tools/javac/diags/examples/SunApiPlural/SunApiFilename.java create mode 100644 langtools/test/tools/javac/diags/examples/SunApiPlural/SunApiPlural.java create mode 100644 langtools/test/tools/javac/diags/examples/SunApiPluralAdditional/SunApiFilename.java create mode 100644 langtools/test/tools/javac/diags/examples/SunApiPluralAdditional/SunApiPlural.java create mode 100644 langtools/test/tools/javac/diags/examples/SunApiPluralAdditional/SunApiPluralAdditional.java create mode 100644 langtools/test/tools/javac/diags/examples/SunProprietary.java create mode 100644 langtools/test/tools/javac/diags/examples/SuperNotAllowedInEnum.java create mode 100644 langtools/test/tools/javac/diags/examples/ThrowsNotAllowedInAnno.java create mode 100644 langtools/test/tools/javac/diags/examples/TryResourceNotSupported.java create mode 100644 langtools/test/tools/javac/diags/examples/TryWithoutCatchOrFinally.java create mode 100644 langtools/test/tools/javac/diags/examples/TryWithoutCatchOrFinallyOrResource.java create mode 100644 langtools/test/tools/javac/diags/examples/TypeAnnotationsNotSupported.java create mode 100644 langtools/test/tools/javac/diags/examples/TypeFoundRequired.java create mode 100644 langtools/test/tools/javac/diags/examples/TypeNoParams.java create mode 100644 langtools/test/tools/javac/diags/examples/TypeReqClassArray.java create mode 100644 langtools/test/tools/javac/diags/examples/TypeReqRef.java create mode 100644 langtools/test/tools/javac/diags/examples/TypeVarCantBeDeref.java create mode 100644 langtools/test/tools/javac/diags/examples/TypeVarMayNotBeFollowedByOtherBounds.java create mode 100644 langtools/test/tools/javac/diags/examples/TypesIncompatible.java create mode 100644 langtools/test/tools/javac/diags/examples/UncheckedAssign.java create mode 100644 langtools/test/tools/javac/diags/examples/UncheckedAssignToVar.java create mode 100644 langtools/test/tools/javac/diags/examples/UncheckedCall.java create mode 100644 langtools/test/tools/javac/diags/examples/UncheckedCast.java create mode 100644 langtools/test/tools/javac/diags/examples/UncheckedClash.java create mode 100644 langtools/test/tools/javac/diags/examples/UncheckedFilename.java create mode 100644 langtools/test/tools/javac/diags/examples/UncheckedFilenameAdditional.java create mode 100644 langtools/test/tools/javac/diags/examples/UncheckedGenericArrayCreation.java create mode 100644 langtools/test/tools/javac/diags/examples/UncheckedImplement.java create mode 100644 langtools/test/tools/javac/diags/examples/UncheckedMethodInvocation.java create mode 100644 langtools/test/tools/javac/diags/examples/UncheckedPlural/UncheckedFilename.java create mode 100644 langtools/test/tools/javac/diags/examples/UncheckedPlural/UncheckedPlural.java create mode 100644 langtools/test/tools/javac/diags/examples/UncheckedPluralAdditional/UncheckedFilename1.java create mode 100644 langtools/test/tools/javac/diags/examples/UncheckedPluralAdditional/UncheckedFilename2.java create mode 100644 langtools/test/tools/javac/diags/examples/UncheckedPluralAdditional/UncheckedPluralAdditional.java create mode 100644 langtools/test/tools/javac/diags/examples/UnclosedBytecodeIdent.java create mode 100644 langtools/test/tools/javac/diags/examples/UnclosedCharLiteral.java create mode 100644 langtools/test/tools/javac/diags/examples/UnclosedComment.java create mode 100644 langtools/test/tools/javac/diags/examples/UnclosedStringLiteral.java create mode 100644 langtools/test/tools/javac/diags/examples/UndefinedLabel.java create mode 100644 langtools/test/tools/javac/diags/examples/UndeterminedType1.java create mode 100644 langtools/test/tools/javac/diags/examples/UnmatchedProcessorOptions/UnmatchedProcessorOptions.java create mode 100644 langtools/test/tools/javac/diags/examples/UnmatchedProcessorOptions/processors/AnnoProc.java create mode 100644 langtools/test/tools/javac/diags/examples/UnnamedPackage.java create mode 100644 langtools/test/tools/javac/diags/examples/UnreachableStatement.java create mode 100644 langtools/test/tools/javac/diags/examples/UnreportedException.java create mode 100644 langtools/test/tools/javac/diags/examples/UnreportedExceptionDefaultConstructor.java create mode 100644 langtools/test/tools/javac/diags/examples/UnsupportedBinaryLiteral.java create mode 100644 langtools/test/tools/javac/diags/examples/UnsupportedEncoding.java create mode 100644 langtools/test/tools/javac/diags/examples/UnsupportedFpLit.java create mode 100644 langtools/test/tools/javac/diags/examples/UnsupportedUnderscoreLiteral.java create mode 100644 langtools/test/tools/javac/diags/examples/VarMightAlreadyBeAssigned.java create mode 100644 langtools/test/tools/javac/diags/examples/VarMightNotHaveBeenInitialized.java create mode 100644 langtools/test/tools/javac/diags/examples/VarargsClash.java create mode 100644 langtools/test/tools/javac/diags/examples/VarargsFilename.java create mode 100644 langtools/test/tools/javac/diags/examples/VarargsFilenameAdditional.java create mode 100644 langtools/test/tools/javac/diags/examples/VarargsImplement.java create mode 100644 langtools/test/tools/javac/diags/examples/VarargsNonReifiableType.java create mode 100644 langtools/test/tools/javac/diags/examples/VarargsNotSupported.java create mode 100644 langtools/test/tools/javac/diags/examples/VarargsOverride.java create mode 100644 langtools/test/tools/javac/diags/examples/VarargsPlural/VarargsFilename.java create mode 100644 langtools/test/tools/javac/diags/examples/VarargsPlural/VarargsPlural.java create mode 100644 langtools/test/tools/javac/diags/examples/VarargsPluralAdditional/VarargsFilename.java create mode 100644 langtools/test/tools/javac/diags/examples/VarargsPluralAdditional/VarargsPlural.java create mode 100644 langtools/test/tools/javac/diags/examples/VarargsPluralAdditional/VarargsPluralAdditional.java create mode 100644 langtools/test/tools/javac/diags/examples/Verbose.java create mode 100644 langtools/test/tools/javac/diags/examples/VoidNotAllowed.java create mode 100644 langtools/test/tools/javac/diags/examples/WarnForwardRef.java create mode 100644 langtools/test/tools/javac/diags/examples/WarnProcMessager/WarnProcMessager.java create mode 100644 langtools/test/tools/javac/diags/examples/WarnProcMessager/processors/AnnoProc.java create mode 100644 langtools/test/tools/javac/diags/examples/WarnSelfRef.java create mode 100644 langtools/test/tools/javac/diags/examples/WarnSyntheticNameConflict.java create mode 100644 langtools/test/tools/javac/diags/examples/WarningAndWerror.java create mode 100644 langtools/test/tools/javac/diags/examples/WhereCaptured.java create mode 100644 langtools/test/tools/javac/diags/examples/WhereCaptured1.java create mode 100644 langtools/test/tools/javac/diags/examples/WhereIntersection.java create mode 100644 langtools/test/tools/javac/diags/examples/WhereTypeVar.java create mode 100644 langtools/test/tools/javac/diags/examples/WrongNumberTypeArgs.java diff --git a/langtools/make/build.xml b/langtools/make/build.xml index 1abad67a9df..d269f396534 100644 --- a/langtools/make/build.xml +++ b/langtools/make/build.xml @@ -322,6 +322,35 @@ datafile="${build.coverage.dir}/cobertura.ser"/> + + + + + + + + + + + + + + + +