& external_addresses) {
#define ADD(addr) external_addresses.append((address)(addr));
ADD(round_constsAddr());
- ADD(permsAndRotsAddr());
+ ADD(avx2_round_constsAddr());
+ ADD(avx2_rotate_constsAddr());
#undef ADD
}
#endif // INCLUDE_CDS
diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp
index efb282ce3f2..4cdcb1770bb 100644
--- a/src/hotspot/cpu/x86/vm_version_x86.cpp
+++ b/src/hotspot/cpu/x86/vm_version_x86.cpp
@@ -1323,7 +1323,8 @@ void VM_Version::get_processor_features() {
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
}
- if (UseSHA && supports_evex() && supports_avx512bw()) {
+ if (UseSHA && ((supports_evex() && supports_avx512vlbw()) ||
+ (EnableX86ECoreOpts && !supports_hybrid()))) {
if (FLAG_IS_DEFAULT(UseSHA3Intrinsics)) {
FLAG_SET_DEFAULT(UseSHA3Intrinsics, true);
}
diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad
index db87f81d6c4..ab39692b44b 100644
--- a/src/hotspot/cpu/x86/x86.ad
+++ b/src/hotspot/cpu/x86/x86.ad
@@ -1742,14 +1742,10 @@ static inline void movfp(MacroAssembler* masm, enum FP_PREC pt,
// ja -> b # a
// jp -> NaN # NaN
// jb -> a # b
-// je #
-// |-jz -> a | b # a & b
-// | -> a #
+// je -> a | b # a & b
static void emit_fp_min_max(MacroAssembler* masm, XMMRegister dst,
- XMMRegister a, XMMRegister b,
- XMMRegister xmmt, Register rt,
+ XMMRegister a, XMMRegister b, Register rt,
bool min, enum FP_PREC pt) {
-
Label nan, zero, below, above, done;
emit_fp_ucom(masm, pt, a, b);
@@ -1759,31 +1755,26 @@ static void emit_fp_min_max(MacroAssembler* masm, XMMRegister dst,
} else {
__ jccb(Assembler::above, done);
}
-
__ jccb(Assembler::parity, nan); // PF=1
__ jccb(Assembler::below, below); // CF=1
// equal
- __ vpxor(xmmt, xmmt, xmmt, Assembler::AVX_128bit);
- emit_fp_ucom(masm, pt, a, xmmt);
-
- __ jccb(Assembler::equal, zero);
- movfp(masm, pt, dst, a, rt);
-
- __ jmp(done);
-
- __ bind(zero);
+ // Using bitwise operations is a low cost way to compute the correct result
+ // for zero and non-zero inputs in this scenario except for NaN, which is
+ // handled separately. The mantissa and exponent are valid with either
+ // bitwise operation. For zero inputs, the sign bit is chosen according to
+ // whether a minimum or maximum value is required.
if (min) {
+ // Negative sign preserved when available (e.g., min(+0, -0) -> -0)
__ vpor(dst, a, b, Assembler::AVX_128bit);
} else {
+ // Positive sign preserved when available (e.g., max(+0, -0) -> +0)
__ vpand(dst, a, b, Assembler::AVX_128bit);
}
-
__ jmp(done);
__ bind(above);
movfp(masm, pt, dst, min ? b : a, rt);
-
__ jmp(done);
__ bind(nan);
@@ -7376,18 +7367,18 @@ instruct minmaxF_reg_avx10_2(regF dst, regF a, regF b)
ins_pipe( pipe_slow );
%}
-instruct minmaxF_reduction_reg_avx10_2(regF dst, regF a, regF b, regF xtmp, rRegI rtmp, rFlagsReg cr)
+instruct minmaxF_reduction_reg_avx10_2(regF dst, regF a, regF b, rRegI rtmp, rFlagsReg cr)
%{
predicate(VM_Version::supports_avx10_2() && VLoopReductions::is_reduction(n));
match(Set dst (MaxF a b));
match(Set dst (MinF a b));
- effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr);
+ effect(USE a, USE b, TEMP rtmp, KILL cr);
- format %{ "minmaxF_reduction $dst, $a, $b \t! using $xtmp and $rtmp as TEMP" %}
+ format %{ "minmaxF_reduction $dst, $a, $b \t! using $rtmp as TEMP" %}
ins_encode %{
int opcode = this->ideal_Opcode();
bool min = (opcode == Op_MinF) ? true : false;
- emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register,
+ emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $rtmp$$Register,
min, fp_prec_flt /*pt*/);
%}
ins_pipe( pipe_slow );
@@ -7412,18 +7403,18 @@ instruct minmaxF_reg(legRegF dst, legRegF a, legRegF b, legRegF tmp, legRegF atm
ins_pipe( pipe_slow );
%}
-instruct minmaxF_reduction_reg(legRegF dst, legRegF a, legRegF b, legRegF xtmp, rRegI rtmp, rFlagsReg cr)
+instruct minmaxF_reduction_reg(legRegF dst, legRegF a, legRegF b, rRegI rtmp, rFlagsReg cr)
%{
predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n));
match(Set dst (MaxF a b));
match(Set dst (MinF a b));
- effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr);
+ effect(USE a, USE b, TEMP rtmp, KILL cr);
- format %{ "minmaxF_reduction $dst, $a, $b \t!using $xtmp and $rtmp as TEMP" %}
+ format %{ "minmaxF_reduction $dst, $a, $b \t!using $rtmp as TEMP" %}
ins_encode %{
int opcode = this->ideal_Opcode();
bool min = (opcode == Op_MinF) ? true : false;
- emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register,
+ emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $rtmp$$Register,
min, fp_prec_flt /*pt*/);
%}
ins_pipe( pipe_slow );
@@ -7445,18 +7436,18 @@ instruct minmaxD_reg_avx10_2(regD dst, regD a, regD b)
ins_pipe( pipe_slow );
%}
-instruct minmaxD_reduction_reg_avx10_2(regD dst, regD a, regD b, regD xtmp, rRegI rtmp, rFlagsReg cr)
+instruct minmaxD_reduction_reg_avx10_2(regD dst, regD a, regD b, rRegI rtmp, rFlagsReg cr)
%{
predicate(VM_Version::supports_avx10_2() && VLoopReductions::is_reduction(n));
match(Set dst (MaxD a b));
match(Set dst (MinD a b));
- effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr);
+ effect(USE a, USE b, TEMP rtmp, KILL cr);
- format %{ "minmaxD_reduction $dst, $a, $b \t! using $xtmp and $rtmp as TEMP" %}
+ format %{ "minmaxD_reduction $dst, $a, $b \t! using $rtmp as TEMP" %}
ins_encode %{
int opcode = this->ideal_Opcode();
bool min = (opcode == Op_MinD) ? true : false;
- emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register,
+ emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $rtmp$$Register,
min, fp_prec_dbl /*pt*/);
%}
ins_pipe( pipe_slow );
@@ -7481,18 +7472,18 @@ instruct minmaxD_reg(legRegD dst, legRegD a, legRegD b, legRegD tmp, legRegD atm
ins_pipe( pipe_slow );
%}
-instruct minmaxD_reduction_reg(legRegD dst, legRegD a, legRegD b, legRegD xtmp, rRegL rtmp, rFlagsReg cr)
+instruct minmaxD_reduction_reg(legRegD dst, legRegD a, legRegD b, rRegL rtmp, rFlagsReg cr)
%{
predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n));
match(Set dst (MaxD a b));
match(Set dst (MinD a b));
- effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr);
+ effect(USE a, USE b, TEMP rtmp, KILL cr);
- format %{ "minmaxD_reduction $dst, $a, $b \t! using $xtmp and $rtmp as TEMP" %}
+ format %{ "minmaxD_reduction $dst, $a, $b \t! using $rtmp as TEMP" %}
ins_encode %{
int opcode = this->ideal_Opcode();
bool min = (opcode == Op_MinD) ? true : false;
- emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register,
+ emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $rtmp$$Register,
min, fp_prec_dbl /*pt*/);
%}
ins_pipe( pipe_slow );
diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp
index db7a7d5651b..04673e904de 100644
--- a/src/hotspot/share/classfile/javaClasses.hpp
+++ b/src/hotspot/share/classfile/javaClasses.hpp
@@ -132,6 +132,7 @@ class java_lang_String : AllStatic {
static inline bool is_latin1(oop java_string);
static inline bool deduplication_forbidden(oop java_string);
static inline bool deduplication_requested(oop java_string);
+ static inline bool deduplication_requested_or_forbidden(oop java_string);
static inline int length(oop java_string);
static inline int length(oop java_string, typeArrayOop string_value);
static size_t utf8_length(oop java_string);
diff --git a/src/hotspot/share/classfile/javaClasses.inline.hpp b/src/hotspot/share/classfile/javaClasses.inline.hpp
index 21ad62f8408..7843126c870 100644
--- a/src/hotspot/share/classfile/javaClasses.inline.hpp
+++ b/src/hotspot/share/classfile/javaClasses.inline.hpp
@@ -91,6 +91,10 @@ bool java_lang_String::deduplication_requested(oop java_string) {
return is_flag_set(java_string, _deduplication_requested_mask);
}
+bool java_lang_String::deduplication_requested_or_forbidden(oop java_string) {
+ return is_flag_set(java_string, _deduplication_requested_mask | _deduplication_forbidden_mask);
+}
+
void java_lang_String::set_deduplication_forbidden(oop java_string) {
test_and_set_flag(java_string, _deduplication_forbidden_mask);
}
diff --git a/src/hotspot/share/classfile/vmIntrinsics.cpp b/src/hotspot/share/classfile/vmIntrinsics.cpp
index f9b12df84ca..cec3586a50b 100644
--- a/src/hotspot/share/classfile/vmIntrinsics.cpp
+++ b/src/hotspot/share/classfile/vmIntrinsics.cpp
@@ -487,6 +487,7 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) {
if (!UseSHA512Intrinsics) return true;
break;
case vmIntrinsics::_double_keccak:
+ case vmIntrinsics::_quad_keccak:
case vmIntrinsics::_sha3_implCompress:
if (!UseSHA3Intrinsics) return true;
break;
diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp
index 3f85fd16b61..de4eea669a1 100644
--- a/src/hotspot/share/classfile/vmIntrinsics.hpp
+++ b/src/hotspot/share/classfile/vmIntrinsics.hpp
@@ -526,9 +526,12 @@ class methodHandle;
\
/* support for sun.security.provider.SHAKE128Parallel */ \
do_class(sun_security_provider_sha3_parallel, "sun/security/provider/SHA3Parallel") \
- do_intrinsic(_double_keccak, sun_security_provider_sha3_parallel, double_keccak_name, double_keccak_signature, F_S) \
+ do_intrinsic(_double_keccak, sun_security_provider_sha3_parallel, double_keccak_name, double_keccak_signature, F_S) \
do_name( double_keccak_name, "doubleKeccak") \
do_signature(double_keccak_signature, "([J[J)I") \
+ do_intrinsic(_quad_keccak, sun_security_provider_sha3_parallel, quad_keccak_name, quad_keccak_signature, F_S) \
+ do_name( quad_keccak_name, "quadKeccak") \
+ do_signature(quad_keccak_signature, "([J[J[J[J)I") \
\
/* support for sun.security.provider.DigestBase */ \
do_class(sun_security_provider_digestbase, "sun/security/provider/DigestBase") \
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp
index 929f3b30afe..07eb653bc94 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp
@@ -991,7 +991,7 @@ public:
// state is cached, therefore, during concurrent class unloading phase,
// we will not touch the metadata of unloading nmethods
{
- ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);
+ ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCache, worker_id);
ShenandoahIsNMethodAliveClosure is_nmethod_alive;
_nmethod_itr.nmethods_do(&is_nmethod_alive);
}
@@ -1004,9 +1004,8 @@ void ShenandoahConcurrentGC::op_weak_roots() {
assert(heap->is_concurrent_weak_root_in_progress(), "Only during this phase");
{
// Concurrent weak root processing
- ShenandoahTimingsTracker t(ShenandoahPhaseTimings::conc_weak_roots_work);
- ShenandoahGCWorkerPhase worker_phase(ShenandoahPhaseTimings::conc_weak_roots_work);
- ShenandoahConcurrentWeakRootsEvacUpdateTask task(_generation, ShenandoahPhaseTimings::conc_weak_roots_work);
+ ShenandoahGCWorkerPhase worker_phase(ShenandoahPhaseTimings::conc_weak_roots);
+ ShenandoahConcurrentWeakRootsEvacUpdateTask task(_generation, ShenandoahPhaseTimings::conc_weak_roots);
heap->workers()->run_task(&task);
}
@@ -1080,7 +1079,7 @@ public:
}
if (!ShenandoahHeap::heap()->unload_classes()) {
- ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);
+ ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCache, worker_id);
ShenandoahEvacUpdateCodeCacheClosure cl;
_nmethod_itr.nmethods_do(&cl);
}
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp
index be0da3e54ba..4db8821399f 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp
@@ -36,7 +36,6 @@
#include "gc/shenandoah/shenandoahReferenceProcessor.hpp"
#include "gc/shenandoah/shenandoahRootProcessor.inline.hpp"
#include "gc/shenandoah/shenandoahScanRemembered.inline.hpp"
-#include "gc/shenandoah/shenandoahStringDedup.hpp"
#include "gc/shenandoah/shenandoahTaskqueue.inline.hpp"
#include "gc/shenandoah/shenandoahUtils.hpp"
#include "memory/iterator.inline.hpp"
@@ -57,12 +56,9 @@ public:
void work(uint worker_id) {
ShenandoahConcurrentWorkerSession worker_session(worker_id);
- ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::conc_mark, ShenandoahPhaseTimings::ParallelMark, worker_id, true);
+ ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::conc_mark, ShenandoahPhaseTimings::Work, worker_id, true);
SuspendibleThreadSetJoiner stsj;
- StringDedup::Requests requests;
- _cm->mark_loop(worker_id, _terminator, GENERATION, true /*cancellable*/,
- ShenandoahStringDedup::is_enabled() ? ENQUEUE_DEDUP : NO_DEDUP,
- &requests);
+ _cm->mark_loop(worker_id, _terminator, GENERATION, true /*cancellable*/);
}
};
@@ -71,20 +67,19 @@ class ShenandoahFinalMarkingTask : public WorkerTask {
private:
ShenandoahConcurrentMark* _cm;
TaskTerminator* _terminator;
- bool _dedup_string;
ThreadsClaimTokenScope _threads_claim_token_scope; // needed for Threads::possibly_parallel_threads_do
public:
- ShenandoahFinalMarkingTask(ShenandoahConcurrentMark* cm, TaskTerminator* terminator, bool dedup_string) :
- WorkerTask("Shenandoah Final Mark"), _cm(cm), _terminator(terminator), _dedup_string(dedup_string),
+ ShenandoahFinalMarkingTask(ShenandoahConcurrentMark* cm, TaskTerminator* terminator) :
+ WorkerTask("Shenandoah Final Mark"), _cm(cm), _terminator(terminator),
_threads_claim_token_scope() {
}
void work(uint worker_id) {
ShenandoahHeap* heap = ShenandoahHeap::heap();
+ ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::finish_mark, ShenandoahPhaseTimings::Work, worker_id, true);
ShenandoahParallelWorkerSession worker_session(worker_id);
- StringDedup::Requests requests;
// First drain remaining SATB buffers.
{
ShenandoahObjToScanQueue* q = _cm->get_queue(worker_id);
@@ -98,9 +93,7 @@ public:
ShenandoahFlushSATB tc(satb_mq_set);
Threads::possibly_parallel_threads_do(true /* is_par */, &tc);
}
- _cm->mark_loop(worker_id, _terminator, GENERATION, false /*not cancellable*/,
- _dedup_string ? ENQUEUE_DEDUP : NO_DEDUP,
- &requests);
+ _cm->mark_loop(worker_id, _terminator, GENERATION, false /*not cancellable*/);
assert(_cm->task_queues()->is_empty(), "Should be empty");
}
};
@@ -278,22 +271,22 @@ void ShenandoahConcurrentMark::finish_mark_work() {
switch (_generation->type()) {
case YOUNG:{
- ShenandoahFinalMarkingTask task(this, &terminator, ShenandoahStringDedup::is_enabled());
+ ShenandoahFinalMarkingTask task(this, &terminator);
heap->workers()->run_task(&task);
break;
}
case OLD:{
- ShenandoahFinalMarkingTask task(this, &terminator, ShenandoahStringDedup::is_enabled());
+ ShenandoahFinalMarkingTask task(this, &terminator);
heap->workers()->run_task(&task);
break;
}
case GLOBAL:{
- ShenandoahFinalMarkingTask task(this, &terminator, ShenandoahStringDedup::is_enabled());
+ ShenandoahFinalMarkingTask task(this, &terminator);
heap->workers()->run_task(&task);
break;
}
case NON_GEN:{
- ShenandoahFinalMarkingTask task(this, &terminator, ShenandoahStringDedup::is_enabled());
+ ShenandoahFinalMarkingTask task(this, &terminator);
heap->workers()->run_task(&task);
break;
}
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp
index 7be3141a4fa..b2d578c599d 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp
@@ -347,7 +347,7 @@ void ShenandoahDegenGC::op_reset() {
void ShenandoahDegenGC::op_mark() {
assert(!_generation->is_concurrent_mark_in_progress(), "Should be reset");
- ShenandoahGCPhase phase(ShenandoahPhaseTimings::degen_gc_stw_mark);
+ ShenandoahGCPhase phase(ShenandoahPhaseTimings::degen_gc_mark);
ShenandoahSTWMark mark(_generation, false /*full gc*/);
mark.mark();
}
@@ -410,7 +410,7 @@ void ShenandoahDegenGC::op_cleanup_early() {
}
void ShenandoahDegenGC::op_evacuate() {
- ShenandoahGCPhase phase(ShenandoahPhaseTimings::degen_gc_stw_evac);
+ ShenandoahGCPhase phase(ShenandoahPhaseTimings::degen_gc_evac);
ShenandoahHeap::heap()->evacuate_collection_set(_generation, false /* concurrent*/);
}
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp
index 1c1011a03e6..4af2c9b1e5d 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp
@@ -669,7 +669,7 @@ void ShenandoahGenerationalHeap::coalesce_and_fill_old_regions(bool concurrent)
void work(uint worker_id) override {
ShenandoahWorkerTimingsTracker timer(_phase,
- ShenandoahPhaseTimings::ScanClusters,
+ ShenandoahPhaseTimings::Work,
worker_id, true);
ShenandoahHeapRegion* region;
while ((region = _regions.next()) != nullptr) {
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
index fb35f5861d8..835b2cf3732 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
@@ -1127,10 +1127,12 @@ public:
void work(uint worker_id) {
if (_concurrent) {
+ ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::conc_evac, ShenandoahPhaseTimings::Work, worker_id, true);
ShenandoahConcurrentWorkerSession worker_session(worker_id);
SuspendibleThreadSetJoiner stsj;
do_work();
} else {
+ ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::degen_gc_evac, ShenandoahPhaseTimings::Work, worker_id, true);
ShenandoahParallelWorkerSession worker_session(worker_id);
do_work();
}
@@ -2533,10 +2535,12 @@ public:
void work(uint worker_id) {
if (CONCURRENT) {
+ ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::conc_update_refs, ShenandoahPhaseTimings::Work, worker_id, true);
ShenandoahConcurrentWorkerSession worker_session(worker_id);
SuspendibleThreadSetJoiner stsj;
do_work(worker_id);
} else {
+ ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::degen_gc_update_refs, ShenandoahPhaseTimings::Work, worker_id, true);
ShenandoahParallelWorkerSession worker_session(worker_id);
do_work(worker_id);
}
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp
index dfd921fdf0b..a72c557a5fe 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp
@@ -51,10 +51,11 @@ void ShenandoahMark::end_mark() {
ShenandoahMark::ShenandoahMark(ShenandoahGeneration* generation) :
_generation(generation),
_task_queues(generation->task_queues()),
- _old_gen_task_queues(generation->old_gen_task_queues()) {
+ _old_gen_task_queues(generation->old_gen_task_queues()),
+ _string_dedup(StringDedup::is_enabled()) {
}
-template
+template
void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, StringDedup::Requests* const req, bool update_refs) {
ShenandoahObjToScanQueue* q = get_queue(w);
ShenandoahObjToScanQueue* old_q = get_old_queue(w);
@@ -77,7 +78,7 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, StringDedup::R
heap->flush_liveness_cache(w);
}
-template
+template
void ShenandoahMark::mark_loop(uint worker_id, TaskTerminator* terminator,
ShenandoahGenerationType generation_type, StringDedup::Requests* const req) {
bool update_refs = ShenandoahHeap::heap()->has_forwarded_objects();
@@ -102,35 +103,24 @@ void ShenandoahMark::mark_loop(uint worker_id, TaskTerminator* terminator,
}
void ShenandoahMark::mark_loop(uint worker_id, TaskTerminator* terminator, ShenandoahGenerationType generation_type,
- bool cancellable, StringDedupMode dedup_mode, StringDedup::Requests* const req) {
- if (cancellable) {
- switch(dedup_mode) {
- case NO_DEDUP:
- mark_loop(worker_id, terminator, generation_type, req);
- break;
- case ENQUEUE_DEDUP:
- mark_loop(worker_id, terminator, generation_type, req);
- break;
- case ALWAYS_DEDUP:
- mark_loop(worker_id, terminator, generation_type, req);
- break;
+ bool cancellable) {
+ if (_string_dedup) {
+ StringDedup::Requests req;
+ if (cancellable) {
+ mark_loop(worker_id, terminator, generation_type, &req);
+ } else {
+ mark_loop(worker_id, terminator, generation_type, &req);
}
} else {
- switch(dedup_mode) {
- case NO_DEDUP:
- mark_loop(worker_id, terminator, generation_type, req);
- break;
- case ENQUEUE_DEDUP:
- mark_loop(worker_id, terminator, generation_type, req);
- break;
- case ALWAYS_DEDUP:
- mark_loop(worker_id, terminator, generation_type, req);
- break;
+ if (cancellable) {
+ mark_loop(worker_id, terminator, generation_type, nullptr);
+ } else {
+ mark_loop(worker_id, terminator, generation_type, nullptr);
}
}
}
-template
+template
void ShenandoahMark::mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint worker_id, TaskTerminator *terminator, StringDedup::Requests* const req) {
uintx stride = ShenandoahMarkLoopStride;
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp
index 951779a2ab6..ee29c76dcaf 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp
@@ -34,12 +34,6 @@
#include "gc/shenandoah/shenandoahHeap.hpp"
#include "gc/shenandoah/shenandoahTaskqueue.hpp"
-enum StringDedupMode {
- NO_DEDUP, // Do not do anything for String deduplication
- ENQUEUE_DEDUP, // Enqueue candidate Strings for deduplication, if meet age threshold
- ALWAYS_DEDUP // Enqueue Strings for deduplication
-};
-
class ShenandoahMarkingContext;
// Base class for mark
@@ -50,6 +44,7 @@ protected:
ShenandoahGeneration* const _generation;
ShenandoahObjToScanQueueSet* const _task_queues;
ShenandoahObjToScanQueueSet* const _old_gen_task_queues;
+ bool const _string_dedup;
protected:
ShenandoahMark(ShenandoahGeneration* generation);
@@ -76,7 +71,7 @@ public:
private:
// ---------- Marking loop and tasks
- template
+ template
inline void do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveData* live_data, StringDedup::Requests* const req, ShenandoahMarkTask* task, uint worker_id);
template
@@ -88,10 +83,10 @@ private:
template
inline void count_liveness(ShenandoahLiveData* live_data, oop obj, Klass* klass, uint worker_id);
- template
+ template
void mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint worker_id, TaskTerminator *t, StringDedup::Requests* const req);
- template
+ template
void mark_loop_prework(uint worker_id, TaskTerminator *terminator, StringDedup::Requests* const req, bool update_refs);
template
@@ -104,15 +99,14 @@ private:
ShenandoahMarkingContext* const mark_context,
bool weak, oop obj);
- template
- inline void dedup_string(oop obj, StringDedup::Requests* const req);
+ static inline void dedup_string(oop obj, StringDedup::Requests* const req);
protected:
- template
+ template
void mark_loop(uint worker_id, TaskTerminator* terminator, ShenandoahGenerationType generation_type,
StringDedup::Requests* const req);
void mark_loop(uint worker_id, TaskTerminator* terminator, ShenandoahGenerationType generation_type,
- bool cancellable, StringDedupMode dedup_mode, StringDedup::Requests* const req);
+ bool cancellable);
};
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHMARK_HPP
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp
index 78a3a2e1ca9..71ef99b17ac 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp
@@ -38,7 +38,6 @@
#include "gc/shenandoah/shenandoahMarkingContext.inline.hpp"
#include "gc/shenandoah/shenandoahOldGeneration.hpp"
#include "gc/shenandoah/shenandoahScanRemembered.inline.hpp"
-#include "gc/shenandoah/shenandoahStringDedup.inline.hpp"
#include "gc/shenandoah/shenandoahTaskqueue.inline.hpp"
#include "gc/shenandoah/shenandoahUtils.hpp"
#include "memory/iterator.inline.hpp"
@@ -48,21 +47,7 @@
#include "utilities/devirtualizer.inline.hpp"
#include "utilities/powerOfTwo.hpp"
-template
-void ShenandoahMark::dedup_string(oop obj, StringDedup::Requests* const req) {
- if (STRING_DEDUP == ENQUEUE_DEDUP) {
- if (ShenandoahStringDedup::is_candidate(obj)) {
- req->add(obj);
- }
- } else if (STRING_DEDUP == ALWAYS_DEDUP) {
- if (ShenandoahStringDedup::is_string_candidate(obj) &&
- !ShenandoahStringDedup::dedup_requested(obj)) {
- req->add(obj);
- }
- }
-}
-
-template
+template
void ShenandoahMark::do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveData* live_data, StringDedup::Requests* const req, ShenandoahMarkTask* task, uint worker_id) {
oop obj = task->obj();
@@ -78,13 +63,14 @@ void ShenandoahMark::do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveD
Klass* klass = obj->klass();
if (klass->is_instance_klass()) {
// Case 1: Normal oop, process as usual.
+ if (STRING_DEDUP && (klass == vmClasses::String_klass())) {
+ dedup_string(obj, req);
+ }
if (klass->is_stack_chunk_instance_klass()) {
// Loom doesn't support mixing of weak marking and strong marking of stack chunks.
cl->set_weak(false);
}
-
obj->oop_iterate(cl);
- dedup_string(obj, req);
} else if (klass->is_objArray_klass()) {
// Case 2: Object array instance and no chunk is set. Must be the first
// time we visit it, start the chunked processing.
@@ -108,6 +94,22 @@ void ShenandoahMark::do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveD
}
}
+void ShenandoahMark::dedup_string(oop obj, StringDedup::Requests* const req) {
+ assert(req != nullptr, "Should be available if dedup is enabled");
+
+ // Skip if already requested or dedup is forbidden.
+ // The overwhelming majority of Strings would be filtered here.
+ // These bits are also sticky, so older Strings would be filtered here too.
+ if (java_lang_String::deduplication_requested_or_forbidden(obj)) {
+ return;
+ }
+
+ // Accept deduplication request.
+ if (!java_lang_String::test_and_set_deduplication_requested(obj)) {
+ req->add(obj);
+ }
+}
+
template
inline void ShenandoahMark::count_liveness(ShenandoahLiveData* live_data, oop obj, Klass* klass, uint worker_id) {
const ShenandoahHeap* const heap = ShenandoahHeap::heap();
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp
index 7337ec316af..73ad316a892 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp
@@ -78,7 +78,7 @@ public:
}
void work(uint worker_id) override {
- ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::conc_coalesce_and_fill, ShenandoahPhaseTimings::ScanClusters, worker_id);
+ ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::conc_coalesce_and_fill, ShenandoahPhaseTimings::Work, worker_id);
for (uint region_idx = worker_id; region_idx < _coalesce_and_fill_region_count; region_idx += _nworkers) {
ShenandoahHeapRegion* r = _coalesce_and_fill_region_array[region_idx];
if (r->is_humongous()) {
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.cpp b/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.cpp
index a7a74f30a4b..bad48225f10 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.cpp
@@ -41,14 +41,14 @@ ShenandoahClassUnloadingTask::ShenandoahClassUnloadingTask(ShenandoahPhaseTiming
void ShenandoahClassUnloadingTask::work(uint worker_id) {
{
- ShenandoahWorkerTimingsTracker x(_phase, ShenandoahPhaseTimings::CodeCacheUnload, worker_id);
+ ShenandoahWorkerTimingsTracker x(_phase, ShenandoahPhaseTimings::CodeCache, worker_id);
_code_cache_task.work(worker_id);
}
// Clean all klasses that were not unloaded.
// The weak metadata in klass doesn't need to be
// processed if there was no unloading.
if (_unloading_occurred) {
- ShenandoahWorkerTimingsTracker x(_phase, ShenandoahPhaseTimings::CLDUnlink, worker_id);
+ ShenandoahWorkerTimingsTracker x(_phase, ShenandoahPhaseTimings::Classes, worker_id);
_klass_cleaning_task.work();
}
}
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.inline.hpp
index 4403e51b62f..1f21971c63d 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.inline.hpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.inline.hpp
@@ -54,7 +54,7 @@ ShenandoahParallelWeakRootsCleaningTask::~ShenandoahParallel
template
void ShenandoahParallelWeakRootsCleaningTask::work(uint worker_id) {
{
- ShenandoahWorkerTimingsTracker x(_phase, ShenandoahPhaseTimings::VMWeakRoots, worker_id);
+ ShenandoahWorkerTimingsTracker x(_phase, ShenandoahPhaseTimings::VMWeaks, worker_id);
_weak_processing_task.work(worker_id, _is_alive, _keep_alive);
}
}
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.cpp b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.cpp
index ad12bfc5a89..ca418ab45d4 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.cpp
@@ -40,14 +40,19 @@
#define SHENANDOAH_US_WORKER_NOTIME_FORMAT "%3s"
#define SHENANDOAH_PARALLELISM_FORMAT "%4.2lf"
-#define SHENANDOAH_PHASE_DECLARE_NAME(type, title) \
- title,
+#define SHENANDOAH_PHASE_DECLARE_DESC(name, desc, has_worker_phase) desc,
+#define SHENANDOAH_PHASE_DECLARE_HAS_WORKER_PHASE(name, desc, has_worker_phase) has_worker_phase,
-const char* ShenandoahPhaseTimings::_phase_names[] = {
- SHENANDOAH_PHASE_DO(SHENANDOAH_PHASE_DECLARE_NAME)
+const char* ShenandoahPhaseTimings::_desc[] = {
+ SHENANDOAH_PHASE_DO(SHENANDOAH_PHASE_DECLARE_DESC)
};
-#undef SHENANDOAH_PHASE_DECLARE_NAME
+bool ShenandoahPhaseTimings::_has_worker_phase[] = {
+ SHENANDOAH_PHASE_DO(SHENANDOAH_PHASE_DECLARE_HAS_WORKER_PHASE)
+};
+
+#undef SHENANDOAH_PHASE_DECLARE_DESC
+#undef SHENANDOAH_PHASE_DECLARE_HAS_WORKER_PHASE
ShenandoahPhaseTimings::ShenandoahPhaseTimings(uint max_workers) :
_max_workers(max_workers) {
@@ -55,22 +60,17 @@ ShenandoahPhaseTimings::ShenandoahPhaseTimings(uint max_workers) :
// Initialize everything to sane defaults
for (uint i = 0; i < _num_phases; i++) {
-#define SHENANDOAH_WORKER_DATA_NULL(type, title) \
_worker_data[i] = nullptr;
- SHENANDOAH_PAR_PHASE_DO(,, SHENANDOAH_WORKER_DATA_NULL)
-#undef SHENANDOAH_WORKER_DATA_NULL
_cycle_data[i] = uninitialized();
}
// Then punch in the worker-related data.
- // Every worker phase get a bunch of internal objects, except
- // the very first slot, which is "" and is not populated.
for (uint i = 0; i < _num_phases; i++) {
- if (is_worker_phase(Phase(i))) {
- int c = 0;
-#define SHENANDOAH_WORKER_DATA_INIT(type, title) \
- if (c++ != 0) _worker_data[i + c] = new ShenandoahWorkerData(nullptr, title, _max_workers);
- SHENANDOAH_PAR_PHASE_DO(,, SHENANDOAH_WORKER_DATA_INIT)
+ if (has_worker_phases(Phase(i))) {
+ int c = i + 1;
+#define SHENANDOAH_WORKER_DATA_INIT(name, desc, has_worker_phase) \
+ _worker_data[c++] = new ShenandoahWorkerData(nullptr, desc, _max_workers);
+ SHENANDOAH_WORKER_PHASE_DO(,, SHENANDOAH_WORKER_DATA_INIT)
#undef SHENANDOAH_WORKER_DATA_INIT
}
}
@@ -79,59 +79,23 @@ ShenandoahPhaseTimings::ShenandoahPhaseTimings(uint max_workers) :
assert(_policy != nullptr, "Can not be null");
}
-ShenandoahPhaseTimings::Phase ShenandoahPhaseTimings::worker_par_phase(Phase phase, ParPhase par_phase) {
- assert(is_worker_phase(phase), "Phase should accept worker phase times: %s", phase_name(phase));
- Phase p = Phase(phase + 1 + par_phase);
- assert(p >= 0 && p < _num_phases, "Out of bound for: %s", phase_name(phase));
+ShenandoahPhaseTimings::Phase ShenandoahPhaseTimings::compute_phase_slot(Phase phase, WorkerPhase worker_phase) {
+ assert(has_worker_phases(phase), "Phase should accept worker phase times: %s", phase_desc(phase));
+ Phase p = Phase(phase + 1 + worker_phase);
+ assert(p >= 0 && p < _num_phases, "Out of bound for: %s", phase_desc(phase));
return p;
}
-ShenandoahWorkerData* ShenandoahPhaseTimings::worker_data(Phase phase, ParPhase par_phase) {
- Phase p = worker_par_phase(phase, par_phase);
+ShenandoahWorkerData* ShenandoahPhaseTimings::worker_data(Phase phase, WorkerPhase worker_phase) {
+ Phase p = compute_phase_slot(phase, worker_phase);
ShenandoahWorkerData* wd = _worker_data[p];
- assert(wd != nullptr, "Counter initialized: %s", phase_name(p));
+ assert(wd != nullptr, "Counter initialized: %s", phase_desc(p));
return wd;
}
-bool ShenandoahPhaseTimings::is_worker_phase(Phase phase) {
- assert(phase >= 0 && phase < _num_phases, "Out of bounds");
- switch (phase) {
- case init_evac:
- case init_scan_rset:
- case finish_mark:
- case purge_weak_par:
- case full_gc_mark:
- case full_gc_update_roots:
- case full_gc_adjust_roots:
- case degen_gc_stw_mark:
- case degen_gc_mark:
- case degen_gc_update_roots:
- case full_gc_weakrefs:
- case full_gc_purge_class_unload:
- case full_gc_purge_weak_par:
- case degen_gc_coalesce_and_fill:
- case degen_gc_weakrefs:
- case degen_gc_purge_class_unload:
- case degen_gc_purge_weak_par:
- case heap_iteration_roots:
- case conc_mark:
- case conc_mark_roots:
- case conc_thread_roots:
- case conc_weak_roots_work:
- case conc_weak_refs:
- case conc_strong_roots:
- case conc_coalesce_and_fill:
- case promote_in_place:
- return true;
- default:
- return false;
- }
-}
-
bool ShenandoahPhaseTimings::is_root_work_phase(Phase phase) {
switch (phase) {
case finish_mark:
- case init_evac:
case degen_gc_update_roots:
case full_gc_mark:
case full_gc_update_roots:
@@ -147,9 +111,7 @@ void ShenandoahPhaseTimings::set_cycle_data(Phase phase, double time, bool shoul
if (should_aggregate) {
_cycle_data[phase] = (cycle_data == uninitialized()) ? time : (cycle_data + time);
} else {
-#ifdef ASSERT
- assert(cycle_data == uninitialized(), "Should not be set yet: %s, current value: %lf", phase_name(phase), cycle_data);
-#endif
+ assert(cycle_data == uninitialized(), "Should not be set yet: %s, current value: %lf", phase_desc(phase), cycle_data);
_cycle_data[phase] = time;
}
}
@@ -161,38 +123,37 @@ void ShenandoahPhaseTimings::record_phase_time(Phase phase, double time, bool sh
}
void ShenandoahPhaseTimings::record_workers_start(Phase phase) {
- assert(is_worker_phase(phase), "Phase should accept worker phase times: %s", phase_name(phase));
+ assert(has_worker_phases(phase), "Phase should accept worker phase times: %s", phase_desc(phase));
// Special case: these phases can enter multiple times, need to reset
// their worker data every time.
if (phase == heap_iteration_roots) {
- for (uint i = 1; i < _num_par_phases; i++) {
- worker_data(phase, ParPhase(i))->reset();
+ for (uint i = 0; i < _num_par_phases; i++) {
+ worker_data(phase, WorkerPhase(i))->reset();
}
}
#ifdef ASSERT
- for (uint i = 1; i < _num_par_phases; i++) {
- ShenandoahWorkerData* wd = worker_data(phase, ParPhase(i));
+ for (uint i = 0; i < _num_par_phases; i++) {
+ ShenandoahWorkerData* wd = worker_data(phase, WorkerPhase(i));
for (uint c = 0; c < _max_workers; c++) {
assert(wd->get(c) == ShenandoahWorkerData::uninitialized(),
- "Should not be set: %s", phase_name(worker_par_phase(phase, ParPhase(i))));
+ "Should not be set: %s", phase_desc(compute_phase_slot(phase, WorkerPhase(i))));
}
}
#endif
}
void ShenandoahPhaseTimings::record_workers_end(Phase phase) {
- assert(is_worker_phase(phase), "Phase should accept worker phase times: %s", phase_name(phase));
+ assert(has_worker_phases(phase), "Phase should accept worker phase times: %s", phase_desc(phase));
}
void ShenandoahPhaseTimings::flush_par_workers_to_cycle() {
for (uint pi = 0; pi < _num_phases; pi++) {
Phase phase = Phase(pi);
- if (is_worker_phase(phase)) {
- double sum = uninitialized();
- for (uint i = 1; i < _num_par_phases; i++) {
- ShenandoahWorkerData* wd = worker_data(phase, ParPhase(i));
+ if (has_worker_phases(phase)) {
+ for (uint i = 0; i < _num_par_phases; i++) {
+ ShenandoahWorkerData* wd = worker_data(phase, WorkerPhase(i));
double worker_sum = uninitialized();
for (uint c = 0; c < _max_workers; c++) {
double worker_time = wd->get(c);
@@ -207,17 +168,8 @@ void ShenandoahPhaseTimings::flush_par_workers_to_cycle() {
if (worker_sum != uninitialized()) {
// add to each line in phase
set_cycle_data(Phase(phase + i + 1), worker_sum);
- if (sum == uninitialized()) {
- sum = worker_sum;
- } else {
- sum += worker_sum;
- }
}
}
- if (sum != uninitialized()) {
- // add to total for phase
- set_cycle_data(Phase(phase + 1), sum);
- }
}
}
}
@@ -237,23 +189,29 @@ void ShenandoahPhaseTimings::flush_cycle_to_global() {
void ShenandoahPhaseTimings::print_cycle_on(outputStream* out) const {
out->cr();
- out->print_cr("All times are wall-clock times, except per-root-class counters, that are sum over");
- out->print_cr("all workers. Dividing the over the root stage time estimates parallelism.");
+ out->print_cr(" All times are wall-clock times, except for ones explicitly marked as \"total\", those are");
+ out->print_cr(" sum over all workers. Dividing the total over the root stage time estimates parallelism.");
out->cr();
for (uint i = 0; i < _num_phases; i++) {
double v = _cycle_data[i] * 1000000.0;
if (v > 0) {
- out->print(SHENANDOAH_PHASE_NAME_FORMAT " " SHENANDOAH_US_TIME_FORMAT " us", _phase_names[i], v);
+ out->print(SHENANDOAH_PHASE_NAME_FORMAT " " SHENANDOAH_US_TIME_FORMAT " us", _desc[i], v);
- if (is_worker_phase(Phase(i))) {
- double total = _cycle_data[i + 1] * 1000000.0;
+ if (has_worker_phases(Phase(i))) {
+ double total = 0;
+ for (uint pi = 0; pi < _num_par_phases; pi++) {
+ uint idx = i + 1 + pi;
+ if (_cycle_data[idx] != uninitialized()) {
+ total += _cycle_data[idx];
+ }
+ }
if (total > 0) {
- out->print(", parallelism: " SHENANDOAH_PARALLELISM_FORMAT "x", total / v);
+ out->print(" with " SHENANDOAH_PARALLELISM_FORMAT "x parallelism", total * 1000000.0 / v);
}
}
if (_worker_data[i] != nullptr) {
- out->print(", workers (us): ");
+ out->print(" total, per worker: ");
for (uint c = 0; c < _max_workers; c++) {
double tv = _worker_data[i]->get(c);
if (tv != ShenandoahWorkerData::uninitialized()) {
@@ -277,8 +235,8 @@ void ShenandoahPhaseTimings::print_global_on(outputStream* out) const {
out->print_cr(" \"a\" is average time for each phase, look at levels to see if average makes sense.");
out->print_cr(" \"lvls\" are quantiles: 0%% (minimum), 25%%, 50%% (median), 75%%, 100%% (maximum).");
out->cr();
- out->print_cr(" All times are wall-clock times, except per-root-class counters, that are sum over");
- out->print_cr(" all workers. Dividing the over the root stage time estimates parallelism.");
+ out->print_cr(" All times are wall-clock times, except for ones explicitly marked as \"total\", those are");
+ out->print_cr(" sum over all workers. Dividing the total over the root stage time estimates parallelism.");
out->cr();
for (uint i = 0; i < _num_phases; i++) {
@@ -291,7 +249,7 @@ void ShenandoahPhaseTimings::print_global_on(outputStream* out) const {
SHENANDOAH_US_TIME_FORMAT ", "
SHENANDOAH_US_TIME_FORMAT ", "
SHENANDOAH_US_TIME_FORMAT ")",
- _phase_names[i],
+ _desc[i],
_global_data[i].sum(),
_global_data[i].avg() * 1000000.0,
_global_data[i].num(),
@@ -306,21 +264,21 @@ void ShenandoahPhaseTimings::print_global_on(outputStream* out) const {
}
ShenandoahWorkerTimingsTracker::ShenandoahWorkerTimingsTracker(ShenandoahPhaseTimings::Phase phase,
- ShenandoahPhaseTimings::ParPhase par_phase, uint worker_id, bool cumulative) :
+ ShenandoahPhaseTimings::WorkerPhase worker_phase, uint worker_id, bool cumulative) :
_timings(ShenandoahHeap::heap()->phase_timings()),
- _phase(phase), _par_phase(par_phase), _worker_id(worker_id) {
+ _phase(phase), _worker_phase(worker_phase), _worker_id(worker_id) {
- assert(_timings->worker_data(_phase, _par_phase)->get(_worker_id) == ShenandoahWorkerData::uninitialized() || cumulative,
- "Should not be set yet: %s", ShenandoahPhaseTimings::phase_name(_timings->worker_par_phase(_phase, _par_phase)));
+ assert(_timings->worker_data(_phase, _worker_phase)->get(_worker_id) == ShenandoahWorkerData::uninitialized() || cumulative,
+ "Should not be set yet: %s", ShenandoahPhaseTimings::phase_desc(_timings->compute_phase_slot(_phase, _worker_phase)));
_start_time = os::elapsedTime();
}
ShenandoahWorkerTimingsTracker::~ShenandoahWorkerTimingsTracker() {
- _timings->worker_data(_phase, _par_phase)->set_or_add(_worker_id, os::elapsedTime() - _start_time);
+ _timings->worker_data(_phase, _worker_phase)->set_or_add(_worker_id, os::elapsedTime() - _start_time);
if (ShenandoahPhaseTimings::is_root_work_phase(_phase)) {
ShenandoahPhaseTimings::Phase root_phase = _phase;
- ShenandoahPhaseTimings::Phase cur_phase = _timings->worker_par_phase(root_phase, _par_phase);
- _event.commit(GCId::current(), _worker_id, ShenandoahPhaseTimings::phase_name(cur_phase));
+ ShenandoahPhaseTimings::Phase cur_phase = _timings->compute_phase_slot(root_phase, _worker_phase);
+ _event.commit(GCId::current(), _worker_id, ShenandoahPhaseTimings::phase_desc(cur_phase));
}
}
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp
index bb21cd5be66..385ab10893c 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp
@@ -34,177 +34,171 @@
class ShenandoahCollectorPolicy;
class outputStream;
-#define SHENANDOAH_PAR_PHASE_DO(CNT_PREFIX, DESC_PREFIX, f) \
- f(CNT_PREFIX ## TotalWork, DESC_PREFIX "") \
- f(CNT_PREFIX ## ThreadRoots, DESC_PREFIX "Thread Roots") \
- f(CNT_PREFIX ## CodeCacheRoots, DESC_PREFIX "Code Cache Roots") \
- f(CNT_PREFIX ## VMStrongRoots, DESC_PREFIX "VM Strong Roots") \
- f(CNT_PREFIX ## VMWeakRoots, DESC_PREFIX "VM Weak Roots") \
- f(CNT_PREFIX ## CLDGRoots, DESC_PREFIX "CLDG Roots") \
- f(CNT_PREFIX ## CodeCacheUnload, DESC_PREFIX "Unload Code Caches") \
- f(CNT_PREFIX ## CLDUnlink, DESC_PREFIX "Unlink CLDs") \
- f(CNT_PREFIX ## WeakRefProc, DESC_PREFIX "Weak References") \
- f(CNT_PREFIX ## ParallelMark, DESC_PREFIX "Parallel Mark") \
- f(CNT_PREFIX ## ScanClusters, DESC_PREFIX "Scan Clusters") \
- // end
+#define SHENANDOAH_WORKER_PHASE_DO(NAME_PREFIX, DESC_PREFIX, f) \
+ f(NAME_PREFIX ## Work, DESC_PREFIX "Work", false) \
+ f(NAME_PREFIX ## Threads, DESC_PREFIX "Threads", false) \
+ f(NAME_PREFIX ## CodeCache, DESC_PREFIX "Code Cache", false) \
+ f(NAME_PREFIX ## VMStrongs, DESC_PREFIX "VM Strongs", false) \
+ f(NAME_PREFIX ## VMWeaks, DESC_PREFIX "VM Weaks", false) \
+ f(NAME_PREFIX ## Classes, DESC_PREFIX "Classes", false) \
+ // END
-#define SHENANDOAH_PHASE_DO(f) \
- f(conc_reset, "Concurrent Reset") \
- f(conc_reset_after_collect, "Concurrent Reset After Collect") \
- f(conc_reset_old, "Concurrent Reset (OLD)") \
- f(init_mark_gross, "Pause Init Mark (G)") \
- f(init_mark, "Pause Init Mark (N)") \
- f(init_mark_verify, " Verify") \
- f(init_manage_tlabs, " Manage TLABs") \
- f(init_swap_rset, " Swap Remembered Set") \
- f(init_transfer_satb, " Transfer Old From SATB") \
- f(init_update_region_states, " Update Region States") \
- f(init_propagate_gc_state, " Propagate GC State") \
- \
- f(init_scan_rset, "Concurrent Scan Remembered Set") \
- SHENANDOAH_PAR_PHASE_DO(init_scan_rset_, " RS: ", f) \
- \
- f(conc_mark_roots, "Concurrent Mark Roots ") \
- SHENANDOAH_PAR_PHASE_DO(conc_mark_roots, " CMR: ", f) \
- f(conc_mark, "Concurrent Marking") \
- SHENANDOAH_PAR_PHASE_DO(conc_mark, " CM: ", f) \
- f(conc_mark_satb_flush, " Flush SATB") \
- \
- f(final_mark_gross, "Pause Final Mark (G)") \
- f(final_mark, "Pause Final Mark (N)") \
- f(final_mark_verify, " Verify") \
- f(finish_mark, " Finish Mark") \
- f(final_mark_propagate_gc_state, " Propagate GC State") \
- SHENANDOAH_PAR_PHASE_DO(finish_mark_, " FM: ", f) \
- f(purge, " System Purge") \
- SHENANDOAH_PAR_PHASE_DO(purge_cu_par_, " CU: ", f) \
- f(purge_weak_par, " Weak Roots") \
- SHENANDOAH_PAR_PHASE_DO(purge_weak_par_, " WR: ", f) \
- f(final_update_region_states, " Update Region States") \
- f(final_manage_labs, " Manage GC/TLABs") \
- f(choose_cset, " Choose Collection Set") \
- f(final_rebuild_freeset, " Rebuild Free Set") \
- f(init_evac, " Initial Evacuation") \
- SHENANDOAH_PAR_PHASE_DO(evac_, " E: ", f) \
- \
- f(conc_thread_roots, "Concurrent Thread Roots") \
- SHENANDOAH_PAR_PHASE_DO(conc_thread_roots_, " CTR: ", f) \
- f(conc_weak_refs, "Concurrent Weak References") \
- SHENANDOAH_PAR_PHASE_DO(conc_weak_refs_, " CWRF: ", f) \
- f(conc_weak_roots, "Concurrent Weak Roots") \
- f(conc_weak_roots_work, " Roots") \
- SHENANDOAH_PAR_PHASE_DO(conc_weak_roots_work_, " CWR: ", f) \
- f(conc_weak_roots_rendezvous, " Rendezvous") \
- f(conc_cleanup_early, "Concurrent Cleanup") \
- f(conc_class_unload, "Concurrent Class Unloading") \
- f(conc_class_unload_unlink, " Unlink Stale") \
- f(conc_class_unload_unlink_sd, " System Dictionary") \
- f(conc_class_unload_unlink_weak_klass, " Weak Class Links") \
- f(conc_class_unload_unlink_code_roots, " Code Roots") \
- f(conc_class_unload_rendezvous, " Rendezvous") \
- f(conc_class_unload_purge, " Purge Unlinked") \
- f(conc_class_unload_purge_coderoots, " Code Roots") \
- f(conc_class_unload_purge_cldg, " CLDG") \
- f(conc_class_unload_purge_ec, " Exception Caches") \
- f(conc_strong_roots, "Concurrent Strong Roots") \
- SHENANDOAH_PAR_PHASE_DO(conc_strong_roots_, " CSR: ", f) \
- f(conc_evac, "Concurrent Evacuation") \
- f(conc_update_card_table, "Concurrent Update Cards") \
- f(conc_final_roots, "Concurrent Final Roots") \
- f(promote_in_place, " Promote Regions") \
- f(final_verify_gross, "Pause Final Verify (G)") \
- f(final_verify, "Pause Final Verify (N)") \
- \
- f(init_update_refs_gross, "Pause Init Update Refs (G)") \
- f(init_update_refs, "Pause Init Update Refs (N)") \
- f(init_update_refs_verify, " Verify") \
- \
- f(conc_update_refs_prepare, "Concurrent Update Refs Prepare") \
- f(conc_update_refs, "Concurrent Update Refs") \
- f(conc_update_thread_roots, "Concurrent Update Thread Roots") \
- \
- f(final_update_refs_gross, "Pause Final Update Refs (G)") \
- f(final_update_refs, "Pause Final Update Refs (N)") \
- f(final_update_refs_verify, " Verify") \
- f(final_update_refs_update_region_states, " Update Region States") \
- f(final_update_refs_transfer_satb, " Transfer Old From SATB") \
- f(final_update_refs_trash_cset, " Trash Collection Set") \
- f(final_update_refs_rebuild_freeset, " Rebuild Free Set") \
- f(final_update_refs_propagate_gc_state, " Propagate GC State") \
- \
- f(conc_cleanup_complete, "Concurrent Cleanup") \
- f(conc_coalesce_and_fill, "Concurrent Coalesce and Fill") \
- SHENANDOAH_PAR_PHASE_DO(conc_coalesce_, " CC&F: ", f) \
- \
- f(degen_gc_gross, "Pause Degenerated GC (G)") \
- f(degen_gc, "Pause Degenerated GC (N)") \
- f(degen_gc_un_self_forward, " Un-Self-Forward") \
- f(degen_gc_stw_mark, " Degen STW Mark") \
- SHENANDOAH_PAR_PHASE_DO(degen_gc_stw_mark_, " DSM: ", f) \
- f(degen_gc_mark, " Degen Mark") \
- SHENANDOAH_PAR_PHASE_DO(degen_gc_mark_, " DM: ", f) \
- f(degen_gc_purge, " System Purge") \
- f(degen_gc_weakrefs, " Weak References") \
- SHENANDOAH_PAR_PHASE_DO(degen_gc_weakrefs_p_, " WRP: ", f) \
- f(degen_gc_purge_class_unload, " Unload Classes") \
- SHENANDOAH_PAR_PHASE_DO(degen_gc_purge_cu_par_, " DCU: ", f) \
- f(degen_gc_purge_weak_par, " Weak Roots") \
- SHENANDOAH_PAR_PHASE_DO(degen_gc_purge_weak_p_, " DWR: ", f) \
- f(degen_gc_purge_cldg, " CLDG") \
- f(degen_gc_final_update_region_states, " Update Region States") \
- f(degen_gc_final_manage_labs, " Manage GC/TLABs") \
- f(degen_gc_choose_cset, " Choose Collection Set") \
- f(degen_gc_final_rebuild_freeset, " Rebuild Free Set") \
- f(degen_gc_stw_evac, " Evacuation") \
- f(degen_gc_init_update_refs_manage_gclabs, " Manage GCLABs") \
- f(degen_gc_update_refs, " Update References") \
- f(degen_gc_final_update_refs_update_region_states," Update Region States") \
- f(degen_gc_final_update_refs_trash_cset, " Trash Collection Set") \
- f(degen_gc_final_update_refs_rebuild_freeset, " Rebuild Free Set") \
- f(degen_gc_update_roots, " Degen Update Roots") \
- SHENANDOAH_PAR_PHASE_DO(degen_gc_update_, " DU: ", f) \
- f(degen_gc_cleanup_complete, " Cleanup") \
- f(degen_gc_promote_regions, " Degen Promote Regions") \
- f(degen_gc_coalesce_and_fill, " Degen Coalesce and Fill") \
- SHENANDOAH_PAR_PHASE_DO(degen_coalesce_, " DC&F", f) \
- f(degen_gc_propagate_gc_state, " Propagate GC State") \
- \
- f(full_gc_gross, "Pause Full GC (G)") \
- f(full_gc, "Pause Full GC (N)") \
- f(full_gc_un_self_forward, " Un-Self-Forward") \
- f(full_gc_heapdump_pre, " Pre Heap Dump") \
- f(full_gc_prepare, " Prepare") \
- f(full_gc_update_roots, " Update Roots") \
- SHENANDOAH_PAR_PHASE_DO(full_gc_update_roots_, " FU: ", f) \
- f(full_gc_mark, " Mark") \
- SHENANDOAH_PAR_PHASE_DO(full_gc_mark_, " FM: ", f) \
- f(full_gc_purge, " System Purge") \
- f(full_gc_weakrefs, " Weak References") \
- SHENANDOAH_PAR_PHASE_DO(full_gc_weakrefs_p_, " WRP: ", f) \
- f(full_gc_purge_class_unload, " Unload Classes") \
- SHENANDOAH_PAR_PHASE_DO(full_gc_purge_cu_par_, " CU: ", f) \
- f(full_gc_purge_weak_par, " Weak Roots") \
- SHENANDOAH_PAR_PHASE_DO(full_gc_purge_weak_p_, " WR: ", f) \
- f(full_gc_purge_cldg, " CLDG") \
- f(full_gc_calculate_addresses, " Calculate Addresses") \
- f(full_gc_calculate_addresses_regular, " Regular Objects") \
- f(full_gc_calculate_addresses_humong, " Humongous Objects") \
- f(full_gc_adjust_pointers, " Adjust Pointers") \
- f(full_gc_adjust_roots, " Adjust Roots") \
- SHENANDOAH_PAR_PHASE_DO(full_gc_adjust_roots_, " FA: ", f) \
- f(full_gc_copy_objects, " Copy Objects") \
- f(full_gc_copy_objects_regular, " Regular Objects") \
- f(full_gc_copy_objects_humong, " Humongous Objects") \
- f(full_gc_recompute_generation_usage, " Recompute generation usage") \
- f(full_gc_copy_objects_reset_complete, " Reset Complete Bitmap") \
- f(full_gc_copy_objects_rebuild, " Rebuild Region Sets") \
- f(full_gc_reconstruct_remembered_set, " Reconstruct Remembered Set") \
- f(full_gc_heapdump_post, " Post Heap Dump") \
- f(full_gc_propagate_gc_state, " Propagate GC State") \
- \
- f(heap_iteration_roots, "Heap Iteration") \
- SHENANDOAH_PAR_PHASE_DO(heap_iteration_roots_, " HI: ", f) \
- // end
+#define SHENANDOAH_SIMPLE_PHASE_DEF(f, NAME, DESC) \
+ f(NAME, DESC, false)
+
+#define SHENANDOAH_WORKER_PHASE_DEF(f, NAME_PREFIX, MAIN_DESC, DESC_PREFIX) \
+ f(NAME_PREFIX, MAIN_DESC, true) \
+ SHENANDOAH_WORKER_PHASE_DO(NAME_PREFIX, DESC_PREFIX, f)
+
+#define SHENANDOAH_PHASE_DO(f) \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_reset, "Concurrent Reset") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, init_mark_gross, "Pause Init Mark (G)") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, init_mark, "Pause Init Mark (N)") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, init_mark_verify, " Verify") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, init_manage_tlabs, " Manage TLABs") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, init_swap_rset, " Swap Remembered Set") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, init_transfer_satb, " Transfer Old From SATB") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, init_update_region_states, " Update Region States") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, init_propagate_gc_state, " Propagate GC State") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, init_scan_rset, "Concurrent Scan Remembered Set", \
+ " RS: ") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, conc_mark_roots, "Concurrent Mark Roots", \
+ " CMR: ") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, conc_mark, "Concurrent Marking", \
+ " CM: ") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_mark_satb_flush, " Flush SATB") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_mark_gross, "Pause Final Mark (G)") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_mark, "Pause Final Mark (N)") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_mark_verify, " Verify") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, finish_mark, " Finish Mark", \
+ " FM: ") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_mark_propagate_gc_state, " Propagate GC State") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, purge, " System Purge", \
+ " CU: ") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, purge_weak_par, " Weak Roots", \
+ " WR: ") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_update_region_states, " Update Region States") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_manage_labs, " Manage GC/TLABs") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, choose_cset, " Choose Collection Set") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_rebuild_freeset, " Rebuild Free Set") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, conc_thread_roots, "Concurrent Thread Roots", \
+ " CTR: ") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, conc_weak_refs, "Concurrent Weak References", \
+ " CWRF: ") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, conc_weak_roots, "Concurrent Weak Roots", \
+ " CWR: ") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_weak_roots_rendezvous, " Rendezvous") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_cleanup_early, "Concurrent Cleanup, Early") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_class_unload, "Concurrent Class Unloading") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_class_unload_unlink, " Unlink Stale") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_class_unload_unlink_sd, " System Dictionary") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_class_unload_unlink_weak_klass, " Weak Class Links") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_class_unload_unlink_code_roots, " Code Roots") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_class_unload_rendezvous, " Rendezvous") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_class_unload_purge, " Purge Unlinked") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_class_unload_purge_coderoots, " Code Roots") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_class_unload_purge_cldg, " CLDG") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_class_unload_purge_ec, " Exception Caches") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, conc_strong_roots, "Concurrent Strong Roots", \
+ " CSR: ") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, conc_evac, "Concurrent Evacuation", \
+ " CE: ") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_update_card_table, "Concurrent Update Cards") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_final_roots, "Concurrent Final Roots") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, promote_in_place, " Promote Regions", \
+ " PIP: ") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_verify_gross, "Pause Final Verify (G)") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_verify, "Pause Final Verify (N)") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, init_update_refs_gross, "Pause Init Update Refs (G)") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, init_update_refs, "Pause Init Update Refs (N)") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, init_update_refs_verify, " Verify") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_update_refs_prepare, "Concurrent Update Refs Prepare") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, conc_update_refs, "Concurrent Update Refs", \
+ " CUR: ") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_update_thread_roots, "Concurrent Update Thread Roots") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_update_refs_gross, "Pause Final Update Refs (G)") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_update_refs, "Pause Final Update Refs (N)") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_update_refs_verify, " Verify") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_update_refs_update_region_states, " Update Region States") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_update_refs_transfer_satb, " Transfer Old From SATB") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_update_refs_trash_cset, " Trash Collection Set") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_update_refs_rebuild_freeset, " Rebuild Free Set") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_update_refs_propagate_gc_state, " Propagate GC State") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_cleanup_complete, "Concurrent Cleanup, Complete") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, conc_coalesce_and_fill, "Concurrent Coalesce and Fill", \
+ " CC&F: ") \
+ \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_gross, "Pause Degenerated GC (G)") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc, "Pause Degenerated GC (N)") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_un_self_forward, " Un-Self-Forward") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, degen_gc_mark, " Mark", \
+ " DM: ") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_purge, " System Purge") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, degen_gc_weakrefs, " Weak References", \
+ " WRP: ") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, degen_gc_purge_class_unload, " Unload Classes", \
+ " DCU: ") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, degen_gc_purge_weak_par, " Weak Roots", \
+ " DWR: ") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_purge_cldg, " CLDG") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_final_update_region_states, " Update Region States") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_final_manage_labs, " Manage GC/TLABs") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_choose_cset, " Choose Collection Set") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_final_rebuild_freeset, " Rebuild Free Set") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, degen_gc_evac, " Evacuation", \
+ " DE: ") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_init_update_refs_manage_gclabs, " Manage GCLABs") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, degen_gc_update_refs, " Update References", \
+ " DUR: ") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_final_update_refs_update_region_states, " Update Region States") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_final_update_refs_trash_cset, " Trash Collection Set") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_final_update_refs_rebuild_freeset, " Rebuild Free Set") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, degen_gc_update_roots, " Degen Update Roots", \
+ " DU: ") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_cleanup_complete, " Cleanup") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_promote_regions, " Degen Promote Regions") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, degen_gc_coalesce_and_fill, " Degen Coalesce and Fill", \
+ " DC&F") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_propagate_gc_state, " Propagate GC State") \
+ \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_gross, "Pause Full GC (G)") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc, "Pause Full GC (N)") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_un_self_forward, " Un-Self-Forward") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_heapdump_pre, " Pre Heap Dump") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_prepare, " Prepare") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, full_gc_update_roots, " Update Roots", \
+ " FU: ") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, full_gc_mark, " Mark", \
+ " FM: ") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_purge, " System Purge") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, full_gc_weakrefs, " Weak References", \
+ " WRP: ") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, full_gc_purge_class_unload, " Unload Classes", \
+ " CU: ") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, full_gc_purge_weak_par, " Weak Roots", \
+ " WR: ") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_purge_cldg, " CLDG") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_calculate_addresses, " Calculate Addresses") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_calculate_addresses_regular, " Regular Objects") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_calculate_addresses_humong, " Humongous Objects") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_adjust_pointers, " Adjust Pointers") \
+ SHENANDOAH_WORKER_PHASE_DEF(f, full_gc_adjust_roots, " Adjust Roots", \
+ " FA: ") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_copy_objects, " Copy Objects") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_copy_objects_regular, " Regular Objects") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_copy_objects_humong, " Humongous Objects") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_recompute_generation_usage, " Recompute generation usage") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_copy_objects_reset_complete, " Reset Complete Bitmap") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_copy_objects_rebuild, " Rebuild Region Sets") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_reconstruct_remembered_set, " Reconstruct Remembered Set") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_heapdump_post, " Post Heap Dump") \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_propagate_gc_state, " Propagate GC State") \
+ \
+ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_reset_after_collect, "Concurrent Reset After Collect") \
+ \
+ SHENANDOAH_WORKER_PHASE_DEF(f, heap_iteration_roots, "Heap Iteration", \
+ " HI: ") \
+ // END
typedef WorkerDataArray ShenandoahWorkerData;
@@ -212,7 +206,7 @@ class ShenandoahPhaseTimings : public CHeapObj {
friend class ShenandoahGCPhase;
friend class ShenandoahWorkerTimingsTracker;
public:
-#define SHENANDOAH_PHASE_DECLARE_ENUM(type, title) type,
+#define SHENANDOAH_PHASE_DECLARE_ENUM(name, desc, has_worker_phase) name,
enum Phase {
SHENANDOAH_PHASE_DO(SHENANDOAH_PHASE_DECLARE_ENUM)
@@ -220,8 +214,8 @@ public:
_invalid_phase = _num_phases
};
- enum ParPhase {
- SHENANDOAH_PAR_PHASE_DO(,, SHENANDOAH_PHASE_DECLARE_ENUM)
+ enum WorkerPhase {
+ SHENANDOAH_WORKER_PHASE_DO(,, SHENANDOAH_PHASE_DECLARE_ENUM)
_num_par_phases
};
@@ -231,16 +225,16 @@ private:
uint _max_workers;
double _cycle_data[_num_phases];
HdrSeq _global_data[_num_phases];
- static const char* _phase_names[_num_phases];
+ static const char* _desc[_num_phases];
+ static bool _has_worker_phase[_num_phases];
ShenandoahWorkerData* _worker_data[_num_phases];
ShenandoahCollectorPolicy* _policy;
- static bool is_worker_phase(Phase phase);
static bool is_root_work_phase(Phase phase);
- ShenandoahWorkerData* worker_data(Phase phase, ParPhase par_phase);
- Phase worker_par_phase(Phase phase, ParPhase par_phase);
+ ShenandoahWorkerData* worker_data(Phase phase, WorkerPhase par_phase);
+ static Phase compute_phase_slot(Phase phase, WorkerPhase worker_phase);
void set_cycle_data(Phase phase, double time, bool should_aggregate = false);
static double uninitialized() { return -1; }
@@ -256,9 +250,14 @@ public:
void flush_par_workers_to_cycle();
void flush_cycle_to_global();
- static const char* phase_name(Phase phase) {
+ static const char* phase_desc(Phase phase) {
assert(phase >= 0 && phase < _num_phases, "Out of bounds: %d", phase);
- return _phase_names[phase];
+ return _desc[phase];
+ }
+
+ static bool has_worker_phases(Phase phase) {
+ assert(phase >= 0 && phase < _num_phases, "Out of bounds: %d", phase);
+ return _has_worker_phase[phase];
}
void print_cycle_on(outputStream* out) const;
@@ -269,14 +268,14 @@ class ShenandoahWorkerTimingsTracker : public StackObj {
private:
ShenandoahPhaseTimings* const _timings;
ShenandoahPhaseTimings::Phase const _phase;
- ShenandoahPhaseTimings::ParPhase const _par_phase;
+ ShenandoahPhaseTimings::WorkerPhase const _worker_phase;
uint const _worker_id;
double _start_time;
EventGCPhaseParallel _event;
public:
ShenandoahWorkerTimingsTracker(ShenandoahPhaseTimings::Phase phase,
- ShenandoahPhaseTimings::ParPhase par_phase,
+ ShenandoahPhaseTimings::WorkerPhase worker_phase,
uint worker_id,
bool cumulative = false);
~ShenandoahWorkerTimingsTracker();
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp
index 37e9729b7ff..c24735b92cf 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp
@@ -547,11 +547,11 @@ public:
virtual void work(uint worker_id) {
if (_concurrent) {
ShenandoahConcurrentWorkerSession worker_session(worker_id);
- ShenandoahWorkerTimingsTracker x(_phase, ShenandoahPhaseTimings::WeakRefProc, worker_id);
+ ShenandoahWorkerTimingsTracker x(_phase, ShenandoahPhaseTimings::Work, worker_id);
_reference_processor->work();
} else {
ShenandoahParallelWorkerSession worker_session(worker_id);
- ShenandoahWorkerTimingsTracker x(_phase, ShenandoahPhaseTimings::WeakRefProc, worker_id);
+ ShenandoahWorkerTimingsTracker x(_phase, ShenandoahPhaseTimings::Work, worker_id);
_reference_processor->work();
}
}
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp
index 80825ac43ad..91f6f605a84 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp
@@ -49,7 +49,7 @@ uint ShenandoahJavaThreadsIterator::claim() {
}
void ShenandoahJavaThreadsIterator::threads_do(ThreadClosure* cl, uint worker_id) {
- ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::ThreadRoots, worker_id);
+ ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::Threads, worker_id);
for (uint i = claim(); i < _length; i = claim()) {
for (uint t = i; t < MIN2(_length, i + _stride); t++) {
cl->do_thread(thread_at(t));
@@ -63,13 +63,13 @@ ShenandoahThreadRoots::ShenandoahThreadRoots(ShenandoahPhaseTimings::Phase phase
_threads_claim_token_scope() {}
void ShenandoahThreadRoots::oops_do(OopClosure* oops_cl, NMethodClosure* code_cl, uint worker_id) {
- ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::ThreadRoots, worker_id);
+ ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::Threads, worker_id);
ResourceMark rm;
Threads::possibly_parallel_oops_do(_is_par, oops_cl, code_cl);
}
void ShenandoahThreadRoots::threads_do(ThreadClosure* tc, uint worker_id) {
- ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::ThreadRoots, worker_id);
+ ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::Threads, worker_id);
ResourceMark rm;
Threads::possibly_parallel_threads_do(_is_par, tc);
}
@@ -78,7 +78,7 @@ ShenandoahCodeCacheRoots::ShenandoahCodeCacheRoots(ShenandoahPhaseTimings::Phase
}
void ShenandoahCodeCacheRoots::nmethods_do(NMethodClosure* nmethod_cl, uint worker_id) {
- ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);
+ ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCache, worker_id);
_coderoots_iterator.possibly_parallel_nmethods_do(nmethod_cl);
}
@@ -153,7 +153,7 @@ void ShenandoahConcurrentRootScanner::roots_do(OopClosure* oops, uint worker_id)
_cld_roots.cld_do(&clds_cl, worker_id);
{
- ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);
+ ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCache, worker_id);
NMethodToOopClosure nmethods(oops, !NMethodToOopClosure::FixRelocations);
_codecache_snapshot->parallel_nmethods_do(&nmethods);
}
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp
index a62f1c7fd66..4694a1e0519 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp
@@ -46,7 +46,7 @@ ShenandoahVMWeakRoots::ShenandoahVMWeakRoots(ShenandoahPhaseTimings:
template
template
void ShenandoahVMWeakRoots::oops_do(T* cl, uint worker_id) {
- ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::VMWeakRoots, worker_id);
+ ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::VMWeaks, worker_id);
_weak_roots.oops_do(cl);
}
@@ -54,7 +54,7 @@ template
template
void ShenandoahVMWeakRoots::weak_oops_do(IsAlive* is_alive, KeepAlive* keep_alive, uint worker_id) {
ShenandoahCleanUpdateWeakOopsClosure cl(is_alive, keep_alive);
- ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::VMWeakRoots, worker_id);
+ ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::VMWeaks, worker_id);
_weak_roots.oops_do(&cl);
}
@@ -71,7 +71,7 @@ ShenandoahVMRoots::ShenandoahVMRoots(ShenandoahPhaseTimings::Phase p
template
template
void ShenandoahVMRoots::oops_do(T* cl, uint worker_id) {
- ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::VMStrongRoots, worker_id);
+ ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::VMStrongs, worker_id);
_strong_roots.oops_do(cl);
}
@@ -104,12 +104,12 @@ template
void ShenandoahClassLoaderDataRoots::cld_do_impl(CldDo f, CLDClosure* clds, uint worker_id) {
if (CONCURRENT) {
if (_semaphore.try_acquire()) {
- ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CLDGRoots, worker_id);
+ ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::Classes, worker_id);
f(clds);
_semaphore.claim_all();
}
} else {
- ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CLDGRoots, worker_id);
+ ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::Classes, worker_id);
f(clds);
}
}
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp
index 23edc780e47..c678760faf6 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp
@@ -36,7 +36,6 @@
#include "gc/shenandoah/shenandoahPhaseTimings.hpp"
#include "gc/shenandoah/shenandoahRootVerifier.hpp"
#include "gc/shenandoah/shenandoahScanRemembered.inline.hpp"
-#include "gc/shenandoah/shenandoahStringDedup.hpp"
#include "gc/shenandoah/shenandoahUtils.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/jniHandles.hpp"
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp
index 73935ed4e91..18fdfff125d 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp
@@ -63,7 +63,7 @@ void ShenandoahSTWMarkTask::work(uint worker_id) {
ShenandoahSTWMark::ShenandoahSTWMark(ShenandoahGeneration* generation, bool full_gc) :
ShenandoahMark(generation),
- _root_scanner(full_gc ? ShenandoahPhaseTimings::full_gc_mark : ShenandoahPhaseTimings::degen_gc_stw_mark),
+ _root_scanner(full_gc ? ShenandoahPhaseTimings::full_gc_mark : ShenandoahPhaseTimings::degen_gc_mark),
_terminator(ShenandoahHeap::heap()->workers()->active_workers(), task_queues()),
_full_gc(full_gc) {
assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a Shenandoah safepoint");
@@ -151,10 +151,8 @@ void ShenandoahSTWMark::mark_roots(uint worker_id) {
}
void ShenandoahSTWMark::finish_mark(uint worker_id) {
- ShenandoahPhaseTimings::Phase phase = _full_gc ? ShenandoahPhaseTimings::full_gc_mark : ShenandoahPhaseTimings::degen_gc_stw_mark;
- ShenandoahWorkerTimingsTracker timer(phase, ShenandoahPhaseTimings::ParallelMark, worker_id);
- StringDedup::Requests requests;
+ ShenandoahPhaseTimings::Phase phase = _full_gc ? ShenandoahPhaseTimings::full_gc_mark : ShenandoahPhaseTimings::degen_gc_mark;
+ ShenandoahWorkerTimingsTracker timer(phase, ShenandoahPhaseTimings::Work, worker_id);
- mark_loop(worker_id, &_terminator, _generation->type(), false /* not cancellable */,
- ShenandoahStringDedup::is_enabled() ? ALWAYS_DEDUP : NO_DEDUP, &requests);
+ mark_loop(worker_id, &_terminator, _generation->type(), false /* not cancellable */);
}
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp
index 7ae148a7144..c3a82b987e2 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp
@@ -808,7 +808,7 @@ void ShenandoahScanRememberedTask::work(uint worker_id) {
}
void ShenandoahScanRememberedTask::do_work(uint worker_id) {
- ShenandoahWorkerTimingsTracker x(ShenandoahPhaseTimings::init_scan_rset, ShenandoahPhaseTimings::ScanClusters, worker_id);
+ ShenandoahWorkerTimingsTracker x(ShenandoahPhaseTimings::init_scan_rset, ShenandoahPhaseTimings::Work, worker_id);
ShenandoahObjToScanQueue* q = _queue_set->queue(worker_id);
ShenandoahObjToScanQueue* old = _old_queue_set == nullptr ? nullptr : _old_queue_set->queue(worker_id);
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.inline.hpp
deleted file mode 100644
index 1559dd81849..00000000000
--- a/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.inline.hpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2019, 2021, 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.
- *
- */
-
-#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHSTRINGDEDUP_INLINE_HPP
-#define SHARE_GC_SHENANDOAH_SHENANDOAHSTRINGDEDUP_INLINE_HPP
-
-#include "gc/shenandoah/shenandoahStringDedup.hpp"
-
-#include "classfile/javaClasses.inline.hpp"
-#include "gc/shenandoah/shenandoahHeap.inline.hpp"
-#include "oops/markWord.hpp"
-
-bool ShenandoahStringDedup::is_string_candidate(oop obj) {
- assert(Thread::current()->is_Worker_thread(),
- "Only from a GC worker thread");
- return java_lang_String::is_instance(obj) &&
- java_lang_String::value(obj) != nullptr;
-}
-
-bool ShenandoahStringDedup::dedup_requested(oop obj) {
- return java_lang_String::test_and_set_deduplication_requested(obj);
-}
-
-bool ShenandoahStringDedup::is_candidate(oop obj) {
- if (!is_string_candidate(obj)) {
- return false;
- }
-
- uint age = ShenandoahHeap::get_object_age(obj);
- return (age <= markWord::max_age) &&
- StringDedup::is_below_threshold_age(age) &&
- !dedup_requested(obj);
-}
-
-#endif // SHARE_GC_SHENANDOAH_SHENANDOAHSTRINGDEDUP_INLINE_HPP
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp b/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp
index ac6c826a3f2..c4204d852d5 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp
@@ -143,7 +143,7 @@ bool ShenandoahTimingsTracker::is_current_phase_valid() {
ShenandoahGCPhase::ShenandoahGCPhase(ShenandoahPhaseTimings::Phase phase) :
ShenandoahTimingsTracker(phase),
_timer(ShenandoahHeap::heap()->gc_timer()) {
- _timer->register_gc_phase_start(ShenandoahPhaseTimings::phase_name(phase), Ticks::now());
+ _timer->register_gc_phase_start(ShenandoahPhaseTimings::phase_desc(phase), Ticks::now());
}
ShenandoahGCPhase::~ShenandoahGCPhase() {
@@ -164,9 +164,9 @@ ShenandoahWorkerSession::ShenandoahWorkerSession(uint worker_id) {
}
ShenandoahConcurrentWorkerSession::~ShenandoahConcurrentWorkerSession() {
- _event.commit(GCId::current(), ShenandoahPhaseTimings::phase_name(ShenandoahGCPhase::current_phase()));
+ _event.commit(GCId::current(), ShenandoahPhaseTimings::phase_desc(ShenandoahGCPhase::current_phase()));
}
ShenandoahParallelWorkerSession::~ShenandoahParallelWorkerSession() {
- _event.commit(GCId::current(), WorkerThread::worker_id(), ShenandoahPhaseTimings::phase_name(ShenandoahGCPhase::current_phase()));
+ _event.commit(GCId::current(), WorkerThread::worker_id(), ShenandoahPhaseTimings::phase_desc(ShenandoahGCPhase::current_phase()));
}
diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp
index fe4a7f8a5db..2f48fffcaa2 100644
--- a/src/hotspot/share/opto/c2compiler.cpp
+++ b/src/hotspot/share/opto/c2compiler.cpp
@@ -792,6 +792,7 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) {
case vmIntrinsics::_sha5_implCompress:
case vmIntrinsics::_sha3_implCompress:
case vmIntrinsics::_double_keccak:
+ case vmIntrinsics::_quad_keccak:
case vmIntrinsics::_digestBase_implCompressMB:
case vmIntrinsics::_multiplyToLen:
case vmIntrinsics::_squareToLen:
diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp
index 22acbf1c53e..49e59c70c47 100644
--- a/src/hotspot/share/opto/escape.cpp
+++ b/src/hotspot/share/opto/escape.cpp
@@ -505,19 +505,19 @@ bool ConnectionGraph::can_reduce_phi_check_inputs(PhiNode* ophi) const {
// We can reduce the Cmp if it's a comparison between the Phi and a constant.
// I require the 'other' input to be a constant so that I can move the Cmp
// around safely.
-bool ConnectionGraph::can_reduce_cmp(Node* n, Node* cmp) const {
+bool ConnectionGraph::can_reduce_cmp(PhiNode* phi, Node* cmp) const {
assert(cmp->Opcode() == Op_CmpP || cmp->Opcode() == Op_CmpN, "not expected node: %s", cmp->Name());
Node* left = cmp->in(1);
Node* right = cmp->in(2);
- return (left == n || right == n) &&
+ return (left == phi || right == phi) &&
(left->is_Con() || right->is_Con()) &&
cmp->outcnt() == 1;
}
// We are going to check if any of the SafePointScalarMerge entries
// in the SafePoint reference the Phi that we are checking.
-bool ConnectionGraph::has_been_reduced(PhiNode* n, SafePointNode* sfpt) const {
+bool ConnectionGraph::has_been_reduced(PhiNode* phi, SafePointNode* sfpt) const {
JVMState *jvms = sfpt->jvms();
for (uint i = jvms->debug_start(); i < jvms->debug_end(); i++) {
@@ -525,7 +525,7 @@ bool ConnectionGraph::has_been_reduced(PhiNode* n, SafePointNode* sfpt) const {
if (sfpt_in->is_SafePointScalarMerge()) {
SafePointScalarMergeNode* smerge = sfpt_in->as_SafePointScalarMerge();
Node* nsr_ptr = sfpt->in(smerge->merge_pointer_idx(jvms));
- if (nsr_ptr == n) {
+ if (nsr_ptr == phi) {
return true;
}
}
@@ -542,6 +542,8 @@ bool ConnectionGraph::has_been_reduced(PhiNode* n, SafePointNode* sfpt) const {
// - Phi -> CastPP -> SafePoints
// - Phi -> CastPP -> AddP -> Load
bool ConnectionGraph::can_reduce_check_users(Node* n, uint nesting) const {
+ assert((n->is_Phi() && nesting == 0) || (n->is_CastPP() && nesting > 0),
+ "invalid node class %s and nesting %d combination", n->Name(), nesting);
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
Node* use = n->fast_out(i);
@@ -582,37 +584,21 @@ bool ConnectionGraph::can_reduce_check_users(Node* n, uint nesting) const {
return false;
}
- bool is_trivial_control = use->in(0) == nullptr || use->in(0) == n->in(0);
- if (!is_trivial_control) {
- // If it's not a trivial control then we check if we can reduce the
- // CmpP/N used by the If controlling the cast.
- if (use->in(0)->is_IfTrue() || use->in(0)->is_IfFalse()) {
- Node* iff = use->in(0)->in(0);
- // We may have an OpaqueConstantBool node between If and Bool nodes. But we could also have a sub class of IfNode,
- // for example, an OuterStripMinedLoopEnd or a Parse Predicate. Bail out in all these cases.
- bool can_reduce = (iff->Opcode() == Op_If) && iff->in(1)->is_Bool() && iff->in(1)->in(1)->is_Cmp();
- if (can_reduce) {
- Node* iff_cmp = iff->in(1)->in(1);
- int opc = iff_cmp->Opcode();
- can_reduce = (opc == Op_CmpP || opc == Op_CmpN) && can_reduce_cmp(n, iff_cmp);
- }
- if (!can_reduce) {
-#ifndef PRODUCT
- if (TraceReduceAllocationMerges) {
- tty->print_cr("Can NOT reduce Phi %d on invocation %d. CastPP %d doesn't have simple control.", n->_idx, _invocation, use->_idx);
- n->dump(5);
- }
-#endif
- return false;
- }
+ if (!can_reduce_phi_at_castpp(n->as_Phi(), use->as_CastPP())) {
+#ifdef ASSERT
+ if (TraceReduceAllocationMerges) {
+ tty->print_cr("Can NOT reduce Phi %d on invocation %d. CastPP %d doesn't have simple control.", n->_idx, _invocation, use->_idx);
+ n->dump(5);
}
+#endif
+ return false;
}
if (!can_reduce_check_users(use, nesting+1)) {
return false;
}
} else if (use->Opcode() == Op_CmpP || use->Opcode() == Op_CmpN) {
- if (!can_reduce_cmp(n, use)) {
+ if (!can_reduce_cmp(n->as_Phi(), use)) {
NOT_PRODUCT(if (TraceReduceAllocationMerges) tty->print_cr("Can NOT reduce Phi %d on invocation %d. CmpP/N %d isn't reducible.", n->_idx, _invocation, use->_idx);)
return false;
}
@@ -625,6 +611,33 @@ bool ConnectionGraph::can_reduce_check_users(Node* n, uint nesting) const {
return true;
}
+// Returns true if the CastPP's control is simple enough to reduce the Phi:
+// 1) no control,
+// 2) control is the same Region as the Phi, or
+// 3) an IfTrue/IfFalse coming from an CmpP/N between the phi and a constant.
+bool ConnectionGraph::can_reduce_phi_at_castpp(PhiNode* phi, CastPPNode* castpp) const {
+ if (castpp->in(0) == nullptr || castpp->in(0) == phi->in(0)) {
+ return true;
+ }
+ // If it's not a trivial control then we check if we can reduce the
+ // CmpP/N used by the If controlling the cast.
+ if (!(castpp->in(0)->is_IfTrue() || castpp->in(0)->is_IfFalse())) {
+ return false; // Only If control is considered
+ } else {
+ Node* iff = castpp->in(0)->in(0);
+ // We may have an OpaqueConstantBool node between If and Bool nodes. But we could also have a sub class of IfNode,
+ // for example, an OuterStripMinedLoopEnd or a Parse Predicate. Bail out in all these cases.
+ if (iff->Opcode() == Op_If && iff->in(1)->is_Bool() && iff->in(1)->in(1)->is_Cmp()) {
+ Node* iff_cmp = iff->in(1)->in(1);
+ int opc = iff_cmp->Opcode();
+ if ((opc == Op_CmpP || opc == Op_CmpN) && can_reduce_cmp(phi, iff_cmp)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
// Returns true if: 1) It's profitable to reduce the merge, and 2) The Phi is
// only used in some certain code shapes. Check comments in
// 'can_reduce_phi_inputs' and 'can_reduce_phi_users' for more
@@ -878,9 +891,9 @@ Node* ConnectionGraph::split_castpp_load_through_phi(Node* curr_addp, Node* curr
// \|/
// Phi # "Field" Phi
//
-void ConnectionGraph::reduce_phi_on_castpp_field_load(Node* curr_castpp, GrowableArray &alloc_worklist) {
- Node* ophi = curr_castpp->in(1);
- assert(ophi->is_Phi(), "Expected this to be a Phi node.");
+void ConnectionGraph::reduce_phi_on_castpp_field_load(CastPPNode* curr_castpp, GrowableArray &alloc_worklist) {
+ PhiNode* ophi = curr_castpp->in(1)->as_Phi();
+ precond(can_reduce_phi_at_castpp(ophi, curr_castpp));
// Identify which base should be used for AddP->Load later when spliting the
// CastPP->Loads through ophi. Three kind of values may be stored in this
@@ -1374,7 +1387,7 @@ void ConnectionGraph::reduce_phi(PhiNode* ophi, GrowableArray &alloc_work
// splitting CastPPs we make reference to the inputs of the Cmp that is used
// by the If controlling the CastPP.
for (uint i = 0; i < castpps.size(); i++) {
- reduce_phi_on_castpp_field_load(castpps.at(i), alloc_worklist);
+ reduce_phi_on_castpp_field_load(castpps.at(i)->as_CastPP(), alloc_worklist);
_compile->print_method(PHASE_EA_AFTER_PHI_CASTPP_REDUCTION, 6, castpps.at(i));
}
@@ -2285,6 +2298,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call) {
strcmp(call->as_CallLeaf()->_name, "sha512_implCompressMB") == 0 ||
strcmp(call->as_CallLeaf()->_name, "sha3_implCompress") == 0 ||
strcmp(call->as_CallLeaf()->_name, "double_keccak") == 0 ||
+ strcmp(call->as_CallLeaf()->_name, "quad_keccak") == 0 ||
strcmp(call->as_CallLeaf()->_name, "sha3_implCompressMB") == 0 ||
strcmp(call->as_CallLeaf()->_name, "multiplyToLen") == 0 ||
strcmp(call->as_CallLeaf()->_name, "squareToLen") == 0 ||
diff --git a/src/hotspot/share/opto/escape.hpp b/src/hotspot/share/opto/escape.hpp
index f60807d786a..681f096681a 100644
--- a/src/hotspot/share/opto/escape.hpp
+++ b/src/hotspot/share/opto/escape.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2026, 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
@@ -609,14 +609,15 @@ private:
Node* specialize_cmp(Node* base, Node* curr_ctrl);
Node* specialize_castpp(Node* castpp, Node* base, Node* current_control);
- bool can_reduce_cmp(Node* n, Node* cmp) const;
+ bool can_reduce_cmp(PhiNode* n, Node* cmp) const;
bool has_been_reduced(PhiNode* n, SafePointNode* sfpt) const;
bool can_reduce_phi(PhiNode* ophi) const;
bool can_reduce_check_users(Node* n, uint nesting) const;
bool can_reduce_phi_check_inputs(PhiNode* ophi) const;
+ bool can_reduce_phi_at_castpp(PhiNode* phi, CastPPNode* castpp) const;
void reduce_phi_on_field_access(Node* previous_addp, GrowableArray &alloc_worklist);
- void reduce_phi_on_castpp_field_load(Node* castpp, GrowableArray &alloc_worklist);
+ void reduce_phi_on_castpp_field_load(CastPPNode* castpp, GrowableArray &alloc_worklist);
void reduce_phi_on_cmp(Node* cmp);
bool reduce_phi_on_safepoints(PhiNode* ophi);
bool reduce_phi_on_safepoints_helper(Node* ophi, Node* cast, Node* selector, Unique_Node_List& safepoints);
diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp
index 21b9aa9ed00..7251783d771 100644
--- a/src/hotspot/share/opto/library_call.cpp
+++ b/src/hotspot/share/opto/library_call.cpp
@@ -600,7 +600,8 @@ bool LibraryCallKit::try_to_inline(int predicate) {
case vmIntrinsics::_sha3_implCompress:
return inline_digestBase_implCompress(intrinsic_id());
case vmIntrinsics::_double_keccak:
- return inline_double_keccak();
+ case vmIntrinsics::_quad_keccak:
+ return inline_keccak(intrinsic_id());
case vmIntrinsics::_digestBase_implCompressMB:
return inline_digestBase_implCompressMB(predicate);
@@ -8471,33 +8472,60 @@ bool LibraryCallKit::inline_digestBase_implCompress(vmIntrinsics::ID id) {
return true;
}
-//------------------------------inline_double_keccak
-bool LibraryCallKit::inline_double_keccak() {
- address stubAddr;
+//------------------------------inline_keccak
+bool LibraryCallKit::inline_keccak(vmIntrinsics::ID id) {
+ address stubAddr = nullptr;
const char *stubName;
assert(UseSHA3Intrinsics, "need SHA3 intrinsics support");
- assert(callee()->signature()->size() == 2, "double_keccak has 2 parameters");
+ assert((id == vmIntrinsics::_double_keccak && callee()->signature()->size() == 2) ||
+ (id == vmIntrinsics::_quad_keccak && callee()->signature()->size() == 4),
+ "double_keccak wrong number of parameters");
+
+ int parmCnt = 0;
+ switch (id) {
+ case vmIntrinsics::_double_keccak:
+ stubAddr = StubRoutines::double_keccak();
+ stubName = "double_keccak";
+ parmCnt = 2;
+ break;
+ case vmIntrinsics::_quad_keccak:
+ stubAddr = StubRoutines::quad_keccak();
+ stubName = "quad_keccak";
+ parmCnt = 4;
+ break;
+ default:
+ ShouldNotReachHere();
+ }
- stubAddr = StubRoutines::double_keccak();
- stubName = "double_keccak";
if (!stubAddr) return false;
- Node* status0 = argument(0);
- Node* status1 = argument(1);
+ Node* state[4];
+ for (int i = 0; iskip_assertion_predicates_with_halt();
- Node *iffm = ctrl->in(0);
- Node *opqzm = iffm->in(1)->in(1)->in(2);
- assert(opqzm->in(1) == main_limit, "do not understand situation");
+ Node* const zero_trip_guard_success_proj = cl->skip_assertion_predicates_with_halt();
+ DEBUG_ONLY(ensure_zero_trip_guard_proj(zero_trip_guard_success_proj, true));
+ Node* const zero_trip_guard = zero_trip_guard_success_proj->in(0);
+ Node* const opaque_zero_trip_guard = zero_trip_guard->in(1)->in(1)->in(2);
+ assert(opaque_zero_trip_guard->in(1) == main_limit, "unexpected limit node: %s", opaque_zero_trip_guard->in(1)->Name());
// Find the pre-loop limit; we will expand its iterations to
// not ever trip low tests.
- Node *p_f = iffm->in(0);
+ Node* pre_loop_exit_proj = zero_trip_guard->in(0);
// pre loop may have been optimized out
- if (p_f->Opcode() != Op_IfFalse) {
+ if (!pre_loop_exit_proj->is_IfFalse()) {
return;
}
- CountedLoopEndNode *pre_end = p_f->in(0)->as_CountedLoopEnd();
- assert(pre_end->loopnode()->is_pre_loop(), "");
- Node *pre_opaq1 = pre_end->limit();
+ CountedLoopEndNode* pre_end = pre_loop_exit_proj->in(0)->as_CountedLoopEnd();
+ assert(pre_end->loopnode()->is_pre_loop(), "not a pre loop");
+ Node* pre_loop_limit = pre_end->limit();
// Occasionally it's possible for a pre-loop Opaque1 node to be
// optimized away and then another round of loop opts attempted.
// We can not optimize this particular loop in that case.
- if (pre_opaq1->Opcode() != Op_Opaque1) {
+ if (pre_loop_limit->Opcode() != Op_Opaque1) {
return;
}
- Opaque1Node *pre_opaq = (Opaque1Node*)pre_opaq1;
- Node *pre_limit = pre_opaq->in(1);
+ Opaque1Node* pre_loop_limit_opaque = pre_loop_limit->as_Opaque1();
+ Node* pre_limit = pre_loop_limit_opaque->in(1);
Node* pre_limit_ctrl = get_ctrl(pre_limit);
// Where do we put new limit calculations
@@ -2777,7 +2778,7 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) {
// Ensure the original loop limit is available from the
// pre-loop Opaque1 node.
- Node *orig_limit = pre_opaq->original_loop_limit();
+ Node *orig_limit = pre_loop_limit_opaque->original_loop_limit();
if (orig_limit == nullptr || _igvn.type(orig_limit) == Type::TOP) {
return;
}
@@ -2846,7 +2847,7 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) {
// 'limit' maybe pinned below the zero trip test (probably from a
// previous round of rce), in which case, it can't be used in the
// zero trip test expression which must occur before the zero test's if.
- if (is_dominator(ctrl, limit_ctrl)) {
+ if (is_dominator(zero_trip_guard_success_proj, limit_ctrl)) {
continue; // Don't rce this check but continue looking for other candidates.
}
@@ -2867,7 +2868,7 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) {
// As above for the 'limit', the 'offset' maybe pinned below the
// zero trip test.
- if (is_dominator(ctrl, offset_ctrl)) {
+ if (is_dominator(zero_trip_guard_success_proj, offset_ctrl)) {
continue; // Don't rce this check but continue looking for other candidates.
}
@@ -2902,16 +2903,15 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) {
Node* int_limit = limit;
limit = new ConvI2LNode(limit);
register_new_node(limit, next_limit_ctrl);
+ Node* ctrl_target_for_data_rewire = zero_trip_guard_success_proj;
// Adjust pre and main loop limits to guard the correct iteration set
if (cmp->Opcode() == Op_CmpU) { // Unsigned compare is really 2 tests
- if (b_test._test == BoolTest::lt) { // Range checks always use lt
+ if (b_test._test == BoolTest::lt) {
+ // Range checks always use lt
// The underflow and overflow limits: 0 <= scale*I+offset < limit
add_constraint(stride_con, lscale_con, offset, zero, limit, next_limit_ctrl, &pre_limit, &main_limit);
- Node* init = cl->uncasted_init_trip(true);
- Node* opaque_init = new OpaqueLoopInitNode(C, init);
- register_new_node(opaque_init, loop_entry);
InitializedAssertionPredicateCreator initialized_assertion_predicate_creator(this);
if (abs_stride_is_one) {
@@ -2938,12 +2938,15 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) {
TemplateAssertionPredicateCreator template_assertion_predicate_creator(cl, scale_con , int_offset, int_limit,
this);
loop_entry = template_assertion_predicate_creator.create(loop_entry);
+ // Make sure to rewire data dependencies on the removed check to the Template Assertion Predicate in order
+ // to update them correctly when further splitting the main loop later.
+ ctrl_target_for_data_rewire = loop_entry;
// Initialized Assertion Predicate for the value of the initial main-loop.
+ Node* init = cl->uncasted_init_trip(true);
loop_entry = initialized_assertion_predicate_creator.create(init, loop_entry, stride_con, scale_con,
int_offset, int_limit,
AssertionPredicateType::InitValue);
-
} else {
if (PrintOpto) {
tty->print_cr("missed RCE opportunity");
@@ -2982,6 +2985,7 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) {
continue; // Unhandled case
}
}
+
// Only update variable tracking control for new nodes if it's indeed a range check that can be eliminated (and
// limits are updated)
new_limit_ctrl = next_limit_ctrl;
@@ -2996,10 +3000,10 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) {
// Find loads off the surviving projection; remove their control edge
for (DUIterator_Fast imax, i = dp->fast_outs(imax); i < imax; i++) {
Node* cd = dp->fast_out(i); // Control-dependent node
- if (cd->is_Load() && cd->depends_only_on_test()) { // Loads can now float around in the loop
- // Allow the load to float around in the loop, or before it
- // but NOT before the pre-loop.
- _igvn.replace_input_of(cd, 0, ctrl); // ctrl, not null
+ if (cd->is_Load() && cd->depends_only_on_test()) {
+ // Allow a load to float around in the loop, or before it but after this loop's Template Assertion Predicates
+ // or when absent after the loop's zero trip guard.
+ _igvn.replace_input_of(cd, 0, ctrl_target_for_data_rewire);
--i;
--imax;
}
@@ -3020,13 +3024,13 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) {
}
// new pre_limit can push Bool/Cmp/Opaque nodes down (when one of the eliminated condition has parameters that are not
// loop invariant in the pre loop.
- set_ctrl(pre_opaq, new_limit_ctrl);
+ set_ctrl(pre_loop_limit_opaque, new_limit_ctrl);
// Can't use new_limit_ctrl for Bool/Cmp because it can be out of loop while they are loop variant. Conservatively set
// control to latest possible one.
set_ctrl(pre_end->cmp_node(), pre_end->in(0));
set_ctrl(pre_end->in(1), pre_end->in(0));
- _igvn.replace_input_of(pre_opaq, 1, pre_limit);
+ _igvn.replace_input_of(pre_loop_limit_opaque, 1, pre_limit);
// Note:: we are making the main loop limit no longer precise;
// need to round up based on stride.
@@ -3062,14 +3066,14 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) {
_igvn.replace_node(final_iv_placeholder, final_iv);
}
// The OpaqueNode is unshared by design
- assert(opqzm->outcnt() == 1, "cannot hack shared node");
- _igvn.replace_input_of(opqzm, 1, main_limit);
+ assert(opaque_zero_trip_guard->outcnt() == 1, "cannot hack shared node");
+ _igvn.replace_input_of(opaque_zero_trip_guard, 1, main_limit);
// new main_limit can push opaque node for zero trip guard down (when one of the eliminated condition has parameters
// that are not loop invariant in the pre loop).
- set_ctrl(opqzm, new_limit_ctrl);
+ set_ctrl(opaque_zero_trip_guard, new_limit_ctrl);
// Bool/Cmp nodes for zero trip guard should have been assigned control between the main and pre loop (because zero
// trip guard depends on induction variable value out of pre loop) so shouldn't need to be adjusted
- assert(is_dominator(new_limit_ctrl, get_ctrl(iffm->in(1)->in(1))), "control of cmp should be below control of updated input");
+ assert(is_dominator(new_limit_ctrl, get_ctrl(zero_trip_guard->in(1)->in(1))), "control of cmp should be below control of updated input");
C->print_method(PHASE_AFTER_RANGE_CHECK_ELIMINATION, 4, cl);
}
diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp
index 02a7c21fb5d..1afffcadd6e 100644
--- a/src/hotspot/share/opto/runtime.cpp
+++ b/src/hotspot/share/opto/runtime.cpp
@@ -209,6 +209,7 @@ const TypeFunc* OptoRuntime::_digestBase_implCompress_without_sha3_Type = null
const TypeFunc* OptoRuntime::_digestBase_implCompressMB_with_sha3_Type = nullptr;
const TypeFunc* OptoRuntime::_digestBase_implCompressMB_without_sha3_Type = nullptr;
const TypeFunc* OptoRuntime::_double_keccak_Type = nullptr;
+const TypeFunc* OptoRuntime::_quad_keccak_Type = nullptr;
const TypeFunc* OptoRuntime::_multiplyToLen_Type = nullptr;
const TypeFunc* OptoRuntime::_montgomeryMultiply_Type = nullptr;
const TypeFunc* OptoRuntime::_montgomerySquare_Type = nullptr;
@@ -1221,6 +1222,26 @@ static const TypeFunc* make_double_keccak_Type() {
return TypeFunc::make(domain, range);
}
+static const TypeFunc* make_quad_keccak_Type() {
+ int argcnt = 4;
+
+ const Type** fields = TypeTuple::fields(argcnt);
+ int argp = TypeFunc::Parms;
+ fields[argp++] = TypePtr::NOTNULL; // status0
+ fields[argp++] = TypePtr::NOTNULL; // status1
+ fields[argp++] = TypePtr::NOTNULL; // status2
+ fields[argp++] = TypePtr::NOTNULL; // status3
+
+ assert(argp == TypeFunc::Parms + argcnt, "correct decoding");
+ const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields);
+
+ // result type needed
+ fields = TypeTuple::fields(1);
+ fields[TypeFunc::Parms + 0] = TypeInt::INT;
+ const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields);
+ return TypeFunc::make(domain, range);
+}
+
static const TypeFunc* make_multiplyToLen_Type() {
// create input type (domain)
int num_args = 5;
@@ -2305,6 +2326,7 @@ void OptoRuntime::initialize_types() {
_digestBase_implCompressMB_with_sha3_Type = make_digestBase_implCompressMB_Type(/* is_sha3= */ true);
_digestBase_implCompressMB_without_sha3_Type = make_digestBase_implCompressMB_Type(/* is_sha3= */ false);
_double_keccak_Type = make_double_keccak_Type();
+ _quad_keccak_Type = make_quad_keccak_Type();
_multiplyToLen_Type = make_multiplyToLen_Type();
_montgomeryMultiply_Type = make_montgomeryMultiply_Type();
_montgomerySquare_Type = make_montgomerySquare_Type();
diff --git a/src/hotspot/share/opto/runtime.hpp b/src/hotspot/share/opto/runtime.hpp
index b8cdd9a962a..af8a206e10c 100644
--- a/src/hotspot/share/opto/runtime.hpp
+++ b/src/hotspot/share/opto/runtime.hpp
@@ -162,6 +162,7 @@ class OptoRuntime : public AllStatic {
static const TypeFunc* _digestBase_implCompressMB_with_sha3_Type;
static const TypeFunc* _digestBase_implCompressMB_without_sha3_Type;
static const TypeFunc* _double_keccak_Type;
+ static const TypeFunc* _quad_keccak_Type;
static const TypeFunc* _multiplyToLen_Type;
static const TypeFunc* _montgomeryMultiply_Type;
static const TypeFunc* _montgomerySquare_Type;
@@ -537,6 +538,11 @@ private:
return _double_keccak_Type;
}
+ static inline const TypeFunc* quad_keccak_Type() {
+ assert(_quad_keccak_Type != nullptr, "should be initialized");
+ return _quad_keccak_Type;
+ }
+
static inline const TypeFunc* multiplyToLen_Type() {
assert(_multiplyToLen_Type != nullptr, "should be initialized");
return _multiplyToLen_Type;
diff --git a/src/hotspot/share/runtime/stubDeclarations.hpp b/src/hotspot/share/runtime/stubDeclarations.hpp
index ed1b3ea2e78..bef6a0c27f0 100644
--- a/src/hotspot/share/runtime/stubDeclarations.hpp
+++ b/src/hotspot/share/runtime/stubDeclarations.hpp
@@ -830,6 +830,8 @@
sha3_implCompress) \
do_stub(compiler, double_keccak) \
do_entry(compiler, double_keccak, double_keccak, double_keccak) \
+ do_stub(compiler, quad_keccak) \
+ do_entry(compiler, quad_keccak, quad_keccak, quad_keccak) \
do_stub(compiler, sha3_implCompressMB) \
do_entry(compiler, sha3_implCompressMB, sha3_implCompressMB, \
sha3_implCompressMB) \
diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java b/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java
index 6564f40545a..6bd70c3cdd6 100644
--- a/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java
+++ b/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java
@@ -827,7 +827,7 @@ public final class ML_KEM {
private short[][][] generateA(byte[] rho, Boolean transposed) {
short[][][] a = new short[mlKem_k][mlKem_k][];
- int nrPar = 2;
+ int nrPar = 4;
int rhoLen = rho.length;
byte[] seedBuf = new byte[XOF_BLOCK_LEN];
System.arraycopy(rho, 0, seedBuf, 0, rho.length);
diff --git a/src/java.base/share/classes/sun/security/provider/ML_DSA.java b/src/java.base/share/classes/sun/security/provider/ML_DSA.java
index 1e27349a5d0..9c4e2c898b6 100644
--- a/src/java.base/share/classes/sun/security/provider/ML_DSA.java
+++ b/src/java.base/share/classes/sun/security/provider/ML_DSA.java
@@ -1146,7 +1146,7 @@ public class ML_DSA {
a[i] = new int[mlDsa_l][];
}
- int nrPar = 2;
+ int nrPar = 4;
int rhoLen = seed.length;
byte[] seedBuf = new byte[SHAKE128_BLOCK_SIZE];
System.arraycopy(seed, 0, seedBuf, 0, seed.length);
diff --git a/src/java.base/share/classes/sun/security/provider/SHA3.java b/src/java.base/share/classes/sun/security/provider/SHA3.java
index 5eafface0d3..45599396cdb 100644
--- a/src/java.base/share/classes/sun/security/provider/SHA3.java
+++ b/src/java.base/share/classes/sun/security/provider/SHA3.java
@@ -97,6 +97,7 @@ public abstract class SHA3 extends DigestBase {
private SHA3(String name, int digestLength, byte suffix, int c) {
super(name, digestLength, (WIDTH - c));
this.suffix = suffix;
+ blockSizeCheck();
}
@Override
@@ -113,6 +114,14 @@ public abstract class SHA3 extends DigestBase {
Preconditions.checkIndex(ofs + blockSize - 1, b.length, Preconditions.AIOOBE_FORMATTER);
}
+ private void blockSizeCheck() {
+ switch(blockSize) {
+ case 72, 104, 136, 144, 168: break;
+ default:
+ throw new ProviderException("Invalid SHA3 blocksize:" + blockSize);
+ }
+ }
+
/**
* Core compression function. Processes blockSize bytes at a time
* and updates the state of this object.
diff --git a/src/java.base/share/classes/sun/security/provider/SHA3Parallel.java b/src/java.base/share/classes/sun/security/provider/SHA3Parallel.java
index 0851d4a9216..caf6a7a2899 100644
--- a/src/java.base/share/classes/sun/security/provider/SHA3Parallel.java
+++ b/src/java.base/share/classes/sun/security/provider/SHA3Parallel.java
@@ -36,7 +36,7 @@ import static sun.security.provider.ByteArrayAccess.l2bLittle;
import static sun.security.provider.SHA3.keccak;
/*
- * This class is for making it possible that NRPAR (= 2) (rather restricted)
+ * This class is for making it possible that NRPAR (= 4) (rather restricted)
* SHAKE computations execute in parallel.
* The restrictions are:
* 1. The messages processed should be such that the absorb phase should
@@ -54,7 +54,7 @@ public class SHA3Parallel {
private static final int DM = 5; // dimension of lanesArr
private byte[][] buffers;
private long[][] lanesArr;
- private static final int NRPAR = 2;
+ private static final int NRPAR = 4;
private SHA3Parallel(byte[][] buffers, int blockSize) throws InvalidAlgorithmParameterException {
if ((buffers.length != NRPAR) || (buffers[0].length < blockSize)) {
@@ -81,13 +81,20 @@ public class SHA3Parallel {
}
public int squeezeBlock() {
- int retVal = doubleKeccak(lanesArr[0], lanesArr[1]);
+ int retVal = quadKeccak(lanesArr[0], lanesArr[1], lanesArr[2], lanesArr[3]);
for (int i = 0; i < NRPAR; i++) {
l2bLittle(lanesArr[i], 0, buffers[i], 0, blockSize);
}
return retVal;
}
+ @IntrinsicCandidate
+ private static int quadKeccak(long[] lanes0, long[] lanes1, long[] lanes2, long[] lanes3) {
+ doubleKeccak(lanes0, lanes1);
+ doubleKeccak(lanes2, lanes3);
+ return 1;
+ }
+
@IntrinsicCandidate
private static int doubleKeccak(long[] lanes0, long[] lanes1) {
doubleKeccakJava(lanes0, lanes1);
diff --git a/src/java.desktop/share/classes/java/awt/EventQueue.java b/src/java.desktop/share/classes/java/awt/EventQueue.java
index 5a933a6cdf4..576b4443694 100644
--- a/src/java.desktop/share/classes/java/awt/EventQueue.java
+++ b/src/java.desktop/share/classes/java/awt/EventQueue.java
@@ -853,8 +853,10 @@ public class EventQueue {
newEventQueue.previousQueue = topQueue;
topQueue.nextQueue = newEventQueue;
- if (SunToolkit.currentEventQueue == topQueue) {
- SunToolkit.currentEventQueue = newEventQueue;
+ synchronized (SunToolkit.class) {
+ if (SunToolkit.getSystemEventQueueImplPP() == topQueue) {
+ SunToolkit.currentEventQueue = newEventQueue;
+ }
}
pushPopCond.signalAll();
@@ -913,8 +915,10 @@ public class EventQueue {
topQueue.dispatchThread.setEventQueue(prevQueue);
}
- if (SunToolkit.currentEventQueue == this) {
- SunToolkit.currentEventQueue = prevQueue;
+ synchronized (SunToolkit.class) {
+ if (SunToolkit.getSystemEventQueueImplPP() == this) {
+ SunToolkit.currentEventQueue = prevQueue;
+ }
}
// Wake up EDT waiting in getNextEvent(), so it can
diff --git a/src/java.desktop/share/classes/java/awt/TrayIcon.java b/src/java.desktop/share/classes/java/awt/TrayIcon.java
index c72c018867c..fd4afc3abda 100644
--- a/src/java.desktop/share/classes/java/awt/TrayIcon.java
+++ b/src/java.desktop/share/classes/java/awt/TrayIcon.java
@@ -125,7 +125,6 @@ public class TrayIcon {
if (!SystemTray.isSupported()) {
throw new UnsupportedOperationException();
}
- SunToolkit.insertTargetMapping(this);
}
/**
diff --git a/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java b/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java
index d8f97562c6c..997c3bfd8d9 100644
--- a/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java
+++ b/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java
@@ -99,22 +99,39 @@ public class MultiPixelPackedSampleModel extends SampleModel
* either {@code DataBuffer.TYPE_BYTE},
* {@code DataBuffer.TYPE_USHORT}, or
* {@code DataBuffer.TYPE_INT}
+ * @throws IllegalArgumentException if either {@code w} or {@code h}
+ * is less than or equal to 0
+ * @throws RasterFormatException if the number of bits per pixel
+ * is not a power of 2 or if a power of 2 number of
+ * pixels do not fit in one data element.
*/
public MultiPixelPackedSampleModel(int dataType,
int w,
int h,
int numberOfBits) {
- this(dataType,w,h,
- numberOfBits,
- (w*numberOfBits+DataBuffer.getDataTypeSize(dataType)-1)/
- DataBuffer.getDataTypeSize(dataType),
- 0);
+ long size = (long)w * h;
+ if (w <= 0 || h <= 0) {
+ throw new IllegalArgumentException("Width ("+w+") and height ("+
+ h+") must be > 0");
+ }
+ if (size > Integer.MAX_VALUE) {
+ throw new IllegalArgumentException("Dimensions (width="+w+
+ " height="+h+") are too large");
+ }
+
if (dataType != DataBuffer.TYPE_BYTE &&
dataType != DataBuffer.TYPE_USHORT &&
- dataType != DataBuffer.TYPE_INT) {
- throw new IllegalArgumentException("Unsupported data type "+
+ dataType != DataBuffer.TYPE_INT)
+ {
+ throw new IllegalArgumentException("Unsupported dataType: "+
dataType);
}
+ long sls = ((long)w*numberOfBits+DataBuffer.getDataTypeSize(dataType)-1)/
+ DataBuffer.getDataTypeSize(dataType);
+ if (sls > Integer.MAX_VALUE) {
+ throw new RasterFormatException("Pixels do not fit");
+ }
+ this(dataType, w, h, numberOfBits, (int)sls, 0);
}
/**
@@ -130,15 +147,23 @@ public class MultiPixelPackedSampleModel extends SampleModel
* @param scanlineStride the line stride of the image data
* @param dataBitOffset the data bit offset for the region of image
* data described
- * @throws RasterFormatException if the number of bits per pixel
- * is not a power of 2 or if a power of 2 number of
- * pixels do not fit in one data element.
- * @throws IllegalArgumentException if {@code w} or
- * {@code h} is not greater than 0
* @throws IllegalArgumentException if {@code dataType} is not
* either {@code DataBuffer.TYPE_BYTE},
* {@code DataBuffer.TYPE_USHORT}, or
* {@code DataBuffer.TYPE_INT}
+ * @throws IllegalArgumentException if either {@code w} or {@code h}
+ * is less than or equal to 0
+ * @throws IllegalArgumentException if {@code scanlineStride}
+ * is less than or equal to 0
+ * @throws RasterFormatException if
+ * {@code ((numberOfBits * (long)w) + DataBuffer.getDataTypeSize(dataType) - 1)
+ * / DataBuffer.getDataTypeSize(dataType)}
+ * is greater than {@code scanlineStride}
+ * @throws RasterFormatException if the number of bits per pixel
+ * is not a power of 2 or if a power of 2 number of
+ * pixels do not fit in one data element.
+ * @throws IllegalArgumentException if {@code dataBitOffset} is less than zero,
+ * or not a multiple of {@code numberOfBits}.
*/
public MultiPixelPackedSampleModel(int dataType, int w, int h,
int numberOfBits,
@@ -151,11 +176,27 @@ public class MultiPixelPackedSampleModel extends SampleModel
throw new IllegalArgumentException("Unsupported data type "+
dataType);
}
+ if ((numberOfBits <= 0) || ((numberOfBits & (numberOfBits - 1)) != 0)) {
+ throw new RasterFormatException("numberOfBits per pixel must be a power of 2");
+ }
+ if (scanlineStride <= 0) {
+ throw new IllegalArgumentException("scanlineStride must be > 0");
+ }
+ int dataTypeSize = DataBuffer.getDataTypeSize(dataType);
+ if ((((numberOfBits * (long)w) + dataTypeSize - 1) / dataTypeSize) > scanlineStride) {
+ throw new RasterFormatException("scanlineStride is too small for width");
+ }
+ if (dataBitOffset < 0) {
+ throw new IllegalArgumentException("dataBitOffset must be >= 0");
+ }
+ if ((dataBitOffset % numberOfBits) != 0) {
+ throw new IllegalArgumentException("dataBitOffset must be a multiple of bits per pixel");
+ }
this.dataType = dataType;
this.pixelBitStride = numberOfBits;
this.scanlineStride = scanlineStride;
this.dataBitOffset = dataBitOffset;
- this.dataElementSize = DataBuffer.getDataTypeSize(dataType);
+ this.dataElementSize = dataTypeSize;
this.pixelsPerDataElement = dataElementSize/numberOfBits;
if (pixelsPerDataElement*numberOfBits != dataElementSize) {
throw new RasterFormatException("MultiPixelPackedSampleModel " +
@@ -320,22 +361,12 @@ public class MultiPixelPackedSampleModel extends SampleModel
* subset of the bands of this
* {@code MultiPixelPackedSampleModel}. Since a
* {@code MultiPixelPackedSampleModel} only has one band, the
- * bands argument must have a length of one and indicate the zeroth
- * band.
- * @param bands the specified bands
- * @return a new {@code SampleModel} with a subset of bands of
+ * bands argument is ignored.
+ * @param bands the specified bands (ignored)
+ * @return a new {@code SampleModel} with the same bands as
* this {@code MultiPixelPackedSampleModel}.
- * @throws RasterFormatException if the number of bands requested
- * is not one.
- * @throws IllegalArgumentException if {@code w} or
- * {@code h} is not greater than 0
*/
public SampleModel createSubsetSampleModel(int[] bands) {
- if (bands != null) {
- if (bands.length != 1)
- throw new RasterFormatException("MultiPixelPackedSampleModel has "
- + "only one band.");
- }
SampleModel sm = createCompatibleSampleModel(width, height);
return sm;
}
diff --git a/src/java.desktop/share/classes/java/awt/image/Raster.java b/src/java.desktop/share/classes/java/awt/image/Raster.java
index 3312a39b693..8f35d5819ab 100644
--- a/src/java.desktop/share/classes/java/awt/image/Raster.java
+++ b/src/java.desktop/share/classes/java/awt/image/Raster.java
@@ -200,8 +200,8 @@ public class Raster {
* @throws IllegalArgumentException if {@code bands} is less than 1
* @throws IllegalArgumentException if {@code w} and {@code h} are not
* both > 0
- * @throws IllegalArgumentException if the product of {@code w}
- * and {@code h} is greater than {@code Integer.MAX_VALUE}
+ * @throws IllegalArgumentException if the product of {@code w},
+ * {@code h} and {@code bands} is greater than {@code Integer.MAX_VALUE}
* @throws RasterFormatException if computing either
* {@code location.x + w} or
* {@code location.y + h} results in integer overflow
@@ -218,6 +218,14 @@ public class Raster {
throw new IllegalArgumentException("Dimensions (width="+w+
" height="+h+") are too large");
}
+ if (bands < 1) {
+ throw new IllegalArgumentException("Number of bands ("+
+ bands+") must be greater than 0");
+ }
+ long slsz = (long)w * bands;
+ if (slsz > Integer.MAX_VALUE) {
+ throw new IllegalArgumentException("width * bands is too large");
+ }
int[] bandOffsets = new int[bands];
for (int i = 0; i < bands; i++) {
bandOffsets[i] = i;
diff --git a/src/java.desktop/share/classes/sun/awt/AppContext.java b/src/java.desktop/share/classes/sun/awt/AppContext.java
deleted file mode 100644
index b81869040b4..00000000000
--- a/src/java.desktop/share/classes/sun/awt/AppContext.java
+++ /dev/null
@@ -1,692 +0,0 @@
-/*
- * Copyright (c) 1998, 2026, 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. Oracle 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.
- *
- * 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 sun.awt;
-
-import java.awt.EventQueue;
-import java.awt.Window;
-import java.awt.SystemTray;
-import java.awt.TrayIcon;
-import java.awt.Toolkit;
-import java.awt.GraphicsEnvironment;
-import java.awt.event.InvocationEvent;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.IdentityHashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.HashSet;
-import java.beans.PropertyChangeSupport;
-import java.beans.PropertyChangeListener;
-import java.lang.ref.SoftReference;
-
-import sun.util.logging.PlatformLogger;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * The AppContext is a table referenced by ThreadGroup which stores
- * application service instances. (If you are not writing an application
- * service, or don't know what one is, please do not use this class.)
- * The AppContext allows a context access to what would otherwise be
- * potentially dangerous services, such as the ability to peek at
- * EventQueues or change the look-and-feel of a Swing application.
- *
- * Most application services use a singleton object to provide their
- * services, either as a default (such as getSystemEventQueue or
- * getDefaultToolkit) or as static methods with class data (System).
- * The AppContext works with the former method by extending the concept
- * of "default" to be ThreadGroup-specific. Application services
- * lookup their singleton in the AppContext.
- *
- * For example, here we have a Foo service, with its pre-AppContext
- * code:
- *
{@code
- * public class Foo {
- * private static Foo defaultFoo = new Foo();
- *
- * public static Foo getDefaultFoo() {
- * return defaultFoo;
- * }
- *
- * ... Foo service methods
- * }
- * }
- *
- * The problem with the above is that the Foo service is global in scope,
- * so that untrusted code can execute methods on the
- * single, shared Foo instance. The Foo service therefore either needs
- * to block its use by untrusted code using a SecurityManager test, or
- * restrict its capabilities so that it doesn't matter if untrusted code
- * executes it.
- *
- * Here's the Foo class written to use the AppContext:
- *
- * Since a separate AppContext can exist for each ThreadGroup, trusted
- * and untrusted code have access to different Foo instances. This allows
- * untrusted code access to "system-wide" services -- the service remains
- * within the AppContext "sandbox". For example, say malicious code
- * wants to peek all of the key events on the EventQueue to listen for
- * passwords; if separate EventQueues are used for each ThreadGroup
- * using AppContexts, the only key events that code will be able to
- * listen to are its own. A more reasonable request would be to
- * change the Swing default look-and-feel; with that default stored in
- * an AppContext, the look-and-feel will change without
- * disrupting other contexts.
- *
- * @author Thomas Ball
- * @author Fred Ecks
- */
-public final class AppContext {
- private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.AppContext");
-
- /* Since the contents of an AppContext are unique to each Java
- * session, this class should never be serialized. */
-
- /* A map of AppContexts, referenced by ThreadGroup.
- */
- private static final Map threadGroup2appContext =
- Collections.synchronizedMap(new IdentityHashMap());
-
- /**
- * Returns a set containing all {@code AppContext}s.
- */
- public static Set getAppContexts() {
- synchronized (threadGroup2appContext) {
- return new HashSet(threadGroup2appContext.values());
- }
- }
-
- /* The main "system" AppContext, used by everything not otherwise
- contained in another AppContext. It is implicitly created for
- standalone apps only.
- */
- private static volatile AppContext mainAppContext;
-
- private static class GetAppContextLock {}
- private static final Object getAppContextLock = new GetAppContextLock();
-
- /*
- * The hash map associated with this AppContext. A private delegate
- * is used instead of subclassing HashMap so as to avoid all of
- * HashMap's potentially risky methods, such as clear(), elements(),
- * putAll(), etc.
- */
- private final Map