diff --git a/8214535-support-Jmap-parallel.patch b/8214535-support-Jmap-parallel.patch new file mode 100755 index 0000000000000000000000000000000000000000..7dc84e29cdfb7995c83fc6b727fde8a4b81c2ac4 --- /dev/null +++ b/8214535-support-Jmap-parallel.patch @@ -0,0 +1,858 @@ +From 65e9f0b4c719146b0958cb3c01fd31e11e49ec37 Mon Sep 17 00:00:00 2001 +Date: Tue, 16 Mar 2021 07:09:57 +0000 +Subject: [PATCH 4/4] backport JDK-8214535 to support Jmap parallel + +--- + src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 25 ++++ + src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 4 + + .../gc/parallel/parallelScavengeHeap.cpp | 64 +++++++++++ + .../gc/parallel/parallelScavengeHeap.hpp | 22 +++- + src/hotspot/share/gc/parallel/psOldGen.cpp | 32 ++++++ + src/hotspot/share/gc/parallel/psOldGen.hpp | 11 ++ + src/hotspot/share/gc/shared/collectedHeap.hpp | 11 ++ + .../share/gc/shared/vmGCOperations.cpp | 2 +- + .../share/gc/shared/vmGCOperations.hpp | 5 +- + src/hotspot/share/gc/shared/workgroup.hpp | 21 ++++ + src/hotspot/share/memory/heapInspection.cpp | 108 ++++++++++++++++-- + src/hotspot/share/memory/heapInspection.hpp | 44 ++++++- + src/hotspot/share/runtime/arguments.hpp | 12 +- + src/hotspot/share/services/attachListener.cpp | 15 ++- + .../share/classes/sun/tools/jmap/JMap.java | 41 +++++-- + test/jdk/sun/tools/jmap/BasicJMapTest.java | 55 +++++++++ + 16 files changed, 442 insertions(+), 30 deletions(-) + +diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +index 7e9c6254c..fd2da14a3 100644 +--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp ++++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +@@ -77,6 +77,7 @@ + #include "gc/shared/weakProcessor.hpp" + #include "logging/log.hpp" + #include "memory/allocation.hpp" ++#include "memory/heapInspection.hpp" + #include "memory/iterator.hpp" + #include "memory/metaspaceShared.hpp" + #include "memory/resourceArea.hpp" +@@ -2208,6 +2209,30 @@ void G1CollectedHeap::object_iterate(ObjectClosure* cl) { + heap_region_iterate(&blk); + } + ++class G1ParallelObjectIterator : public ParallelObjectIterator { ++private: ++ G1CollectedHeap* _heap; ++ HeapRegionClaimer _claimer; ++ ++public: ++ G1ParallelObjectIterator(uint thread_num) : ++ _heap(G1CollectedHeap::heap()), ++ _claimer(thread_num == 0 ? G1CollectedHeap::heap()->workers()->active_workers() : thread_num) {} ++ ++ virtual void object_iterate(ObjectClosure* cl, uint worker_id) { ++ _heap->object_iterate_parallel(cl, worker_id, &_claimer); ++ } ++}; ++ ++ParallelObjectIterator* G1CollectedHeap::parallel_object_iterator(uint thread_num) { ++ return new G1ParallelObjectIterator(thread_num); ++} ++ ++void G1CollectedHeap::object_iterate_parallel(ObjectClosure* cl, uint worker_id, HeapRegionClaimer* claimer) { ++ IterateObjectClosureRegionClosure blk(cl); ++ heap_region_par_iterate_from_worker_offset(&blk, claimer, worker_id); ++} ++ + void G1CollectedHeap::heap_region_iterate(HeapRegionClosure* cl) const { + _hrm.iterate(cl); + } +diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +index bb46cae83..82f59d69b 100644 +--- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp ++++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +@@ -1125,9 +1125,13 @@ public: + + // Iteration functions. + ++ void object_iterate_parallel(ObjectClosure* cl, uint worker_id, HeapRegionClaimer* claimer); ++ + // Iterate over all objects, calling "cl.do_object" on each. + virtual void object_iterate(ObjectClosure* cl); + ++ virtual ParallelObjectIterator* parallel_object_iterator(uint thread_num); ++ + virtual void safe_object_iterate(ObjectClosure* cl) { + object_iterate(cl); + } +diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +index 29f967fb3..66e1b32a6 100644 +--- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp ++++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +@@ -523,6 +523,70 @@ void ParallelScavengeHeap::object_iterate(ObjectClosure* cl) { + old_gen()->object_iterate(cl); + } + ++// The HeapBlockClaimer is used during parallel iteration over the heap, ++// allowing workers to claim heap areas ("blocks"), gaining exclusive rights to these. ++// The eden and survivor spaces are treated as single blocks as it is hard to divide ++// these spaces. ++// The old space is divided into fixed-size blocks. ++class HeapBlockClaimer : public StackObj { ++ size_t _claimed_index; ++ ++public: ++ static const size_t InvalidIndex = SIZE_MAX; ++ static const size_t EdenIndex = 0; ++ static const size_t SurvivorIndex = 1; ++ static const size_t NumNonOldGenClaims = 2; ++ ++ HeapBlockClaimer() : _claimed_index(EdenIndex) { } ++ // Claim the block and get the block index. ++ size_t claim_and_get_block() { ++ size_t block_index; ++ block_index = Atomic::add(1u, &_claimed_index) - 1; // TODO: original impl is: Atomic::fetch_and_add(&_claimed_index, 1u); ++ ++ PSOldGen* old_gen = ParallelScavengeHeap::heap()->old_gen(); ++ size_t num_claims = old_gen->num_iterable_blocks() + NumNonOldGenClaims; ++ ++ return block_index < num_claims ? block_index : InvalidIndex; ++ } ++}; ++ ++void ParallelScavengeHeap::object_iterate_parallel(ObjectClosure* cl, ++ HeapBlockClaimer* claimer) { ++ size_t block_index = claimer->claim_and_get_block(); ++ // Iterate until all blocks are claimed ++ if (block_index == HeapBlockClaimer::EdenIndex) { ++ young_gen()->eden_space()->object_iterate(cl); ++ block_index = claimer->claim_and_get_block(); ++ } ++ if (block_index == HeapBlockClaimer::SurvivorIndex) { ++ young_gen()->from_space()->object_iterate(cl); ++ young_gen()->to_space()->object_iterate(cl); ++ block_index = claimer->claim_and_get_block(); ++ } ++ while (block_index != HeapBlockClaimer::InvalidIndex) { ++ old_gen()->object_iterate_block(cl, block_index - HeapBlockClaimer::NumNonOldGenClaims); ++ block_index = claimer->claim_and_get_block(); ++ } ++} ++ ++class PSScavengeParallelObjectIterator : public ParallelObjectIterator { ++private: ++ ParallelScavengeHeap* _heap; ++ HeapBlockClaimer _claimer; ++ ++public: ++ PSScavengeParallelObjectIterator() : ++ _heap(ParallelScavengeHeap::heap()), ++ _claimer() {} ++ ++ virtual void object_iterate(ObjectClosure* cl, uint worker_id) { ++ _heap->object_iterate_parallel(cl, &_claimer); ++ } ++}; ++ ++ParallelObjectIterator* ParallelScavengeHeap::parallel_object_iterator(uint thread_num) { ++ return new PSScavengeParallelObjectIterator(); ++} + + HeapWord* ParallelScavengeHeap::block_start(const void* addr) const { + if (young_gen()->is_in_reserved(addr)) { +diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp +index 5d18efb92..0a9b7bd3f 100644 +--- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp ++++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp +@@ -44,6 +44,7 @@ + class AdjoiningGenerations; + class GCHeapSummary; + class GCTaskManager; ++class HeapBlockClaimer; + class MemoryManager; + class MemoryPool; + class PSAdaptiveSizePolicy; +@@ -79,6 +80,8 @@ class ParallelScavengeHeap : public CollectedHeap { + MemoryPool* _survivor_pool; + MemoryPool* _old_pool; + ++ WorkGang _workers; ++ + virtual void initialize_serviceability(); + + void trace_heap(GCWhen::Type when, const GCTracer* tracer); +@@ -93,7 +96,20 @@ class ParallelScavengeHeap : public CollectedHeap { + + public: + ParallelScavengeHeap(GenerationSizer* policy) : +- CollectedHeap(), _collector_policy(policy), _death_march_count(0) { } ++ CollectedHeap(), ++ _collector_policy(policy), ++ _death_march_count(0), ++ _young_manager(NULL), ++ _old_manager(NULL), ++ _eden_pool(NULL), ++ _survivor_pool(NULL), ++ _old_pool(NULL), ++ _workers("GC Thread", ++ ParallelGCThreads, ++ true /* are_GC_task_threads */, ++ false /* are_ConcurrentGC_threads */) { ++ _workers.initialize_workers(); ++ } + + // For use by VM operations + enum CollectionType { +@@ -217,6 +233,8 @@ class ParallelScavengeHeap : public CollectedHeap { + + void object_iterate(ObjectClosure* cl); + void safe_object_iterate(ObjectClosure* cl) { object_iterate(cl); } ++ void object_iterate_parallel(ObjectClosure* cl, HeapBlockClaimer* claimer); ++ virtual ParallelObjectIterator* parallel_object_iterator(uint thread_num); + + HeapWord* block_start(const void* addr) const; + size_t block_size(const HeapWord* addr) const; +@@ -232,6 +250,8 @@ class ParallelScavengeHeap : public CollectedHeap { + virtual void gc_threads_do(ThreadClosure* tc) const; + virtual void print_tracing_info() const; + ++ virtual WorkGang* get_safepoint_workers() { return &_workers; } ++ + void verify(VerifyOption option /* ignored */); + + // Resize the young generation. The reserved space for the +diff --git a/src/hotspot/share/gc/parallel/psOldGen.cpp b/src/hotspot/share/gc/parallel/psOldGen.cpp +index 35844b14b..dbb5148fd 100644 +--- a/src/hotspot/share/gc/parallel/psOldGen.cpp ++++ b/src/hotspot/share/gc/parallel/psOldGen.cpp +@@ -213,6 +213,38 @@ HeapWord* PSOldGen::allocate(size_t word_size) { + return res; + } + ++size_t PSOldGen::num_iterable_blocks() const { ++ return (object_space()->used_in_bytes() + IterateBlockSize - 1) / IterateBlockSize; ++} ++ ++void PSOldGen::object_iterate_block(ObjectClosure* cl, size_t block_index) { ++ size_t block_word_size = IterateBlockSize / HeapWordSize; ++ assert((block_word_size % (ObjectStartArray::block_size)) == 0, ++ "Block size not a multiple of start_array block"); ++ ++ MutableSpace *space = object_space(); ++ ++ HeapWord* begin = space->bottom() + block_index * block_word_size; ++ HeapWord* end = MIN2(space->top(), begin + block_word_size); ++ ++ if (!start_array()->object_starts_in_range(begin, end)) { ++ return; ++ } ++ ++ // Get object starting at or reaching into this block. ++ HeapWord* start = start_array()->object_start(begin); ++ if (start < begin) { ++ start += oop(start)->size(); ++ } ++ assert(start >= begin, ++ "Object address" PTR_FORMAT " must be larger or equal to block address at " PTR_FORMAT, ++ p2i(start), p2i(begin)); ++ // Iterate all objects until the end. ++ for (HeapWord* p = start; p < end; p += oop(p)->size()) { ++ cl->do_object(oop(p)); ++ } ++} ++ + HeapWord* PSOldGen::expand_and_allocate(size_t word_size) { + expand(word_size*HeapWordSize); + if (GCExpandToAllocateDelayMillis > 0) { +diff --git a/src/hotspot/share/gc/parallel/psOldGen.hpp b/src/hotspot/share/gc/parallel/psOldGen.hpp +index fa27f5a04..fa6e4849b 100644 +--- a/src/hotspot/share/gc/parallel/psOldGen.hpp ++++ b/src/hotspot/share/gc/parallel/psOldGen.hpp +@@ -59,6 +59,9 @@ class PSOldGen : public CHeapObj { + const size_t _min_gen_size; + const size_t _max_gen_size; + ++ // Block size for parallel iteration ++ static const size_t IterateBlockSize = 1024 * 1024; ++ + // Used when initializing the _name field. + static inline const char* select_name(); + +@@ -195,6 +198,14 @@ class PSOldGen : public CHeapObj { + void oop_iterate(OopIterateClosure* cl) { object_space()->oop_iterate(cl); } + void object_iterate(ObjectClosure* cl) { object_space()->object_iterate(cl); } + ++ // Number of blocks to be iterated over in the used part of old gen. ++ size_t num_iterable_blocks() const; ++ // Iterate the objects starting in block block_index within [bottom, top) of the ++ // old gen. The object just reaching into this block is not iterated over. ++ // A block is an evenly sized non-overlapping part of the old gen of ++ // IterateBlockSize bytes. ++ void object_iterate_block(ObjectClosure* cl, size_t block_index); ++ + // Debugging - do not use for time critical operations + virtual void print() const; + virtual void print_on(outputStream* st) const; +diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp +index 47acf22cb..bcd4da29a 100644 +--- a/src/hotspot/share/gc/shared/collectedHeap.hpp ++++ b/src/hotspot/share/gc/shared/collectedHeap.hpp +@@ -28,6 +28,7 @@ + #include "gc/shared/gcCause.hpp" + #include "gc/shared/gcWhen.hpp" + #include "memory/allocation.hpp" ++#include "memory/heapInspection.hpp" + #include "runtime/handles.hpp" + #include "runtime/perfData.hpp" + #include "runtime/safepoint.hpp" +@@ -42,6 +43,7 @@ + // class defines the functions that a heap must implement, and contains + // infrastructure common to all heaps. + ++class AbstractGangTask; + class AdaptiveSizePolicy; + class BarrierSet; + class CollectorPolicy; +@@ -83,6 +85,11 @@ class GCHeapLog : public EventLogBase { + } + }; + ++class ParallelObjectIterator : public CHeapObj { ++public: ++ virtual void object_iterate(ObjectClosure* cl, uint worker_id) = 0; ++}; ++ + // + // CollectedHeap + // GenCollectedHeap +@@ -434,6 +441,10 @@ class CollectedHeap : public CHeapObj { + // Iterate over all objects, calling "cl.do_object" on each. + virtual void object_iterate(ObjectClosure* cl) = 0; + ++ virtual ParallelObjectIterator* parallel_object_iterator(uint thread_num) { ++ return NULL; ++ } ++ + // Similar to object_iterate() except iterates only + // over live objects. + virtual void safe_object_iterate(ObjectClosure* cl) = 0; +diff --git a/src/hotspot/share/gc/shared/vmGCOperations.cpp b/src/hotspot/share/gc/shared/vmGCOperations.cpp +index b02305a6e..728290a7b 100644 +--- a/src/hotspot/share/gc/shared/vmGCOperations.cpp ++++ b/src/hotspot/share/gc/shared/vmGCOperations.cpp +@@ -154,7 +154,7 @@ void VM_GC_HeapInspection::doit() { + } + HeapInspection inspect(_csv_format, _print_help, _print_class_stats, + _columns); +- inspect.heap_inspection(_out); ++ inspect.heap_inspection(_out, _parallel_thread_num); + } + + +diff --git a/src/hotspot/share/gc/shared/vmGCOperations.hpp b/src/hotspot/share/gc/shared/vmGCOperations.hpp +index 65876e559..ef73b45de 100644 +--- a/src/hotspot/share/gc/shared/vmGCOperations.hpp ++++ b/src/hotspot/share/gc/shared/vmGCOperations.hpp +@@ -125,18 +125,21 @@ class VM_GC_HeapInspection: public VM_GC_Operation { + private: + outputStream* _out; + bool _full_gc; ++ uint _parallel_thread_num; + bool _csv_format; // "comma separated values" format for spreadsheet. + bool _print_help; + bool _print_class_stats; + const char* _columns; + public: +- VM_GC_HeapInspection(outputStream* out, bool request_full_gc) : ++ VM_GC_HeapInspection(outputStream* out, bool request_full_gc, ++ uint parallel_thread_num = 1) : + VM_GC_Operation(0 /* total collections, dummy, ignored */, + GCCause::_heap_inspection /* GC Cause */, + 0 /* total full collections, dummy, ignored */, + request_full_gc) { + _out = out; + _full_gc = request_full_gc; ++ _parallel_thread_num = parallel_thread_num; + _csv_format = false; + _print_help = false; + _print_class_stats = false; +diff --git a/src/hotspot/share/gc/shared/workgroup.hpp b/src/hotspot/share/gc/shared/workgroup.hpp +index 8b46d3bc4..109649df0 100644 +--- a/src/hotspot/share/gc/shared/workgroup.hpp ++++ b/src/hotspot/share/gc/shared/workgroup.hpp +@@ -228,6 +228,27 @@ protected: + virtual AbstractGangWorker* allocate_worker(uint which); + }; + ++// Temporarily try to set the number of active workers. ++// It's not guaranteed that it succeeds, and users need to ++// query the number of active workers. ++class WithUpdatedActiveWorkers : public StackObj { ++private: ++ AbstractWorkGang* const _gang; ++ const uint _old_active_workers; ++ ++public: ++ WithUpdatedActiveWorkers(AbstractWorkGang* gang, uint requested_num_workers) : ++ _gang(gang), ++ _old_active_workers(gang->active_workers()) { ++ uint capped_num_workers = MIN2(requested_num_workers, gang->total_workers()); ++ gang->update_active_workers(capped_num_workers); ++ } ++ ++ ~WithUpdatedActiveWorkers() { ++ _gang->update_active_workers(_old_active_workers); ++ } ++}; ++ + // Several instances of this class run in parallel as workers for a gang. + class AbstractGangWorker: public WorkerThread { + public: +diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp +index 9c2cdc117..dbc0eb274 100644 +--- a/src/hotspot/share/memory/heapInspection.cpp ++++ b/src/hotspot/share/memory/heapInspection.cpp +@@ -31,6 +31,7 @@ + #include "memory/resourceArea.hpp" + #include "oops/oop.inline.hpp" + #include "oops/reflectionAccessorImplKlassHelper.hpp" ++#include "runtime/atomic.hpp" + #include "runtime/os.hpp" + #include "utilities/globalDefinitions.hpp" + #include "utilities/macros.hpp" +@@ -236,6 +237,41 @@ size_t KlassInfoTable::size_of_instances_in_words() const { + return _size_of_instances_in_words; + } + ++// Return false if the entry could not be recorded on account ++// of running out of space required to create a new entry. ++bool KlassInfoTable::merge_entry(const KlassInfoEntry* cie) { ++ Klass* k = cie->klass(); ++ KlassInfoEntry* elt = lookup(k); ++ // elt may be NULL if it's a new klass for which we ++ // could not allocate space for a new entry in the hashtable. ++ if (elt != NULL) { ++ elt->set_count(elt->count() + cie->count()); ++ elt->set_words(elt->words() + cie->words()); ++ _size_of_instances_in_words += cie->words(); ++ return true; ++ } ++ return false; ++} ++ ++class KlassInfoTableMergeClosure : public KlassInfoClosure { ++ private: ++ KlassInfoTable* _dest; ++ bool _success; ++ public: ++ KlassInfoTableMergeClosure(KlassInfoTable* table) : _dest(table), _success(true) {} ++ void do_cinfo(KlassInfoEntry* cie) { ++ _success &= _dest->merge_entry(cie); ++ } ++ bool success() { return _success; } ++}; ++ ++// merge from table ++bool KlassInfoTable::merge(KlassInfoTable* table) { ++ KlassInfoTableMergeClosure closure(this); ++ table->iterate(&closure); ++ return closure.success(); ++} ++ + int KlassInfoHisto::sort_helper(KlassInfoEntry** e1, KlassInfoEntry** e2) { + return (*e1)->compare(*e1,*e2); + } +@@ -687,7 +723,7 @@ class HistoClosure : public KlassInfoClosure { + class RecordInstanceClosure : public ObjectClosure { + private: + KlassInfoTable* _cit; +- size_t _missed_count; ++ uintx _missed_count; + BoolObjectClosure* _filter; + public: + RecordInstanceClosure(KlassInfoTable* cit, BoolObjectClosure* filter) : +@@ -701,7 +737,7 @@ class RecordInstanceClosure : public ObjectClosure { + } + } + +- size_t missed_count() { return _missed_count; } ++ uintx missed_count() { return _missed_count; } + + private: + bool should_visit(oop obj) { +@@ -709,15 +745,73 @@ class RecordInstanceClosure : public ObjectClosure { + } + }; + +-size_t HeapInspection::populate_table(KlassInfoTable* cit, BoolObjectClosure *filter) { +- ResourceMark rm; ++// Heap inspection for every worker. ++// When native OOM hanppens for KlassInfoTable, set _success to false. ++void ParHeapInspectTask::work(uint worker_id) { ++ uintx missed_count = 0; ++ bool merge_success = true; ++ if (!Atomic::load(&_success)) { ++ // other worker has failed on parallel iteration. ++ return; ++ } + ++ KlassInfoTable cit(false); ++ if (cit.allocation_failed()) { ++ // fail to allocate memory, stop parallel mode ++ Atomic::store(false, &_success); ++ return; ++ } ++ RecordInstanceClosure ric(&cit, _filter); ++ _poi->object_iterate(&ric, worker_id); ++ missed_count = ric.missed_count(); ++ { ++ MutexLocker x(&_mutex); ++ merge_success = _shared_cit->merge(&cit); ++ } ++ if (merge_success) { ++ Atomic::add(missed_count, &_missed_count); ++ } else { ++ Atomic::store(false, &_success); ++ } ++} ++ ++size_t HeapInspection::populate_table(KlassInfoTable* cit, BoolObjectClosure *filter, uint parallel_thread_num) { ++ // Try parallel first. ++ if (parallel_thread_num > 1) { ++ ResourceMark rm; ++ ++ WorkGang* gang = Universe::heap()->get_safepoint_workers(); ++ if (gang != NULL) { ++ // The GC provided a WorkGang to be used during a safepoint. ++ ++ // Can't run with more threads than provided by the WorkGang. ++ WithUpdatedActiveWorkers update_and_restore(gang, parallel_thread_num); ++ ++ ParallelObjectIterator* poi = Universe::heap()->parallel_object_iterator(gang->active_workers()); ++ if (poi != NULL) { ++ // The GC supports parallel object iteration. ++ ++ ParHeapInspectTask task(poi, cit, filter); ++ // Run task with the active workers. ++ ++ gang->run_task(&task); ++ ++ delete poi; ++ if (task.success()) { ++ return task.missed_count(); ++ } ++ } ++ } ++ } ++ ++ ResourceMark rm; ++ // If no parallel iteration available, run serially. + RecordInstanceClosure ric(cit, filter); + Universe::heap()->safe_object_iterate(&ric); + return ric.missed_count(); + } + +-void HeapInspection::heap_inspection(outputStream* st) { ++void HeapInspection::heap_inspection(outputStream* st, uint parallel_thread_num) { + ResourceMark rm; + + if (_print_help) { +@@ -741,9 +835,9 @@ void HeapInspection::heap_inspection(outputStream* st) { + KlassInfoTable cit(_print_class_stats); + if (!cit.allocation_failed()) { + // populate table with object allocation info +- size_t missed_count = populate_table(&cit); ++ uintx missed_count = populate_table(&cit, NULL, parallel_thread_num); + if (missed_count != 0) { +- st->print_cr("WARNING: Ran out of C-heap; undercounted " SIZE_FORMAT ++ st->print_cr("WARNING: Ran out of C-heap; undercounted " UINTX_FORMAT + " total instances in data below", + missed_count); + } +diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp +index d8935dc68..026293bf7 100644 +--- a/src/hotspot/share/memory/heapInspection.hpp ++++ b/src/hotspot/share/memory/heapInspection.hpp +@@ -25,12 +25,15 @@ + #ifndef SHARE_VM_MEMORY_HEAPINSPECTION_HPP + #define SHARE_VM_MEMORY_HEAPINSPECTION_HPP + ++#include "gc/shared/workgroup.hpp" + #include "memory/allocation.hpp" + #include "oops/objArrayOop.hpp" + #include "oops/oop.hpp" + #include "oops/annotations.hpp" + #include "utilities/macros.hpp" + ++class ParallelObjectIterator; ++ + #if INCLUDE_SERVICES + + +@@ -261,6 +264,8 @@ class KlassInfoTable: public StackObj { + void iterate(KlassInfoClosure* cic); + bool allocation_failed() { return _buckets == NULL; } + size_t size_of_instances_in_words() const; ++ bool merge(KlassInfoTable* table); ++ bool merge_entry(const KlassInfoEntry* cie); + + friend class KlassInfoHisto; + friend class KlassHierarchy; +@@ -364,11 +369,46 @@ class HeapInspection : public StackObj { + bool print_class_stats, const char *columns) : + _csv_format(csv_format), _print_help(print_help), + _print_class_stats(print_class_stats), _columns(columns) {} +- void heap_inspection(outputStream* st) NOT_SERVICES_RETURN; +- size_t populate_table(KlassInfoTable* cit, BoolObjectClosure* filter = NULL) NOT_SERVICES_RETURN_(0); ++ void heap_inspection(outputStream* st, uint parallel_thread_num = 1) NOT_SERVICES_RETURN; ++ size_t populate_table(KlassInfoTable* cit, BoolObjectClosure* filter = NULL, uint parallel_thread_num = 1) NOT_SERVICES_RETURN_(0); + static void find_instances_at_safepoint(Klass* k, GrowableArray* result) NOT_SERVICES_RETURN; + private: + void iterate_over_heap(KlassInfoTable* cit, BoolObjectClosure* filter = NULL); + }; + ++// Parallel heap inspection task. Parallel inspection can fail due to ++// a native OOM when allocating memory for TL-KlassInfoTable. ++// _success will be set false on an OOM, and serial inspection tried. ++class ParHeapInspectTask : public AbstractGangTask { ++private: ++ ParallelObjectIterator *_poi; ++ KlassInfoTable *_shared_cit; ++ BoolObjectClosure *_filter; ++ uintx _missed_count; ++ bool _success; ++ Mutex _mutex; ++ ++public: ++ ParHeapInspectTask(ParallelObjectIterator *poi, ++ KlassInfoTable *shared_cit, ++ BoolObjectClosure *filter) : ++ AbstractGangTask("Iterating heap"), ++ _poi(poi), ++ _shared_cit(shared_cit), ++ _filter(filter), ++ _missed_count(0), ++ _success(true), ++ _mutex(Mutex::leaf, "Parallel heap iteration data merge lock") {} ++ ++ uintx missed_count() const { ++ return _missed_count; ++ } ++ ++ bool success() { ++ return _success; ++ } ++ ++ virtual void work(uint worker_id); ++}; ++ + #endif // SHARE_VM_MEMORY_HEAPINSPECTION_HPP +diff --git a/src/hotspot/share/runtime/arguments.hpp b/src/hotspot/share/runtime/arguments.hpp +index bd439aab0..9827a4c66 100644 +--- a/src/hotspot/share/runtime/arguments.hpp ++++ b/src/hotspot/share/runtime/arguments.hpp +@@ -450,12 +450,6 @@ class Arguments : AllStatic { + static ArgsRange check_memory_size(julong size, julong min_size, julong max_size); + static ArgsRange parse_memory_size(const char* s, julong* long_arg, + julong min_size, julong max_size = max_uintx); +- // Parse a string for a unsigned integer. Returns true if value +- // is an unsigned integer greater than or equal to the minimum +- // parameter passed and returns the value in uintx_arg. Returns +- // false otherwise, with uintx_arg undefined. +- static bool parse_uintx(const char* value, uintx* uintx_arg, +- uintx min_size); + + // methods to build strings from individual args + static void build_jvm_args(const char* arg); +@@ -493,6 +487,12 @@ class Arguments : AllStatic { + public: + // Parses the arguments, first phase + static jint parse(const JavaVMInitArgs* args); ++ // Parse a string for a unsigned integer. Returns true if value ++ // is an unsigned integer greater than or equal to the minimum ++ // parameter passed and returns the value in uintx_arg. Returns ++ // false otherwise, with uintx_arg undefined. ++ static bool parse_uintx(const char* value, uintx* uintx_arg, ++ uintx min_size); + // Apply ergonomics + static jint apply_ergo(); + // Adjusts the arguments after the OS have adjusted the arguments +diff --git a/src/hotspot/share/services/attachListener.cpp b/src/hotspot/share/services/attachListener.cpp +index fc77970a0..b0f3b2e87 100644 +--- a/src/hotspot/share/services/attachListener.cpp ++++ b/src/hotspot/share/services/attachListener.cpp +@@ -258,9 +258,11 @@ jint dump_heap(AttachOperation* op, outputStream* out) { + // + // Input arguments :- + // arg0: "-live" or "-all" ++// arg1: parallel thread number + static jint heap_inspection(AttachOperation* op, outputStream* out) { + bool live_objects_only = true; // default is true to retain the behavior before this change is made + const char* arg0 = op->arg(0); ++ uint parallel_thread_num = MAX2(1, (uint)os::initial_active_processor_count() * 3 / 8); + if (arg0 != NULL && (strlen(arg0) > 0)) { + if (strcmp(arg0, "-all") != 0 && strcmp(arg0, "-live") != 0) { + out->print_cr("Invalid argument to inspectheap operation: %s", arg0); +@@ -268,7 +270,18 @@ static jint heap_inspection(AttachOperation* op, outputStream* out) { + } + live_objects_only = strcmp(arg0, "-live") == 0; + } +- VM_GC_HeapInspection heapop(out, live_objects_only /* request full gc */); ++ ++ const char* num_str = op->arg(1); ++ if (num_str != NULL && num_str[0] != '\0') { ++ uintx num; ++ if (!Arguments::parse_uintx(num_str, &num, 0)) { ++ out->print_cr("Invalid parallel thread number: [%s]", num_str); ++ return JNI_ERR; ++ } ++ parallel_thread_num = num == 0 ? parallel_thread_num : (uint)num; ++ } ++ ++ VM_GC_HeapInspection heapop(out, live_objects_only /* request full gc */, parallel_thread_num); + VMThread::execute(&heapop); + return JNI_OK; + } +diff --git a/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java b/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java +index f2db61ab7..9af74f362 100644 +--- a/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java ++++ b/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java +@@ -149,18 +149,28 @@ public class JMap { + throws AttachNotSupportedException, IOException, + UnsupportedEncodingException { + String liveopt = "-all"; +- if (options.equals("") || options.equals("all")) { +- // pass +- } +- else if (options.equals("live")) { +- liveopt = "-live"; +- } +- else { +- usage(1); ++ String parallel = null; ++ String subopts[] = options.split(","); ++ ++ for (int i = 0; i < subopts.length; i++) { ++ String subopt = subopts[i]; ++ if (subopt.equals("") || subopt.equals("all")) { ++ // pass ++ } else if (subopt.equals("live")) { ++ liveopt = "-live"; ++ } else if (subopt.startsWith("parallel=")) { ++ parallel = subopt.substring("parallel=".length()); ++ if (parallel == null) { ++ System.err.println("Fail: no number provided in option: '" + subopt + "'"); ++ System.exit(1); ++ } ++ } else { ++ usage(1); ++ } + } + + // inspectHeap is not the same as jcmd GC.class_histogram +- executeCommandForPid(pid, "inspectheap", liveopt); ++ executeCommandForPid(pid, "inspectheap", liveopt, parallel); + } + + private static void dump(String pid, String options) +@@ -246,9 +256,8 @@ public class JMap { + System.err.println(" to connect to running process and print class loader statistics"); + System.err.println(" jmap -finalizerinfo "); + System.err.println(" to connect to running process and print information on objects awaiting finalization"); +- System.err.println(" jmap -histo[:live] "); ++ System.err.println(" jmap -histo: "); + System.err.println(" to connect to running process and print histogram of java object heap"); +- System.err.println(" if the \"live\" suboption is specified, only count live objects"); + System.err.println(" jmap -dump: "); + System.err.println(" to connect to running process and dump java heap"); + System.err.println(" jmap -? -h --help"); +@@ -261,6 +270,16 @@ public class JMap { + System.err.println(" file= dump heap to "); + System.err.println(""); + System.err.println(" Example: jmap -dump:live,format=b,file=heap.bin "); ++ System.err.println(""); ++ System.err.println(" histo-options:"); ++ System.err.println(" live count only live objects"); ++ System.err.println(" all count all objects in the heap (default if one of \"live\" or \"all\" is not specified)"); ++ System.err.println(" parallel= parallel threads number for heap iteration:"); ++ System.err.println(" parallel=0 default behavior, use predefined number of threads"); ++ System.err.println(" parallel=1 disable parallel heap iteration"); ++ System.err.println(" parallel= use N threads for parallel heap iteration"); ++ System.err.println(""); ++ System.err.println(" Example: jmap -histo:live,parallel=2 "); + System.exit(exit); + } + } +diff --git a/test/jdk/sun/tools/jmap/BasicJMapTest.java b/test/jdk/sun/tools/jmap/BasicJMapTest.java +index c0432dede..960705e24 100644 +--- a/test/jdk/sun/tools/jmap/BasicJMapTest.java ++++ b/test/jdk/sun/tools/jmap/BasicJMapTest.java +@@ -45,6 +45,35 @@ import jdk.testlibrary.ProcessTools; + * @build jdk.test.lib.hprof.util.* + * @run main/timeout=240 BasicJMapTest + */ ++ ++/* ++ * @test id=Parallel ++ * @summary Unit test for jmap utility (Parallel GC) ++ * @key intermittent ++ * @library /lib/testlibrary ++ * @library /test/lib ++ * @build jdk.testlibrary.* ++ * @build jdk.test.lib.hprof.* ++ * @build jdk.test.lib.hprof.model.* ++ * @build jdk.test.lib.hprof.parser.* ++ * @build jdk.test.lib.hprof.util.* ++ * @run main/othervm/timeout=240 -XX:+UseParallelGC BasicJMapTest ++ */ ++ ++/* ++ * @test id=G1 ++ * @summary Unit test for jmap utility (G1 GC) ++ * @key intermittent ++ * @library /lib/testlibrary ++ * @library /test/lib ++ * @build jdk.testlibrary.* ++ * @build jdk.test.lib.hprof.* ++ * @build jdk.test.lib.hprof.model.* ++ * @build jdk.test.lib.hprof.parser.* ++ * @build jdk.test.lib.hprof.util.* ++ * @run main/othervm/timeout=240 -XX:+UseG1GC BasicJMapTest ++ */ ++ + public class BasicJMapTest { + + private static ProcessBuilder processBuilder = new ProcessBuilder(); +@@ -68,6 +97,32 @@ public class BasicJMapTest { + output.shouldHaveExitValue(0); + } + ++ private static void testHistoParallelZero() throws Exception { ++ OutputAnalyzer output = jmap("-histo:parallel=0"); ++ output.shouldHaveExitValue(0); ++ } ++ ++ private static void testHistoParallel() throws Exception { ++ OutputAnalyzer output = jmap("-histo:parallel=2"); ++ output.shouldHaveExitValue(0); ++ } ++ ++ private static void testHistoNonParallel() throws Exception { ++ OutputAnalyzer output = jmap("-histo:parallel=1"); ++ output.shouldHaveExitValue(0); ++ } ++ ++ private static void testHistoMultipleParameters() throws Exception { ++ OutputAnalyzer output = jmap("-histo:parallel=2,live"); ++ output.shouldHaveExitValue(0); ++ output = jmap("-histo:live,parallel=2"); ++ output.shouldHaveExitValue(0); ++ output = jmap("-histo:parallel=2,all"); ++ output.shouldHaveExitValue(0); ++ output = jmap("-histo:all,parallel=2"); ++ output.shouldHaveExitValue(0); ++ } ++ + private static void testFinalizerInfo() throws Exception { + OutputAnalyzer output = jmap("-finalizerinfo"); + output.shouldHaveExitValue(0); +-- +2.19.0 + diff --git a/8217856-ZGC-Break-out-C2-matching-rules-into-separat.patch b/8217856-ZGC-Break-out-C2-matching-rules-into-separat.patch index a1dd7dea25f59962995a933b09be7c5eef4a99ee..df9f0a658f564e82ea66beacffbcb3b7381df5cb 100644 --- a/8217856-ZGC-Break-out-C2-matching-rules-into-separat.patch +++ b/8217856-ZGC-Break-out-C2-matching-rules-into-separat.patch @@ -3,8 +3,8 @@ index 6878962..bb9721c 100644 --- a/make/hotspot/gensrc/GensrcAdlc.gmk +++ b/make/hotspot/gensrc/GensrcAdlc.gmk @@ -146,6 +146,12 @@ ifeq ($(call check-jvm-feature, compiler2), true) - ))) - endif + $d/os_cpu/$(HOTSPOT_TARGET_OS)_$(HOTSPOT_TARGET_CPU_ARCH)/$(HOTSPOT_TARGET_OS)_$(HOTSPOT_TARGET_CPU_ARCH).ad \ + ))) + ifeq ($(call check-jvm-feature, zgc), true) + AD_SRC_FILES += $(call uniq, $(wildcard $(foreach d, $(AD_SRC_ROOTS), \ @@ -12,9 +12,9 @@ index 6878962..bb9721c 100644 + ))) + endif + - SINGLE_AD_SRCFILE := $(ADLC_SUPPORT_DIR)/all-ad-src.ad - - INSERT_FILENAME_AWK_SCRIPT := \ + ifeq ($(call check-jvm-feature, shenandoahgc), true) + AD_SRC_FILES += $(call uniq, $(wildcard $(foreach d, $(AD_SRC_ROOTS), \ + $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/shenandoah/shenandoah_$(HOTSPOT_TARGET_CPU).ad \ diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 05b36e2..18e774f 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad diff --git a/8217918-C2-XX-AggressiveUnboxing-is-broken.patch b/8217918-C2-XX-AggressiveUnboxing-is-broken.patch new file mode 100755 index 0000000000000000000000000000000000000000..03a94c27513b8b7fbb17ed319c482db16c2ca9d1 --- /dev/null +++ b/8217918-C2-XX-AggressiveUnboxing-is-broken.patch @@ -0,0 +1,263 @@ +From 8da2787209da1906e3a92fff95dc46abe793b433 Mon Sep 17 00:00:00 2001 +Date: Thu, 18 Mar 2021 12:36:13 +0000 +Subject: [PATCH 3/4] 8217918: C2 -XX:+AggressiveUnboxing is broken + +--- + src/hotspot/share/opto/cfgnode.hpp | 4 +- + src/hotspot/share/opto/phaseX.cpp | 96 ++++++++++++++++++++++++------ + src/hotspot/share/opto/phaseX.hpp | 10 ++++ + src/hotspot/share/opto/type.cpp | 16 +++++ + src/hotspot/share/opto/type.hpp | 4 ++ + 5 files changed, 111 insertions(+), 19 deletions(-) + +diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp +index 0d8c9b33b..04029ca91 100644 +--- a/src/hotspot/share/opto/cfgnode.hpp ++++ b/src/hotspot/share/opto/cfgnode.hpp +@@ -118,11 +118,13 @@ class JProjNode : public ProjNode { + // can turn PhiNodes into copys in-place by NULL'ing out their RegionNode + // input in slot 0. + class PhiNode : public TypeNode { ++ friend class PhaseRenumberLive; ++ + const TypePtr* const _adr_type; // non-null only for Type::MEMORY nodes. + // The following fields are only used for data PhiNodes to indicate + // that the PhiNode represents the value of a known instance field. + int _inst_mem_id; // Instance memory id (node index of the memory Phi) +- const int _inst_id; // Instance id of the memory slice. ++ int _inst_id; // Instance id of the memory slice. + const int _inst_index; // Alias index of the instance memory slice. + // Array elements references have the same alias_idx but different offset. + const int _inst_offset; // Offset of the instance memory slice. +diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp +index 9d5d4deed..f4a38cd28 100644 +--- a/src/hotspot/share/opto/phaseX.cpp ++++ b/src/hotspot/share/opto/phaseX.cpp +@@ -463,55 +463,115 @@ PhaseRemoveUseless::PhaseRemoveUseless(PhaseGVN *gvn, Unique_Node_List *worklist + PhaseRenumberLive::PhaseRenumberLive(PhaseGVN* gvn, + Unique_Node_List* worklist, Unique_Node_List* new_worklist, + PhaseNumber phase_num) : +- PhaseRemoveUseless(gvn, worklist, Remove_Useless_And_Renumber_Live) { +- ++ PhaseRemoveUseless(gvn, worklist, Remove_Useless_And_Renumber_Live), ++ _new_type_array(C->comp_arena()), ++ _old2new_map(C->unique(), C->unique(), -1), ++ _delayed(Thread::current()->resource_area()), ++ _is_pass_finished(false), ++ _live_node_count(C->live_nodes()) ++{ + assert(RenumberLiveNodes, "RenumberLiveNodes must be set to true for node renumbering to take place"); + assert(C->live_nodes() == _useful.size(), "the number of live nodes must match the number of useful nodes"); + assert(gvn->nodes_size() == 0, "GVN must not contain any nodes at this point"); ++ assert(_delayed.size() == 0, "should be empty"); + +- uint old_unique_count = C->unique(); +- uint live_node_count = C->live_nodes(); + uint worklist_size = worklist->size(); + +- // Storage for the updated type information. +- Type_Array new_type_array(C->comp_arena()); +- + // Iterate over the set of live nodes. +- uint current_idx = 0; // The current new node ID. Incremented after every assignment. +- for (uint i = 0; i < _useful.size(); i++) { +- Node* n = _useful.at(i); +- // Sanity check that fails if we ever decide to execute this phase after EA +- assert(!n->is_Phi() || n->as_Phi()->inst_mem_id() == -1, "should not be linked to data Phi"); +- const Type* type = gvn->type_or_null(n); +- new_type_array.map(current_idx, type); ++ for (uint current_idx = 0; current_idx < _useful.size(); current_idx++) { ++ Node* n = _useful.at(current_idx); + + bool in_worklist = false; + if (worklist->member(n)) { + in_worklist = true; + } + ++ const Type* type = gvn->type_or_null(n); ++ _new_type_array.map(current_idx, type); ++ ++ assert(_old2new_map.at(n->_idx) == -1, "already seen"); ++ _old2new_map.at_put(n->_idx, current_idx); ++ + n->set_idx(current_idx); // Update node ID. + + if (in_worklist) { + new_worklist->push(n); + } + +- current_idx++; ++ if (update_embedded_ids(n) < 0) { ++ _delayed.push(n); // has embedded IDs; handle later ++ } + } + + assert(worklist_size == new_worklist->size(), "the new worklist must have the same size as the original worklist"); +- assert(live_node_count == current_idx, "all live nodes must be processed"); ++ assert(_live_node_count == _useful.size(), "all live nodes must be processed"); ++ ++ _is_pass_finished = true; // pass finished; safe to process delayed updates ++ ++ while (_delayed.size() > 0) { ++ Node* n = _delayed.pop(); ++ int no_of_updates = update_embedded_ids(n); ++ assert(no_of_updates > 0, "should be updated"); ++ } + + // Replace the compiler's type information with the updated type information. +- gvn->replace_types(new_type_array); ++ gvn->replace_types(_new_type_array); + + // Update the unique node count of the compilation to the number of currently live nodes. +- C->set_unique(live_node_count); ++ C->set_unique(_live_node_count); + + // Set the dead node count to 0 and reset dead node list. + C->reset_dead_node_list(); + } + ++int PhaseRenumberLive::new_index(int old_idx) { ++ assert(_is_pass_finished, "not finished"); ++ if (_old2new_map.at(old_idx) == -1) { // absent ++ // Allocate a placeholder to preserve uniqueness ++ _old2new_map.at_put(old_idx, _live_node_count); ++ _live_node_count++; ++ } ++ return _old2new_map.at(old_idx); ++} ++ ++int PhaseRenumberLive::update_embedded_ids(Node* n) { ++ int no_of_updates = 0; ++ if (n->is_Phi()) { ++ PhiNode* phi = n->as_Phi(); ++ if (phi->_inst_id != -1) { ++ if (!_is_pass_finished) { ++ return -1; // delay ++ } ++ int new_idx = new_index(phi->_inst_id); ++ assert(new_idx != -1, ""); ++ phi->_inst_id = new_idx; ++ no_of_updates++; ++ } ++ if (phi->_inst_mem_id != -1) { ++ if (!_is_pass_finished) { ++ return -1; // delay ++ } ++ int new_idx = new_index(phi->_inst_mem_id); ++ assert(new_idx != -1, ""); ++ phi->_inst_mem_id = new_idx; ++ no_of_updates++; ++ } ++ } ++ ++ const Type* type = _new_type_array.fast_lookup(n->_idx); ++ if (type != NULL && type->isa_oopptr() && type->is_oopptr()->is_known_instance()) { ++ if (!_is_pass_finished) { ++ return -1; // delay ++ } ++ int old_idx = type->is_oopptr()->instance_id(); ++ int new_idx = new_index(old_idx); ++ const Type* new_type = type->is_oopptr()->with_instance_id(new_idx); ++ _new_type_array.map(n->_idx, new_type); ++ no_of_updates++; ++ } ++ ++ return no_of_updates; ++} + + //============================================================================= + //------------------------------PhaseTransform--------------------------------- +diff --git a/src/hotspot/share/opto/phaseX.hpp b/src/hotspot/share/opto/phaseX.hpp +index 3b33a8cb2..ef5eb488e 100644 +--- a/src/hotspot/share/opto/phaseX.hpp ++++ b/src/hotspot/share/opto/phaseX.hpp +@@ -157,6 +157,16 @@ public: + // Phase that first performs a PhaseRemoveUseless, then it renumbers compiler + // structures accordingly. + class PhaseRenumberLive : public PhaseRemoveUseless { ++protected: ++ Type_Array _new_type_array; // Storage for the updated type information. ++ GrowableArray _old2new_map; ++ Node_List _delayed; ++ bool _is_pass_finished; ++ uint _live_node_count; ++ ++ int update_embedded_ids(Node* n); ++ int new_index(int old_idx); ++ + public: + PhaseRenumberLive(PhaseGVN* gvn, + Unique_Node_List* worklist, Unique_Node_List* new_worklist, +diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp +index 0078b8773..964f9d247 100644 +--- a/src/hotspot/share/opto/type.cpp ++++ b/src/hotspot/share/opto/type.cpp +@@ -3456,6 +3456,12 @@ const TypePtr* TypeOopPtr::with_inline_depth(int depth) const { + return make(_ptr, _offset, _instance_id, _speculative, depth); + } + ++//------------------------------with_instance_id-------------------------------- ++const TypePtr* TypeOopPtr::with_instance_id(int instance_id) const { ++ assert(_instance_id != -1, "should be known"); ++ return make(_ptr, _offset, instance_id, _speculative, _inline_depth); ++} ++ + //------------------------------meet_instance_id-------------------------------- + int TypeOopPtr::meet_instance_id( int instance_id ) const { + // Either is 'TOP' instance? Return the other instance! +@@ -4059,6 +4065,11 @@ const TypePtr *TypeInstPtr::with_inline_depth(int depth) const { + return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, _instance_id, _speculative, depth); + } + ++const TypePtr *TypeInstPtr::with_instance_id(int instance_id) const { ++ assert(is_known_instance(), "should be known"); ++ return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, instance_id, _speculative, _inline_depth); ++} ++ + //============================================================================= + // Convenience common pre-built types. + const TypeAryPtr *TypeAryPtr::RANGE; +@@ -4529,6 +4540,11 @@ const TypePtr *TypeAryPtr::with_inline_depth(int depth) const { + return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _instance_id, _speculative, depth); + } + ++const TypePtr *TypeAryPtr::with_instance_id(int instance_id) const { ++ assert(is_known_instance(), "should be known"); ++ return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, instance_id, _speculative, _inline_depth); ++} ++ + //============================================================================= + + //------------------------------hash------------------------------------------- +diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp +index ca92fe3ab..e9ed7ce40 100644 +--- a/src/hotspot/share/opto/type.hpp ++++ b/src/hotspot/share/opto/type.hpp +@@ -1048,6 +1048,8 @@ public: + virtual bool would_improve_type(ciKlass* exact_kls, int inline_depth) const; + virtual const TypePtr* with_inline_depth(int depth) const; + ++ virtual const TypePtr* with_instance_id(int instance_id) const; ++ + virtual const Type *xdual() const; // Compute dual right now. + // the core of the computation of the meet for TypeOopPtr and for its subclasses + virtual const Type *xmeet_helper(const Type *t) const; +@@ -1124,6 +1126,7 @@ class TypeInstPtr : public TypeOopPtr { + // Speculative type helper methods. + virtual const Type* remove_speculative() const; + virtual const TypePtr* with_inline_depth(int depth) const; ++ virtual const TypePtr* with_instance_id(int instance_id) const; + + // the core of the computation of the meet of 2 types + virtual const Type *xmeet_helper(const Type *t) const; +@@ -1211,6 +1214,7 @@ public: + // Speculative type helper methods. + virtual const Type* remove_speculative() const; + virtual const TypePtr* with_inline_depth(int depth) const; ++ virtual const TypePtr* with_instance_id(int instance_id) const; + + // the core of the computation of the meet of 2 types + virtual const Type *xmeet_helper(const Type *t) const; +-- +2.19.0 + diff --git a/8229495-SIGILL-in-C2-generated-OSR-compilation.patch b/8229495-SIGILL-in-C2-generated-OSR-compilation.patch deleted file mode 100644 index 4dbaf788f761189434506ae28d3379982532d6d8..0000000000000000000000000000000000000000 --- a/8229495-SIGILL-in-C2-generated-OSR-compilation.patch +++ /dev/null @@ -1,564 +0,0 @@ -diff --git a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp -index 5ee23f7..b847caf 100644 ---- a/src/hotspot/share/opto/classes.hpp -+++ b/src/hotspot/share/opto/classes.hpp -@@ -226,6 +226,8 @@ macro(NegF) - macro(NeverBranch) - macro(OnSpinWait) - macro(Opaque1) -+macro(OpaqueLoopInit) -+macro(OpaqueLoopStride) - macro(Opaque2) - macro(Opaque3) - macro(Opaque4) -diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp -index e5559a2..efe4cff 100644 ---- a/src/hotspot/share/opto/compile.cpp -+++ b/src/hotspot/share/opto/compile.cpp -@@ -1987,7 +1987,17 @@ void Compile::remove_opaque4_nodes(PhaseIterGVN &igvn) { - for (int i = opaque4_count(); i > 0; i--) { - Node* opaq = opaque4_node(i-1); - assert(opaq->Opcode() == Op_Opaque4, "Opaque4 only"); -+ // With Opaque4 nodes, the expectation is that the test of input 1 -+ // is always equal to the constant value of input 2. So we can -+ // remove the Opaque4 and replace it by input 2. In debug builds, -+ // leave the non constant test in instead to sanity check that it -+ // never fails (if it does, that subgraph was constructed so, at -+ // runtime, a Halt node is executed). -+ #ifdef ASSERT -+ igvn.replace_node(opaq, opaq->in(1)); -+ #else - igvn.replace_node(opaq, opaq->in(2)); -+ #endif - } - assert(opaque4_count() == 0, "should be empty"); - } -diff --git a/src/hotspot/share/opto/loopPredicate.cpp b/src/hotspot/share/opto/loopPredicate.cpp -index 6e85398..a6d2257 100644 ---- a/src/hotspot/share/opto/loopPredicate.cpp -+++ b/src/hotspot/share/opto/loopPredicate.cpp -@@ -1243,8 +1243,9 @@ ProjNode* PhaseIdealLoop::insert_initial_skeleton_predicate(IfNode* iff, IdealLo - Node* init, Node* limit, jint stride, - Node* rng, bool &overflow, - Deoptimization::DeoptReason reason) { -+ // First predicate for the initial value on first loop iteration - assert(proj->_con && predicate_proj->_con, "not a range check?"); -- Node* opaque_init = new Opaque1Node(C, init); -+ Node* opaque_init = new OpaqueLoopInitNode(C, init); - register_new_node(opaque_init, upper_bound_proj); - BoolNode* bol = rc_predicate(loop, upper_bound_proj, scale, offset, opaque_init, limit, stride, rng, (stride > 0) != (scale > 0), overflow); - Node* opaque_bol = new Opaque4Node(C, bol, _igvn.intcon(1)); // This will go away once loop opts are over -@@ -1252,6 +1253,22 @@ ProjNode* PhaseIdealLoop::insert_initial_skeleton_predicate(IfNode* iff, IdealLo - ProjNode* new_proj = create_new_if_for_predicate(predicate_proj, NULL, reason, overflow ? Op_If : iff->Opcode()); - _igvn.replace_input_of(new_proj->in(0), 1, opaque_bol); - assert(opaque_init->outcnt() > 0, "should be used"); -+ // Second predicate for init + (current stride - initial stride) -+ // This is identical to the previous predicate initially but as -+ // unrolling proceeds current stride is updated. -+ Node* init_stride = loop->_head->as_CountedLoop()->stride(); -+ Node* opaque_stride = new OpaqueLoopStrideNode(C, init_stride); -+ register_new_node(opaque_stride, new_proj); -+ Node* max_value = new SubINode(opaque_stride, init_stride); -+ register_new_node(max_value, new_proj); -+ max_value = new AddINode(opaque_init, max_value); -+ register_new_node(max_value, new_proj); -+ bol = rc_predicate(loop, new_proj, scale, offset, max_value, limit, stride, rng, (stride > 0) != (scale > 0), overflow); -+ opaque_bol = new Opaque4Node(C, bol, _igvn.intcon(1)); -+ register_new_node(opaque_bol, new_proj); -+ new_proj = create_new_if_for_predicate(predicate_proj, NULL, reason, overflow ? Op_If : iff->Opcode()); -+ _igvn.replace_input_of(new_proj->in(0), 1, opaque_bol); -+ assert(max_value->outcnt() > 0, "should be used"); - return new_proj; - } - -diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp -index 5e6faaa..89628bb 100644 ---- a/src/hotspot/share/opto/loopTransform.cpp -+++ b/src/hotspot/share/opto/loopTransform.cpp -@@ -1080,7 +1080,7 @@ void PhaseIdealLoop::ensure_zero_trip_guard_proj(Node* node, bool is_main_loop) - // CastII/ConvI2L nodes cause some data paths to die. For consistency, - // the control paths must die too but the range checks were removed by - // predication. The range checks that we add here guarantee that they do. --void PhaseIdealLoop::copy_skeleton_predicates_to_main_loop_helper(Node* predicate, Node* start, Node* end, -+void PhaseIdealLoop::copy_skeleton_predicates_to_main_loop_helper(Node* predicate, Node* init, Node* stride, - IdealLoopTree* outer_loop, LoopNode* outer_main_head, - uint dd_main_head, const uint idx_before_pre_post, - const uint idx_after_post_before_pre, Node* zero_trip_guard_proj_main, -@@ -1098,6 +1098,10 @@ void PhaseIdealLoop::copy_skeleton_predicates_to_main_loop_helper(Node* predicat - predicate = iff->in(0); - Node* current_proj = outer_main_head->in(LoopNode::EntryControl); - Node* prev_proj = current_proj; -+ Node* opaque_init = new OpaqueLoopInitNode(C, init); -+ register_new_node(opaque_init, outer_main_head->in(LoopNode::EntryControl)); -+ Node* opaque_stride = new OpaqueLoopStrideNode(C, stride); -+ register_new_node(opaque_stride, outer_main_head->in(LoopNode::EntryControl)); - while (predicate != NULL && predicate->is_Proj() && predicate->in(0)->is_If()) { - iff = predicate->in(0)->as_If(); - uncommon_proj = iff->proj_out(1 - predicate->as_Proj()->_con); -@@ -1108,11 +1112,10 @@ void PhaseIdealLoop::copy_skeleton_predicates_to_main_loop_helper(Node* predicat - // Clone the skeleton predicate twice and initialize one with the initial - // value of the loop induction variable. Leave the other predicate - // to be initialized when increasing the stride during loop unrolling. -- prev_proj = clone_skeleton_predicate(iff, start, predicate, uncommon_proj, current_proj, outer_loop, prev_proj); -- assert(skeleton_predicate_has_opaque(prev_proj->in(0)->as_If()) == (start->Opcode() == Op_Opaque1), ""); -- prev_proj = clone_skeleton_predicate(iff, end, predicate, uncommon_proj, current_proj, outer_loop, prev_proj); -- assert(skeleton_predicate_has_opaque(prev_proj->in(0)->as_If()) == (end->Opcode() == Op_Opaque1), ""); -- -+ prev_proj = clone_skeleton_predicate(iff, opaque_init, NULL, predicate, uncommon_proj, current_proj, outer_loop, prev_proj); -+ assert(skeleton_predicate_has_opaque(prev_proj->in(0)->as_If()), ""); -+ prev_proj = clone_skeleton_predicate(iff, init, stride, predicate, uncommon_proj, current_proj, outer_loop, prev_proj); -+ assert(!skeleton_predicate_has_opaque(prev_proj->in(0)->as_If()), ""); - // Rewire any control inputs from the cloned skeleton predicates down to the main and post loop for data nodes that are part of the - // main loop (and were cloned to the pre and post loop). - for (DUIterator i = predicate->outs(); predicate->has_out(i); i++) { -@@ -1177,14 +1180,14 @@ bool PhaseIdealLoop::skeleton_predicate_has_opaque(IfNode* iff) { - } - continue; - } -- if (op == Op_Opaque1) { -+ if (n->is_Opaque1()) { - return true; - } - } - return false; - } - --Node* PhaseIdealLoop::clone_skeleton_predicate(Node* iff, Node* value, Node* predicate, Node* uncommon_proj, -+Node* PhaseIdealLoop::clone_skeleton_predicate(Node* iff, Node* new_init, Node* new_stride, Node* predicate, Node* uncommon_proj, - Node* current_proj, IdealLoopTree* outer_loop, Node* prev_proj) { - Node_Stack to_clone(2); - to_clone.push(iff->in(1), 1); -@@ -1204,12 +1207,19 @@ Node* PhaseIdealLoop::clone_skeleton_predicate(Node* iff, Node* value, Node* pre - to_clone.push(m, 1); - continue; - } -- if (op == Op_Opaque1) { -+ if (m->is_Opaque1()) { - if (n->_idx < current) { - n = n->clone(); -+ register_new_node(n, current_proj); -+ } -+ if (op == Op_OpaqueLoopInit) { -+ n->set_req(i, new_init); -+ } else { -+ assert(op == Op_OpaqueLoopStride, "unexpected opaque node"); -+ if (new_stride != NULL) { -+ n->set_req(i, new_stride); -+ } - } -- n->set_req(i, value); -- register_new_node(n, current_proj); - to_clone.set_node(n); - } - for (;;) { -@@ -1259,7 +1269,7 @@ Node* PhaseIdealLoop::clone_skeleton_predicate(Node* iff, Node* value, Node* pre - return proj; - } - --void PhaseIdealLoop::copy_skeleton_predicates_to_main_loop(CountedLoopNode* pre_head, Node* start, Node* end, -+void PhaseIdealLoop::copy_skeleton_predicates_to_main_loop(CountedLoopNode* pre_head, Node* init, Node* stride, - IdealLoopTree* outer_loop, LoopNode* outer_main_head, - uint dd_main_head, const uint idx_before_pre_post, - const uint idx_after_post_before_pre, Node* zero_trip_guard_proj_main, -@@ -1279,10 +1289,10 @@ void PhaseIdealLoop::copy_skeleton_predicates_to_main_loop(CountedLoopNode* pre_ - } - } - predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate); -- copy_skeleton_predicates_to_main_loop_helper(predicate, start, end, outer_loop, outer_main_head, dd_main_head, -+ copy_skeleton_predicates_to_main_loop_helper(predicate, init, stride, outer_loop, outer_main_head, dd_main_head, - idx_before_pre_post, idx_after_post_before_pre, zero_trip_guard_proj_main, - zero_trip_guard_proj_post, old_new); -- copy_skeleton_predicates_to_main_loop_helper(profile_predicate, start, end, outer_loop, outer_main_head, dd_main_head, -+ copy_skeleton_predicates_to_main_loop_helper(profile_predicate, init, stride, outer_loop, outer_main_head, dd_main_head, - idx_before_pre_post, idx_after_post_before_pre, zero_trip_guard_proj_main, - zero_trip_guard_proj_post, old_new); - } -@@ -1433,10 +1443,8 @@ void PhaseIdealLoop::insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_ - // CastII for the main loop: - Node* castii = cast_incr_before_loop( pre_incr, min_taken, main_head ); - assert(castii != NULL, "no castII inserted"); -- Node* opaque_castii = new Opaque1Node(C, castii); -- register_new_node(opaque_castii, outer_main_head->in(LoopNode::EntryControl)); - assert(post_head->in(1)->is_IfProj(), "must be zero-trip guard If node projection of the post loop"); -- copy_skeleton_predicates_to_main_loop(pre_head, castii, opaque_castii, outer_loop, outer_main_head, dd_main_head, -+ copy_skeleton_predicates_to_main_loop(pre_head, castii, stride, outer_loop, outer_main_head, dd_main_head, - idx_before_pre_post, idx_after_post_before_pre, min_taken, post_head->in(1), old_new); - - // Step B4: Shorten the pre-loop to run only 1 iteration (for now). -@@ -1722,6 +1730,11 @@ void PhaseIdealLoop::update_main_loop_skeleton_predicates(Node* ctrl, CountedLoo - Node* prev_proj = ctrl; - LoopNode* outer_loop_head = loop_head->skip_strip_mined(); - IdealLoopTree* outer_loop = get_loop(outer_loop_head); -+ // Compute the value of the loop induction variable at the end of the -+ // first iteration of the unrolled loop: init + new_stride_con - init_inc -+ int new_stride_con = stride_con * 2; -+ Node* max_value = _igvn.intcon(new_stride_con); -+ set_ctrl(max_value, C->root()); - while (entry != NULL && entry->is_Proj() && entry->in(0)->is_If()) { - IfNode* iff = entry->in(0)->as_If(); - ProjNode* proj = iff->proj_out(1 - entry->as_Proj()->_con); -@@ -1737,18 +1750,8 @@ void PhaseIdealLoop::update_main_loop_skeleton_predicates(Node* ctrl, CountedLoo - // tell. Kill it in any case. - _igvn.replace_input_of(iff, 1, iff->in(1)->in(2)); - } else { -- // Add back the predicate for the value at the beginning of the first entry -- prev_proj = clone_skeleton_predicate(iff, init, entry, proj, ctrl, outer_loop, prev_proj); -- assert(!skeleton_predicate_has_opaque(prev_proj->in(0)->as_If()), "unexpected"); -- // Compute the value of the loop induction variable at the end of the -- // first iteration of the unrolled loop: init + new_stride_con - init_inc -- int init_inc = stride_con/loop_head->unrolled_count(); -- assert(init_inc != 0, "invalid loop increment"); -- int new_stride_con = stride_con * 2; -- Node* max_value = _igvn.intcon(new_stride_con - init_inc); -- max_value = new AddINode(init, max_value); -- register_new_node(max_value, get_ctrl(iff->in(1))); -- prev_proj = clone_skeleton_predicate(iff, max_value, entry, proj, ctrl, outer_loop, prev_proj); -+ //Add back predicates updated for the new stride. -+ prev_proj = clone_skeleton_predicate(iff, init, max_value, entry, proj, ctrl, outer_loop, prev_proj); - assert(!skeleton_predicate_has_opaque(prev_proj->in(0)->as_If()), "unexpected"); - } - } -@@ -2547,22 +2550,22 @@ int PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { - // The underflow and overflow limits: 0 <= scale*I+offset < limit - add_constraint(stride_con, lscale_con, offset, zero, limit, pre_ctrl, &pre_limit, &main_limit); - Node* init = cl->init_trip(); -- Node* opaque_init = new Opaque1Node(C, init); -+ Node* opaque_init = new OpaqueLoopInitNode(C, init); - register_new_node(opaque_init, predicate_proj); -+ // predicate on first value of first iteration -+ predicate_proj = add_range_check_predicate(loop, cl, predicate_proj, scale_con, int_offset, int_limit, stride_con, init); -+ assert(!skeleton_predicate_has_opaque(predicate_proj->in(0)->as_If()), "unexpected"); - // template predicate so it can be updated on next unrolling - predicate_proj = add_range_check_predicate(loop, cl, predicate_proj, scale_con, int_offset, int_limit, stride_con, opaque_init); - assert(skeleton_predicate_has_opaque(predicate_proj->in(0)->as_If()), "unexpected"); -- // predicate on first value of first iteration -- predicate_proj = add_range_check_predicate(loop, cl, predicate_proj, scale_con, int_offset, int_limit, stride_con, init); -- assert(!skeleton_predicate_has_opaque(predicate_proj->in(0)->as_If()), "unexpected"); -- int init_inc = stride_con/cl->unrolled_count(); -- assert(init_inc != 0, "invalid loop increment"); -- Node* max_value = _igvn.intcon(stride_con - init_inc); -- max_value = new AddINode(init, max_value); -+ Node* opaque_stride = new OpaqueLoopStrideNode(C, cl->stride()); -+ register_new_node(opaque_stride, predicate_proj); -+ Node* max_value = new SubINode(opaque_stride, cl->stride()); -+ register_new_node(max_value, predicate_proj); -+ max_value = new AddINode(opaque_init, max_value); - register_new_node(max_value, predicate_proj); -- // predicate on last value of first iteration (in case unrolling has already happened) - predicate_proj = add_range_check_predicate(loop, cl, predicate_proj, scale_con, int_offset, int_limit, stride_con, max_value); -- assert(!skeleton_predicate_has_opaque(predicate_proj->in(0)->as_If()), "unexpected"); -+ assert(skeleton_predicate_has_opaque(predicate_proj->in(0)->as_If()), "unexpected"); - } else { - if (PrintOpto) { - tty->print_cr("missed RCE opportunity"); -diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp -index 53b9692..7c54113 100644 ---- a/src/hotspot/share/opto/loopnode.hpp -+++ b/src/hotspot/share/opto/loopnode.hpp -@@ -748,13 +748,13 @@ private: - #ifdef ASSERT - void ensure_zero_trip_guard_proj(Node* node, bool is_main_loop); - #endif -- void copy_skeleton_predicates_to_main_loop_helper(Node* predicate, Node* start, Node* end, IdealLoopTree* outer_loop, LoopNode* outer_main_head, -+ void copy_skeleton_predicates_to_main_loop_helper(Node* predicate, Node* init, Node* stride, IdealLoopTree* outer_loop, LoopNode* outer_main_head, - uint dd_main_head, const uint idx_before_pre_post, const uint idx_after_post_before_pre, - Node* zero_trip_guard_proj_main, Node* zero_trip_guard_proj_post, const Node_List &old_new); -- void copy_skeleton_predicates_to_main_loop(CountedLoopNode* pre_head, Node* start, Node* end, IdealLoopTree* outer_loop, LoopNode* outer_main_head, -+ void copy_skeleton_predicates_to_main_loop(CountedLoopNode* pre_head, Node* init, Node* stride, IdealLoopTree* outer_loop, LoopNode* outer_main_head, - uint dd_main_head, const uint idx_before_pre_post, const uint idx_after_post_before_pre, - Node* zero_trip_guard_proj_main, Node* zero_trip_guard_proj_post, const Node_List &old_new); -- Node* clone_skeleton_predicate(Node* iff, Node* value, Node* predicate, Node* uncommon_proj, -+ Node* clone_skeleton_predicate(Node* iff, Node* new_init, Node* new_stride, Node* predicate, Node* uncommon_proj, - Node* current_proj, IdealLoopTree* outer_loop, Node* prev_proj); - bool skeleton_predicate_has_opaque(IfNode* iff); - void update_main_loop_skeleton_predicates(Node* ctrl, CountedLoopNode* loop_head, Node* init, int stride_con); -diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp -index 6b85529..adbee17 100644 ---- a/src/hotspot/share/opto/loopopts.cpp -+++ b/src/hotspot/share/opto/loopopts.cpp -@@ -890,30 +890,42 @@ void PhaseIdealLoop::try_move_store_after_loop(Node* n) { - Node *PhaseIdealLoop::split_if_with_blocks_pre( Node *n ) { - // Cloning these guys is unlikely to win - int n_op = n->Opcode(); -- if( n_op == Op_MergeMem ) return n; -- if( n->is_Proj() ) return n; -+ if (n_op == Op_MergeMem) { -+ return n; -+ } -+ if (n->is_Proj()) { -+ return n; -+ } - // Do not clone-up CmpFXXX variations, as these are always - // followed by a CmpI -- if( n->is_Cmp() ) return n; -+ if (n->is_Cmp()) { -+ return n; -+ } - // Attempt to use a conditional move instead of a phi/branch -- if( ConditionalMoveLimit > 0 && n_op == Op_Region ) { -+ if (ConditionalMoveLimit > 0 && n_op == Op_Region) { - Node *cmov = conditional_move( n ); -- if( cmov ) return cmov; -+ if (cmov) { -+ return cmov; -+ } - } -- if( n->is_CFG() || n->is_LoadStore() ) -+ if (n->is_CFG() || n->is_LoadStore()) { - return n; -- if( n_op == Op_Opaque1 || // Opaque nodes cannot be mod'd -- n_op == Op_Opaque2 ) { -- if( !C->major_progress() ) // If chance of no more loop opts... -+ } -+ if (n->is_Opaque1() || // Opaque nodes cannot be mod'd -+ n_op == Op_Opaque2) { -+ if (!C->major_progress()) { // If chance of no more loop opts... - _igvn._worklist.push(n); // maybe we'll remove them -+ } - return n; - } - -- if( n->is_Con() ) return n; // No cloning for Con nodes -- -+ if (n->is_Con()) { -+ return n; // No cloning for Con nodes -+ } - Node *n_ctrl = get_ctrl(n); -- if( !n_ctrl ) return n; // Dead node -- -+ if (!n_ctrl) { -+ return n; // Dead node -+ } - Node* res = try_move_store_before_loop(n, n_ctrl); - if (res != NULL) { - return n; -diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp -index cf8eab1..8331d25 100644 ---- a/src/hotspot/share/opto/macro.cpp -+++ b/src/hotspot/share/opto/macro.cpp -@@ -2617,9 +2617,10 @@ void PhaseMacroExpand::eliminate_macro_nodes() { - break; - case Node::Class_OuterStripMinedLoop: - break; -+ case Node::Class_Opaque1: -+ break; - default: - assert(n->Opcode() == Op_LoopLimit || -- n->Opcode() == Op_Opaque1 || - n->Opcode() == Op_Opaque2 || - n->Opcode() == Op_Opaque3 || - BarrierSet::barrier_set()->barrier_set_c2()->is_gc_barrier_node(n), -@@ -2661,7 +2662,7 @@ bool PhaseMacroExpand::expand_macro_nodes() { - C->remove_macro_node(n); - _igvn._worklist.push(n); - success = true; -- } else if (n->Opcode() == Op_Opaque1 || n->Opcode() == Op_Opaque2) { -+ } else if (n->is_Opaque1() || n->Opcode() == Op_Opaque2) { - _igvn.replace_node(n, n->in(1)); - success = true; - #if INCLUDE_RTM_OPT -diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp -index 2a42e99..0eac634 100644 ---- a/src/hotspot/share/opto/node.hpp -+++ b/src/hotspot/share/opto/node.hpp -@@ -116,6 +116,7 @@ class MulNode; - class MultiNode; - class MultiBranchNode; - class NeverBranchNode; -+class Opaque1Node; - class OuterStripMinedLoopNode; - class OuterStripMinedLoopEndNode; - class Node; -@@ -611,10 +612,10 @@ public: - // This enum is used only for C2 ideal and mach nodes with is_() methods - // so that it's values fits into 16 bits. - enum NodeClasses { -- Bit_Node = 0x0000, -- Class_Node = 0x0000, -- ClassMask_Node = 0xFFFF, -- -+ Bit_Node = 0x00000000, -+ Class_Node = 0x00000000, -+ ClassMask_Node = 0xFFFFFFFF, -+ - DEFINE_CLASS_ID(Multi, Node, 0) - DEFINE_CLASS_ID(SafePoint, Multi, 0) - DEFINE_CLASS_ID(Call, SafePoint, 0) -@@ -720,6 +721,7 @@ public: - DEFINE_CLASS_ID(Vector, Node, 13) - DEFINE_CLASS_ID(ClearArray, Node, 14) - DEFINE_CLASS_ID(Halt, Node, 15) -+ DEFINE_CLASS_ID(Opaque1, Node, 16) - - _max_classes = ClassMask_Halt - }; -@@ -746,12 +748,12 @@ public: - }; - - private: -- jushort _class_id; -+ juint _class_id; - jushort _flags; - - protected: - // These methods should be called from constructors only. -- void init_class_id(jushort c) { -+ void init_class_id(juint c) { - _class_id = c; // cast out const - } - void init_flags(jushort fl) { -@@ -764,7 +766,7 @@ protected: - } - - public: -- const jushort class_id() const { return _class_id; } -+ const juint class_id() const { return _class_id; } - - const jushort flags() const { return _flags; } - -@@ -865,6 +867,7 @@ public: - DEFINE_CLASS_QUERY(Mul) - DEFINE_CLASS_QUERY(Multi) - DEFINE_CLASS_QUERY(MultiBranch) -+ DEFINE_CLASS_QUERY(Opaque1) - DEFINE_CLASS_QUERY(OuterStripMinedLoop) - DEFINE_CLASS_QUERY(OuterStripMinedLoopEnd) - DEFINE_CLASS_QUERY(Parm) -diff --git a/src/hotspot/share/opto/opaquenode.hpp b/src/hotspot/share/opto/opaquenode.hpp -index f97de4a..4c00528 100644 ---- a/src/hotspot/share/opto/opaquenode.hpp -+++ b/src/hotspot/share/opto/opaquenode.hpp -@@ -38,6 +38,7 @@ class Opaque1Node : public Node { - Opaque1Node(Compile* C, Node *n) : Node(NULL, n) { - // Put it on the Macro nodes list to removed during macro nodes expansion. - init_flags(Flag_is_macro); -+ init_class_id(Class_Opaque1); - C->add_macro_node(this); - } - // Special version for the pre-loop to hold the original loop limit -@@ -45,6 +46,7 @@ class Opaque1Node : public Node { - Opaque1Node(Compile* C, Node *n, Node* orig_limit) : Node(NULL, n, orig_limit) { - // Put it on the Macro nodes list to removed during macro nodes expansion. - init_flags(Flag_is_macro); -+ init_class_id(Class_Opaque1); - C->add_macro_node(this); - } - Node* original_loop_limit() { return req()==3 ? in(2) : NULL; } -@@ -52,6 +54,20 @@ class Opaque1Node : public Node { - virtual const Type *bottom_type() const { return TypeInt::INT; } - virtual Node* Identity(PhaseGVN* phase); - }; -+// Opaque nodes specific to range check elimination handling -+class OpaqueLoopInitNode : public Opaque1Node { -+ public: -+ OpaqueLoopInitNode(Compile* C, Node *n) : Opaque1Node(C, n) { -+ } -+ virtual int Opcode() const; -+}; -+ -+class OpaqueLoopStrideNode : public Opaque1Node { -+ public: -+ OpaqueLoopStrideNode(Compile* C, Node *n) : Opaque1Node(C, n) { -+ } -+ virtual int Opcode() const; -+}; - - //------------------------------Opaque2Node------------------------------------ - // A node to prevent unwanted optimizations. Allows constant folding. Stops -diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp -index ad7fb42..85c4dfe 100644 ---- a/src/hotspot/share/runtime/vmStructs.cpp -+++ b/src/hotspot/share/runtime/vmStructs.cpp -@@ -951,7 +951,7 @@ typedef PaddedEnd PaddedObjectMonitor; - c2_nonstatic_field(Node, _outcnt, node_idx_t) \ - c2_nonstatic_field(Node, _outmax, node_idx_t) \ - c2_nonstatic_field(Node, _idx, const node_idx_t) \ -- c2_nonstatic_field(Node, _class_id, jushort) \ -+ c2_nonstatic_field(Node, _class_id, juint) \ - c2_nonstatic_field(Node, _flags, jushort) \ - \ - c2_nonstatic_field(Compile, _root, RootNode*) \ -diff --git a/test/hotspot/jtreg/compiler/loopopts/TestRCEAfterUnrolling.java b/test/hotspot/jtreg/compiler/loopopts/TestRCEAfterUnrolling.java -new file mode 100644 -index 0000000..06bca79 ---- /dev/null -+++ b/test/hotspot/jtreg/compiler/loopopts/TestRCEAfterUnrolling.java -@@ -0,0 +1,78 @@ -+/* -+ * Copyright (c) 2020, 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 8229495 -+ * @summary SIGILL in C2 generated OSR compilation. -+ * -+ * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=TestRCEAfterUnrolling::test TestRCEAfterUnrolling -+ * -+ */ -+ -+public class TestRCEAfterUnrolling { -+ -+ public static int iFld = 0; -+ public static short sFld = 1; -+ -+ public static void main(String[] strArr) { -+ test(); -+ } -+ -+ public static int test() { -+ int x = 11; -+ int y = 0; -+ int j = 0; -+ int iArr[] = new int[400]; -+ -+ init(iArr); -+ -+ for (int i = 0; i < 2; i++) { -+ doNothing(); -+ for (j = 10; j > 1; j -= 2) { -+ sFld += (short)j; -+ iArr = iArr; -+ y += (j * 3); -+ x = (iArr[j - 1]/ x); -+ x = sFld; -+ } -+ int k = 1; -+ while (++k < 8) { -+ iFld += x; -+ } -+ } -+ return Float.floatToIntBits(654) + x + j + y; -+ } -+ -+ // Inlined -+ public static void doNothing() { -+ } -+ -+ // Inlined -+ public static void init(int[] a) { -+ for (int j = 0; j < a.length; j++) { -+ a[j] = 0; -+ } -+ } -+} -+ diff --git a/8236512-PKCS11-Connection-closed-after-Cipher-doFinal-and-NoPadding.patch b/8236512-PKCS11-Connection-closed-after-Cipher-doFinal-and-NoPadding.patch deleted file mode 100755 index 58489bc2664f52942bd93940adc4e9478302ee36..0000000000000000000000000000000000000000 --- a/8236512-PKCS11-Connection-closed-after-Cipher-doFinal-and-NoPadding.patch +++ /dev/null @@ -1,479 +0,0 @@ -diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11AEADCipher.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11AEADCipher.java -index d1b9d06d8..82d0dc164 100644 ---- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11AEADCipher.java -+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11AEADCipher.java -@@ -1,4 +1,5 @@ --/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. -+/* -+ * Copyright (c) 2019, 2020, 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 -@@ -334,25 +335,25 @@ final class P11AEADCipher extends CipherSpi { - } - - private void cancelOperation() { -+ // cancel operation by finishing it; avoid killSession as some -+ // hardware vendors may require re-login -+ int bufLen = doFinalLength(0); -+ byte[] buffer = new byte[bufLen]; -+ byte[] in = dataBuffer.toByteArray(); -+ int inLen = in.length; - try { -- if (session.hasObjects() == false) { -- session = token.killSession(session); -- return; -+ if (encrypt) { -+ token.p11.C_Encrypt(session.id(), 0, in, 0, inLen, -+ 0, buffer, 0, bufLen); - } else { -- // cancel operation by finishing it -- int bufLen = doFinalLength(0); -- byte[] buffer = new byte[bufLen]; -- -- if (encrypt) { -- token.p11.C_Encrypt(session.id(), 0, buffer, 0, bufLen, -- 0, buffer, 0, bufLen); -- } else { -- token.p11.C_Decrypt(session.id(), 0, buffer, 0, bufLen, -- 0, buffer, 0, bufLen); -- } -+ token.p11.C_Decrypt(session.id(), 0, in, 0, inLen, -+ 0, buffer, 0, bufLen); - } - } catch (PKCS11Exception e) { -- throw new ProviderException("Cancel failed", e); -+ if (encrypt) { -+ throw new ProviderException("Cancel failed", e); -+ } -+ // ignore failure for decryption - } - } - -@@ -434,18 +435,21 @@ final class P11AEADCipher extends CipherSpi { - if (!initialized) { - return; - } -+ initialized = false; -+ - try { - if (session == null) { - return; - } -+ - if (doCancel && token.explicitCancel) { - cancelOperation(); - } - } finally { - p11Key.releaseKeyID(); - session = token.releaseSession(session); -+ dataBuffer.reset(); - } -- initialized = false; - } - - // see JCE spec -diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java -index cc4535e7b..470a888cd 100644 ---- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java -+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2003, 2020, 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 -@@ -409,10 +409,12 @@ final class P11Cipher extends CipherSpi { - return; - } - initialized = false; -+ - try { - if (session == null) { - return; - } -+ - if (doCancel && token.explicitCancel) { - cancelOperation(); - } -@@ -426,22 +428,21 @@ final class P11Cipher extends CipherSpi { - - private void cancelOperation() { - token.ensureValid(); -- if (session.hasObjects() == false) { -- session = token.killSession(session); -- return; -- } else { -- try { -- // cancel operation by finishing it -- int bufLen = doFinalLength(0); -- byte[] buffer = new byte[bufLen]; -- if (encrypt) { -- token.p11.C_EncryptFinal(session.id(), 0, buffer, 0, bufLen); -- } else { -- token.p11.C_DecryptFinal(session.id(), 0, buffer, 0, bufLen); -- } -- } catch (PKCS11Exception e) { -+ // cancel operation by finishing it; avoid killSession as some -+ // hardware vendors may require re-login -+ try { -+ int bufLen = doFinalLength(0); -+ byte[] buffer = new byte[bufLen]; -+ if (encrypt) { -+ token.p11.C_EncryptFinal(session.id(), 0, buffer, 0, bufLen); -+ } else { -+ token.p11.C_DecryptFinal(session.id(), 0, buffer, 0, bufLen); -+ } -+ } catch (PKCS11Exception e) { -+ if (encrypt) { - throw new ProviderException("Cancel failed", e); - } -+ // ignore failure for decryption - } - } - -diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Mac.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Mac.java -index 338cb215d..634e0855f 100644 ---- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Mac.java -+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Mac.java -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2003, 2020, 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,10 +124,12 @@ final class P11Mac extends MacSpi { - return; - } - initialized = false; -+ - try { - if (session == null) { - return; - } -+ - if (doCancel && token.explicitCancel) { - cancelOperation(); - } -@@ -139,15 +141,12 @@ final class P11Mac extends MacSpi { - - private void cancelOperation() { - token.ensureValid(); -- if (session.hasObjects() == false) { -- session = token.killSession(session); -- return; -- } else { -- try { -- token.p11.C_SignFinal(session.id(), 0); -- } catch (PKCS11Exception e) { -- throw new ProviderException("Cancel failed", e); -- } -+ // cancel operation by finishing it; avoid killSession as some -+ // hardware vendors may require re-login -+ try { -+ token.p11.C_SignFinal(session.id(), 0); -+ } catch (PKCS11Exception e) { -+ throw new ProviderException("Cancel failed", e); - } - } - -@@ -209,7 +208,6 @@ final class P11Mac extends MacSpi { - ensureInitialized(); - return token.p11.C_SignFinal(session.id(), 0); - } catch (PKCS11Exception e) { -- reset(true); - throw new ProviderException("doFinal() failed", e); - } finally { - reset(false); -diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11PSSSignature.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11PSSSignature.java -index 763fb98a8..0a470b932 100644 ---- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11PSSSignature.java -+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11PSSSignature.java -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2019, 2020, 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 -@@ -223,10 +223,12 @@ final class P11PSSSignature extends SignatureSpi { - return; - } - initialized = false; -+ - try { - if (session == null) { - return; - } -+ - if (doCancel && token.explicitCancel) { - cancelOperation(); - } -@@ -242,14 +244,10 @@ final class P11PSSSignature extends SignatureSpi { - token.ensureValid(); - if (DEBUG) System.out.print("Cancelling operation"); - -- if (session.hasObjects() == false) { -- if (DEBUG) System.out.println(" by killing session"); -- session = token.killSession(session); -- return; -- } -- // "cancel" operation by finishing it -- if (mode == M_SIGN) { -- try { -+ // cancel operation by finishing it; avoid killSession as some -+ // hardware vendors may require re-login -+ try { -+ if (mode == M_SIGN) { - if (type == T_UPDATE) { - if (DEBUG) System.out.println(" by C_SignFinal"); - token.p11.C_SignFinal(session.id(), 0); -@@ -259,11 +257,7 @@ final class P11PSSSignature extends SignatureSpi { - if (DEBUG) System.out.println(" by C_Sign"); - token.p11.C_Sign(session.id(), digest); - } -- } catch (PKCS11Exception e) { -- throw new ProviderException("cancel failed", e); -- } -- } else { // M_VERIFY -- try { -+ } else { // M_VERIFY - byte[] signature = - new byte[(p11Key.length() + 7) >> 3]; - if (type == T_UPDATE) { -@@ -275,10 +269,12 @@ final class P11PSSSignature extends SignatureSpi { - if (DEBUG) System.out.println(" by C_Verify"); - token.p11.C_Verify(session.id(), digest, signature); - } -- } catch (PKCS11Exception e) { -- // will fail since the signature is incorrect -- // XXX check error code - } -+ } catch (PKCS11Exception e) { -+ if (mode == M_SIGN) { -+ throw new ProviderException("cancel failed", e); -+ } -+ // ignore failure for verification - } - } - -diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11RSACipher.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11RSACipher.java -index 3f32501e0..06d65e893 100644 ---- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11RSACipher.java -+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11RSACipher.java -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2003, 2020, 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 -@@ -247,10 +247,12 @@ final class P11RSACipher extends CipherSpi { - return; - } - initialized = false; -+ - try { - if (session == null) { - return; - } -+ - if (doCancel && token.explicitCancel) { - cancelOperation(); - } -@@ -264,36 +266,33 @@ final class P11RSACipher extends CipherSpi { - // state variables such as "initialized" - private void cancelOperation() { - token.ensureValid(); -- if (session.hasObjects() == false) { -- session = token.killSession(session); -- return; -- } else { -- try { -- PKCS11 p11 = token.p11; -- int inLen = maxInputSize; -- int outLen = buffer.length; -- long sessId = session.id(); -- switch (mode) { -- case MODE_ENCRYPT: -- p11.C_Encrypt(sessId, 0, buffer, 0, inLen, 0, buffer, 0, outLen); -- break; -- case MODE_DECRYPT: -- p11.C_Decrypt(sessId, 0, buffer, 0, inLen, 0, buffer, 0, outLen); -- break; -- case MODE_SIGN: -- byte[] tmpBuffer = new byte[maxInputSize]; -- p11.C_Sign(sessId, tmpBuffer); -- break; -- case MODE_VERIFY: -- p11.C_VerifyRecover(sessId, buffer, 0, inLen, buffer, -- 0, outLen); -- break; -- default: -- throw new ProviderException("internal error"); -- } -- } catch (PKCS11Exception e) { -- // XXX ensure this always works, ignore error -+ // cancel operation by finishing it; avoid killSession as some -+ // hardware vendors may require re-login -+ try { -+ PKCS11 p11 = token.p11; -+ int inLen = maxInputSize; -+ int outLen = buffer.length; -+ long sessId = session.id(); -+ switch (mode) { -+ case MODE_ENCRYPT: -+ p11.C_Encrypt(sessId, 0, buffer, 0, inLen, 0, buffer, 0, outLen); -+ break; -+ case MODE_DECRYPT: -+ p11.C_Decrypt(sessId, 0, buffer, 0, inLen, 0, buffer, 0, outLen); -+ break; -+ case MODE_SIGN: -+ byte[] tmpBuffer = new byte[maxInputSize]; -+ p11.C_Sign(sessId, tmpBuffer); -+ break; -+ case MODE_VERIFY: -+ p11.C_VerifyRecover(sessId, buffer, 0, inLen, buffer, -+ 0, outLen); -+ break; -+ default: -+ throw new ProviderException("internal error"); - } -+ } catch (PKCS11Exception e) { -+ // XXX ensure this always works, ignore error - } - } - -@@ -362,6 +361,7 @@ final class P11RSACipher extends CipherSpi { - private int implDoFinal(byte[] out, int outOfs, int outLen) - throws BadPaddingException, IllegalBlockSizeException { - if (bufOfs > maxInputSize) { -+ reset(true); - throw new IllegalBlockSizeException("Data must not be longer " - + "than " + maxInputSize + " bytes"); - } -diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Signature.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Signature.java -index 159c65f59..f41538cda 100644 ---- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Signature.java -+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Signature.java -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. -+ * Copyright (c) 2003, 2020, 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 -@@ -270,10 +270,12 @@ final class P11Signature extends SignatureSpi { - return; - } - initialized = false; -+ - try { - if (session == null) { - return; - } -+ - if (doCancel && token.explicitCancel) { - cancelOperation(); - } -@@ -284,59 +286,51 @@ final class P11Signature extends SignatureSpi { - } - - private void cancelOperation() { -- - token.ensureValid(); -- if (session.hasObjects() == false) { -- session = token.killSession(session); -- return; -- } else { -- // "cancel" operation by finishing it -- // XXX make sure all this always works correctly -+ // cancel operation by finishing it; avoid killSession as some -+ // hardware vendors may require re-login -+ try { - if (mode == M_SIGN) { -- try { -- if (type == T_UPDATE) { -- token.p11.C_SignFinal(session.id(), 0); -- } else { -- byte[] digest; -- if (type == T_DIGEST) { -- digest = md.digest(); -- } else { // T_RAW -- digest = buffer; -- } -- token.p11.C_Sign(session.id(), digest); -+ if (type == T_UPDATE) { -+ token.p11.C_SignFinal(session.id(), 0); -+ } else { -+ byte[] digest; -+ if (type == T_DIGEST) { -+ digest = md.digest(); -+ } else { // T_RAW -+ digest = buffer; - } -- } catch (PKCS11Exception e) { -- throw new ProviderException("cancel failed", e); -+ token.p11.C_Sign(session.id(), digest); - } - } else { // M_VERIFY - byte[] signature; -- try { -- if (keyAlgorithm.equals("DSA")) { -- signature = new byte[40]; -- } else { -- signature = new byte[(p11Key.length() + 7) >> 3]; -- } -- if (type == T_UPDATE) { -- token.p11.C_VerifyFinal(session.id(), signature); -- } else { -- byte[] digest; -- if (type == T_DIGEST) { -- digest = md.digest(); -- } else { // T_RAW -- digest = buffer; -- } -- token.p11.C_Verify(session.id(), digest, signature); -- } -- } catch (PKCS11Exception e) { -- long errorCode = e.getErrorCode(); -- if ((errorCode == CKR_SIGNATURE_INVALID) || -- (errorCode == CKR_SIGNATURE_LEN_RANGE)) { -- // expected since signature is incorrect -- return; -+ if (keyAlgorithm.equals("DSA")) { -+ signature = new byte[40]; -+ } else { -+ signature = new byte[(p11Key.length() + 7) >> 3]; -+ } -+ if (type == T_UPDATE) { -+ token.p11.C_VerifyFinal(session.id(), signature); -+ } else { -+ byte[] digest; -+ if (type == T_DIGEST) { -+ digest = md.digest(); -+ } else { // T_RAW -+ digest = buffer; - } -- throw new ProviderException("cancel failed", e); -+ token.p11.C_Verify(session.id(), digest, signature); -+ } -+ } -+ } catch (PKCS11Exception e) { -+ if (mode == M_VERIFY) { -+ long errorCode = e.getErrorCode(); -+ if ((errorCode == CKR_SIGNATURE_INVALID) || -+ (errorCode == CKR_SIGNATURE_LEN_RANGE)) { -+ // expected since signature is incorrect -+ return; - } - } -+ throw new ProviderException("cancel failed", e); - } - } - --- -2.19.1 - diff --git a/8240353.patch b/8240353.patch new file mode 100755 index 0000000000000000000000000000000000000000..6aa496caa3117ec3826f47450313ce22f014679d --- /dev/null +++ b/8240353.patch @@ -0,0 +1,65 @@ +commit 29fd7a83a66269e360af353c64d945612be62623 +Date: Thu Feb 4 16:37:53 2021 +0800 + + 8240353: AArch64: missing support for -XX:+ExtendedDTraceProbes in C1 + + Summary: : java -XX:+ExtendedDTraceProbes throws SIGILL + LLT: java -XX:+ExtendedDTraceProbes + Patch Type: backport + Bug url: https://bugs.openjdk.java.net/browse/JDK-8240353 + +diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +index 7798aa509..a8e89cde0 100644 +--- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp ++++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * +@@ -449,12 +449,9 @@ int LIR_Assembler::emit_unwind_handler() { + } + + if (compilation()->env()->dtrace_method_probes()) { +- __ call_Unimplemented(); +-#if 0 +- __ movptr(Address(rsp, 0), rax); +- __ mov_metadata(Address(rsp, sizeof(void*)), method()->constant_encoding()); +- __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit))); +-#endif ++ __ mov(c_rarg0, rthread); ++ __ mov_metadata(c_rarg1, method()->constant_encoding()); ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), c_rarg0, c_rarg1); + } + + if (method()->is_synchronized() || compilation()->env()->dtrace_method_probes()) { +diff --git a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp +index 2344e0be3..3f5ab6641 100644 +--- a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp ++++ b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * +@@ -1123,6 +1123,16 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { + } + break; + ++ case dtrace_object_alloc_id: ++ { // c_rarg0: object ++ StubFrame f(sasm, "dtrace_object_alloc", dont_gc_arguments); ++ save_live_registers(sasm); ++ ++ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc), c_rarg0); ++ ++ restore_live_registers(sasm); ++ } ++ break; + + default: + { StubFrame f(sasm, "unimplemented entry", dont_gc_arguments); diff --git a/8250861-Crash-in-MinINode-Ideal.patch b/8250861-Crash-in-MinINode-Ideal.patch deleted file mode 100644 index 0c0651f99fdb66d731c4bdc6669c156438e541db..0000000000000000000000000000000000000000 --- a/8250861-Crash-in-MinINode-Ideal.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- a/src/hotspot/share/opto/addnode.cpp Mon Nov 02 20:20:05 2020 +0100 -+++ b/src/hotspot/share/opto/addnode.cpp Wed Nov 04 10:42:35 2020 +0100 -@@ -917,7 +917,7 @@ - - // Transform MIN2(x + c0, MIN2(x + c1, z)) into MIN2(x + MIN2(c0, c1), z) - // if x == y and the additions can't overflow. -- if (phase->eqv(x,y) && -+ if (phase->eqv(x,y) && tx != NULL && - !can_overflow(tx, x_off) && - !can_overflow(tx, y_off)) { - return new MinINode(phase->transform(new AddINode(x, phase->intcon(MIN2(x_off, y_off)))), r->in(2)); -@@ -925,7 +925,7 @@ - } else { - // Transform MIN2(x + c0, y + c1) into x + MIN2(c0, c1) - // if x == y and the additions can't overflow. -- if (phase->eqv(x,y) && -+ if (phase->eqv(x,y) && tx != NULL && - !can_overflow(tx, x_off) && - !can_overflow(tx, y_off)) { - return new AddINode(x,phase->intcon(MIN2(x_off,y_off))); diff --git a/8254078-DataOutputStream-is-very-slow-post-disabling.patch b/8254078-DataOutputStream-is-very-slow-post-disabling.patch new file mode 100755 index 0000000000000000000000000000000000000000..5f7b52a0d91f8f754aafbf2dfd1cc50c5deba436 --- /dev/null +++ b/8254078-DataOutputStream-is-very-slow-post-disabling.patch @@ -0,0 +1,218 @@ +From 0f9ef0bc57aa0e7d8457b645374be74d510ea7ae Mon Sep 17 00:00:00 2001 +Date: Thu, 18 Mar 2021 12:35:14 +0000 +Subject: [PATCH 2/4] 8254078: DataOutputStream is very slow post disabling + +--- + .../classes/java/io/DataInputStream.java | 7 +- + .../classes/java/io/DataOutputStream.java | 24 ++-- + .../bench/java/io/DataOutputStreamTest.java | 124 ++++++++++++++++++ + 3 files changed, 144 insertions(+), 11 deletions(-) + create mode 100644 test/micro/org/openjdk/bench/java/io/DataOutputStreamTest.java + +diff --git a/src/java.base/share/classes/java/io/DataInputStream.java b/src/java.base/share/classes/java/io/DataInputStream.java +index f92c4f91b..114857691 100644 +--- a/src/java.base/share/classes/java/io/DataInputStream.java ++++ b/src/java.base/share/classes/java/io/DataInputStream.java +@@ -31,9 +31,10 @@ package java.io; + * way. An application uses a data output stream to write data that + * can later be read by a data input stream. + *

+- * DataInputStream is not necessarily safe for multithreaded access. +- * Thread safety is optional and is the responsibility of users of +- * methods in this class. ++ * A DataInputStream is not safe for use by multiple concurrent ++ * threads. If a DataInputStream is to be used by more than one ++ * thread then access to the data input stream should be controlled ++ * by appropriate synchronization. + * + * @author Arthur van Hoff + * @see java.io.DataOutputStream +diff --git a/src/java.base/share/classes/java/io/DataOutputStream.java b/src/java.base/share/classes/java/io/DataOutputStream.java +index 392abba92..7c0962442 100644 +--- a/src/java.base/share/classes/java/io/DataOutputStream.java ++++ b/src/java.base/share/classes/java/io/DataOutputStream.java +@@ -29,6 +29,11 @@ package java.io; + * A data output stream lets an application write primitive Java data + * types to an output stream in a portable way. An application can + * then use a data input stream to read the data back in. ++ *

++ * A DataOutputStream is not safe for use by multiple concurrent ++ * threads. If a DataOutputStream is to be used by more than one ++ * thread then access to the data output stream should be controlled ++ * by appropriate synchronization. + * + * @author unascribed + * @see java.io.DataInputStream +@@ -164,8 +169,9 @@ class DataOutputStream extends FilterOutputStream implements DataOutput { + * @see java.io.FilterOutputStream#out + */ + public final void writeShort(int v) throws IOException { +- out.write((v >>> 8) & 0xFF); +- out.write((v >>> 0) & 0xFF); ++ writeBuffer[0] = (byte)(v >>> 8); ++ writeBuffer[1] = (byte)(v >>> 0); ++ out.write(writeBuffer, 0, 2); + incCount(2); + } + +@@ -179,8 +185,9 @@ class DataOutputStream extends FilterOutputStream implements DataOutput { + * @see java.io.FilterOutputStream#out + */ + public final void writeChar(int v) throws IOException { +- out.write((v >>> 8) & 0xFF); +- out.write((v >>> 0) & 0xFF); ++ writeBuffer[0] = (byte)(v >>> 8); ++ writeBuffer[1] = (byte)(v >>> 0); ++ out.write(writeBuffer, 0, 2); + incCount(2); + } + +@@ -194,10 +201,11 @@ class DataOutputStream extends FilterOutputStream implements DataOutput { + * @see java.io.FilterOutputStream#out + */ + public final void writeInt(int v) throws IOException { +- out.write((v >>> 24) & 0xFF); +- out.write((v >>> 16) & 0xFF); +- out.write((v >>> 8) & 0xFF); +- out.write((v >>> 0) & 0xFF); ++ writeBuffer[0] = (byte)(v >>> 24); ++ writeBuffer[1] = (byte)(v >>> 16); ++ writeBuffer[2] = (byte)(v >>> 8); ++ writeBuffer[3] = (byte)(v >>> 0); ++ out.write(writeBuffer, 0, 4); + incCount(4); + } + +diff --git a/test/micro/org/openjdk/bench/java/io/DataOutputStreamTest.java b/test/micro/org/openjdk/bench/java/io/DataOutputStreamTest.java +new file mode 100644 +index 000000000..2f573e6dd +--- /dev/null ++++ b/test/micro/org/openjdk/bench/java/io/DataOutputStreamTest.java +@@ -0,0 +1,124 @@ ++/* ++ * Copyright (c) 2020, Red Hat Inc. 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 org.openjdk.bench.java.io; ++ ++import org.openjdk.jmh.annotations.*; ++ ++import java.io.*; ++import java.util.concurrent.TimeUnit; ++ ++@BenchmarkMode(Mode.AverageTime) ++@OutputTimeUnit(TimeUnit.MICROSECONDS) ++@Fork(value = 1, warmups = 0) ++@Measurement(iterations = 6, time = 1) ++@Warmup(iterations=2, time = 2) ++@State(Scope.Benchmark) ++public class DataOutputStreamTest { ++ ++ public enum BasicType {CHAR, SHORT, INT, STRING} ++ @Param({"CHAR", "SHORT", "INT", /* "STRING"*/}) BasicType basicType; ++ ++ @Param({"4096"}) int size; ++ ++ final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(size); ++ File f; ++ String outputString; ++ FileOutputStream fileOutputStream; ++ DataOutput bufferedFileStream, rawFileStream, byteArrayStream; ++ ++ @Setup(Level.Trial) ++ public void setup() throws Exception { ++ f = File.createTempFile("DataOutputStreamTest","out"); ++ fileOutputStream = new FileOutputStream(f); ++ byteArrayStream = new DataOutputStream(byteArrayOutputStream); ++ rawFileStream = new DataOutputStream(fileOutputStream); ++ bufferedFileStream = new DataOutputStream(new BufferedOutputStream(fileOutputStream)); ++ outputString = new String(new byte[size]); ++ } ++ ++ public void writeChars(DataOutput dataOutput) ++ throws Exception { ++ for (int i = 0; i < size; i += 2) { ++ dataOutput.writeChar(i); ++ } ++ } ++ ++ public void writeShorts(DataOutput dataOutput) ++ throws Exception { ++ for (int i = 0; i < size; i += 2) { ++ dataOutput.writeShort(i); ++ } ++ } ++ ++ public void writeInts(DataOutput dataOutput) ++ throws Exception { ++ for (int i = 0; i < size; i += 4) { ++ dataOutput.writeInt(i); ++ } ++ } ++ ++ public void writeString(DataOutput dataOutput) ++ throws Exception { ++ dataOutput.writeChars(outputString); ++ } ++ ++ public void write(DataOutput dataOutput) ++ throws Exception { ++ switch (basicType) { ++ case CHAR: ++ writeChars(dataOutput); ++ break; ++ case SHORT: ++ writeShorts(dataOutput); ++ break; ++ case INT: ++ writeInts(dataOutput); ++ break; ++ case STRING: ++ writeString(dataOutput); ++ break; ++ } ++ } ++ ++ @Benchmark ++ public void dataOutputStreamOverByteArray() throws Exception { ++ byteArrayOutputStream.reset(); ++ write(byteArrayStream); ++ byteArrayOutputStream.flush(); ++ } ++ ++ @Benchmark ++ public void dataOutputStreamOverRawFileStream() throws Exception { ++ fileOutputStream.getChannel().position(0); ++ write(rawFileStream); ++ fileOutputStream.flush(); ++ } ++ ++ @Benchmark ++ public void dataOutputStreamOverBufferedFileStream() throws Exception{ ++ fileOutputStream.getChannel().position(0); ++ write(bufferedFileStream); ++ fileOutputStream.flush(); ++ } ++} +-- +2.19.0 + diff --git a/8255781-Bump-patch-update-version-for-OpenJDK-jdk-11.0.9.1.patch b/8255781-Bump-patch-update-version-for-OpenJDK-jdk-11.0.9.1.patch deleted file mode 100644 index bab887d65cda1e189b85f5b1c77d00a002482ed6..0000000000000000000000000000000000000000 --- a/8255781-Bump-patch-update-version-for-OpenJDK-jdk-11.0.9.1.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- a/make/autoconf/version-numbers Mon Nov 02 20:12:55 2020 +0100 -+++ b/make/autoconf/version-numbers Mon Nov 02 20:20:05 2020 +0100 -@@ -29,11 +29,11 @@ - DEFAULT_VERSION_FEATURE=11 - DEFAULT_VERSION_INTERIM=0 - DEFAULT_VERSION_UPDATE=9 --DEFAULT_VERSION_PATCH=0 -+DEFAULT_VERSION_PATCH=1 - DEFAULT_VERSION_EXTRA1=0 - DEFAULT_VERSION_EXTRA2=0 - DEFAULT_VERSION_EXTRA3=0 --DEFAULT_VERSION_DATE=2020-10-20 -+DEFAULT_VERSION_DATE=2020-11-04 - DEFAULT_VERSION_CLASSFILE_MAJOR=55 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" - DEFAULT_VERSION_CLASSFILE_MINOR=0 - DEFAULT_ACCEPTABLE_BOOT_VERSIONS="10 11" diff --git a/Fix-the-memcpy-symbol-issue-during-JDK11-x64-build.patch b/Fix-the-memcpy-symbol-issue-during-JDK11-x64-build.patch new file mode 100755 index 0000000000000000000000000000000000000000..b6ac2b6766e52ef1d40a186168cb70e5333f8d22 --- /dev/null +++ b/Fix-the-memcpy-symbol-issue-during-JDK11-x64-build.patch @@ -0,0 +1,23 @@ +From ae703c0e86c278359f1bddcf35ccba87b556d901 Mon Sep 17 00:00:00 2001 +Date: Thu, 18 Mar 2021 12:37:11 +0000 +Subject: [PATCH 4/4] Fix the memcpy symbol issue during JDK11 x64 build + +--- + make/lib/Awt2dLibraries.gmk | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/make/lib/Awt2dLibraries.gmk b/make/lib/Awt2dLibraries.gmk +index 207a459ae..7b0441507 100644 +--- a/make/lib/Awt2dLibraries.gmk ++++ b/make/lib/Awt2dLibraries.gmk +@@ -597,6 +597,7 @@ else + $(eval $(call SetupJdkLibrary, BUILD_LIBHARFBUZZ, \ + NAME := harfbuzz, \ + EXCLUDE_FILES := $(LIBHARFBUZZ_EXCLUDE_FILES), \ ++ EXTRA_FILES := $(LIBMEMCPY_FILES), \ + TOOLCHAIN := TOOLCHAIN_LINK_CXX, \ + CFLAGS := $(CFLAGS_JDKLIB) $(LIBHARFBUZZ_CFLAGS), \ + CXXFLAGS := $(CXXFLAGS_JDKLIB) $(LIBHARFBUZZ_CFLAGS), \ +-- +2.19.0 + diff --git a/add-G1-Full-GC-optimization.patch b/add-G1-Full-GC-optimization.patch new file mode 100755 index 0000000000000000000000000000000000000000..1ccdfb0319be37ad13d835f10b3c4d06573056d1 --- /dev/null +++ b/add-G1-Full-GC-optimization.patch @@ -0,0 +1,752 @@ +From 54bd3b89d00c7eba9119e3dfa3d49b7c9ec79d30 Mon Sep 17 00:00:00 2001 +Date: Tue, 16 Mar 2021 07:09:02 +0000 +Subject: [PATCH 3/4] add G1 Full GC optimization + +--- + src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 15 +++- + src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 2 +- + src/hotspot/share/gc/g1/g1FullCollector.cpp | 5 ++ + src/hotspot/share/gc/g1/g1FullCollector.hpp | 3 + + .../share/gc/g1/g1FullGCCompactTask.cpp | 14 +++ + .../share/gc/g1/g1FullGCCompactTask.hpp | 1 + + src/hotspot/share/gc/g1/g1FullGCMarkTask.cpp | 2 + + .../share/gc/g1/g1FullGCMarker.inline.hpp | 5 ++ + .../share/gc/g1/g1FullGCPrepareTask.cpp | 52 ++++++++--- + .../share/gc/g1/g1FullGCPrepareTask.hpp | 7 +- + src/hotspot/share/gc/g1/g1MarkLiveWords.cpp | 37 ++++++++ + src/hotspot/share/gc/g1/g1MarkLiveWords.hpp | 34 +++++++ + src/hotspot/share/gc/g1/g1MarkRegionCache.cpp | 49 +++++++++++ + src/hotspot/share/gc/g1/g1MarkRegionCache.hpp | 40 +++++++++ + src/hotspot/share/gc/g1/g1_globals.hpp | 10 ++- + src/hotspot/share/gc/g1/heapRegion.cpp | 3 +- + src/hotspot/share/gc/g1/heapRegion.hpp | 9 +- + src/hotspot/share/gc/g1/heapRegionManager.hpp | 1 + + src/hotspot/share/gc/g1/heapRegionSet.cpp | 15 ---- + src/hotspot/share/gc/g1/heapRegionSet.hpp | 2 - + test/hotspot/jtreg/gc/g1/TestG1NoMoving.java | 88 +++++++++++++++++++ + 21 files changed, 359 insertions(+), 35 deletions(-) + create mode 100644 src/hotspot/share/gc/g1/g1MarkLiveWords.cpp + create mode 100644 src/hotspot/share/gc/g1/g1MarkLiveWords.hpp + create mode 100644 src/hotspot/share/gc/g1/g1MarkRegionCache.cpp + create mode 100644 src/hotspot/share/gc/g1/g1MarkRegionCache.hpp + create mode 100644 test/hotspot/jtreg/gc/g1/TestG1NoMoving.java + +diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +index 130f8ec0a..7e9c6254c 100644 +--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp ++++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +@@ -2571,6 +2571,17 @@ void G1CollectedHeap::gc_epilogue(bool full) { + _numa->print_statistics(); + } + ++void G1CollectedHeap::verify_numa_regions(const char* desc) { ++ LogTarget(Trace, gc, heap, verify) lt; ++ ++ if (lt.is_enabled()) { ++ LogStream ls(lt); ++ // Iterate all heap regions to print matching between preferred numa id and actual numa id. ++ G1NodeIndexCheckClosure cl(desc, _numa, &ls); ++ heap_region_iterate(&cl); ++ } ++} ++ + HeapWord* G1CollectedHeap::do_collection_pause(size_t word_size, + uint gc_count_before, + bool* succeeded, +@@ -2975,7 +2986,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { + _verifier->verify_before_gc(verify_type); + + _verifier->check_bitmaps("GC Start"); +- ++ verify_numa_regions("GC Start"); + #if COMPILER2_OR_JVMCI + DerivedPointerTable::clear(); + #endif +@@ -3129,7 +3140,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { + + _verifier->verify_after_gc(verify_type); + _verifier->check_bitmaps("GC End"); +- ++ verify_numa_regions("GC End"); + assert(!_ref_processor_stw->discovery_enabled(), "Postcondition"); + _ref_processor_stw->verify_no_references_recorded(); + +diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +index aafaf6a08..bb46cae83 100644 +--- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp ++++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +@@ -722,7 +722,7 @@ private: + void print_taskqueue_stats() const; + void reset_taskqueue_stats(); + #endif // TASKQUEUE_STATS +- ++ void verify_numa_regions(const char* desc); + // Schedule the VM operation that will do an evacuation pause to + // satisfy an allocation request of word_size. *succeeded will + // return whether the VM operation was successful (it did do an +diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp +index 4362ee87e..661a3dd9f 100644 +--- a/src/hotspot/share/gc/g1/g1FullCollector.cpp ++++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp +@@ -37,6 +37,7 @@ + #include "gc/g1/g1OopClosures.hpp" + #include "gc/g1/g1Policy.hpp" + #include "gc/g1/g1StringDedup.hpp" ++#include "gc/g1/g1MarkRegionCache.hpp" + #include "gc/shared/adaptiveSizePolicy.hpp" + #include "gc/shared/gcTraceTime.inline.hpp" + #include "gc/shared/preservedMarks.hpp" +@@ -120,9 +121,11 @@ G1FullCollector::G1FullCollector(G1CollectedHeap* heap, GCMemoryManager* memory_ + _preserved_marks_set.init(_num_workers); + _markers = NEW_C_HEAP_ARRAY(G1FullGCMarker*, _num_workers, mtGC); + _compaction_points = NEW_C_HEAP_ARRAY(G1FullGCCompactionPoint*, _num_workers, mtGC); ++ _no_moving_region_compaction_points = NEW_C_HEAP_ARRAY(G1FullGCCompactionPoint*, _num_workers, mtGC); + for (uint i = 0; i < _num_workers; i++) { + _markers[i] = new G1FullGCMarker(i, _preserved_marks_set.get(i), mark_bitmap()); + _compaction_points[i] = new G1FullGCCompactionPoint(); ++ _no_moving_region_compaction_points[i] = new G1FullGCCompactionPoint(); + _oop_queue_set.register_queue(i, marker(i)->oop_stack()); + _array_queue_set.register_queue(i, marker(i)->objarray_stack()); + } +@@ -132,9 +135,11 @@ G1FullCollector::~G1FullCollector() { + for (uint i = 0; i < _num_workers; i++) { + delete _markers[i]; + delete _compaction_points[i]; ++ delete _no_moving_region_compaction_points[i]; + } + FREE_C_HEAP_ARRAY(G1FullGCMarker*, _markers); + FREE_C_HEAP_ARRAY(G1FullGCCompactionPoint*, _compaction_points); ++ FREE_C_HEAP_ARRAY(G1FullGCCompactionPoint*, _no_moving_region_compaction_points); + } + + void G1FullCollector::prepare_collection() { +diff --git a/src/hotspot/share/gc/g1/g1FullCollector.hpp b/src/hotspot/share/gc/g1/g1FullCollector.hpp +index 0b97abeea..f81fe1059 100644 +--- a/src/hotspot/share/gc/g1/g1FullCollector.hpp ++++ b/src/hotspot/share/gc/g1/g1FullCollector.hpp +@@ -66,6 +66,8 @@ class G1FullCollector : StackObj { + G1IsAliveClosure _is_alive; + ReferenceProcessorIsAliveMutator _is_alive_mutator; + ++ G1FullGCCompactionPoint** _no_moving_region_compaction_points; ++ + static uint calc_active_workers(); + + G1FullGCSubjectToDiscoveryClosure _always_subject_to_discovery; +@@ -83,6 +85,7 @@ public: + uint workers() { return _num_workers; } + G1FullGCMarker* marker(uint id) { return _markers[id]; } + G1FullGCCompactionPoint* compaction_point(uint id) { return _compaction_points[id]; } ++ G1FullGCCompactionPoint* no_moving_region_compaction_point(uint id) { return _no_moving_region_compaction_points[id]; } + OopQueueSet* oop_queue_set() { return &_oop_queue_set; } + ObjArrayTaskQueueSet* array_queue_set() { return &_array_queue_set; } + PreservedMarksSet* preserved_mark_set() { return &_preserved_marks_set; } +diff --git a/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp b/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp +index 0c2fc088f..eab1b2121 100644 +--- a/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp ++++ b/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp +@@ -87,6 +87,11 @@ void G1FullGCCompactTask::compact_region(HeapRegion* hr) { + hr->complete_compaction(); + } + ++void G1FullGCCompactTask::process_no_moving_region(HeapRegion* hr) { ++ collector()->mark_bitmap()->clear_region(hr); ++ hr->reset_no_compaction_region_during_compaction(); ++} ++ + void G1FullGCCompactTask::work(uint worker_id) { + Ticks start = Ticks::now(); + GrowableArray* compaction_queue = collector()->compaction_point(worker_id)->regions(); +@@ -96,6 +101,15 @@ void G1FullGCCompactTask::work(uint worker_id) { + compact_region(*it); + } + ++ if (G1FullGCNoMoving) { ++ GrowableArray* no_move_region_queue = collector()->no_moving_region_compaction_point(worker_id)->regions(); ++ for (GrowableArrayIterator it = no_move_region_queue->begin(); ++ it != no_move_region_queue->end(); ++ ++it) { ++ process_no_moving_region(*it); ++ } ++ } ++ + G1ResetHumongousClosure hc(collector()->mark_bitmap()); + G1CollectedHeap::heap()->heap_region_par_iterate_from_worker_offset(&hc, &_claimer, worker_id); + log_task("Compaction task", worker_id, start); +diff --git a/src/hotspot/share/gc/g1/g1FullGCCompactTask.hpp b/src/hotspot/share/gc/g1/g1FullGCCompactTask.hpp +index 6c8eaf596..25221599a 100644 +--- a/src/hotspot/share/gc/g1/g1FullGCCompactTask.hpp ++++ b/src/hotspot/share/gc/g1/g1FullGCCompactTask.hpp +@@ -41,6 +41,7 @@ protected: + + private: + void compact_region(HeapRegion* hr); ++ void process_no_moving_region(HeapRegion* hr); + + public: + G1FullGCCompactTask(G1FullCollector* collector) : +diff --git a/src/hotspot/share/gc/g1/g1FullGCMarkTask.cpp b/src/hotspot/share/gc/g1/g1FullGCMarkTask.cpp +index d2c4b8d60..d982ef94a 100644 +--- a/src/hotspot/share/gc/g1/g1FullGCMarkTask.cpp ++++ b/src/hotspot/share/gc/g1/g1FullGCMarkTask.cpp +@@ -29,6 +29,7 @@ + #include "gc/g1/g1FullGCMarkTask.hpp" + #include "gc/g1/g1FullGCOopClosures.inline.hpp" + #include "gc/g1/g1FullGCReferenceProcessorExecutor.hpp" ++#include "gc/g1/g1MarkLiveWords.hpp" + #include "gc/shared/gcTraceTime.inline.hpp" + #include "gc/shared/referenceProcessor.hpp" + #include "memory/iterator.inline.hpp" +@@ -42,6 +43,7 @@ G1FullGCMarkTask::G1FullGCMarkTask(G1FullCollector* collector) : + } + + void G1FullGCMarkTask::work(uint worker_id) { ++ G1MarkLiveWords g1_mark_live_words; + Ticks start = Ticks::now(); + ResourceMark rm; + G1FullGCMarker* marker = collector()->marker(worker_id); +diff --git a/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp b/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp +index 98a2fe7f1..78555b30f 100644 +--- a/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp ++++ b/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp +@@ -31,6 +31,7 @@ + #include "gc/g1/g1FullGCOopClosures.inline.hpp" + #include "gc/g1/g1StringDedup.hpp" + #include "gc/g1/g1StringDedupQueue.hpp" ++#include "gc/g1/g1MarkLiveWords.hpp" + #include "gc/shared/preservedMarks.inline.hpp" + #include "oops/access.inline.hpp" + #include "oops/compressedOops.inline.hpp" +@@ -68,6 +69,10 @@ template inline void G1FullGCMarker::mark_and_push(T* p) { + if (!CompressedOops::is_null(heap_oop)) { + oop obj = CompressedOops::decode_not_null(heap_oop); + if (mark_object(obj)) { ++ uint hr_index = G1CollectedHeap::heap()->addr_to_region((HeapWord*)obj); ++ if (_tl_live_words_cache != NULL) { ++ _tl_live_words_cache->inc_live(hr_index, (size_t)obj->size()); ++ } + _oop_stack.push(obj); + assert(_bitmap->is_marked(obj), "Must be marked now - map self"); + } else { +diff --git a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp +index 3f0e18fc8..2cc9c87d0 100644 +--- a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp ++++ b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp +@@ -78,7 +78,8 @@ bool G1FullGCPrepareTask::has_freed_regions() { + void G1FullGCPrepareTask::work(uint worker_id) { + Ticks start = Ticks::now(); + G1FullGCCompactionPoint* compaction_point = collector()->compaction_point(worker_id); +- G1CalculatePointersClosure closure(collector()->mark_bitmap(), compaction_point); ++ G1FullGCCompactionPoint* no_moving_regions_compaction_point = collector()->no_moving_region_compaction_point(worker_id); ++ G1CalculatePointersClosure closure(collector()->mark_bitmap(), compaction_point, no_moving_regions_compaction_point); + G1CollectedHeap::heap()->heap_region_par_iterate_from_start(&closure, &_hrclaimer); + + // Update humongous region sets +@@ -93,11 +94,14 @@ void G1FullGCPrepareTask::work(uint worker_id) { + } + + G1FullGCPrepareTask::G1CalculatePointersClosure::G1CalculatePointersClosure(G1CMBitMap* bitmap, +- G1FullGCCompactionPoint* cp) : ++ G1FullGCCompactionPoint* cp, ++ G1FullGCCompactionPoint* no_moving_regions_cp) : + _g1h(G1CollectedHeap::heap()), + _bitmap(bitmap), + _cp(cp), +- _humongous_regions_removed(0) { } ++ _no_moving_regions_cp(no_moving_regions_cp), ++ _humongous_regions_removed(0), ++ _hr_live_bytes_threshold((size_t)HeapRegion::GrainBytes * G1NoMovingRegionLiveBytesLowerThreshold / 100) { } + + void G1FullGCPrepareTask::G1CalculatePointersClosure::free_humongous_region(HeapRegion* hr) { + FreeRegionList dummy_free_list("Dummy Free List for G1MarkSweep"); +@@ -113,7 +117,7 @@ void G1FullGCPrepareTask::G1CalculatePointersClosure::free_humongous_region(Heap + void G1FullGCPrepareTask::G1CalculatePointersClosure::reset_region_metadata(HeapRegion* hr) { + hr->rem_set()->clear(); + hr->clear_cardtable(); +- ++ hr->set_live_words_after_mark((size_t)0); + if (_g1h->g1_hot_card_cache()->use_cache()) { + _g1h->g1_hot_card_cache()->reset_card_counts(hr); + } +@@ -151,13 +155,41 @@ void G1FullGCPrepareTask::G1CalculatePointersClosure::prepare_for_compaction_wor + } + + void G1FullGCPrepareTask::G1CalculatePointersClosure::prepare_for_compaction(HeapRegion* hr) { +- if (!_cp->is_initialized()) { +- hr->set_compaction_top(hr->bottom()); +- _cp->initialize(hr, true); ++ size_t live_bytes_after_mark = hr->live_bytes_after_mark(); ++ if(!G1FullGCNoMoving || live_bytes_after_mark < _hr_live_bytes_threshold || hr->is_humongous()) { ++ if (!_cp->is_initialized()) { ++ hr->set_compaction_top(hr->bottom()); ++ _cp->initialize(hr, true); ++ } ++ // Add region to the compaction queue and prepare it. ++ _cp->add(hr); ++ prepare_for_compaction_work(_cp, hr); ++ } else { ++ prepare_no_moving_region(hr); ++ _no_moving_regions_cp->add(hr); ++ log_debug(gc, phases)("no moving region index: %u, live bytes: "SIZE_FORMAT, hr->hrm_index(), live_bytes_after_mark); ++ } ++} ++ ++void G1FullGCPrepareTask::G1CalculatePointersClosure::prepare_no_moving_region(const HeapRegion* hr) { ++ const HeapRegion* current = hr; ++ assert(!current->is_humongous(), "Should be no humongous regions"); ++ HeapWord* limit = current->top(); ++ HeapWord* next_addr = current->bottom(); ++ while (next_addr < limit) { ++ Prefetch::write(next_addr, PrefetchScanIntervalInBytes); ++ oop obj = oop(next_addr); ++ size_t obj_size = obj->size(); ++ if (_bitmap->is_marked(next_addr)) { ++ if (obj->forwardee() != NULL) { ++ obj->init_mark_raw(); ++ } ++ } else { ++ // Fill dummy object to replace dead object ++ Universe::heap()->fill_with_dummy_object(next_addr, next_addr + obj_size, true); ++ } ++ next_addr += obj_size; + } +- // Add region to the compaction queue and prepare it. +- _cp->add(hr); +- prepare_for_compaction_work(_cp, hr); + } + + void G1FullGCPrepareTask::prepare_serial_compaction() { +diff --git a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp +index fcaf797a1..57b53c9dd 100644 +--- a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp ++++ b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp +@@ -39,7 +39,6 @@ class G1FullGCPrepareTask : public G1FullGCTask { + protected: + volatile bool _freed_regions; + HeapRegionClaimer _hrclaimer; +- + void set_freed_regions(); + + public: +@@ -54,16 +53,20 @@ protected: + G1CollectedHeap* _g1h; + G1CMBitMap* _bitmap; + G1FullGCCompactionPoint* _cp; ++ G1FullGCCompactionPoint* _no_moving_regions_cp; + uint _humongous_regions_removed; ++ size_t _hr_live_bytes_threshold; + + virtual void prepare_for_compaction(HeapRegion* hr); + void prepare_for_compaction_work(G1FullGCCompactionPoint* cp, HeapRegion* hr); + void free_humongous_region(HeapRegion* hr); + void reset_region_metadata(HeapRegion* hr); ++ void prepare_no_moving_region(const HeapRegion* hr); + + public: + G1CalculatePointersClosure(G1CMBitMap* bitmap, +- G1FullGCCompactionPoint* cp); ++ G1FullGCCompactionPoint* cp, ++ G1FullGCCompactionPoint* no_moving_regions_cp); + + void update_sets(); + bool do_heap_region(HeapRegion* hr); +diff --git a/src/hotspot/share/gc/g1/g1MarkLiveWords.cpp b/src/hotspot/share/gc/g1/g1MarkLiveWords.cpp +new file mode 100644 +index 000000000..32da3800a +--- /dev/null ++++ b/src/hotspot/share/gc/g1/g1MarkLiveWords.cpp +@@ -0,0 +1,37 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co. Ltd. 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. Alibaba designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * 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. ++ */ ++ ++#include "gc/g1/g1MarkLiveWords.hpp" ++ ++__thread G1MarkRegionCache* _tl_live_words_cache; ++ ++G1MarkLiveWords::G1MarkLiveWords() { ++ if (G1FullGCNoMoving) { ++ _tl_live_words_cache = new G1MarkRegionCache(); ++ } ++} ++ ++G1MarkLiveWords::~G1MarkLiveWords() { ++ if (G1FullGCNoMoving) { ++ delete _tl_live_words_cache; ++ _tl_live_words_cache = NULL; ++ } ++} +diff --git a/src/hotspot/share/gc/g1/g1MarkLiveWords.hpp b/src/hotspot/share/gc/g1/g1MarkLiveWords.hpp +new file mode 100644 +index 000000000..a11a4ca52 +--- /dev/null ++++ b/src/hotspot/share/gc/g1/g1MarkLiveWords.hpp +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co. Ltd. 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. Alibaba designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * 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. ++ */ ++ ++#ifndef SHARE_VM_GC_G1_G1MARKLIVEWORDS_HPP ++#define SHARE_VM_GC_G1_G1MARKLIVEWORDS_HPP ++ ++#include "gc/g1/g1MarkRegionCache.hpp" ++ ++extern __thread G1MarkRegionCache* _tl_live_words_cache; ++class G1MarkLiveWords { ++public: ++ G1MarkLiveWords(); ++ ~G1MarkLiveWords(); ++}; ++ ++#endif +diff --git a/src/hotspot/share/gc/g1/g1MarkRegionCache.cpp b/src/hotspot/share/gc/g1/g1MarkRegionCache.cpp +new file mode 100644 +index 000000000..37922e8cf +--- /dev/null ++++ b/src/hotspot/share/gc/g1/g1MarkRegionCache.cpp +@@ -0,0 +1,49 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co. Ltd. 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. Alibaba designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * 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. ++ */ ++ ++#include "gc/g1/g1MarkRegionCache.hpp" ++#include "gc/g1/heapRegion.inline.hpp" ++#include "runtime/atomic.hpp" ++ ++G1MarkRegionCache::G1MarkRegionCache() { ++ _cache = NEW_C_HEAP_ARRAY(size_t, G1CollectedHeap::heap()->max_regions(), mtGC); ++ memset(_cache, 0 , sizeof(size_t)*G1CollectedHeap::heap()->max_regions()); ++} ++void G1MarkRegionCache::inc_live(uint hr_index, size_t words) { ++ _cache[hr_index] += words; ++} ++ ++void* G1MarkRegionCache::operator new(size_t size) { ++ return (address)AllocateHeap(size, mtGC, CURRENT_PC, AllocFailStrategy::RETURN_NULL); ++} ++ ++void G1MarkRegionCache::operator delete(void* p) { ++ FreeHeap(p); ++} ++ ++G1MarkRegionCache::~G1MarkRegionCache() { ++ for (uint i = 0; i < G1CollectedHeap::heap()->max_regions(); ++i) { ++ if (_cache[i]) { ++ Atomic::add(_cache[i], G1CollectedHeap::heap()->region_at(i)->live_words_addr()); ++ } ++ } ++ FREE_C_HEAP_ARRAY(size_t, _cache); ++} +diff --git a/src/hotspot/share/gc/g1/g1MarkRegionCache.hpp b/src/hotspot/share/gc/g1/g1MarkRegionCache.hpp +new file mode 100644 +index 000000000..0615fcab6 +--- /dev/null ++++ b/src/hotspot/share/gc/g1/g1MarkRegionCache.hpp +@@ -0,0 +1,40 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co. Ltd. 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. Alibaba designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * 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. ++ */ ++ ++#ifndef SHARE_VM_GC_G1_G1MARKREGIONCACHE_HPP ++#define SHARE_VM_GC_G1_G1MARKREGIONCACHE_HPP ++ ++#include "memory/allocation.hpp" ++ ++class G1MarkRegionCache { ++private: ++ size_t* _cache; ++public: ++ G1MarkRegionCache(); ++ void inc_live(uint hr_index, size_t words); ++ ++ void* operator new(size_t size); ++ void operator delete(void* p); ++ ++ ~G1MarkRegionCache(); ++}; ++ ++#endif +diff --git a/src/hotspot/share/gc/g1/g1_globals.hpp b/src/hotspot/share/gc/g1/g1_globals.hpp +index 8c7aec847..e035e0713 100644 +--- a/src/hotspot/share/gc/g1/g1_globals.hpp ++++ b/src/hotspot/share/gc/g1/g1_globals.hpp +@@ -302,6 +302,14 @@ + "Verify the code root lists attached to each heap region.") \ + \ + develop(bool, G1VerifyBitmaps, false, \ +- "Verifies the consistency of the marking bitmaps") ++ "Verifies the consistency of the marking bitmaps") \ ++ \ ++ product(double, G1NoMovingRegionLiveBytesLowerThreshold, 98.0, \ ++ "The Lower Threshold of Heap Region Live bytes percent" \ ++ "in G1 Mark Sweep phase") \ ++ range(50.0, 100.0) \ ++ \ ++ product(bool, G1FullGCNoMoving, false, \ ++ "full gc support no moving region mode ") + + #endif // SHARE_VM_GC_G1_G1_GLOBALS_HPP +diff --git a/src/hotspot/share/gc/g1/heapRegion.cpp b/src/hotspot/share/gc/g1/heapRegion.cpp +index 85840bc6f..c81695eae 100644 +--- a/src/hotspot/share/gc/g1/heapRegion.cpp ++++ b/src/hotspot/share/gc/g1/heapRegion.cpp +@@ -243,7 +243,8 @@ HeapRegion::HeapRegion(uint hrm_index, + _surv_rate_group(NULL), _age_index(-1), + _prev_top_at_mark_start(NULL), _next_top_at_mark_start(NULL), + _recorded_rs_length(0), _predicted_elapsed_time_ms(0), +- _node_index(G1NUMA::UnknownNodeIndex) ++ _node_index(G1NUMA::UnknownNodeIndex), ++ _live_words(0) + { + _rem_set = new HeapRegionRemSet(bot, this); + +diff --git a/src/hotspot/share/gc/g1/heapRegion.hpp b/src/hotspot/share/gc/g1/heapRegion.hpp +index 12a4eb8c3..023febbfc 100644 +--- a/src/hotspot/share/gc/g1/heapRegion.hpp ++++ b/src/hotspot/share/gc/g1/heapRegion.hpp +@@ -246,7 +246,7 @@ class HeapRegion: public G1ContiguousSpace { + // in each heap region. + size_t _prev_marked_bytes; // Bytes known to be live via last completed marking. + size_t _next_marked_bytes; // Bytes known to be live via in-progress marking. +- ++ size_t _live_words; + // The calculated GC efficiency of the region. + double _gc_efficiency; + +@@ -320,6 +320,10 @@ class HeapRegion: public G1ContiguousSpace { + ~((1 << (size_t) LogOfHRGrainBytes) - 1); + } + ++ void reset_no_compaction_region_during_compaction() { ++ zero_marked_bytes(); ++ init_top_at_mark_start(); ++ } + + // Returns whether a field is in the same region as the obj it points to. + template +@@ -369,6 +373,9 @@ class HeapRegion: public G1ContiguousSpace { + + // The number of bytes marked live in the region in the last marking phase. + size_t marked_bytes() { return _prev_marked_bytes; } ++ size_t* live_words_addr() { return &_live_words; } ++ size_t live_bytes_after_mark() { return _live_words * HeapWordSize; } ++ void set_live_words_after_mark(size_t live_words) { _live_words = live_words; } + size_t live_bytes() { + return (top() - prev_top_at_mark_start()) * HeapWordSize + marked_bytes(); + } +diff --git a/src/hotspot/share/gc/g1/heapRegionManager.hpp b/src/hotspot/share/gc/g1/heapRegionManager.hpp +index 3edc1a9fb..85e6e024e 100644 +--- a/src/hotspot/share/gc/g1/heapRegionManager.hpp ++++ b/src/hotspot/share/gc/g1/heapRegionManager.hpp +@@ -29,6 +29,7 @@ + #include "gc/g1/g1NUMA.hpp" + #include "gc/g1/g1RegionToSpaceMapper.hpp" + #include "gc/g1/heapRegionSet.hpp" ++#include "gc/g1/g1RegionsOnNodes.hpp" + #include "services/memoryUsage.hpp" + + class HeapRegion; +diff --git a/src/hotspot/share/gc/g1/heapRegionSet.cpp b/src/hotspot/share/gc/g1/heapRegionSet.cpp +index eb8430ff6..322f0e32a 100644 +--- a/src/hotspot/share/gc/g1/heapRegionSet.cpp ++++ b/src/hotspot/share/gc/g1/heapRegionSet.cpp +@@ -244,21 +244,6 @@ void FreeRegionList::remove_starting_at(HeapRegion* first, uint num_regions) { + verify_optional(); + } + +-uint FreeRegionList::num_of_regions_in_range(uint start, uint end) const { +- HeapRegion* cur = _head; +- uint num = 0; +- while (cur != NULL) { +- uint index = cur->hrm_index(); +- if (index > end) { +- break; +- } else if (index >= start) { +- num++; +- } +- cur = cur->next(); +- } +- return num; +-} +- + void FreeRegionList::verify() { + // See comment in HeapRegionSetBase::verify() about MT safety and + // verification. +diff --git a/src/hotspot/share/gc/g1/heapRegionSet.hpp b/src/hotspot/share/gc/g1/heapRegionSet.hpp +index 71b89668a..2ad10acf7 100644 +--- a/src/hotspot/share/gc/g1/heapRegionSet.hpp ++++ b/src/hotspot/share/gc/g1/heapRegionSet.hpp +@@ -230,8 +230,6 @@ public: + + virtual void verify(); + +- uint num_of_regions_in_range(uint start, uint end) const; +- + using HeapRegionSetBase::length; + uint length(uint node_index) const; + }; +diff --git a/test/hotspot/jtreg/gc/g1/TestG1NoMoving.java b/test/hotspot/jtreg/gc/g1/TestG1NoMoving.java +new file mode 100644 +index 000000000..2f892773b +--- /dev/null ++++ b/test/hotspot/jtreg/gc/g1/TestG1NoMoving.java +@@ -0,0 +1,88 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co. Ltd. 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. Alibaba designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * 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. ++ */ ++ ++/* ++ * @test TestG1NoMoving ++ * @summary Test that a full gc with -XX:+G1FullGCNoMoving ++ * @key gc ++ * @requires vm.gc.G1 ++ * @library /test/lib ++ * @modules java.base/jdk.internal.misc ++ * java.management ++ * @run main/othervm TestG1NoMoving ++ */ ++ ++import java.util.regex.Matcher; ++import java.util.regex.Pattern; ++ ++import java.util.ArrayList; ++import java.util.List; ++ ++import jdk.test.lib.Platform; ++import jdk.test.lib.process.OutputAnalyzer; ++import jdk.test.lib.process.ProcessTools; ++ ++public class TestG1NoMoving { ++ public static void runTest() throws Exception { ++ final String[] arguments = { ++ "-XX:+UseG1GC", ++ "-XX:+G1FullGCNoMoving", ++ "-Xmx8m", ++ "-Xms8M", ++ "-Xlog:gc+phases=debug", ++ "-XX:G1HeapRegionSize=1m", ++ GCTest.class.getName() ++ }; ++ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(arguments); ++ OutputAnalyzer output = new OutputAnalyzer(pb.start()); ++ System.out.println(output.getStdout()); ++ ++ String pattern = ".*no moving region.*"; ++ Pattern r = Pattern.compile(pattern); ++ Matcher m = r.matcher(output.getStdout()); ++ ++ if (!m.find()) { ++ throw new RuntimeException("Could not find any no moving region output"); ++ } ++ ++ } ++ ++ public static void main(String[] args) throws Exception { ++ runTest(); ++ } ++ ++ static class GCTest { ++ public static List memory; ++ public static void main(String[] args) throws Exception { ++ memory = new ArrayList<>(); ++ try { ++ while (true) { ++ memory.add(new char[1024]); ++ System.gc(); ++ } ++ } catch (OutOfMemoryError e) { ++ memory = null; ++ System.gc(); ++ } ++ } ++ } ++} ++ +-- +2.19.0 + diff --git a/add-LazyBox-feature.patch b/add-LazyBox-feature.patch new file mode 100755 index 0000000000000000000000000000000000000000..25d293e4e98ae668ecb2b1c60f1c11b4b5adba04 --- /dev/null +++ b/add-LazyBox-feature.patch @@ -0,0 +1,1078 @@ +From 616dd14fb435476b0f9fb6696084fd71dd6ecc05 Mon Sep 17 00:00:00 2001 +Date: Tue, 16 Mar 2021 07:00:07 +0000 +Subject: [PATCH 2/4] add LazyBox feature + +--- + src/hotspot/share/opto/c2_globals.hpp | 6 + + src/hotspot/share/opto/callGenerator.cpp | 33 ++- + src/hotspot/share/opto/callnode.cpp | 18 ++ + src/hotspot/share/opto/callnode.hpp | 15 ++ + src/hotspot/share/opto/compile.cpp | 5 + + src/hotspot/share/opto/doCall.cpp | 50 +++++ + src/hotspot/share/opto/graphKit.cpp | 189 +++++++++++++++- + src/hotspot/share/opto/graphKit.hpp | 9 + + src/hotspot/share/opto/parse.hpp | 3 + + src/hotspot/share/opto/parse1.cpp | 2 +- + src/hotspot/share/opto/parse2.cpp | 25 ++- + src/hotspot/share/opto/parse3.cpp | 8 + + src/hotspot/share/opto/phase.hpp | 1 + + src/hotspot/share/opto/phaseX.cpp | 211 ++++++++++++++++++ + src/hotspot/share/opto/phaseX.hpp | 20 ++ + src/hotspot/share/opto/phasetype.hpp | 2 + + src/hotspot/share/runtime/arguments.cpp | 13 ++ + .../jvm/hotspot/opto/CompilerPhaseType.java | 1 + + .../jtreg/compiler/lazybox/TestLazyBox.java | 82 +++++++ + 19 files changed, 679 insertions(+), 14 deletions(-) + create mode 100644 test/hotspot/jtreg/compiler/lazybox/TestLazyBox.java + +diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp +index 8111a63d4..84c2817e3 100644 +--- a/src/hotspot/share/opto/c2_globals.hpp ++++ b/src/hotspot/share/opto/c2_globals.hpp +@@ -519,6 +519,12 @@ + experimental(bool, AggressiveUnboxing, false, \ + "Control optimizations for aggressive boxing elimination") \ + \ ++ experimental(bool, LazyBox, false, \ ++ "Delay some box operator to speed up some hot path without box ") \ ++ \ ++ experimental(bool, PrintLazyBox, false, \ ++ "Print LazyBox") \ ++ \ + develop(bool, TracePostallocExpand, false, "Trace expanding nodes after" \ + " register allocation.") \ + \ +diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp +index ffe50ed86..a5846537d 100644 +--- a/src/hotspot/share/opto/callGenerator.cpp ++++ b/src/hotspot/share/opto/callGenerator.cpp +@@ -150,12 +150,15 @@ JVMState* DirectCallGenerator::generate(JVMState* jvms) { + } + + CallStaticJavaNode *call = new CallStaticJavaNode(kit.C, tf(), target, method(), kit.bci()); +- if (is_inlined_method_handle_intrinsic(jvms, method())) { +- // To be able to issue a direct call and skip a call to MH.linkTo*/invokeBasic adapter, +- // additional information about the method being invoked should be attached +- // to the call site to make resolution logic work +- // (see SharedRuntime::resolve_static_call_C). +- call->set_override_symbolic_info(true); ++ // LazyBox use DirectCallGenerator insert box node with unexpected bci ++ if (!(LazyBox && method()->is_boxing_method())) { ++ if (is_inlined_method_handle_intrinsic(jvms, method())) { ++ // To be able to issue a direct call and skip a call to MH.linkTo*/invokeBasic adapter, ++ // additional information about the method being invoked should be attached ++ // to the call site to make resolution logic work ++ // (see SharedRuntime::resolve_static_call_C). ++ call->set_override_symbolic_info(true); ++ } + } + _call_node = call; // Save the call node in case we need it later + if (!is_static) { +@@ -416,7 +419,15 @@ void LateInlineCallGenerator::do_late_inline() { + + // Make enough space in the expression stack to transfer + // the incoming arguments and return value. +- map->ensure_stack(jvms, jvms->method()->max_stack()); ++ uint ensure_stack_size = jvms->method()->max_stack(); ++ if (LazyBox && call->_is_lazy_box) { ++ // Make enough space for the arg pushed in insert_box_node ++ int arg_size = jvms->method()->arg_size(); ++ if (jvms->sp() + arg_size > ensure_stack_size) { ++ ensure_stack_size = jvms->sp() + arg_size; ++ } ++ } ++ map->ensure_stack(jvms, ensure_stack_size); + for (uint i1 = 0; i1 < nargs; i1++) { + map->set_argument(jvms, i1, call->in(TypeFunc::Parms + i1)); + } +@@ -442,6 +453,14 @@ void LateInlineCallGenerator::do_late_inline() { + C->set_default_node_notes(entry_nn); + } + ++ if (LazyBox && call->_is_lazy_box) { ++ GraphKit kit(jvms); ++ Node* value = call->in(TypeFunc::Parms); ++ Node* result = kit.inline_lazy_box(call, value); ++ kit.replace_call(call, result, true); ++ return; ++ } ++ + // Now perform the inlining using the synthesized JVMState + JVMState* new_jvms = _inline_cg->generate(jvms); + if (new_jvms == NULL) return; // no change +diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp +index c4064dca0..f17eda879 100644 +--- a/src/hotspot/share/opto/callnode.cpp ++++ b/src/hotspot/share/opto/callnode.cpp +@@ -972,6 +972,10 @@ bool CallJavaNode::validate_symbolic_info() const { + if (method() == NULL) { + return true; // call into runtime or uncommon trap + } ++ if (LazyBox && this->is_CallStaticJava() && ++ this->as_CallStaticJava()->is_boxing_method()) { ++ return true; ++ } + ciMethod* symbolic_info = jvms()->method()->get_method_at_bci(_bci); + ciMethod* callee = method(); + if (symbolic_info->is_method_handle_intrinsic() && !callee->is_method_handle_intrinsic()) { +@@ -1232,6 +1236,20 @@ void SafePointNode::grow_stack(JVMState* jvms, uint grow_by) { + jvms->set_endoff(endoff + grow_by); + } + ++void SafePointNode::desc_stack(JVMState* jvms, uint desc_by) { ++ assert((int)desc_by > 0, "sanity"); ++ int monoff = jvms->monoff(); ++ int scloff = jvms->scloff(); ++ int endoff = jvms->endoff(); ++ assert(endoff == (int)req(), "no other states or debug info after me"); ++ for (uint i = 0; i < desc_by; i++) { ++ del_req_ordered(monoff - 1 - i); ++ } ++ jvms->set_monoff(monoff - desc_by); ++ jvms->set_scloff(scloff - desc_by); ++ jvms->set_endoff(endoff - desc_by); ++} ++ + void SafePointNode::push_monitor(const FastLockNode *lock) { + // Add a LockNode, which points to both the original BoxLockNode (the + // stack space for the monitor) and the Object being locked. +diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp +index cc65d9ef9..c7ea73946 100644 +--- a/src/hotspot/share/opto/callnode.hpp ++++ b/src/hotspot/share/opto/callnode.hpp +@@ -331,6 +331,7 @@ public: + : MultiNode( edges ), + _jvms(jvms), + _oop_map(NULL), ++ _fake_exception_state(false), + _adr_type(adr_type) + { + init_class_id(Class_SafePoint); +@@ -340,6 +341,7 @@ public: + JVMState* const _jvms; // Pointer to list of JVM State objects + const TypePtr* _adr_type; // What type of memory does this node produce? + ReplacedNodes _replaced_nodes; // During parsing: list of pair of nodes from calls to GraphKit::replace_in_map() ++ bool _fake_exception_state; // lazy box may produce exception + + // Many calls take *all* of memory as input, + // but some produce a limited subset of that memory as output. +@@ -398,7 +400,13 @@ public: + int grow_by = (int)stk_size - (int)jvms->stk_size(); + if (grow_by > 0) grow_stack(jvms, grow_by); + } ++ void recover_stack(JVMState* jvms, uint stk_size) { ++ assert(verify_jvms(jvms), "jvms must match"); ++ int desc_by = (int)jvms->stk_size() - (int)stk_size; ++ if (desc_by > 0) desc_stack(jvms, desc_by); ++ } + void grow_stack(JVMState* jvms, uint grow_by); ++ void desc_stack(JVMState* jvms, uint desc_by); + // Handle monitor stack + void push_monitor( const FastLockNode *lock ); + void pop_monitor (); +@@ -708,6 +716,8 @@ public: + } + _is_scalar_replaceable = false; + _is_non_escaping = false; ++ _copy_box = NULL; ++ _is_lazy_box = false; + } + CallStaticJavaNode(const TypeFunc* tf, address addr, const char* name, int bci, + const TypePtr* adr_type) +@@ -718,8 +728,13 @@ public: + _is_scalar_replaceable = false; + _is_non_escaping = false; + _name = name; ++ _copy_box = NULL; ++ _is_lazy_box = false; + } + ++ Node_List* _copy_box; ++ bool _is_lazy_box; ++ + // Result of Escape Analysis + bool _is_scalar_replaceable; + bool _is_non_escaping; +diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp +index f350f9d68..838147f53 100644 +--- a/src/hotspot/share/opto/compile.cpp ++++ b/src/hotspot/share/opto/compile.cpp +@@ -2235,6 +2235,11 @@ void Compile::Optimize() { + + print_method(PHASE_AFTER_PARSING); + ++ if (LazyBox) { ++ PhaseLazyBoxOpt plb(initial_gvn()); ++ print_method(PHASE_LAZYBOXOPT); ++ } ++ + { + // Iterative Global Value Numbering, including ideal transforms + // Initialize IterGVN with types and values from parse-time GVN +diff --git a/src/hotspot/share/opto/doCall.cpp b/src/hotspot/share/opto/doCall.cpp +index c9d06a833..343e9d00d 100644 +--- a/src/hotspot/share/opto/doCall.cpp ++++ b/src/hotspot/share/opto/doCall.cpp +@@ -416,6 +416,49 @@ static bool check_call_consistency(JVMState* jvms, CallGenerator* cg) { + } + #endif // ASSERT + ++void Parse::do_lazybox(ciMethod* callee) { ++ if (!LazyBox) return; ++ ++ // unboxing method will eliminate ++ if (callee->is_unboxing_method()) return; ++ ++ const bool is_virtual = bc() == Bytecodes::_invokevirtual; ++ const bool is_static = bc() == Bytecodes::_invokestatic; ++ const uint nargs = callee->arg_size(); ++ ++ // receiver maybe box node ++ if (is_virtual) { ++ Node* receiver_node = stack(sp() - nargs); ++ if (is_box_use_node(receiver_node)) { ++ Node* replace = insert_box_node(receiver_node); ++ set_stack(sp() - nargs, replace); ++ return; ++ } ++ } ++ ++ // args maybe box node ++ if (is_virtual || is_static) { ++ Node* use = NULL; ++ uint use_idx = -1; ++ int count = 0; ++ for (uint i = nargs; i > 0; i--) { ++ Node* arg = stack(sp() - i); ++ if (is_box_use_node(arg)) { ++ use = arg; ++ use_idx = i; ++ count++; ++ } ++ } ++ ++ // only delay one box node to use ++ if (use != NULL && count == 1) { ++ Node* replace = insert_box_node(use); ++ set_stack(sp() - use_idx, replace); ++ return; ++ } ++ } ++} ++ + //------------------------------do_call---------------------------------------- + // Handle your basic call. Inline if we can & want to, else just setup call. + void Parse::do_call() { +@@ -552,6 +595,13 @@ void Parse::do_call() { + // It decides whether inlining is desirable or not. + CallGenerator* cg = C->call_generator(callee, vtable_index, call_does_dispatch, jvms, try_inline, prof_factor(), speculative_receiver_type); + ++ if (!cg->is_inline()) { ++ inc_sp(nargs); ++ do_lazybox(orig_callee); ++ dec_sp(nargs); ++ JVMState* jvms = sync_jvms(); ++ } ++ + // NOTE: Don't use orig_callee and callee after this point! Use cg->method() instead. + orig_callee = callee = NULL; + +diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp +index 219d272ff..356bd5ccc 100644 +--- a/src/hotspot/share/opto/graphKit.cpp ++++ b/src/hotspot/share/opto/graphKit.cpp +@@ -31,6 +31,7 @@ + #include "memory/resourceArea.hpp" + #include "opto/addnode.hpp" + #include "opto/castnode.hpp" ++#include "opto/callGenerator.hpp" + #include "opto/convertnode.hpp" + #include "opto/graphKit.hpp" + #include "opto/idealKit.hpp" +@@ -317,6 +318,15 @@ JVMState* GraphKit::transfer_exceptions_into_jvms() { + return jvms; + } + ++bool GraphKit::is_box_use_node(const Node* node) { ++ return node->is_Proj() && node->in(0)->is_CallStaticJava() && ++ node->in(0)->as_CallStaticJava()->is_boxing_method(); ++} ++ ++Node* GraphKit::replace_box_use_node(Node* n, Node* replace) { ++ return is_box_use_node(n) ? replace : n; ++} ++ + static inline void add_n_reqs(Node* dstphi, Node* srcphi) { + assert(is_hidden_merge(dstphi), "must be a special merge node"); + assert(is_hidden_merge(srcphi), "must be a special merge node"); +@@ -840,6 +850,19 @@ static bool should_reexecute_implied_by_bytecode(JVMState *jvms, bool is_anewarr + return false; + } + ++// Delay boxnode to uncommon trap ++void GraphKit::add_local(SafePointNode* call, uint idx, Node* local, GrowableArray *delay_boxes) { ++ if (LazyBox && local != NULL && local->is_Proj() && ++ local->as_Proj()->_con == TypeFunc::Parms && ++ local->in(0)->is_CallStaticJava() && ++ local->in(0)->as_CallStaticJava()->is_boxing_method() && ++ call->is_CallStaticJava() && ++ call->as_CallStaticJava()->uncommon_trap_request() != 0) { ++ delay_boxes->append(idx); ++ } ++ call->set_req(idx, local); ++} ++ + // Helper function for adding JVMState and debug information to node + void GraphKit::add_safepoint_edges(SafePointNode* call, bool must_throw) { + // Add the safepoint edges to the call (or other safepoint). +@@ -847,7 +870,8 @@ void GraphKit::add_safepoint_edges(SafePointNode* call, bool must_throw) { + // Make sure dead locals are set to top. This + // should help register allocation time and cut down on the size + // of the deoptimization information. +- assert(dead_locals_are_killed(), "garbage in debug info before safepoint"); ++ // LazyBox may insert box in some bci, resulting in some dead locals not set to top ++ assert(LazyBox || dead_locals_are_killed(), "garbage in debug info before safepoint"); + + // Walk the inline list to fill in the correct set of JVMState's + // Also fill in the associated edges for each JVMState. +@@ -910,6 +934,9 @@ void GraphKit::add_safepoint_edges(SafePointNode* call, bool must_throw) { + // Fill pointer walks backwards from "young:" to "root:" in the diagram above: + uint debug_ptr = call->req(); + ++ // used boxes in uncommon_trap ++ GrowableArray *delay_boxes = new GrowableArray(); ++ + // Loop over the map input edges associated with jvms, add them + // to the call node, & reset all offsets to match call node array. + for (JVMState* in_jvms = youngest_jvms; in_jvms != NULL; ) { +@@ -938,7 +965,7 @@ void GraphKit::add_safepoint_edges(SafePointNode* call, bool must_throw) { + out_jvms->set_locoff(p); + if (!can_prune_locals) { + for (j = 0; j < l; j++) +- call->set_req(p++, in_map->in(k+j)); ++ add_local(call, p++, in_map->in(k+j), delay_boxes); + } else { + p += l; // already set to top above by add_req_batch + } +@@ -949,7 +976,7 @@ void GraphKit::add_safepoint_edges(SafePointNode* call, bool must_throw) { + out_jvms->set_stkoff(p); + if (!can_prune_locals) { + for (j = 0; j < l; j++) +- call->set_req(p++, in_map->in(k+j)); ++ add_local(call, p++, in_map->in(k+j), delay_boxes); + } else if (can_prune_locals && stack_slots_not_pruned != 0) { + // Divide stack into {S0,...,S1}, where S0 is set to top. + uint s1 = stack_slots_not_pruned; +@@ -958,7 +985,8 @@ void GraphKit::add_safepoint_edges(SafePointNode* call, bool must_throw) { + uint s0 = l - s1; + p += s0; // skip the tops preinstalled by add_req_batch + for (j = s0; j < l; j++) +- call->set_req(p++, in_map->in(k+j)); ++ add_local(call, p++, in_map->in(k+j), delay_boxes); ++ } else if (can_prune_locals && stack_slots_not_pruned != 0) { + } else { + p += l; // already set to top above by add_req_batch + } +@@ -992,6 +1020,35 @@ void GraphKit::add_safepoint_edges(SafePointNode* call, bool must_throw) { + in_jvms = in_jvms->caller(); + } + ++ // delay box node in uncommon_trap runtime, treat box as scalarized object ++ for (int index = 0; index < delay_boxes->length(); index++) { ++ assert(LazyBox, "delay boxnode to uncommon_trap need set LazyBox"); ++ assert(call->is_CallStaticJava() && ++ call->as_CallStaticJava()->uncommon_trap_request() != 0, "call node must be uncommon_trap call"); ++ uint idx = delay_boxes->at(index); ++ Node* local = call->in(idx); ++ ++ assert(local->in(0)->is_CallStaticJava(), "sanity"); ++ assert(local->in(0)->as_CallStaticJava()->is_boxing_method(), "sanity"); ++ ++ CallStaticJavaNode* box = local->in(0)->as_CallStaticJava(); ++ ciInstanceKlass* klass = box->method()->holder(); ++ int n_fields = klass->nof_nonstatic_fields(); ++ assert(n_fields == 1, "sanity"); ++ ++ uint first_ind = (call->req() - call->jvms()->scloff()); ++ Node* sobj = new SafePointScalarObjectNode(_gvn.type(local)->isa_oopptr(), ++#ifdef ASSERT ++ NULL, ++#endif // ASSERT ++ first_ind, n_fields); ++ sobj->init_req(0, C->root()); ++ call->add_req(local->in(0)->in(local->as_Proj()->_con)); ++ sobj = _gvn.transform(sobj); ++ call->jvms()->set_endoff(call->req()); ++ call->set_req(idx, sobj); ++ } ++ + assert(debug_ptr == non_debug_edges, "debug info must fit exactly"); + + // Test the correctness of JVMState::debug_xxx accessors: +@@ -4017,6 +4074,130 @@ void GraphKit::inflate_string_slow(Node* src, Node* dst, Node* start, Node* coun + set_memory(st, TypeAryPtr::BYTES); + } + ++Node* GraphKit::insert_box_node(Node* use) { ++ assert(is_box_use_node(use), "use node must be box_use_node"); ++ CallStaticJavaNode* box = use->in(0)->as_CallStaticJava(); ++ // get method from node ++ ciMethod* method = box->method(); ++ CallGenerator* parse_cg = CallGenerator::for_inline(method); ++ CallGenerator* cg = CallGenerator::for_boxing_late_inline(method, parse_cg); ++ ++ Node* arg = box->in(TypeFunc::Parms); ++ Node* res = NULL; ++ ++ { PreserveReexecuteState preexecs(this); ++ ++ int arg_size = method->arg_size(); ++ int stk_size = jvms()->stk_size(); ++ ++ assert(arg_size == 1 || arg_size == 2, "boxing method, arg size must 1 or 2!"); ++ ++ // add arg, ensure stack size ++ ensure_stack(sp() + arg_size); ++ if (arg_size == 1) { ++ push(arg); ++ } else if (arg_size == 2) { ++ push_pair(arg); ++ } ++ ++ dec_sp(arg_size); ++ JVMState* old_jvms = sync_jvms(); ++ JVMState* new_jvms = cg->generate(old_jvms); ++ assert(new_jvms != NULL, "insert box generate fail"); ++ ++ // add new box to late inline ++ CallStaticJavaNode* new_box = cg->call_node(); ++ new_box->_is_lazy_box = true; ++ ++ // Set the box objects and the reexecute bit for the interpreter to reexecute the bytecode if deoptimization happens ++ new_box->jvms()->set_should_reexecute(true); ++ ++ ciInstanceKlass* klass = box->method()->holder(); ++ int n_fields = klass->nof_nonstatic_fields(); ++ assert(n_fields == 1, "sanity"); ++ ++ uint first_ind = new_box->req() - new_box->jvms()->scloff(); ++ Node* sobj = new SafePointScalarObjectNode(_gvn.type(use)->isa_oopptr(), ++#ifdef ASSERT ++ NULL, ++#endif // ASSERT ++ first_ind, n_fields); ++ sobj->init_req(0, C->root()); ++ new_box->add_req(arg); ++ sobj = _gvn.transform(sobj); ++ new_box->jvms()->set_endoff(new_box->req()); ++ for (uint i = 0; i < new_box->req(); i++) { ++ if (new_box->in(i) == use) { ++ new_box->set_req(i, sobj); ++ } ++ } ++ ++ if (box->_copy_box == NULL) { ++ box->_copy_box = new Node_List(); ++ } ++ box->_copy_box->push(new_box); ++ ++ // inserted Box node can't throw exception to handler ++ // convert exception to uncommon_trap in inline_lazy_box ++ SafePointNode* ex_map = new_jvms->map()->next_exception(); ++ ex_map->_fake_exception_state = true; ++ add_exception_states_from(new_jvms); ++ ++ assert(new_jvms->map()->control() != top(), "generate box call node fail"); ++ assert(new_jvms->same_calls_as(old_jvms), "method/bci left unchanged"); ++ set_jvms(new_jvms); ++ res = pop(); ++ set_stack(sp(), top()); ++ recover_stack(stk_size); ++ } ++ return res; ++} ++ ++Node* GraphKit::inline_lazy_box(CallStaticJavaNode* box, Node* value) { ++ assert(box->method()->is_boxing_method(), "must be box method"); ++ ciInstanceKlass* klass = box->method()->holder(); ++ ++ BasicType type = klass->box_klass_type(); ++ ++ if (type == T_BOOLEAN) { ++ // value ? TRUE : FALSE ++ ciSymbol* java_lang_Boolean = ciSymbol::make("Ljava/lang/Boolean;"); ++ ciField* true_field = klass->get_field_by_name(ciSymbol::make("TRUE"), java_lang_Boolean, true); ++ ciField* false_field = klass->get_field_by_name(ciSymbol::make("FALSE"), java_lang_Boolean, true); ++ const TypeInstPtr* tip = TypeInstPtr::make(klass->java_mirror()); ++ Node* java_mirror = _gvn.makecon(tip); ++ Node* true_node = make_constant_from_field(true_field, java_mirror); ++ Node* false_node = make_constant_from_field(false_field, java_mirror); ++ ++ Node* tst = gvn().transform(Bool(CmpI(value, intcon(0)), BoolTest::ne)); ++ IfNode* iff = create_and_map_if(control(), tst, PROB_FAIR, COUNT_UNKNOWN); ++ Node* true_proj = IfTrue(iff); ++ Node* false_proj = IfFalse(iff); ++ RegionNode* region = new RegionNode(3); ++ gvn().set_type(region, Type::CONTROL); ++ region->init_req(1, true_proj); ++ region->init_req(2, false_proj); ++ Node *obj = new PhiNode(region, TypeOopPtr::make_from_klass(klass)); ++ gvn().set_type(obj, obj->bottom_type()); ++ obj->init_req(1, true_node); ++ obj->init_req(2, false_node); ++ set_control(region); ++ return obj; ++ } ++ ++ Node* kls = makecon(TypeKlassPtr::make(klass)); ++ Node* obj = new_instance(kls, NULL, NULL, true); ++ const BasicType primitive_type = klass->box_klass_type(); ++ int value_offset = java_lang_boxing_object::value_offset_in_bytes(primitive_type); ++ const TypeInstPtr* box_type = TypeInstPtr::make(TypePtr::NotNull, klass, ++ false, NULL, 0); ++ const TypePtr* value_field_type = box_type->add_offset(value_offset); ++ const Type *value_type = Type::get_const_basic_type(primitive_type); ++ access_store_at(control(), obj, basic_plus_adr(obj, value_offset), value_field_type, ++ value, value_type, primitive_type, IN_HEAP); ++ return obj; ++} ++ + Node* GraphKit::make_constant_from_field(ciField* field, Node* obj) { + if (!field->is_constant()) { + return NULL; // Field not marked as constant. +diff --git a/src/hotspot/share/opto/graphKit.hpp b/src/hotspot/share/opto/graphKit.hpp +index ef3f784d3..2d5aac53c 100644 +--- a/src/hotspot/share/opto/graphKit.hpp ++++ b/src/hotspot/share/opto/graphKit.hpp +@@ -276,6 +276,8 @@ class GraphKit : public Phase { + #ifdef ASSERT + bool dead_locals_are_killed(); + #endif ++ void add_local(SafePointNode* call, uint idx, Node* local, GrowableArray *delay_boxes); ++ + // The call may deoptimize. Supply required JVM state as debug info. + // If must_throw is true, the call is guaranteed not to return normally. + void add_safepoint_edges(SafePointNode* call, +@@ -478,6 +480,7 @@ class GraphKit : public Phase { + void set_stack(uint idx, Node* c) { map_not_null(); _map->set_stack( _map->_jvms, idx, c); } + void set_argument(uint idx, Node* c){ map_not_null(); _map->set_argument(_map->_jvms, idx, c); } + void ensure_stack(uint stk_size) { map_not_null(); _map->ensure_stack(_map->_jvms, stk_size); } ++ void recover_stack(uint stk_size) { map_not_null(); _map->recover_stack(_map->_jvms, stk_size); } + + // Access unaliased memory + Node* memory(uint alias_idx); +@@ -863,6 +866,12 @@ class GraphKit : public Phase { + void inflate_string(Node* src, Node* dst, const TypeAryPtr* dst_type, Node* count); + void inflate_string_slow(Node* src, Node* dst, Node* start, Node* count); + ++ // lazy box helpers ++ static bool is_box_use_node(const Node* node); ++ static Node* replace_box_use_node(Node* n, Node* replace); ++ Node* insert_box_node(Node* use); ++ Node* inline_lazy_box(CallStaticJavaNode* box, Node* value); ++ + // Handy for making control flow + IfNode* create_and_map_if(Node* ctrl, Node* tst, float prob, float cnt) { + IfNode* iff = new IfNode(ctrl, tst, prob, cnt);// New IfNode's +diff --git a/src/hotspot/share/opto/parse.hpp b/src/hotspot/share/opto/parse.hpp +index aa13e8863..b16671ace 100644 +--- a/src/hotspot/share/opto/parse.hpp ++++ b/src/hotspot/share/opto/parse.hpp +@@ -498,6 +498,9 @@ class Parse : public GraphKit { + + // Note: Intrinsic generation routines may be found in library_call.cpp. + ++ // Helper function to do lazy box in do_call() ++ void do_lazybox(ciMethod* callee); ++ + // Helper function to setup Ideal Call nodes + void do_call(); + +diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp +index f94f028c6..48f111d76 100644 +--- a/src/hotspot/share/opto/parse1.cpp ++++ b/src/hotspot/share/opto/parse1.cpp +@@ -918,7 +918,7 @@ void Parse::do_exceptions() { + + SafePointNode* ex_map; + while ((ex_map = pop_exception_state()) != NULL) { +- if (!method()->has_exception_handlers()) { ++ if (!method()->has_exception_handlers() || ex_map->_fake_exception_state) { + // Common case: Transfer control outward. + // Doing it this early allows the exceptions to common up + // even between adjacent method calls. +diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp +index 2b21881bc..78e83afa5 100644 +--- a/src/hotspot/share/opto/parse2.cpp ++++ b/src/hotspot/share/opto/parse2.cpp +@@ -2660,9 +2660,17 @@ void Parse::do_one_bytecode() { + case Bytecodes::_return: + return_current(NULL); + break; +- +- case Bytecodes::_ireturn: + case Bytecodes::_areturn: ++ a = pop(); ++ if (LazyBox && is_box_use_node(a)) { ++ push(a); ++ b = insert_box_node(a); ++ a = replace_box_use_node(a, b); ++ pop(); ++ } ++ return_current(a); ++ break; ++ case Bytecodes::_ireturn: + case Bytecodes::_freturn: + return_current(pop()); + break; +@@ -2749,6 +2757,19 @@ void Parse::do_one_bytecode() { + maybe_add_safepoint(iter().get_dest()); + a = pop(); + b = pop(); ++ ++ //one of node is box use node, insert box node and replace ++ if (LazyBox && (is_box_use_node(a) ^ is_box_use_node(b))) { ++ push(b); ++ push(a); ++ Node* use = is_box_use_node(a) ? a : b; ++ Node* replace = insert_box_node(use); ++ a = replace_box_use_node(a, replace); ++ b = replace_box_use_node(b, replace); ++ pop(); ++ pop(); ++ } ++ + c = _gvn.transform( new CmpPNode(b, a) ); + c = optimize_cmp_with_klass(c); + do_if(btest, c); +diff --git a/src/hotspot/share/opto/parse3.cpp b/src/hotspot/share/opto/parse3.cpp +index bb4d13002..0b9b14966 100644 +--- a/src/hotspot/share/opto/parse3.cpp ++++ b/src/hotspot/share/opto/parse3.cpp +@@ -244,6 +244,14 @@ void Parse::do_put_xxx(Node* obj, ciField* field, bool is_field) { + // Value to be stored + Node* val = type2size[bt] == 1 ? pop() : pop_pair(); + ++ if (LazyBox && is_box_use_node(val)) { ++ // oop size is 1 ++ push(val); ++ Node* replace = insert_box_node(val); ++ val = replace_box_use_node(val, replace); ++ pop(); ++ } ++ + DecoratorSet decorators = IN_HEAP; + decorators |= is_vol ? MO_SEQ_CST : MO_UNORDERED; + +diff --git a/src/hotspot/share/opto/phase.hpp b/src/hotspot/share/opto/phase.hpp +index 4b0c53ffc..38683f8a7 100644 +--- a/src/hotspot/share/opto/phase.hpp ++++ b/src/hotspot/share/opto/phase.hpp +@@ -59,6 +59,7 @@ public: + Ideal_Loop, // Find idealized trip-counted loops + Macro_Expand, // Expand macro nodes + Peephole, // Apply peephole optimizations ++ LazyBoxOpt, // Apply LazyBox optimization + last_phase + }; + +diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp +index f4a38cd28..c2060e445 100644 +--- a/src/hotspot/share/opto/phaseX.cpp ++++ b/src/hotspot/share/opto/phaseX.cpp +@@ -407,6 +407,217 @@ void NodeHash::operator=(const NodeHash& nh) { + + #endif + ++//============================================================================= ++//------------------------------PhaseLazyBoxOpt------------------------------ ++// Phase that first collecting all the box nodes, if use nodes of a box node are ++// all SafePointNode or it's subclass and the usage is not monitor, scalar and args, then eliminate the box node. ++// else, eliminate the related inserted box node. ++PhaseLazyBoxOpt::PhaseLazyBoxOpt(PhaseGVN *gvn, PhaseNumber phase_num) ++ : Phase(phase_num), ++ _gvn(gvn) { ++ if (PrintLazyBox) { ++ tty->print("LazyBoxOpt for method: %s.%s\n", C->method()->holder()->name()->as_utf8(), C->method()->name()->as_utf8()); ++ } ++ Node_List box_nodes = collect_box_nodes(); ++ for (uint i = 0; i < box_nodes.size(); i++) { ++ CallStaticJavaNode* box_node = (CallStaticJavaNode*)box_nodes[i]; ++ if (is_eliminatable(box_node)) { ++ // delete origin box node ++ if (PrintLazyBox) { ++ tty->print("delete origin box node %d\n", box_node->_idx); ++ } ++ ++ // if copy box not used, remove it ++ if (box_node->_copy_box != NULL) { ++ for (uint j = 0; j < box_node->_copy_box->size(); j++) { ++ CallStaticJavaNode* n = (CallStaticJavaNode*)box_node->_copy_box->at(j); ++ Node* resproj = n->proj_out_or_null(TypeFunc::Parms); ++ if (resproj == NULL) { ++ eliminate_call(n); ++ } ++ } ++ } ++ ++ eliminate_call(box_node); ++ } else if (box_node->_copy_box != NULL) { ++ // delete copy box node ++ if (PrintLazyBox) { ++ tty->print("delete copy box node for box node %d \n", box_node->_idx); ++ } ++ Node* origin_resproj = box_node->proj_out_or_null(TypeFunc::Parms); ++ ++ for (uint j = 0; j < box_node->_copy_box->size(); j++) { ++ CallStaticJavaNode* n = (CallStaticJavaNode*)box_node->_copy_box->at(j); ++ if (PrintLazyBox) { ++ tty->print(" delete copy box node %d\n", n->_idx); ++ } ++ // replace the copy box node resproj by original box node resproj ++ Node* copy_resproj = n->proj_out_or_null(TypeFunc::Parms); ++ ++ if (copy_resproj != NULL) { ++ C->gvn_replace_by(copy_resproj, origin_resproj); ++ } ++ eliminate_call(n); ++ } ++ } ++ } ++ ++ if (C->failing()) return; ++ { ++ ResourceMark rm; ++ PhaseRemoveUseless pru(C->initial_gvn(), C->for_igvn()); ++ } ++} ++ ++Node_List PhaseLazyBoxOpt::collect_box_nodes() { ++ Node_List box_nodes; ++ ++ Node* start_node = C->start(); ++ Node* framptr_node = start_node->raw_out(TypeFunc::FramePtr + 1); ++ ++ for (DUIterator_Fast imax, i = framptr_node->fast_outs(imax); i < imax; i++) { ++ Node* m = framptr_node->fast_out(i); ++ if (m->is_CallStaticJava()) { ++ ciMethod* method = m->as_CallStaticJava()->method(); ++ if (method != NULL && method->is_boxing_method() && m->as_CallStaticJava()->_is_lazy_box == false) { ++ box_nodes.push(m); ++ } ++ } ++ } ++ return box_nodes; ++} ++ ++// determine if a box node is eliminatable ++bool PhaseLazyBoxOpt::is_eliminatable(CallStaticJavaNode* box_node) { ++ assert(!box_node->_is_lazy_box, "must orgin box node"); ++ ++ Node* resproj = box_node->proj_out_or_null(TypeFunc::Parms); ++ if (resproj == NULL) { ++ return true; ++ } ++ ++ for (DUIterator_Fast imax, i = resproj->fast_outs(imax); i < imax; i++) { ++ Node* res = resproj; ++ Node* use_node = res->fast_out(i); ++ if (use_node->is_SafePoint()) { ++ int arg_end = 0; ++ JVMState* youngest_jvms = use_node->jvms(); ++ for (JVMState* jvms = youngest_jvms; jvms != NULL; ) { ++ arg_end = jvms->locoff(); ++ ++ int k, l; ++ // if origin box node is used only in SafePoint's stack and local, so it's not used actually ++ // check local, just check ++ k = jvms->locoff(); ++ l = jvms->loc_size(); ++ for (int j = 0; j < l; j++){ ++ if (use_node->in(k+j) == res) { ++#ifndef PRODUCT ++ if (PrintLazyBox) { ++ tty->print("use node is safepoint, check local!\n"); ++ use_node->dump(0); ++ } ++#endif ++ } ++ } ++ ++ // check stack, just check ++ k = jvms->stkoff(); ++ l = jvms->sp(); ++ for (int j = 0; j < l; j++) { ++ if (use_node->in(k+j) == res) { ++#ifndef PRODUCT ++ if (PrintLazyBox) { ++ tty->print("use node is safepoint, check stack!\n"); ++ use_node->dump(0); ++ } ++#endif ++ } ++ } ++ // check monitor ++ k = jvms->monoff(); ++ l = jvms->mon_size(); ++ for (int j = 0; j < l; j++) { ++ if (use_node->in(k+j) == res) { ++#ifndef PRODUCT ++ if (PrintLazyBox) { ++ tty->print("use node is safepoint, check monitor false!\n"); ++ use_node->dump(0); ++ } ++#endif ++ return false; ++ } ++ } ++ // check scalar ++ k = jvms->scloff(); ++ l = jvms->scl_size(); ++ for (int j = 0; j < l; j++) { ++ if (use_node->in(k+j) == res) { ++#ifndef PRODUCT ++ if (PrintLazyBox) { ++ tty->print("use node is safepoint, check scalar false!\n"); ++ use_node->dump(0); ++ } ++#endif ++ return false; ++ } ++ } ++ jvms = jvms->caller(); ++ } ++ ++ if (use_node->is_CallJava()) { ++ for (int i = TypeFunc::Parms; i < arg_end; i++) { ++ if(use_node->in(i) == res) { ++#ifndef PRODUCT ++ if (PrintLazyBox) { ++ tty->print("use node is CallJava, check args false!\n"); ++ use_node->dump(0); ++ } ++#endif ++ return false; ++ } ++ } ++ } ++ ++ } else { ++#ifndef PRODUCT ++ if (PrintLazyBox) { ++ tty->print("use node %s can't do lazybox!\n", use_node->Name()); ++ use_node->dump(0); ++ } ++#endif ++ return false; ++ } ++ } ++ return true; ++} ++ ++void PhaseLazyBoxOpt::eliminate_call(CallNode* call) { ++ CallProjections projs; ++ call->extract_projections(&projs, false); ++ if (projs.fallthrough_catchproj != NULL) { ++ C->gvn_replace_by(projs.fallthrough_catchproj, call->in(TypeFunc::Control)); ++ } ++ if (projs.fallthrough_memproj != NULL) { ++ C->gvn_replace_by(projs.fallthrough_memproj, call->in(TypeFunc::Memory)); ++ } ++ if (projs.catchall_memproj != NULL) { ++ C->gvn_replace_by(projs.catchall_memproj, C->top()); ++ } ++ if (projs.fallthrough_ioproj != NULL) { ++ C->gvn_replace_by(projs.fallthrough_ioproj, call->in(TypeFunc::I_O)); ++ } ++ if (projs.catchall_ioproj != NULL) { ++ C->gvn_replace_by(projs.catchall_ioproj, C->top()); ++ } ++ if (projs.catchall_catchproj != NULL) { ++ C->gvn_replace_by(projs.catchall_catchproj, C->top()); ++ } ++ if (projs.resproj != NULL) { ++ C->gvn_replace_by(projs.resproj, C->top()); ++ } ++ C->gvn_replace_by(call, C->top()); ++} + + //============================================================================= + //------------------------------PhaseRemoveUseless----------------------------- +diff --git a/src/hotspot/share/opto/phaseX.hpp b/src/hotspot/share/opto/phaseX.hpp +index ef5eb488e..915884b33 100644 +--- a/src/hotspot/share/opto/phaseX.hpp ++++ b/src/hotspot/share/opto/phaseX.hpp +@@ -173,6 +173,26 @@ public: + PhaseNumber phase_num = Remove_Useless_And_Renumber_Live); + }; + ++//------------------------------PhaseLazyBoxOpt------------------------------ ++// Phase that first collecting all the box nodes, if use nodes of a box node are ++// all SafePointNode or it's subclass and the usage is not monitor, scalar and args, then eliminate the box node. ++// else, eliminate the related inserted box node. ++class PhaseLazyBoxOpt : public Phase { ++private: ++ PhaseGVN* _gvn; ++ ++public: ++ PhaseLazyBoxOpt(PhaseGVN *gvn, PhaseNumber phase_num = LazyBoxOpt); ++ ++ // collecting a list of box nodes ++ Node_List collect_box_nodes(); ++ ++ // determine if a box node is eliminatable ++ bool is_eliminatable(CallStaticJavaNode* box_node); ++ ++ void eliminate_call(CallNode* call); ++}; ++ + + //------------------------------PhaseTransform--------------------------------- + // Phases that analyze, then transform. Constructing the Phase object does any +diff --git a/src/hotspot/share/opto/phasetype.hpp b/src/hotspot/share/opto/phasetype.hpp +index 100db1773..7e57cfb07 100644 +--- a/src/hotspot/share/opto/phasetype.hpp ++++ b/src/hotspot/share/opto/phasetype.hpp +@@ -30,6 +30,7 @@ enum CompilerPhaseType { + PHASE_AFTER_STRINGOPTS, + PHASE_BEFORE_REMOVEUSELESS, + PHASE_AFTER_PARSING, ++ PHASE_LAZYBOXOPT, + PHASE_ITER_GVN1, + PHASE_PHASEIDEAL_BEFORE_EA, + PHASE_ITER_GVN_AFTER_EA, +@@ -73,6 +74,7 @@ class CompilerPhaseTypeHelper { + case PHASE_AFTER_STRINGOPTS: return "After StringOpts"; + case PHASE_BEFORE_REMOVEUSELESS: return "Before RemoveUseless"; + case PHASE_AFTER_PARSING: return "After Parsing"; ++ case PHASE_LAZYBOXOPT: return "After LazyBoxOpt"; + case PHASE_ITER_GVN1: return "Iter GVN 1"; + case PHASE_PHASEIDEAL_BEFORE_EA: return "PhaseIdealLoop before EA"; + case PHASE_ITER_GVN_AFTER_EA: return "Iter GVN after EA"; +diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp +index 3e7d48ad5..baf221ec4 100644 +--- a/src/hotspot/share/runtime/arguments.cpp ++++ b/src/hotspot/share/runtime/arguments.cpp +@@ -1969,6 +1969,19 @@ jint Arguments::set_aggressive_opts_flags() { + AggressiveUnboxing = false; + } + } ++ ++ // LazyBox need set AggressiveUnboxing ++ if (LazyBox) { ++ if (!AggressiveUnboxing || UseAOT || EnableJVMCI) { ++ warning("LazyBox is disable because AggressiveUnboxing is disabled or UseAOT/EnableJVMCI is enable"); ++ LazyBox = false; ++ } ++ } ++ ++ if (PrintLazyBox) { ++ PrintLazyBox = LazyBox; ++ } ++ + if (AggressiveOpts || !FLAG_IS_DEFAULT(AutoBoxCacheMax)) { + if (FLAG_IS_DEFAULT(EliminateAutoBox)) { + FLAG_SET_DEFAULT(EliminateAutoBox, true); +diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CompilerPhaseType.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CompilerPhaseType.java +index e0eb10942..0478c56d9 100644 +--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CompilerPhaseType.java ++++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CompilerPhaseType.java +@@ -30,6 +30,7 @@ public enum CompilerPhaseType { + PHASE_BEFORE_STRINGOPTS ("Before StringOpts"), + PHASE_AFTER_STRINGOPTS ("After StringOpts"), + PHASE_BEFORE_REMOVEUSELESS ("Before RemoveUseless"), ++ PHASE_LAZYBOXOPT ("After LazyBoxOpt"), + PHASE_AFTER_PARSING ("After Parsing"), + PHASE_ITER_GVN1 ("Iter GVN 1"), + PHASE_PHASEIDEAL_BEFORE_EA ("PhaseIdealLoop before EA"), +diff --git a/test/hotspot/jtreg/compiler/lazybox/TestLazyBox.java b/test/hotspot/jtreg/compiler/lazybox/TestLazyBox.java +new file mode 100644 +index 000000000..4d9a72db2 +--- /dev/null ++++ b/test/hotspot/jtreg/compiler/lazybox/TestLazyBox.java +@@ -0,0 +1,82 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co. Ltd. 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 ++ * @summary Test whether LazyBox works ++ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+LazyBox ++ * -XX:+AggressiveUnboxing ++ * -XX:CompileCommand=dontinline,compiler/lazybox/TestLazyBox.foo ++ * -XX:CompileCommand=dontinline,compiler/lazybox/TestLazyBox.black ++ * -Xcomp -XX:-TieredCompilation ++ * compiler.lazybox.TestLazyBox ++ */ ++ ++package compiler.lazybox; ++ ++class Wrap { ++ public Object field; ++} ++ ++public class TestLazyBox { ++ public static Integer base = null; ++ ++ public static void main(String[] args) throws Exception{ ++ for(int i = 0; i < 10; i++) { ++ Integer IntObj2 = Integer.valueOf(i); ++ foo(IntObj2); ++ } ++ System.out.println("Passed"); ++ } ++ ++ public static void foo(Integer IntObj2) throws Exception { ++ ++ Integer IntObj = Integer.valueOf(299); ++ base = IntObj; ++ try{ ++ black(IntObj); ++ ++ if (IntObj == IntObj2) { ++ black(IntObj); ++ } ++ ++ if (IntObj.equals(IntObj2)) { ++ black(IntObj); ++ } ++ ++ Wrap wrap = new Wrap(); ++ wrap.field = IntObj; ++ ++ black(wrap.field); ++ } catch(Exception e) { ++ e.printStackTrace(); ++ } ++ } ++ ++ public static void black(Object i) { ++ if (base == i) { ++ System.err.println("Failed tests."); ++ throw new InternalError(); ++ } ++ } ++} +-- +2.19.0 + diff --git a/add-SVE-backend-feature.patch b/add-SVE-backend-feature.patch index 6ef41c32bbcc20adc2c70dde430fe9432fd4e25b..ebd505523f9edbfefd1b51b5cb7ce4d3837c12da 100755 --- a/add-SVE-backend-feature.patch +++ b/add-SVE-backend-feature.patch @@ -12,9 +12,9 @@ index bb9721c8e..3774dd730 100644 + ))) + endif + - ifeq ($(call check-jvm-feature, shenandoahgc), true) + ifeq ($(call check-jvm-feature, zgc), true) AD_SRC_FILES += $(call uniq, $(wildcard $(foreach d, $(AD_SRC_ROOTS), \ - $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/shenandoah/shenandoah_$(HOTSPOT_TARGET_CPU).ad \ + $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/z/z_$(HOTSPOT_TARGET_CPU).ad \ diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 617b2b8fb..eab0101b0 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad diff --git a/downgrade-the-symver-of-log2f-posix-spawn.patch b/downgrade-the-symver-of-log2f-posix-spawn.patch new file mode 100755 index 0000000000000000000000000000000000000000..70d410b0a7bce896c0f9e73a2846f03cea6b5b95 --- /dev/null +++ b/downgrade-the-symver-of-log2f-posix-spawn.patch @@ -0,0 +1,46 @@ +From f9a030a58fcae2352e1b4a629901b6047c2f6610 Mon Sep 17 00:00:00 2001 +Date: Thu, 18 Mar 2021 12:34:06 +0000 +Subject: [PATCH 1/4] downgrade the symver of log2f posix spawn + +--- + src/hotspot/share/opto/parse2.cpp | 8 ++++++++ + src/java.base/unix/native/libjava/ProcessImpl_md.c | 4 ++++ + 2 files changed, 12 insertions(+) + +diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp +index 4cbc57eb8..2b21881bc 100644 +--- a/src/hotspot/share/opto/parse2.cpp ++++ b/src/hotspot/share/opto/parse2.cpp +@@ -45,6 +45,14 @@ + #include "runtime/deoptimization.hpp" + #include "runtime/sharedRuntime.hpp" + ++#ifdef AARCH64 ++ __asm__(".symver log2f,log2f@GLIBC_2.17"); ++#endif ++ ++#ifdef AMD64 ++ __asm__(".symver log2f,log2f@GLIBC_2.2.5"); ++#endif ++ + #ifndef PRODUCT + extern int explicit_null_checks_inserted, + explicit_null_checks_elided; +diff --git a/src/java.base/unix/native/libjava/ProcessImpl_md.c b/src/java.base/unix/native/libjava/ProcessImpl_md.c +index d0c2543ce..09d71b874 100644 +--- a/src/java.base/unix/native/libjava/ProcessImpl_md.c ++++ b/src/java.base/unix/native/libjava/ProcessImpl_md.c +@@ -48,6 +48,10 @@ + + #include "childproc.h" + ++#if defined(amd64) ++ __asm__(".symver posix_spawn,posix_spawn@GLIBC_2.2.5"); ++#endif ++ + /* + * There are 4 possible strategies we might use to "fork": + * +-- +2.19.0 + diff --git a/java-11-openjdk.spec b/java-11-openjdk.spec index 936ad972f3a4f38e38757a80105c70e3a7b18739..cbcb76d8045303a193cf974a47c8d211c13c7a4b 100644 --- a/java-11-openjdk.spec +++ b/java-11-openjdk.spec @@ -114,7 +114,7 @@ # New Version-String scheme-style defines %global majorver 11 -%global securityver 9 +%global securityver 10 # buildjdkver is usually same as %%{majorver}, # but in time of bootstrap of next jdk, it is majorver-1, # and this it is better to change it here, on single place @@ -130,16 +130,21 @@ %global origin_nice OpenJDK %global top_level_dir_name %{origin} %global minorver 0 -%global buildver 11 +%global buildver 9 +%global patchver 0 %global project jdk-updates %global repo jdk11u -%global revision jdk-11.0.9-ga +%global revision jdk-11.0.10-ga %global full_revision %{project}-%{repo}-%{revision} # priority must be 7 digits in total # setting to 1, so debug ones can have 0 %global priority 00000%{minorver}1 +%if %{patchver} +%global newjavaver %{majorver}.%{minorver}.%{securityver}.%{patchver} +%else %global newjavaver %{majorver}.%{minorver}.%{securityver} +%endif %global javaver %{majorver} @@ -735,7 +740,7 @@ Provides: java-src%{?1} = %{epoch}:%{version}-%{release} Name: java-%{javaver}-%{origin} Version: %{newjavaver}.%{buildver} -Release: 10 +Release: 6 # java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons # and this change was brought into RHEL-4. java-1.5.0-ibm packages # also included the epoch in their virtual provides. This created a @@ -823,7 +828,6 @@ Patch37: fix-compile-error-without-disable-precompiled-headers.patch Patch38: fast-serializer-jdk11.patch Patch39: fix-jck-failure-on-FastSerializer.patch Patch40: 8223667-ASAN-build-broken.patch -Patch41: 8229495-SIGILL-in-C2-generated-OSR-compilation.patch Patch42: 8229496-SIGFPE-division-by-zero-in-C2-OSR-compiled-method.patch Patch43: 8243670-Unexpected-test-result-caused-by-C2-MergeMem.patch Patch45: leaf-optimize-in-ParallelScanvageGC.patch @@ -834,9 +838,6 @@ Patch49: 8237483-AArch64-C1-OopMap-inserted-twice-fatal-error.patch Patch50: 8248336-AArch64-C2-offset-overflow-in-BoxLockNode-em.patch # 11.0.9 -Patch51: 8255781-Bump-patch-update-version-for-OpenJDK-jdk-11.0.9.1.patch -Patch52: 8250861-Crash-in-MinINode-Ideal.patch -Patch53: 8236512-PKCS11-Connection-closed-after-Cipher-doFinal-and-NoPadding.patch Patch54: 8207160-ClassReader-adjustMethodParams-can-potentially-return-null-if-the-args-list-is-empty.patch Patch55: 8215047-Task-terminators-do-not-complete-termination-in-consistent-state.patch Patch56: 8247766-aarch64-guarantee-val-1U--nbits-failed-Field-too-big-for-insn.patch @@ -844,6 +845,16 @@ Patch57: add-zgc-parameter-adaptation-feature.patch Patch58: add-integerCache-feature.patch Patch59: add-SVE-backend-feature.patch +#11.0.10 +Patch60: 8240353.patch +Patch61: downgrade-the-symver-of-log2f-posix-spawn.patch +Patch62: 8254078-DataOutputStream-is-very-slow-post-disabling.patch +Patch63: 8217918-C2-XX-AggressiveUnboxing-is-broken.patch +Patch64: Fix-the-memcpy-symbol-issue-during-JDK11-x64-build.patch +Patch65: add-LazyBox-feature.patch +Patch66: add-G1-Full-GC-optimization.patch +Patch67: 8214535-support-Jmap-parallel.patch + BuildRequires: autoconf BuildRequires: alsa-lib-devel BuildRequires: binutils @@ -856,6 +867,7 @@ BuildRequires: freetype-devel BuildRequires: giflib-devel BuildRequires: gcc-c++ BuildRequires: gdb +BuildRequires: harfbuzz-devel BuildRequires: lcms2-devel BuildRequires: libjpeg-devel BuildRequires: libpng-devel @@ -1097,7 +1109,6 @@ pushd %{top_level_dir_name} %patch38 -p1 %patch39 -p1 %patch40 -p1 -%patch41 -p1 %patch42 -p1 %patch43 -p1 %patch45 -p1 @@ -1106,15 +1117,20 @@ pushd %{top_level_dir_name} %patch48 -p1 %patch49 -p1 %patch50 -p1 -%patch51 -p1 -%patch52 -p1 -%patch53 -p1 %patch54 -p1 %patch55 -p1 %patch56 -p1 %patch57 -p1 %patch58 -p1 %patch59 -p1 +%patch60 -p1 +%patch61 -p1 +%patch62 -p1 +%patch63 -p1 +%patch64 -p1 +%patch65 -p1 +%patch66 -p1 +%patch67 -p1 popd # openjdk %patch1000 @@ -1219,6 +1235,7 @@ bash ../configure \ --with-giflib=system \ --with-libpng=system \ --with-lcms=system \ + --with-harfbuzz=system \ --with-stdc++lib=dynamic \ --with-extra-cxxflags="$EXTRA_CPP_FLAGS" \ --with-extra-cflags="$EXTRA_CFLAGS" \ @@ -1408,7 +1425,7 @@ if ! echo $suffix | grep -q "debug" ; then # Install Javadoc documentation install -d -m 755 $RPM_BUILD_ROOT%{_javadocdir} cp -a %{buildoutputdir -- $suffix}/images/docs $RPM_BUILD_ROOT%{_javadocdir}/%{uniquejavadocdir -- $suffix} - cp -a %{buildoutputdir -- $suffix}/bundles/jdk-%{newjavaver}.1+%{buildver}-docs.zip $RPM_BUILD_ROOT%{_javadocdir}/%{uniquejavadocdir -- $suffix}.zip + cp -a %{buildoutputdir -- $suffix}/bundles/jdk-%{newjavaver}+%{buildver}-docs.zip $RPM_BUILD_ROOT%{_javadocdir}/%{uniquejavadocdir -- $suffix}.zip fi # Install icons and menu entries @@ -1617,6 +1634,31 @@ require "copy_jdk_configs.lua" %changelog +* Fri Mar 19 2021 aijm - 1:11.0.10.9-6 +- add 8214535-support-Jmap-parallel.patch + +* Fri Mar 19 2021 aijm - 1:11.0.10.9-5 +- add add-G1-Full-GC-optimization.patch + +* Fri Mar 19 2021 kuenking111 - 1:11.0.10.9-4 +- add add-LazyBox-feature.patch + +* Fri Mar 19 2021 aijm - 1:11.0.10.9-3 +- add downgrade-the-symver-of-log2f-posix-spawn.patch +- add 8254078-DataOutputStream-is-very-slow-post-disabling.patch +- add 8217918-C2-XX-AggressiveUnboxing-is-broken.patch +- add Fix-the-memcpy-symbol-issue-during-JDK11-x64-build.patch + +* Sun Feb 7 2021 jdkboy - 1:11.0.10.9-2 +- remove redundant file info + +* Thu Feb 5 2021 eapen - 1:11.0.10.9-1 +- add 8240353.patch + +* Thu Feb 5 2021 eapen - 1:11.0.10.9-0 +- update to 11.0.10+9(GA) +- use system harfbuzz now this is supported + * Thu Dec 24 2020 kuenking - 1:11.0.9.11-10 - add add-SVE-backend-feature.patch diff --git a/jdk-updates-jdk11u-jdk-11.0.9-ga.tar.xz b/jdk-updates-jdk11u-jdk-11.0.10-ga.tar.xz similarity index 76% rename from jdk-updates-jdk11u-jdk-11.0.9-ga.tar.xz rename to jdk-updates-jdk11u-jdk-11.0.10-ga.tar.xz index e388d6935d7b15b3af95abf66b1bd2b5779978bb..baafed89f233fe8379526945e66e406f2afad321 100644 Binary files a/jdk-updates-jdk11u-jdk-11.0.9-ga.tar.xz and b/jdk-updates-jdk11u-jdk-11.0.10-ga.tar.xz differ diff --git a/update_package.sh b/update_package.sh index e381ba12f481007667be2a320239c82dddc8a2e8..d39c42731825f40086f780a4efab9c9d89555325 100644 --- a/update_package.sh +++ b/update_package.sh @@ -7,7 +7,7 @@ set -e export PROJECT_NAME="jdk-updates" export REPO_NAME="jdk11u" # warning, clonning without shenadnaoh prefix, you will clone pure jdk - thus without shenandaoh GC -export VERSION="jdk-11.0.8-ga" +export VERSION="jdk-11.0.10-ga" export COMPRESSION=xz # unset tapsets overrides export OPENJDK_URL=""