Merge branch 'JDK-8348611' into JDK-8344159

This commit is contained in:
Archie L. Cobbs 2025-07-03 16:06:42 -05:00
commit a0d489596d
196 changed files with 3471 additions and 1349 deletions

View File

@ -62,5 +62,8 @@
// thread so it is easier to track down. You can override these options by setting the environment
// variable UBSAN_OPTIONS.
ATTRIBUTE_DEFAULT_VISIBILITY ATTRIBUTE_USED const char* __ubsan_default_options() {
return "halt_on_error=1,print_stacktrace=1" _LLVM_SYMBOLIZER(LLVM_SYMBOLIZER);
return "halt_on_error=1,"
"handle_segv=0,"
"handle_sigbus=0,"
"print_stacktrace=1" _LLVM_SYMBOLIZER(LLVM_SYMBOLIZER);
}

View File

@ -543,7 +543,7 @@ void MacroAssembler::generate__ieee754_rem_pio2(address npio2_hw,
// }
//
// /* compute n */
// z = scalbnA(z,q0); /* actual value of z */
// z = scalbn(z,q0); /* actual value of z */
// z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */
// n = (int) z;
// z -= (double)n;
@ -576,7 +576,7 @@ void MacroAssembler::generate__ieee754_rem_pio2(address npio2_hw,
// }
// if(ih==2) {
// z = one - z;
// if(carry!=0) z -= scalbnA(one,q0);
// if(carry!=0) z -= scalbn(one,q0);
// }
// }
//
@ -602,7 +602,7 @@ void MacroAssembler::generate__ieee754_rem_pio2(address npio2_hw,
// jz -= 1; q0 -= 24;
// while(iq[jz]==0) { jz--; q0-=24;}
// } else { /* break z into 24-bit if necessary */
// z = scalbnA(z,-q0);
// z = scalbn(z,-q0);
// if(z>=two24B) {
// fw = (double)((int)(twon24*z));
// iq[jz] = (int)(z-two24B*fw);
@ -612,7 +612,7 @@ void MacroAssembler::generate__ieee754_rem_pio2(address npio2_hw,
// }
//
// /* convert integer "bit" chunk to floating-point value */
// fw = scalbnA(one,q0);
// fw = scalbn(one,q0);
// for(i=jz;i>=0;i--) {
// q[i] = fw*(double)iq[i]; fw*=twon24;
// }
@ -925,7 +925,7 @@ void MacroAssembler::generate__kernel_rem_pio2(address two_over_pi, address pio2
fmovd(v25, 1.0);
fsubd(v18, v25, v18); // z = one - z;
cbzw(rscratch2, IH_HANDLED);
fsubd(v18, v18, v30); // z -= scalbnA(one,q0);
fsubd(v18, v18, v30); // z -= scalbn(one,q0);
}
}
bind(IH_HANDLED);
@ -1026,7 +1026,7 @@ void MacroAssembler::generate__kernel_rem_pio2(address two_over_pi, address pio2
bind(Z_ZERO_CHECK_DONE);
// convert integer "bit" chunk to floating-point value
// v17 = twon24
// update v30, which was scalbnA(1.0, <old q0>);
// update v30, which was scalbn(1.0, <old q0>);
addw(tmp2, rscratch1, 1023); // biased exponent
lsl(tmp2, tmp2, 52); // put at correct position
mov(i, jz);

View File

@ -8257,6 +8257,14 @@ void Assembler::vmaxsh(XMMRegister dst, XMMRegister nds, XMMRegister src) {
emit_int16(0x5F, (0xC0 | encode));
}
void Assembler::eminmaxsh(XMMRegister dst, XMMRegister nds, XMMRegister src, int imm8) {
assert(VM_Version::supports_avx10_2(), "");
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3A, &attributes);
emit_int24(0x53, (0xC0 | encode), imm8);
}
void Assembler::vminsh(XMMRegister dst, XMMRegister nds, XMMRegister src) {
assert(VM_Version::supports_avx512_fp16(), "requires AVX512-FP16");
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
@ -8771,12 +8779,68 @@ void Assembler::vmaxps(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve
emit_int16(0x5F, (0xC0 | encode));
}
void Assembler::evminmaxps(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int imm8, int vector_len) {
assert(VM_Version::supports_avx10_2(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
attributes.reset_is_clear_context();
}
int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
emit_int24(0x52, (0xC0 | encode), imm8);
}
void Assembler::evminmaxps(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int imm8, int vector_len) {
assert(VM_Version::supports_avx10_2(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
if (merge) {
attributes.reset_is_clear_context();
}
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
emit_int8(0x52);
emit_operand(dst, src, 0);
emit_int8(imm8);
}
void Assembler::maxpd(XMMRegister dst, XMMRegister src) {
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int16(0x5F, (0xC0 | encode));
}
void Assembler::evminmaxpd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int imm8, int vector_len) {
assert(VM_Version::supports_avx10_2(), "");
InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
attributes.reset_is_clear_context();
}
int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
emit_int24(0x52, (0xC0 | encode), imm8);
}
void Assembler::evminmaxpd(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int imm8, int vector_len) {
assert(VM_Version::supports_avx10_2(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
if (merge) {
attributes.reset_is_clear_context();
}
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
emit_int8(0x52);
emit_operand(dst, src, 0);
emit_int8(imm8);
}
void Assembler::vmaxpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
assert(vector_len >= AVX_512bit ? VM_Version::supports_evex() : VM_Version::supports_avx(), "");
InstructionAttr attributes(vector_len, /* vex_w */true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
@ -13119,6 +13183,14 @@ void Assembler::vminss(XMMRegister dst, XMMRegister nds, XMMRegister src) {
emit_int16(0x5D, (0xC0 | encode));
}
void Assembler::eminmaxss(XMMRegister dst, XMMRegister nds, XMMRegister src, int imm8) {
assert(VM_Version::supports_avx10_2(), "");
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
emit_int24(0x53, (0xC0 | encode), imm8);
}
void Assembler::vminsd(XMMRegister dst, XMMRegister nds, XMMRegister src) {
assert(VM_Version::supports_avx(), "");
InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
@ -13127,6 +13199,14 @@ void Assembler::vminsd(XMMRegister dst, XMMRegister nds, XMMRegister src) {
emit_int16(0x5D, (0xC0 | encode));
}
void Assembler::eminmaxsd(XMMRegister dst, XMMRegister nds, XMMRegister src, int imm8) {
assert(VM_Version::supports_avx10_2(), "");
InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
emit_int24(0x53, (0xC0 | encode), imm8);
}
void Assembler::vcmppd(XMMRegister dst, XMMRegister nds, XMMRegister src, int cop, int vector_len) {
assert(VM_Version::supports_avx(), "");
assert(vector_len <= AVX_256bit, "");
@ -16526,6 +16606,34 @@ void Assembler::evminph(XMMRegister dst, XMMRegister nds, Address src, int vecto
emit_operand(dst, src, 0);
}
void Assembler::evminmaxph(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int imm8, int vector_len) {
assert(VM_Version::supports_avx10_2(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
attributes.reset_is_clear_context();
}
int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3A, &attributes);
emit_int24(0x52, (0xC0 | encode), imm8);
}
void Assembler::evminmaxph(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int imm8, int vector_len) {
assert(VM_Version::supports_avx10_2(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
attributes.reset_is_clear_context();
}
attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3A, &attributes);
emit_int8(0x52);
emit_operand(dst, src, 0);
emit_int8(imm8);
}
void Assembler::evmaxph(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
assert(VM_Version::supports_avx512_fp16(), "requires AVX512-FP16");
assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), "");

View File

@ -441,6 +441,17 @@ class InstructionAttr;
// See fxsave and xsave(EVEX enabled) documentation for layout
const int FPUStateSizeInWords = 2688 / wordSize;
// AVX10 new minmax instruction control mask encoding.
//
// imm8[4] = 0 (please refer to Table 11.1 of section 11.2 of AVX10 manual[1] for details)
// imm8[3:2] (sign control) = 01 (select sign, please refer to Table 11.5 of section 11.2 of AVX10 manual[1] for details)
// imm8[1:0] = 00 (min) / 01 (max)
//
// [1] https://www.intel.com/content/www/us/en/content-details/856721/intel-advanced-vector-extensions-10-2-intel-avx10-2-architecture-specification.html?wapkw=AVX10
const int AVX10_MINMAX_MAX_COMPARE_SIGN = 0x5;
const int AVX10_MINMAX_MIN_COMPARE_SIGN = 0x4;
// The Intel x86/Amd64 Assembler: Pure assembler doing NO optimizations on the instruction
// level (e.g. mov rax, 0 is not translated into xor rax, rax!); i.e., what you write
// is what you get. The Assembler is generating code into a CodeBuffer.
@ -2745,6 +2756,17 @@ private:
void minpd(XMMRegister dst, XMMRegister src);
void vminpd(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len);
// AVX10.2 floating point minmax instructions
void eminmaxsh(XMMRegister dst, XMMRegister nds, XMMRegister src, int imm8);
void eminmaxss(XMMRegister dst, XMMRegister nds, XMMRegister src, int imm8);
void eminmaxsd(XMMRegister dst, XMMRegister nds, XMMRegister src, int imm8);
void evminmaxph(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int imm8, int vector_len);
void evminmaxph(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int imm8, int vector_len);
void evminmaxps(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int imm8, int vector_len);
void evminmaxps(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int imm8, int vector_len);
void evminmaxpd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int imm8, int vector_len);
void evminmaxpd(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int imm8, int vector_len);
// Maximum of packed integers
void pmaxsb(XMMRegister dst, XMMRegister src);
void vpmaxsb(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len);

View File

@ -1230,6 +1230,21 @@ void C2_MacroAssembler::evminmax_fp(int opcode, BasicType elem_bt,
}
}
void C2_MacroAssembler::vminmax_fp(int opc, BasicType elem_bt, XMMRegister dst, KRegister mask,
XMMRegister src1, XMMRegister src2, int vlen_enc) {
assert(opc == Op_MinV || opc == Op_MinReductionV ||
opc == Op_MaxV || opc == Op_MaxReductionV, "sanity");
int imm8 = (opc == Op_MinV || opc == Op_MinReductionV) ? AVX10_MINMAX_MIN_COMPARE_SIGN
: AVX10_MINMAX_MAX_COMPARE_SIGN;
if (elem_bt == T_FLOAT) {
evminmaxps(dst, mask, src1, src2, true, imm8, vlen_enc);
} else {
assert(elem_bt == T_DOUBLE, "");
evminmaxpd(dst, mask, src1, src2, true, imm8, vlen_enc);
}
}
// Float/Double signum
void C2_MacroAssembler::signum_fp(int opcode, XMMRegister dst, XMMRegister zero, XMMRegister one) {
assert(opcode == Op_SignumF || opcode == Op_SignumD, "sanity");
@ -2537,12 +2552,21 @@ void C2_MacroAssembler::reduceFloatMinMax(int opcode, int vlen, bool is_dst_vali
} else { // i = [0,1]
vpermilps(wtmp, wsrc, permconst[i], vlen_enc);
}
vminmax_fp(opcode, T_FLOAT, wdst, wtmp, wsrc, tmp, atmp, btmp, vlen_enc);
if (VM_Version::supports_avx10_2()) {
vminmax_fp(opcode, T_FLOAT, wdst, k0, wtmp, wsrc, vlen_enc);
} else {
vminmax_fp(opcode, T_FLOAT, wdst, wtmp, wsrc, tmp, atmp, btmp, vlen_enc);
}
wsrc = wdst;
vlen_enc = Assembler::AVX_128bit;
}
if (is_dst_valid) {
vminmax_fp(opcode, T_FLOAT, dst, wdst, dst, tmp, atmp, btmp, Assembler::AVX_128bit);
if (VM_Version::supports_avx10_2()) {
vminmax_fp(opcode, T_FLOAT, dst, k0, wdst, dst, Assembler::AVX_128bit);
} else {
vminmax_fp(opcode, T_FLOAT, dst, wdst, dst, tmp, atmp, btmp, Assembler::AVX_128bit);
}
}
}
@ -2568,12 +2592,23 @@ void C2_MacroAssembler::reduceDoubleMinMax(int opcode, int vlen, bool is_dst_val
assert(i == 0, "%d", i);
vpermilpd(wtmp, wsrc, 1, vlen_enc);
}
vminmax_fp(opcode, T_DOUBLE, wdst, wtmp, wsrc, tmp, atmp, btmp, vlen_enc);
if (VM_Version::supports_avx10_2()) {
vminmax_fp(opcode, T_DOUBLE, wdst, k0, wtmp, wsrc, vlen_enc);
} else {
vminmax_fp(opcode, T_DOUBLE, wdst, wtmp, wsrc, tmp, atmp, btmp, vlen_enc);
}
wsrc = wdst;
vlen_enc = Assembler::AVX_128bit;
}
if (is_dst_valid) {
vminmax_fp(opcode, T_DOUBLE, dst, wdst, dst, tmp, atmp, btmp, Assembler::AVX_128bit);
if (VM_Version::supports_avx10_2()) {
vminmax_fp(opcode, T_DOUBLE, dst, k0, wdst, dst, Assembler::AVX_128bit);
} else {
vminmax_fp(opcode, T_DOUBLE, dst, wdst, dst, tmp, atmp, btmp, Assembler::AVX_128bit);
}
}
}

View File

@ -72,6 +72,9 @@ public:
XMMRegister tmp, XMMRegister atmp, XMMRegister btmp,
int vlen_enc);
void vminmax_fp(int opc, BasicType elem_bt, XMMRegister dst, KRegister mask,
XMMRegister src1, XMMRegister src2, int vlen_enc);
void vpuminmaxq(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister xtmp1, XMMRegister xtmp2, int vlen_enc);
void evminmax_fp(int opcode, BasicType elem_bt,

View File

@ -8841,6 +8841,10 @@ void MacroAssembler::evpmins(BasicType type, XMMRegister dst, KRegister mask, XM
evpminsd(dst, mask, nds, src, merge, vector_len); break;
case T_LONG:
evpminsq(dst, mask, nds, src, merge, vector_len); break;
case T_FLOAT:
evminmaxps(dst, mask, nds, src, merge, AVX10_MINMAX_MIN_COMPARE_SIGN, vector_len); break;
case T_DOUBLE:
evminmaxpd(dst, mask, nds, src, merge, AVX10_MINMAX_MIN_COMPARE_SIGN, vector_len); break;
default:
fatal("Unexpected type argument %s", type2name(type)); break;
}
@ -8856,6 +8860,10 @@ void MacroAssembler::evpmaxs(BasicType type, XMMRegister dst, KRegister mask, XM
evpmaxsd(dst, mask, nds, src, merge, vector_len); break;
case T_LONG:
evpmaxsq(dst, mask, nds, src, merge, vector_len); break;
case T_FLOAT:
evminmaxps(dst, mask, nds, src, merge, AVX10_MINMAX_MAX_COMPARE_SIGN, vector_len); break;
case T_DOUBLE:
evminmaxpd(dst, mask, nds, src, merge, AVX10_MINMAX_MAX_COMPARE_SIGN, vector_len); break;
default:
fatal("Unexpected type argument %s", type2name(type)); break;
}
@ -8871,6 +8879,10 @@ void MacroAssembler::evpmins(BasicType type, XMMRegister dst, KRegister mask, XM
evpminsd(dst, mask, nds, src, merge, vector_len); break;
case T_LONG:
evpminsq(dst, mask, nds, src, merge, vector_len); break;
case T_FLOAT:
evminmaxps(dst, mask, nds, src, merge, AVX10_MINMAX_MIN_COMPARE_SIGN, vector_len); break;
case T_DOUBLE:
evminmaxpd(dst, mask, nds, src, merge, AVX10_MINMAX_MIN_COMPARE_SIGN, vector_len); break;
default:
fatal("Unexpected type argument %s", type2name(type)); break;
}
@ -8886,6 +8898,10 @@ void MacroAssembler::evpmaxs(BasicType type, XMMRegister dst, KRegister mask, XM
evpmaxsd(dst, mask, nds, src, merge, vector_len); break;
case T_LONG:
evpmaxsq(dst, mask, nds, src, merge, vector_len); break;
case T_FLOAT:
evminmaxps(dst, mask, nds, src, merge, AVX10_MINMAX_MAX_COMPARE_SIGN, vector_len); break;
case T_DOUBLE:
evminmaxps(dst, mask, nds, src, merge, AVX10_MINMAX_MAX_COMPARE_SIGN, vector_len); break;
default:
fatal("Unexpected type argument %s", type2name(type)); break;
}

View File

@ -46,6 +46,12 @@
//
/******************************************************************************/
/* Represents 0x7FFFFFFFFFFFFFFF double precision in lower 64 bits*/
ATTRIBUTE_ALIGNED(16) static const juint _ABS_MASK[] =
{
4294967295, 2147483647, 0, 0
};
ATTRIBUTE_ALIGNED(4) static const juint _SIG_MASK[] =
{
0, 1032192
@ -188,10 +194,10 @@ address StubGenerator::generate_libmCbrt() {
StubCodeMark mark(this, stub_id);
address start = __ pc();
Label L_2TAG_PACKET_0_0_1, L_2TAG_PACKET_1_0_1, L_2TAG_PACKET_2_0_1, L_2TAG_PACKET_3_0_1;
Label L_2TAG_PACKET_4_0_1, L_2TAG_PACKET_5_0_1, L_2TAG_PACKET_6_0_1;
Label L_2TAG_PACKET_0_0_1, L_2TAG_PACKET_1_0_1, L_2TAG_PACKET_2_0_1;
Label B1_1, B1_2, B1_4;
address ABS_MASK = (address)_ABS_MASK;
address SIG_MASK = (address)_SIG_MASK;
address EXP_MASK = (address)_EXP_MASK;
address EXP_MSK2 = (address)_EXP_MSK2;
@ -208,8 +214,12 @@ address StubGenerator::generate_libmCbrt() {
__ enter(); // required for proper stackwalking of RuntimeStub frame
__ bind(B1_1);
__ subq(rsp, 24);
__ movsd(Address(rsp), xmm0);
__ ucomisd(xmm0, ExternalAddress(ZERON), r11 /*rscratch*/);
__ jcc(Assembler::equal, L_2TAG_PACKET_1_0_1); // Branch only if x is +/- zero or NaN
__ movq(xmm1, xmm0);
__ andpd(xmm1, ExternalAddress(ABS_MASK), r11 /*rscratch*/);
__ ucomisd(xmm1, ExternalAddress(INF), r11 /*rscratch*/);
__ jcc(Assembler::equal, B1_4); // Branch only if x is +/- INF
__ bind(B1_2);
__ movq(xmm7, xmm0);
@ -228,8 +238,6 @@ address StubGenerator::generate_libmCbrt() {
__ andl(rdx, rax);
__ cmpl(rdx, 0);
__ jcc(Assembler::equal, L_2TAG_PACKET_0_0_1); // Branch only if |x| is denormalized
__ cmpl(rdx, 524032);
__ jcc(Assembler::equal, L_2TAG_PACKET_1_0_1); // Branch only if |x| is INF or NaN
__ shrl(rdx, 8);
__ shrq(r9, 8);
__ andpd(xmm2, xmm0);
@ -297,8 +305,6 @@ address StubGenerator::generate_libmCbrt() {
__ andl(rdx, rax);
__ shrl(rdx, 8);
__ shrq(r9, 8);
__ cmpl(rdx, 0);
__ jcc(Assembler::equal, L_2TAG_PACKET_3_0_1); // Branch only if |x| is zero
__ andpd(xmm2, xmm0);
__ andpd(xmm0, xmm5);
__ orpd(xmm3, xmm2);
@ -322,41 +328,10 @@ address StubGenerator::generate_libmCbrt() {
__ psllq(xmm7, 52);
__ jmp(L_2TAG_PACKET_2_0_1);
__ bind(L_2TAG_PACKET_3_0_1);
__ cmpq(r9, 0);
__ jcc(Assembler::notEqual, L_2TAG_PACKET_4_0_1); // Branch only if x is negative zero
__ xorpd(xmm0, xmm0);
__ jmp(B1_4);
__ bind(L_2TAG_PACKET_4_0_1);
__ movsd(xmm0, ExternalAddress(ZERON), r11 /*rscratch*/);
__ jmp(B1_4);
__ bind(L_2TAG_PACKET_1_0_1);
__ movl(rax, Address(rsp, 4));
__ movl(rdx, Address(rsp));
__ movl(rcx, rax);
__ andl(rcx, 2147483647);
__ cmpl(rcx, 2146435072);
__ jcc(Assembler::above, L_2TAG_PACKET_5_0_1); // Branch only if |x| is NaN
__ cmpl(rdx, 0);
__ jcc(Assembler::notEqual, L_2TAG_PACKET_5_0_1); // Branch only if |x| is NaN
__ cmpl(rax, 2146435072);
__ jcc(Assembler::notEqual, L_2TAG_PACKET_6_0_1); // Branch only if x is negative INF
__ movsd(xmm0, ExternalAddress(INF), r11 /*rscratch*/);
__ jmp(B1_4);
__ bind(L_2TAG_PACKET_6_0_1);
__ movsd(xmm0, ExternalAddress(NEG_INF), r11 /*rscratch*/);
__ jmp(B1_4);
__ bind(L_2TAG_PACKET_5_0_1);
__ movsd(xmm0, Address(rsp));
__ addsd(xmm0, xmm0);
__ movq(Address(rsp, 8), xmm0);
__ bind(B1_4);
__ addq(rsp, 24);
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);

View File

@ -2024,7 +2024,7 @@ bool Matcher::match_rule_supported_vector_masked(int opcode, int vlen, BasicType
if (is_subword_type(bt) && !VM_Version::supports_avx512bw()) {
return false; // Implementation limitation
}
if (is_floating_point_type(bt)) {
if (is_floating_point_type(bt) && !VM_Version::supports_avx10_2()) {
return false; // Implementation limitation
}
return true;
@ -5293,9 +5293,9 @@ instruct mul_reduction64B(rRegI dst, rRegI src1, legVec src2, legVec vtmp1, legV
//--------------------Min/Max Float Reduction --------------------
// Float Min Reduction
instruct minmax_reduction2F(legRegF dst, immF src1, legVec src2, legVec tmp,
legVec atmp, legVec btmp, legVec xmm_1, rFlagsReg cr) %{
predicate(Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT &&
instruct minmax_reduction2F(legRegF dst, immF src1, legVec src2, legVec tmp, legVec atmp,
legVec btmp, legVec xmm_1, rFlagsReg cr) %{
predicate(!VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT &&
((n->Opcode() == Op_MinReductionV && n->in(1)->bottom_type() == TypeF::POS_INF) ||
(n->Opcode() == Op_MaxReductionV && n->in(1)->bottom_type() == TypeF::NEG_INF)) &&
Matcher::vector_length(n->in(2)) == 2);
@ -5316,7 +5316,7 @@ instruct minmax_reduction2F(legRegF dst, immF src1, legVec src2, legVec tmp,
instruct minmax_reductionF(legRegF dst, immF src1, legVec src2, legVec tmp, legVec atmp,
legVec btmp, legVec xmm_0, legVec xmm_1, rFlagsReg cr) %{
predicate(Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT &&
predicate(!VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT &&
((n->Opcode() == Op_MinReductionV && n->in(1)->bottom_type() == TypeF::POS_INF) ||
(n->Opcode() == Op_MaxReductionV && n->in(1)->bottom_type() == TypeF::NEG_INF)) &&
Matcher::vector_length(n->in(2)) >= 4);
@ -5335,9 +5335,9 @@ instruct minmax_reductionF(legRegF dst, immF src1, legVec src2, legVec tmp, legV
ins_pipe( pipe_slow );
%}
instruct minmax_reduction2F_av(legRegF dst, legVec src, legVec tmp,
legVec atmp, legVec btmp, legVec xmm_1, rFlagsReg cr) %{
predicate(Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT &&
instruct minmax_reduction2F_av(legRegF dst, legVec src, legVec tmp, legVec atmp,
legVec btmp, legVec xmm_1, rFlagsReg cr) %{
predicate(!VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT &&
Matcher::vector_length(n->in(2)) == 2);
match(Set dst (MinReductionV dst src));
match(Set dst (MaxReductionV dst src));
@ -5355,9 +5355,9 @@ instruct minmax_reduction2F_av(legRegF dst, legVec src, legVec tmp,
%}
instruct minmax_reductionF_av(legRegF dst, legVec src, legVec tmp,
legVec atmp, legVec btmp, legVec xmm_0, legVec xmm_1, rFlagsReg cr) %{
predicate(Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT &&
instruct minmax_reductionF_av(legRegF dst, legVec src, legVec tmp, legVec atmp, legVec btmp,
legVec xmm_0, legVec xmm_1, rFlagsReg cr) %{
predicate(!VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT &&
Matcher::vector_length(n->in(2)) >= 4);
match(Set dst (MinReductionV dst src));
match(Set dst (MaxReductionV dst src));
@ -5374,12 +5374,78 @@ instruct minmax_reductionF_av(legRegF dst, legVec src, legVec tmp,
ins_pipe( pipe_slow );
%}
instruct minmax_reduction2F_avx10(regF dst, immF src1, vec src2, vec xtmp1) %{
predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT &&
((n->Opcode() == Op_MinReductionV && n->in(1)->bottom_type() == TypeF::POS_INF) ||
(n->Opcode() == Op_MaxReductionV && n->in(1)->bottom_type() == TypeF::NEG_INF)) &&
Matcher::vector_length(n->in(2)) == 2);
match(Set dst (MinReductionV src1 src2));
match(Set dst (MaxReductionV src1 src2));
effect(TEMP dst, TEMP xtmp1);
format %{ "vector_minmax_reduction $dst, $src1, $src2 \t; using $xtmp1 as TEMP" %}
ins_encode %{
int opcode = this->ideal_Opcode();
int vlen = Matcher::vector_length(this, $src2);
__ reduceFloatMinMax(opcode, vlen, false, $dst$$XMMRegister, $src2$$XMMRegister,
xnoreg, xnoreg, xnoreg, $xtmp1$$XMMRegister);
%}
ins_pipe( pipe_slow );
%}
instruct minmax_reductionF_avx10(regF dst, immF src1, vec src2, vec xtmp1, vec xtmp2) %{
predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT &&
((n->Opcode() == Op_MinReductionV && n->in(1)->bottom_type() == TypeF::POS_INF) ||
(n->Opcode() == Op_MaxReductionV && n->in(1)->bottom_type() == TypeF::NEG_INF)) &&
Matcher::vector_length(n->in(2)) >= 4);
match(Set dst (MinReductionV src1 src2));
match(Set dst (MaxReductionV src1 src2));
effect(TEMP dst, TEMP xtmp1, TEMP xtmp2);
format %{ "vector_minmax_reduction $dst, $src1, $src2 \t; using $xtmp1 and $xtmp2 as TEMP" %}
ins_encode %{
int opcode = this->ideal_Opcode();
int vlen = Matcher::vector_length(this, $src2);
__ reduceFloatMinMax(opcode, vlen, false, $dst$$XMMRegister, $src2$$XMMRegister, xnoreg, xnoreg,
xnoreg, $xtmp1$$XMMRegister, $xtmp2$$XMMRegister);
%}
ins_pipe( pipe_slow );
%}
instruct minmax_reduction2F_avx10_av(regF dst, vec src, vec xtmp1) %{
predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT &&
Matcher::vector_length(n->in(2)) == 2);
match(Set dst (MinReductionV dst src));
match(Set dst (MaxReductionV dst src));
effect(TEMP dst, TEMP xtmp1);
format %{ "vector_minmax2F_reduction $dst, $src \t; using $xtmp1 as TEMP" %}
ins_encode %{
int opcode = this->ideal_Opcode();
int vlen = Matcher::vector_length(this, $src);
__ reduceFloatMinMax(opcode, vlen, true, $dst$$XMMRegister, $src$$XMMRegister, xnoreg, xnoreg, xnoreg,
$xtmp1$$XMMRegister);
%}
ins_pipe( pipe_slow );
%}
instruct minmax_reductionF_avx10_av(regF dst, vec src, vec xtmp1, vec xtmp2) %{
predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT &&
Matcher::vector_length(n->in(2)) >= 4);
match(Set dst (MinReductionV dst src));
match(Set dst (MaxReductionV dst src));
effect(TEMP dst, TEMP xtmp1, TEMP xtmp2);
format %{ "vector_minmax2F_reduction $dst, $src \t; using $xtmp1 and $xtmp2 as TEMP" %}
ins_encode %{
int opcode = this->ideal_Opcode();
int vlen = Matcher::vector_length(this, $src);
__ reduceFloatMinMax(opcode, vlen, true, $dst$$XMMRegister, $src$$XMMRegister, xnoreg, xnoreg, xnoreg,
$xtmp1$$XMMRegister, $xtmp2$$XMMRegister);
%}
ins_pipe( pipe_slow );
%}
//--------------------Min Double Reduction --------------------
instruct minmax_reduction2D(legRegD dst, immD src1, legVec src2,
legVec tmp1, legVec tmp2, legVec tmp3, legVec tmp4, // TEMPs
rFlagsReg cr) %{
predicate(Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE &&
instruct minmax_reduction2D(legRegD dst, immD src1, legVec src2, legVec tmp1, legVec tmp2,
legVec tmp3, legVec tmp4, rFlagsReg cr) %{
predicate(!VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE &&
((n->Opcode() == Op_MinReductionV && n->in(1)->bottom_type() == TypeD::POS_INF) ||
(n->Opcode() == Op_MaxReductionV && n->in(1)->bottom_type() == TypeD::NEG_INF)) &&
Matcher::vector_length(n->in(2)) == 2);
@ -5398,10 +5464,9 @@ instruct minmax_reduction2D(legRegD dst, immD src1, legVec src2,
ins_pipe( pipe_slow );
%}
instruct minmax_reductionD(legRegD dst, immD src1, legVec src2,
legVec tmp1, legVec tmp2, legVec tmp3, legVec tmp4, legVec tmp5, // TEMPs
rFlagsReg cr) %{
predicate(Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE &&
instruct minmax_reductionD(legRegD dst, immD src1, legVec src2, legVec tmp1, legVec tmp2,
legVec tmp3, legVec tmp4, legVec tmp5, rFlagsReg cr) %{
predicate(!VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE &&
((n->Opcode() == Op_MinReductionV && n->in(1)->bottom_type() == TypeD::POS_INF) ||
(n->Opcode() == Op_MaxReductionV && n->in(1)->bottom_type() == TypeD::NEG_INF)) &&
Matcher::vector_length(n->in(2)) >= 4);
@ -5421,10 +5486,9 @@ instruct minmax_reductionD(legRegD dst, immD src1, legVec src2,
%}
instruct minmax_reduction2D_av(legRegD dst, legVec src,
legVec tmp1, legVec tmp2, legVec tmp3, legVec tmp4, // TEMPs
rFlagsReg cr) %{
predicate(Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE &&
instruct minmax_reduction2D_av(legRegD dst, legVec src, legVec tmp1, legVec tmp2,
legVec tmp3, legVec tmp4, rFlagsReg cr) %{
predicate(!VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE &&
Matcher::vector_length(n->in(2)) == 2);
match(Set dst (MinReductionV dst src));
match(Set dst (MaxReductionV dst src));
@ -5441,10 +5505,9 @@ instruct minmax_reduction2D_av(legRegD dst, legVec src,
ins_pipe( pipe_slow );
%}
instruct minmax_reductionD_av(legRegD dst, legVec src,
legVec tmp1, legVec tmp2, legVec tmp3, legVec tmp4, legVec tmp5, // TEMPs
rFlagsReg cr) %{
predicate(Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE &&
instruct minmax_reductionD_av(legRegD dst, legVec src, legVec tmp1, legVec tmp2, legVec tmp3,
legVec tmp4, legVec tmp5, rFlagsReg cr) %{
predicate(!VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE &&
Matcher::vector_length(n->in(2)) >= 4);
match(Set dst (MinReductionV dst src));
match(Set dst (MaxReductionV dst src));
@ -5461,6 +5524,75 @@ instruct minmax_reductionD_av(legRegD dst, legVec src,
ins_pipe( pipe_slow );
%}
instruct minmax_reduction2D_avx10(regD dst, immD src1, vec src2, vec xtmp1) %{
predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE &&
((n->Opcode() == Op_MinReductionV && n->in(1)->bottom_type() == TypeD::POS_INF) ||
(n->Opcode() == Op_MaxReductionV && n->in(1)->bottom_type() == TypeD::NEG_INF)) &&
Matcher::vector_length(n->in(2)) == 2);
match(Set dst (MinReductionV src1 src2));
match(Set dst (MaxReductionV src1 src2));
effect(TEMP dst, TEMP xtmp1);
format %{ "vector_minmax2D_reduction $dst, $src1, $src2 ; using $xtmp1 as TEMP" %}
ins_encode %{
int opcode = this->ideal_Opcode();
int vlen = Matcher::vector_length(this, $src2);
__ reduceDoubleMinMax(opcode, vlen, false, $dst$$XMMRegister, $src2$$XMMRegister, xnoreg,
xnoreg, xnoreg, $xtmp1$$XMMRegister);
%}
ins_pipe( pipe_slow );
%}
instruct minmax_reductionD_avx10(regD dst, immD src1, vec src2, vec xtmp1, vec xtmp2) %{
predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE &&
((n->Opcode() == Op_MinReductionV && n->in(1)->bottom_type() == TypeD::POS_INF) ||
(n->Opcode() == Op_MaxReductionV && n->in(1)->bottom_type() == TypeD::NEG_INF)) &&
Matcher::vector_length(n->in(2)) >= 4);
match(Set dst (MinReductionV src1 src2));
match(Set dst (MaxReductionV src1 src2));
effect(TEMP dst, TEMP xtmp1, TEMP xtmp2);
format %{ "vector_minmaxD_reduction $dst, $src1, $src2 ; using $xtmp1 and $xtmp2 as TEMP" %}
ins_encode %{
int opcode = this->ideal_Opcode();
int vlen = Matcher::vector_length(this, $src2);
__ reduceDoubleMinMax(opcode, vlen, false, $dst$$XMMRegister, $src2$$XMMRegister, xnoreg, xnoreg,
xnoreg, $xtmp1$$XMMRegister, $xtmp2$$XMMRegister);
%}
ins_pipe( pipe_slow );
%}
instruct minmax_reduction2D_av_avx10(regD dst, vec src, vec xtmp1) %{
predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE &&
Matcher::vector_length(n->in(2)) == 2);
match(Set dst (MinReductionV dst src));
match(Set dst (MaxReductionV dst src));
effect(TEMP dst, TEMP xtmp1);
format %{ "vector_minmax2D_reduction $dst, $src ; using $xtmp1 as TEMP" %}
ins_encode %{
int opcode = this->ideal_Opcode();
int vlen = Matcher::vector_length(this, $src);
__ reduceDoubleMinMax(opcode, vlen, true, $dst$$XMMRegister, $src$$XMMRegister,
xnoreg, xnoreg, xnoreg, $xtmp1$$XMMRegister);
%}
ins_pipe( pipe_slow );
%}
instruct minmax_reductionD_av_avx10(regD dst, vec src, vec xtmp1, vec xtmp2) %{
predicate(VM_Version::supports_avx10_2() && Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE &&
Matcher::vector_length(n->in(2)) >= 4);
match(Set dst (MinReductionV dst src));
match(Set dst (MaxReductionV dst src));
effect(TEMP dst, TEMP xtmp1, TEMP xtmp2);
format %{ "vector_minmaxD_reduction $dst, $src ; using $xtmp1 and $xtmp2 as TEMP" %}
ins_encode %{
int opcode = this->ideal_Opcode();
int vlen = Matcher::vector_length(this, $src);
__ reduceDoubleMinMax(opcode, vlen, true, $dst$$XMMRegister, $src$$XMMRegister,
xnoreg, xnoreg, xnoreg, $xtmp1$$XMMRegister, $xtmp2$$XMMRegister);
%}
ins_pipe( pipe_slow );
%}
// ====================VECTOR ARITHMETIC=======================================
// --------------------------------- ADD --------------------------------------
@ -6347,9 +6479,25 @@ instruct vminmaxL_reg_evex(vec dst, vec src1, vec src2) %{
ins_pipe( pipe_slow );
%}
// Float/Double vector Min/Max
instruct minmaxFP_avx10_reg(vec dst, vec a, vec b) %{
predicate(VM_Version::supports_avx10_2() &&
is_floating_point_type(Matcher::vector_element_basic_type(n))); // T_FLOAT, T_DOUBLE
match(Set dst (MinV a b));
match(Set dst (MaxV a b));
format %{ "vector_minmaxFP $dst, $a, $b" %}
ins_encode %{
int vlen_enc = vector_length_encoding(this);
int opcode = this->ideal_Opcode();
BasicType elem_bt = Matcher::vector_element_basic_type(this);
__ vminmax_fp(opcode, elem_bt, $dst$$XMMRegister, k0, $a$$XMMRegister, $b$$XMMRegister, vlen_enc);
%}
ins_pipe( pipe_slow );
%}
// Float/Double vector Min/Max
instruct minmaxFP_reg(legVec dst, legVec a, legVec b, legVec tmp, legVec atmp, legVec btmp) %{
predicate(Matcher::vector_length_in_bytes(n) <= 32 &&
predicate(!VM_Version::supports_avx10_2() && Matcher::vector_length_in_bytes(n) <= 32 &&
is_floating_point_type(Matcher::vector_element_basic_type(n)) && // T_FLOAT, T_DOUBLE
UseAVX > 0);
match(Set dst (MinV a b));
@ -6370,8 +6518,8 @@ instruct minmaxFP_reg(legVec dst, legVec a, legVec b, legVec tmp, legVec atmp, l
ins_pipe( pipe_slow );
%}
instruct evminmaxFP_reg_eavx(vec dst, vec a, vec b, vec atmp, vec btmp, kReg ktmp) %{
predicate(Matcher::vector_length_in_bytes(n) == 64 &&
instruct evminmaxFP_reg_evex(vec dst, vec a, vec b, vec atmp, vec btmp, kReg ktmp) %{
predicate(!VM_Version::supports_avx10_2() && Matcher::vector_length_in_bytes(n) == 64 &&
is_floating_point_type(Matcher::vector_element_basic_type(n))); // T_FLOAT, T_DOUBLE
match(Set dst (MinV a b));
match(Set dst (MaxV a b));
@ -10686,8 +10834,22 @@ instruct scalar_binOps_HF_reg(regF dst, regF src1, regF src2)
ins_pipe(pipe_slow);
%}
instruct scalar_minmax_HF_avx10_reg(regF dst, regF src1, regF src2)
%{
predicate(VM_Version::supports_avx10_2());
match(Set dst (MaxHF src1 src2));
match(Set dst (MinHF src1 src2));
format %{ "scalar_min_max_fp16 $dst, $src1, $src2" %}
ins_encode %{
int function = this->ideal_Opcode() == Op_MinHF ? AVX10_MINMAX_MIN_COMPARE_SIGN : AVX10_MINMAX_MAX_COMPARE_SIGN;
__ eminmaxsh($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, function);
%}
ins_pipe( pipe_slow );
%}
instruct scalar_minmax_HF_reg(regF dst, regF src1, regF src2, kReg ktmp, regF xtmp1, regF xtmp2)
%{
predicate(!VM_Version::supports_avx10_2());
match(Set dst (MaxHF src1 src2));
match(Set dst (MinHF src1 src2));
effect(TEMP_DEF dst, TEMP ktmp, TEMP xtmp1, TEMP xtmp2);
@ -10787,8 +10949,37 @@ instruct vector_fma_HF_mem(vec dst, memory src1, vec src2)
ins_pipe( pipe_slow );
%}
instruct vector_minmax_HF_avx10_mem(vec dst, vec src1, memory src2)
%{
predicate(VM_Version::supports_avx10_2());
match(Set dst (MinVHF src1 (VectorReinterpret (LoadVector src2))));
match(Set dst (MaxVHF src1 (VectorReinterpret (LoadVector src2))));
format %{ "vector_min_max_fp16_mem $dst, $src1, $src2" %}
ins_encode %{
int vlen_enc = vector_length_encoding(this);
int function = this->ideal_Opcode() == Op_MinVHF ? AVX10_MINMAX_MIN_COMPARE_SIGN : AVX10_MINMAX_MAX_COMPARE_SIGN;
__ evminmaxph($dst$$XMMRegister, k0, $src1$$XMMRegister, $src2$$Address, true, function, vlen_enc);
%}
ins_pipe( pipe_slow );
%}
instruct vector_minmax_HF_avx10_reg(vec dst, vec src1, vec src2)
%{
predicate(VM_Version::supports_avx10_2());
match(Set dst (MinVHF src1 src2));
match(Set dst (MaxVHF src1 src2));
format %{ "vector_min_max_fp16 $dst, $src1, $src2" %}
ins_encode %{
int vlen_enc = vector_length_encoding(this);
int function = this->ideal_Opcode() == Op_MinVHF ? AVX10_MINMAX_MIN_COMPARE_SIGN : AVX10_MINMAX_MAX_COMPARE_SIGN;
__ evminmaxph($dst$$XMMRegister, k0, $src1$$XMMRegister, $src2$$XMMRegister, true, function, vlen_enc);
%}
ins_pipe( pipe_slow );
%}
instruct vector_minmax_HF_reg(vec dst, vec src1, vec src2, kReg ktmp, vec xtmp1, vec xtmp2)
%{
predicate(!VM_Version::supports_avx10_2());
match(Set dst (MinVHF src1 src2));
match(Set dst (MaxVHF src1 src2));
effect(TEMP_DEF dst, TEMP ktmp, TEMP xtmp1, TEMP xtmp2);

View File

@ -4450,9 +4450,20 @@ instruct loadD(regD dst, memory mem)
ins_pipe(pipe_slow); // XXX
%}
// max = java.lang.Math.max(float a, float b)
instruct maxF_avx10_reg(regF dst, regF a, regF b) %{
predicate(VM_Version::supports_avx10_2());
match(Set dst (MaxF a b));
format %{ "maxF $dst, $a, $b" %}
ins_encode %{
__ eminmaxss($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_MINMAX_MAX_COMPARE_SIGN);
%}
ins_pipe( pipe_slow );
%}
// max = java.lang.Math.max(float a, float b)
instruct maxF_reg(legRegF dst, legRegF a, legRegF b, legRegF tmp, legRegF atmp, legRegF btmp) %{
predicate(UseAVX > 0 && !VLoopReductions::is_reduction(n));
predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && !VLoopReductions::is_reduction(n));
match(Set dst (MaxF a b));
effect(USE a, USE b, TEMP tmp, TEMP atmp, TEMP btmp);
format %{ "maxF $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %}
@ -4463,7 +4474,7 @@ instruct maxF_reg(legRegF dst, legRegF a, legRegF b, legRegF tmp, legRegF atmp,
%}
instruct maxF_reduction_reg(legRegF dst, legRegF a, legRegF b, legRegF xtmp, rRegI rtmp, rFlagsReg cr) %{
predicate(UseAVX > 0 && VLoopReductions::is_reduction(n));
predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n));
match(Set dst (MaxF a b));
effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr);
@ -4475,9 +4486,20 @@ instruct maxF_reduction_reg(legRegF dst, legRegF a, legRegF b, legRegF xtmp, rRe
ins_pipe( pipe_slow );
%}
// max = java.lang.Math.max(double a, double b)
instruct maxD_avx10_reg(regD dst, regD a, regD b) %{
predicate(VM_Version::supports_avx10_2());
match(Set dst (MaxD a b));
format %{ "maxD $dst, $a, $b" %}
ins_encode %{
__ eminmaxsd($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_MINMAX_MAX_COMPARE_SIGN);
%}
ins_pipe( pipe_slow );
%}
// max = java.lang.Math.max(double a, double b)
instruct maxD_reg(legRegD dst, legRegD a, legRegD b, legRegD tmp, legRegD atmp, legRegD btmp) %{
predicate(UseAVX > 0 && !VLoopReductions::is_reduction(n));
predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && !VLoopReductions::is_reduction(n));
match(Set dst (MaxD a b));
effect(USE a, USE b, TEMP atmp, TEMP btmp, TEMP tmp);
format %{ "maxD $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %}
@ -4488,7 +4510,7 @@ instruct maxD_reg(legRegD dst, legRegD a, legRegD b, legRegD tmp, legRegD atmp,
%}
instruct maxD_reduction_reg(legRegD dst, legRegD a, legRegD b, legRegD xtmp, rRegL rtmp, rFlagsReg cr) %{
predicate(UseAVX > 0 && VLoopReductions::is_reduction(n));
predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n));
match(Set dst (MaxD a b));
effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr);
@ -4500,9 +4522,20 @@ instruct maxD_reduction_reg(legRegD dst, legRegD a, legRegD b, legRegD xtmp, rRe
ins_pipe( pipe_slow );
%}
// max = java.lang.Math.min(float a, float b)
instruct minF_avx10_reg(regF dst, regF a, regF b) %{
predicate(VM_Version::supports_avx10_2());
match(Set dst (MinF a b));
format %{ "minF $dst, $a, $b" %}
ins_encode %{
__ eminmaxss($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_MINMAX_MIN_COMPARE_SIGN);
%}
ins_pipe( pipe_slow );
%}
// min = java.lang.Math.min(float a, float b)
instruct minF_reg(legRegF dst, legRegF a, legRegF b, legRegF tmp, legRegF atmp, legRegF btmp) %{
predicate(UseAVX > 0 && !VLoopReductions::is_reduction(n));
predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && !VLoopReductions::is_reduction(n));
match(Set dst (MinF a b));
effect(USE a, USE b, TEMP tmp, TEMP atmp, TEMP btmp);
format %{ "minF $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %}
@ -4513,7 +4546,7 @@ instruct minF_reg(legRegF dst, legRegF a, legRegF b, legRegF tmp, legRegF atmp,
%}
instruct minF_reduction_reg(legRegF dst, legRegF a, legRegF b, legRegF xtmp, rRegI rtmp, rFlagsReg cr) %{
predicate(UseAVX > 0 && VLoopReductions::is_reduction(n));
predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n));
match(Set dst (MinF a b));
effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr);
@ -4525,9 +4558,20 @@ instruct minF_reduction_reg(legRegF dst, legRegF a, legRegF b, legRegF xtmp, rRe
ins_pipe( pipe_slow );
%}
// max = java.lang.Math.min(double a, double b)
instruct minD_avx10_reg(regD dst, regD a, regD b) %{
predicate(VM_Version::supports_avx10_2());
match(Set dst (MinD a b));
format %{ "minD $dst, $a, $b" %}
ins_encode %{
__ eminmaxsd($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_MINMAX_MIN_COMPARE_SIGN);
%}
ins_pipe( pipe_slow );
%}
// min = java.lang.Math.min(double a, double b)
instruct minD_reg(legRegD dst, legRegD a, legRegD b, legRegD tmp, legRegD atmp, legRegD btmp) %{
predicate(UseAVX > 0 && !VLoopReductions::is_reduction(n));
predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && !VLoopReductions::is_reduction(n));
match(Set dst (MinD a b));
effect(USE a, USE b, TEMP tmp, TEMP atmp, TEMP btmp);
format %{ "minD $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %}
@ -4538,7 +4582,7 @@ instruct minD_reg(legRegD dst, legRegD a, legRegD b, legRegD tmp, legRegD atmp,
%}
instruct minD_reduction_reg(legRegD dst, legRegD a, legRegD b, legRegD xtmp, rRegL rtmp, rFlagsReg cr) %{
predicate(UseAVX > 0 && VLoopReductions::is_reduction(n));
predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n));
match(Set dst (MinD a b));
effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr);
@ -6379,7 +6423,7 @@ instruct cmovI_rReg_rReg_memU_ndd(rRegI dst, cmpOpU cop, rFlagsRegU cr, rRegI sr
ins_pipe(pipe_cmov_mem);
%}
instruct cmovI_rReg_rReg_memUCF_ndd(rRegI dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegI src1, memory src2)
instruct cmovI_rReg_rReg_memUCF_ndd(rRegI dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegI src1, memory src2)
%{
predicate(UseAPX);
match(Set dst (CMoveI (Binary cop cr) (Binary src1 (LoadI src2))));
@ -6762,7 +6806,7 @@ instruct cmovL_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegL dst, rRegL src) %{
%}
%}
instruct cmovL_regUCF_ndd(rRegL dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegL src1, rRegL src2)
instruct cmovL_regUCF_ndd(rRegL dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegL src1, rRegL src2)
%{
predicate(UseAPX);
match(Set dst (CMoveL (Binary cop cr) (Binary src1 src2)));
@ -6869,7 +6913,7 @@ instruct cmovL_rReg_rReg_memU_ndd(rRegL dst, cmpOpU cop, rFlagsRegU cr, rRegL sr
ins_pipe(pipe_cmov_mem);
%}
instruct cmovL_rReg_rReg_memUCF_ndd(rRegL dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegL src1, memory src2)
instruct cmovL_rReg_rReg_memUCF_ndd(rRegL dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegL src1, memory src2)
%{
predicate(UseAPX);
match(Set dst (CMoveL (Binary cop cr) (Binary src1 (LoadL src2))));

View File

@ -879,17 +879,6 @@ void os::free_thread(OSThread* osthread) {
////////////////////////////////////////////////////////////////////////////////
// time support
double os::elapsedVTime() {
struct rusage usage;
int retval = getrusage(RUSAGE_THREAD, &usage);
if (retval == 0) {
return usage.ru_utime.tv_sec + usage.ru_stime.tv_sec + (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec) / (1000.0 * 1000);
} else {
// better than nothing, but not much
return elapsedTime();
}
}
// We use mread_real_time here.
// On AIX: If the CPU has a time register, the result will be RTC_POWER and
// it has to be converted to real time. AIX documentations suggests to do
@ -2441,7 +2430,7 @@ static bool thread_cpu_time_unchecked(Thread* thread, jlong* p_sys_time, jlong*
dummy, &dummy_size) == 0) {
tid = pinfo.__pi_tid;
} else {
tty->print_cr("pthread_getthrds_np failed.");
tty->print_cr("pthread_getthrds_np failed, errno: %d.", errno);
error = true;
}
@ -2452,7 +2441,7 @@ static bool thread_cpu_time_unchecked(Thread* thread, jlong* p_sys_time, jlong*
sys_time = thrdentry.ti_ru.ru_stime.tv_sec * 1000000000LL + thrdentry.ti_ru.ru_stime.tv_usec * 1000LL;
user_time = thrdentry.ti_ru.ru_utime.tv_sec * 1000000000LL + thrdentry.ti_ru.ru_utime.tv_usec * 1000LL;
} else {
tty->print_cr("pthread_getthrds_np failed.");
tty->print_cr("getthrds64 failed, errno: %d.", errno);
error = true;
}
}

View File

@ -782,10 +782,6 @@ void os::free_thread(OSThread* osthread) {
////////////////////////////////////////////////////////////////////////////////
// time support
double os::elapsedVTime() {
// better than nothing, but not much
return elapsedTime();
}
#ifdef __APPLE__
void os::Bsd::clock_init() {

View File

@ -1487,16 +1487,6 @@ void os::Linux::capture_initial_stack(size_t max_size) {
////////////////////////////////////////////////////////////////////////////////
// time support
double os::elapsedVTime() {
struct rusage usage;
int retval = getrusage(RUSAGE_THREAD, &usage);
if (retval == 0) {
return (double) (usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) + (double) (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec) / (1000 * 1000);
} else {
// better than nothing, but not much
return elapsedTime();
}
}
void os::Linux::fast_thread_clock_init() {
clockid_t clockid;

View File

@ -1599,8 +1599,6 @@ jlong os::elapsed_frequency() {
return NANOSECS_PER_SEC; // nanosecond resolution
}
bool os::supports_vtime() { return true; }
// Return the real, user, and system times in seconds from an
// arbitrary fixed point in the past.
bool os::getTimesSecs(double* process_real_time,

View File

@ -1194,21 +1194,6 @@ FILETIME java_to_windows_time(jlong l) {
return result;
}
bool os::supports_vtime() { return true; }
double os::elapsedVTime() {
FILETIME created;
FILETIME exited;
FILETIME kernel;
FILETIME user;
if (GetThreadTimes(GetCurrentThread(), &created, &exited, &kernel, &user) != 0) {
// the resolution of windows_to_java_time() should be sufficient (ms)
return (double) (windows_to_java_time(kernel) + windows_to_java_time(user)) / MILLIUNITS;
} else {
return elapsedTime();
}
}
jlong os::javaTimeMillis() {
FILETIME wt;
GetSystemTimeAsFileTime(&wt);

View File

@ -30,6 +30,7 @@
#include "cds/dumpTimeClassInfo.inline.hpp"
#include "cds/heapShared.hpp"
#include "cds/lambdaProxyClassDictionary.hpp"
#include "cds/regeneratedClasses.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "logging/log.hpp"
#include "memory/metaspaceClosure.hpp"
@ -188,7 +189,11 @@ void AOTArtifactFinder::end_scanning_for_oops() {
void AOTArtifactFinder::add_aot_inited_class(InstanceKlass* ik) {
if (CDSConfig::is_initing_classes_at_dump_time()) {
assert(ik->is_initialized(), "must be");
if (RegeneratedClasses::is_regenerated_object(ik)) {
precond(RegeneratedClasses::get_original_object(ik)->is_initialized());
} else {
precond(ik->is_initialized());
}
add_cached_instance_class(ik);
bool created;
@ -243,6 +248,11 @@ void AOTArtifactFinder::add_cached_instance_class(InstanceKlass* ik) {
add_cached_instance_class(intf);
}
InstanceKlass* nest_host = ik->nest_host_or_null();
if (nest_host != nullptr) {
add_cached_instance_class(nest_host);
}
if (CDSConfig::is_dumping_final_static_archive() && ik->defined_by_other_loaders()) {
// The following are not appliable to unregistered classes
return;

View File

@ -26,6 +26,7 @@
#include "cds/archiveBuilder.hpp"
#include "cds/cdsConfig.hpp"
#include "cds/heapShared.hpp"
#include "cds/regeneratedClasses.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "classfile/vmSymbols.hpp"
@ -103,6 +104,10 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
return false;
}
if (RegeneratedClasses::is_regenerated_object(ik)) {
ik = RegeneratedClasses::get_original_object(ik);
}
if (!ik->is_initialized() && !ik->is_being_initialized()) {
return false;
}

View File

@ -575,6 +575,9 @@ ArchiveBuilder::FollowMode ArchiveBuilder::get_follow_mode(MetaspaceClosure::Ref
if (ref->msotype() == MetaspaceObj::ClassType) {
Klass* klass = (Klass*)ref->obj();
assert(klass->is_klass(), "must be");
if (RegeneratedClasses::has_been_regenerated(klass)) {
klass = RegeneratedClasses::get_regenerated_object(klass);
}
if (is_excluded(klass)) {
ResourceMark rm;
log_debug(cds, dynamic)("Skipping class (excluded): %s", klass->external_name());

View File

@ -27,6 +27,7 @@
#include "cds/cdsConfig.hpp"
#include "cds/filemap.hpp"
#include "cds/heapShared.hpp"
#include "cds/regeneratedClasses.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/modules.hpp"
#include "classfile/systemDictionary.hpp"
@ -543,6 +544,10 @@ template <typename T> void ArchiveHeapWriter::relocate_field_in_buffer(T* field_
oop source_referent = load_source_oop_from_buffer<T>(field_addr_in_buffer);
if (source_referent != nullptr) {
if (java_lang_Class::is_instance(source_referent)) {
Klass* k = java_lang_Class::as_Klass(source_referent);
if (RegeneratedClasses::has_been_regenerated(k)) {
source_referent = RegeneratedClasses::get_regenerated_object(k)->java_mirror();
}
// When the source object points to a "real" mirror, the buffered object should point
// to the "scratch" mirror, which has all unarchivable fields scrubbed (to be reinstated
// at run time).
@ -754,6 +759,11 @@ void ArchiveHeapWriter::compute_ptrmap(ArchiveHeapInfo* heap_info) {
Metadata** buffered_field_addr = requested_addr_to_buffered_addr(requested_field_addr);
Metadata* native_ptr = *buffered_field_addr;
guarantee(native_ptr != nullptr, "sanity");
if (RegeneratedClasses::has_been_regenerated(native_ptr)) {
native_ptr = RegeneratedClasses::get_regenerated_object(native_ptr);
}
guarantee(ArchiveBuilder::current()->has_been_buffered((address)native_ptr),
"Metadata %p should have been archived", native_ptr);

View File

@ -817,9 +817,6 @@ bool CDSConfig::is_dumping_regenerated_lambdaform_invokers() {
// that point to the lambda form invokers in the base archive. Such pointers will
// be invalid if lambda form invokers are regenerated in the dynamic archive.
return false;
} else if (CDSConfig::is_dumping_method_handles()) {
// Work around JDK-8310831, as some methods in lambda form holder classes may not get generated.
return false;
} else {
return is_dumping_archive();
}

View File

@ -147,7 +147,7 @@
product(bool, AOTVerifyTrainingData, trueInDebug, DIAGNOSTIC, \
"Verify archived training data") \
\
product(bool, AOTCompileEagerly, false, DIAGNOSTIC, \
product(bool, AOTCompileEagerly, false, EXPERIMENTAL, \
"Compile methods as soon as possible") \
\
/* AOT Code flags */ \

View File

@ -36,6 +36,7 @@
#include "cds/cdsHeapVerifier.hpp"
#include "cds/heapShared.hpp"
#include "cds/metaspaceShared.hpp"
#include "cds/regeneratedClasses.hpp"
#include "classfile/classLoaderData.hpp"
#include "classfile/classLoaderExt.hpp"
#include "classfile/javaClasses.inline.hpp"
@ -337,6 +338,9 @@ bool HeapShared::archive_object(oop obj, oop referrer, KlassSubGraphInfo* subgra
} else if (java_lang_invoke_ResolvedMethodName::is_instance(obj)) {
Method* m = java_lang_invoke_ResolvedMethodName::vmtarget(obj);
if (m != nullptr) {
if (RegeneratedClasses::has_been_regenerated(m)) {
m = RegeneratedClasses::get_regenerated_object(m);
}
InstanceKlass* method_holder = m->method_holder();
AOTArtifactFinder::add_cached_class(method_holder);
}
@ -506,10 +510,17 @@ void HeapShared::copy_and_rescan_aot_inited_mirror(InstanceKlass* ik) {
ik->set_is_runtime_setup_required();
}
oop orig_mirror = ik->java_mirror();
oop m = scratch_java_mirror(ik);
assert(ik->is_initialized(), "must be");
oop orig_mirror;
if (RegeneratedClasses::is_regenerated_object(ik)) {
InstanceKlass* orig_ik = RegeneratedClasses::get_original_object(ik);
precond(orig_ik->is_initialized());
orig_mirror = orig_ik->java_mirror();
} else {
precond(ik->is_initialized());
orig_mirror = ik->java_mirror();
}
oop m = scratch_java_mirror(ik);
int nfields = 0;
for (JavaFieldStream fs(ik); !fs.done(); fs.next()) {
if (fs.access_flags().is_static()) {
@ -1520,6 +1531,13 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap
p2i(scratch_java_mirror(orig_obj)));
}
if (java_lang_Class::is_instance(orig_obj)) {
Klass* k = java_lang_Class::as_Klass(orig_obj);
if (RegeneratedClasses::has_been_regenerated(k)) {
orig_obj = RegeneratedClasses::get_regenerated_object(k)->java_mirror();
}
}
if (CDSConfig::is_initing_classes_at_dump_time()) {
if (java_lang_Class::is_instance(orig_obj)) {
orig_obj = scratch_java_mirror(orig_obj);

View File

@ -224,6 +224,7 @@ void LambdaFormInvokers::regenerate_class(char* class_name, ClassFileStream& st,
result->set_is_generated_shared_class();
if (!klass->is_shared()) {
log_info(aot, lambda)("regenerate_class excluding klass %s %s", class_name, klass->name()->as_C_string());
SystemDictionaryShared::set_excluded(InstanceKlass::cast(klass)); // exclude the existing class from dump
}
log_info(aot, lambda)("Regenerated class %s, old: " INTPTR_FORMAT " new: " INTPTR_FORMAT,

View File

@ -837,11 +837,10 @@ void MetaspaceShared::preload_and_dump(TRAPS) {
struct stat st;
if (os::stat(AOTCache, &st) != 0) {
tty->print_cr("AOTCache creation failed: %s", AOTCache);
vm_exit(0);
} else {
tty->print_cr("AOTCache creation is complete: %s " INT64_FORMAT " bytes", AOTCache, (int64_t)(st.st_size));
vm_exit(0);
}
vm_direct_exit(0);
}
}
}

View File

@ -24,6 +24,7 @@
#include "cds/archiveBuilder.hpp"
#include "cds/regeneratedClasses.hpp"
#include "classfile/vmSymbols.hpp"
#include "memory/universe.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/method.hpp"
@ -34,7 +35,8 @@
#include "utilities/resourceHash.hpp"
using RegeneratedObjTable = ResourceHashtable<address, address, 15889, AnyObj::C_HEAP, mtClassShared>;
static RegeneratedObjTable* _renegerated_objs = nullptr; // InstanceKlass* and Method*
static RegeneratedObjTable* _regenerated_objs = nullptr; // InstanceKlass* and Method* orig_obj -> regen_obj
static RegeneratedObjTable* _original_objs = nullptr; // InstanceKlass* and Method* regen_obj -> orig_obj
static GrowableArrayCHeap<OopHandle, mtClassShared>* _regenerated_mirrors = nullptr;
// The regenerated Klass is not added to any class loader, so we need
@ -46,40 +48,71 @@ void RegeneratedClasses::add_class(InstanceKlass* orig_klass, InstanceKlass* reg
}
_regenerated_mirrors->append(OopHandle(Universe::vm_global(), regen_klass->java_mirror()));
if (_renegerated_objs == nullptr) {
_renegerated_objs = new (mtClass)RegeneratedObjTable();
if (_regenerated_objs == nullptr) {
_regenerated_objs = new (mtClass)RegeneratedObjTable();
}
if (_original_objs == nullptr) {
_original_objs = new (mtClass)RegeneratedObjTable();
}
_renegerated_objs->put((address)orig_klass, (address)regen_klass);
_regenerated_objs->put((address)orig_klass, (address)regen_klass);
_original_objs->put((address)regen_klass, (address)orig_klass);
Array<Method*>* methods = orig_klass->methods();
for (int i = 0; i < methods->length(); i++) {
Method* orig_m = methods->at(i);
Method* regen_m = regen_klass->find_method(orig_m->name(), orig_m->signature());
if (regen_m == nullptr) {
ResourceMark rm;
log_warning(aot)("Method in original class is missing from regenerated class: " INTPTR_FORMAT " %s",
p2i(orig_m), orig_m->external_name());
if (orig_m->name() != vmSymbols::object_initializer_name()) {
// JLI Holder classes are never instantiated, they don't need to have constructors.
// Not printing the warning if the method is a constructor.
log_warning(aot)("Method in original class is missing from regenerated class: " INTPTR_FORMAT " %s",
p2i(orig_m), orig_m->external_name());
}
} else {
_renegerated_objs->put((address)orig_m, (address)regen_m);
_regenerated_objs->put((address)orig_m, (address)regen_m);
_original_objs->put((address)regen_m, (address)orig_m);
}
}
}
bool RegeneratedClasses::has_been_regenerated(address orig_obj) {
if (_renegerated_objs == nullptr) {
if (_regenerated_objs == nullptr) {
return false;
} else {
return _renegerated_objs->get(orig_obj) != nullptr;
return _regenerated_objs->get(orig_obj) != nullptr;
}
}
address RegeneratedClasses::get_regenerated_object(address orig_obj) {
assert(_regenerated_objs != nullptr, "must be");
address* p =_regenerated_objs->get(orig_obj);
assert(p != nullptr, "must be");
return *p;
}
bool RegeneratedClasses::is_regenerated_object(address regen_obj) {
if (_original_objs == nullptr) {
return false;
} else {
return _original_objs->get(regen_obj) != nullptr;
}
}
address RegeneratedClasses::get_original_object(address regen_obj) {
assert(_original_objs != nullptr, "must be");
address* p =_original_objs->get(regen_obj);
assert(p != nullptr, "must be");
return *p;
}
void RegeneratedClasses::record_regenerated_objects() {
assert_locked_or_safepoint(DumpTimeTable_lock);
if (_renegerated_objs != nullptr) {
if (_regenerated_objs != nullptr) {
auto doit = [&] (address orig_obj, address regen_obj) {
ArchiveBuilder::current()->record_regenerated_object(orig_obj, regen_obj);
};
_renegerated_objs->iterate_all(doit);
_regenerated_objs->iterate_all(doit);
}
}
@ -92,7 +125,7 @@ void RegeneratedClasses::cleanup() {
delete _regenerated_mirrors;
_regenerated_mirrors = nullptr;
}
if (_renegerated_objs != nullptr) {
delete _renegerated_objs;
if (_regenerated_objs != nullptr) {
delete _regenerated_objs;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2025, 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
@ -43,7 +43,26 @@ class RegeneratedClasses : public AllStatic {
static void add_class(InstanceKlass* orig_klass, InstanceKlass* regen_klass);
static void cleanup();
static bool has_been_regenerated(address orig_obj);
static address get_regenerated_object(address orig_obj); // orig_obj -> regen_obj
static void record_regenerated_objects();
// Handy functions to avoid type casts
template <class T> static bool has_been_regenerated(T orig_obj) {
return has_been_regenerated((address)orig_obj);
}
template <class T> static T get_regenerated_object(T orig_obj) {
return (T)get_regenerated_object((address)orig_obj);
}
static bool is_regenerated_object(address regen_obj);
static address get_original_object(address regen_obj); // regen_obj -> orig_obj
template <class T> static bool is_regenerated_object(T regen_obj) {
return is_regenerated_object((address)regen_obj);
}
template <class T> static T get_original_object(T regen_obj) {
return (T)get_original_object((address)regen_obj);
}
};
#endif // SHARE_CDS_REGENERATEDCLASSES_HPP

View File

@ -5176,7 +5176,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
assert(module_entry != nullptr, "module_entry should always be set");
// Obtain java.lang.Module
Handle module_handle(THREAD, module_entry->module());
Handle module_handle(THREAD, module_entry->module_oop());
// Allocate mirror and initialize static fields
java_lang_Class::create_mirror(ik,

View File

@ -208,7 +208,7 @@ void ClassLoaderDataShared::clear_archived_oops() {
oop ClassLoaderDataShared::restore_archived_oops_for_null_class_loader_data() {
assert(CDSConfig::is_using_full_module_graph(), "must be");
_archived_boot_loader_data.restore(null_class_loader_data(), false, true);
return _archived_javabase_moduleEntry->module();
return _archived_javabase_moduleEntry->module_oop();
}
void ClassLoaderDataShared::restore_java_platform_loader_from_archive(ClassLoaderData* loader_data) {

View File

@ -1036,15 +1036,15 @@ void java_lang_Class::set_mirror_module_field(JavaThread* current, Klass* k, Han
// If java.base was already defined then patch this particular class with java.base.
if (javabase_was_defined) {
ModuleEntry *javabase_entry = ModuleEntryTable::javabase_moduleEntry();
assert(javabase_entry != nullptr && javabase_entry->module() != nullptr,
assert(javabase_entry != nullptr && javabase_entry->module_oop() != nullptr,
"Setting class module field, " JAVA_BASE_NAME " should be defined");
Handle javabase_handle(current, javabase_entry->module());
Handle javabase_handle(current, javabase_entry->module_oop());
set_module(mirror(), javabase_handle());
}
} else {
assert(Universe::is_module_initialized() ||
(ModuleEntryTable::javabase_defined() &&
(module() == ModuleEntryTable::javabase_moduleEntry()->module())),
(module() == ModuleEntryTable::javabase_moduleEntry()->module_oop())),
"Incorrect java.lang.Module specification while creating mirror");
set_module(mirror(), module());
}
@ -1899,7 +1899,7 @@ oop java_lang_Thread::async_get_stack_trace(oop java_thread, TRAPS) {
return nullptr;
}
class GetStackTraceClosure : public HandshakeClosure {
class GetStackTraceHandshakeClosure : public HandshakeClosure {
public:
const Handle _java_thread;
int _depth;
@ -1907,11 +1907,11 @@ oop java_lang_Thread::async_get_stack_trace(oop java_thread, TRAPS) {
GrowableArray<Method*>* _methods;
GrowableArray<int>* _bcis;
GetStackTraceClosure(Handle java_thread) :
HandshakeClosure("GetStackTraceClosure"), _java_thread(java_thread), _depth(0), _retry_handshake(false),
GetStackTraceHandshakeClosure(Handle java_thread) :
HandshakeClosure("GetStackTraceHandshakeClosure"), _java_thread(java_thread), _depth(0), _retry_handshake(false),
_methods(nullptr), _bcis(nullptr) {
}
~GetStackTraceClosure() {
~GetStackTraceHandshakeClosure() {
delete _methods;
delete _bcis;
}
@ -1977,13 +1977,13 @@ oop java_lang_Thread::async_get_stack_trace(oop java_thread, TRAPS) {
// Handshake with target
ResourceMark rm(THREAD);
HandleMark hm(THREAD);
GetStackTraceClosure gstc(Handle(THREAD, java_thread));
GetStackTraceHandshakeClosure gsthc(Handle(THREAD, java_thread));
do {
Handshake::execute(&gstc, &tlh, thread);
} while (gstc.read_reset_retry());
Handshake::execute(&gsthc, &tlh, thread);
} while (gsthc.read_reset_retry());
// Stop if no stack trace is found.
if (gstc._depth == 0) {
if (gsthc._depth == 0) {
return nullptr;
}
@ -1993,12 +1993,12 @@ oop java_lang_Thread::async_get_stack_trace(oop java_thread, TRAPS) {
if (k->should_be_initialized()) {
k->initialize(CHECK_NULL);
}
objArrayHandle trace = oopFactory::new_objArray_handle(k, gstc._depth, CHECK_NULL);
objArrayHandle trace = oopFactory::new_objArray_handle(k, gsthc._depth, CHECK_NULL);
for (int i = 0; i < gstc._depth; i++) {
methodHandle method(THREAD, gstc._methods->at(i));
for (int i = 0; i < gsthc._depth; i++) {
methodHandle method(THREAD, gsthc._methods->at(i));
oop element = java_lang_StackTraceElement::create(method,
gstc._bcis->at(i),
gsthc._bcis->at(i),
CHECK_NULL);
trace->obj_at_put(i, element);
}

View File

@ -49,7 +49,7 @@
ModuleEntry* ModuleEntryTable::_javabase_module = nullptr;
oop ModuleEntry::module() const { return _module.resolve(); }
oop ModuleEntry::module_oop() const { return _module_handle.resolve(); }
void ModuleEntry::set_location(Symbol* location) {
// _location symbol's refcounts are managed by ModuleEntry,
@ -284,7 +284,7 @@ ModuleEntry::ModuleEntry(Handle module_handle,
}
if (!module_handle.is_null()) {
_module = loader_data->add_handle(module_handle);
_module_handle = loader_data->add_handle(module_handle);
}
set_version(version);
@ -401,7 +401,7 @@ ModuleEntry* ModuleEntry::allocate_archived_entry() const {
memcpy((void*)archived_entry, (void*)this, sizeof(ModuleEntry));
if (CDSConfig::is_dumping_full_module_graph()) {
archived_entry->_archived_module_index = HeapShared::append_root(module());
archived_entry->_archived_module_index = HeapShared::append_root(module_oop());
} else {
archived_entry->_archived_module_index = -1;
}
@ -422,7 +422,7 @@ ModuleEntry* ModuleEntry::allocate_archived_entry() const {
// Clear handles and restore at run time. Handles cannot be archived.
OopHandle null_handle;
archived_entry->_module = null_handle;
archived_entry->_module_handle = null_handle;
// For verify_archived_module_entries()
DEBUG_ONLY(_num_inited_module_entries++);
@ -526,7 +526,7 @@ void ModuleEntry::restore_archived_oops(ClassLoaderData* loader_data) {
assert(CDSConfig::is_using_archive(), "runtime only");
Handle module_handle(Thread::current(), HeapShared::get_root(_archived_module_index, /*clear=*/true));
assert(module_handle.not_null(), "huh");
set_module(loader_data->add_handle(module_handle));
set_module_handle(loader_data->add_handle(module_handle));
// This was cleared to zero during dump time -- we didn't save the value
// because it may be affected by archive relocation.
@ -662,7 +662,7 @@ void ModuleEntryTable::finalize_javabase(Handle module_handle, Symbol* version,
jb_module->set_location(location);
// Once java.base's ModuleEntry _module field is set with the known
// java.lang.Module, java.base is considered "defined" to the VM.
jb_module->set_module(boot_loader_data->add_handle(module_handle));
jb_module->set_module_handle(boot_loader_data->add_handle(module_handle));
// Store pointer to the ModuleEntry for java.base in the java.lang.Module object.
java_lang_Module::set_module_entry(module_handle(), jb_module);
@ -700,7 +700,7 @@ void ModuleEntryTable::patch_javabase_entries(JavaThread* current, Handle module
// We allow -XX:ArchiveHeapTestClass to archive additional classes
// into the CDS heap, but these must be in the unnamed module.
ModuleEntry* unnamed_module = ClassLoaderData::the_null_class_loader_data()->unnamed_module();
Handle unnamed_module_handle(current, unnamed_module->module());
Handle unnamed_module_handle(current, unnamed_module->module_oop());
java_lang_Class::fixup_module_field(k, unnamed_module_handle);
} else
#endif
@ -745,7 +745,7 @@ void ModuleEntry::print(outputStream* st) {
st->print_cr("entry " PTR_FORMAT " name %s module " PTR_FORMAT " loader %s version %s location %s strict %s",
p2i(this),
name_as_C_string(),
p2i(module()),
p2i(module_oop()),
loader_data()->loader_name_and_id(),
version() != nullptr ? version()->as_C_string() : "nullptr",
location() != nullptr ? location()->as_C_string() : "nullptr",

View File

@ -53,7 +53,7 @@ class ModuleClosure;
// A ModuleEntry describes a module that has been defined by a call to JVM_DefineModule.
// It contains:
// - Symbol* containing the module's name.
// - pointer to the java.lang.Module for this module.
// - pointer to the java.lang.Module: the representation of this module as a Java object
// - pointer to the java.security.ProtectionDomain shared by classes defined to this module.
// - ClassLoaderData*, class loader of this module.
// - a growable array containing other module entries that this module can read.
@ -63,7 +63,7 @@ class ModuleClosure;
// data structure. This lock must be taken on all accesses to either table.
class ModuleEntry : public CHeapObj<mtModule> {
private:
OopHandle _module; // java.lang.Module
OopHandle _module_handle; // java.lang.Module
OopHandle _shared_pd; // java.security.ProtectionDomain, cached
// for shared classes from this module
Symbol* _name; // name of this module
@ -96,9 +96,9 @@ public:
~ModuleEntry();
Symbol* name() const { return _name; }
oop module() const;
OopHandle module_handle() const { return _module; }
void set_module(OopHandle j) { _module = j; }
oop module_oop() const;
OopHandle module_handle() const { return _module_handle; }
void set_module_handle(OopHandle j) { _module_handle = j; }
// The shared ProtectionDomain reference is set once the VM loads a shared class
// originated from the current Module. The referenced ProtectionDomain object is
@ -262,7 +262,7 @@ public:
}
static bool javabase_defined() { return ((_javabase_module != nullptr) &&
(_javabase_module->module() != nullptr)); }
(_javabase_module->module_oop() != nullptr)); }
static void finalize_javabase(Handle module_handle, Symbol* version, Symbol* location);
static void patch_javabase_entries(JavaThread* current, Handle module_handle);

View File

@ -773,7 +773,7 @@ void Modules::set_bootloader_unnamed_module(Handle module, TRAPS) {
ClassLoaderData* boot_loader_data = ClassLoaderData::the_null_class_loader_data();
ModuleEntry* unnamed_module = boot_loader_data->unnamed_module();
assert(unnamed_module != nullptr, "boot loader's unnamed ModuleEntry not defined");
unnamed_module->set_module(boot_loader_data->add_handle(module));
unnamed_module->set_module_handle(boot_loader_data->add_handle(module));
// Store pointer to the ModuleEntry in the unnamed module's java.lang.Module object.
java_lang_Module::set_module_entry(module(), unnamed_module);
}
@ -954,8 +954,8 @@ oop Modules::get_named_module(Handle h_loader, const char* package_name) {
get_package_entry_by_name(package_sym, h_loader);
const ModuleEntry* const module_entry = (pkg_entry != nullptr ? pkg_entry->module() : nullptr);
if (module_entry != nullptr && module_entry->module() != nullptr && module_entry->is_named()) {
return module_entry->module();
if (module_entry != nullptr && module_entry->module_oop() != nullptr && module_entry->is_named()) {
return module_entry->module_oop();
}
return nullptr;
}

View File

@ -32,6 +32,7 @@
#include "classfile/javaClasses.inline.hpp"
#include "classfile/stringTable.hpp"
#include "classfile/vmClasses.hpp"
#include "compiler/compileBroker.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/oopStorage.inline.hpp"
#include "gc/shared/oopStorageSet.hpp"
@ -115,6 +116,7 @@ OopStorage* StringTable::_oop_storage;
static size_t _current_size = 0;
static volatile size_t _items_count = 0;
DEBUG_ONLY(static bool _disable_interning_during_cds_dump = false);
volatile bool _alt_hash = false;
@ -346,6 +348,10 @@ bool StringTable::has_work() {
return Atomic::load_acquire(&_has_work);
}
size_t StringTable::items_count_acquire() {
return Atomic::load_acquire(&_items_count);
}
void StringTable::trigger_concurrent_work() {
// Avoid churn on ServiceThread
if (!has_work()) {
@ -504,6 +510,9 @@ oop StringTable::intern(const char* utf8_string, TRAPS) {
}
oop StringTable::intern(const StringWrapper& name, TRAPS) {
assert(!Atomic::load_acquire(&_disable_interning_during_cds_dump),
"All threads that may intern strings should have been stopped before CDS starts copying the interned string table");
// shared table always uses java_lang_String::hash_code
unsigned int hash = hash_wrapped_string(name);
oop found_string = lookup_shared(name, hash);
@ -793,7 +802,7 @@ void StringTable::verify() {
}
// Verification and comp
class VerifyCompStrings : StackObj {
class StringTable::VerifyCompStrings : StackObj {
static unsigned string_hash(oop const& str) {
return java_lang_String::hash_code_noupdate(str);
}
@ -805,7 +814,7 @@ class VerifyCompStrings : StackObj {
string_hash, string_equals> _table;
public:
size_t _errors;
VerifyCompStrings() : _table(unsigned(_items_count / 8) + 1, 0 /* do not resize */), _errors(0) {}
VerifyCompStrings() : _table(unsigned(items_count_acquire() / 8) + 1, 0 /* do not resize */), _errors(0) {}
bool operator()(WeakHandle* val) {
oop s = val->resolve();
if (s == nullptr) {
@ -939,20 +948,31 @@ oop StringTable::lookup_shared(const jchar* name, int len) {
return _shared_table.lookup(wrapped_name, java_lang_String::hash_code(name, len), 0);
}
// This is called BEFORE we enter the CDS safepoint. We can allocate heap objects.
// This should be called when we know no more strings will be added (which will be easy
// to guarantee because CDS runs with a single Java thread. See JDK-8253495.)
// This is called BEFORE we enter the CDS safepoint. We can still allocate Java object arrays to
// be used by the shared strings table.
void StringTable::allocate_shared_strings_array(TRAPS) {
if (!CDSConfig::is_dumping_heap()) {
return;
}
assert(CDSConfig::allow_only_single_java_thread(), "No more interned strings can be added");
if (_items_count > (size_t)max_jint) {
fatal("Too many strings to be archived: %zu", _items_count);
CompileBroker::wait_for_no_active_tasks();
precond(CDSConfig::allow_only_single_java_thread());
// At this point, no more strings will be added:
// - There's only a single Java thread (this thread). It no longer executes Java bytecodes
// so JIT compilation will eventually stop.
// - CompileBroker has no more active tasks, so all JIT requests have been processed.
// This flag will be cleared after intern table dumping has completed, so we can run the
// compiler again (for future AOT method compilation, etc).
DEBUG_ONLY(Atomic::release_store(&_disable_interning_during_cds_dump, true));
if (items_count_acquire() > (size_t)max_jint) {
fatal("Too many strings to be archived: %zu", items_count_acquire());
}
int total = (int)_items_count;
int total = (int)items_count_acquire();
size_t single_array_size = objArrayOopDesc::object_size(total);
log_info(aot)("allocated string table for %d strings", total);
@ -972,7 +992,7 @@ void StringTable::allocate_shared_strings_array(TRAPS) {
// This can only happen if you have an extremely large number of classes that
// refer to more than 16384 * 16384 = 26M interned strings! Not a practical concern
// but bail out for safety.
log_error(aot)("Too many strings to be archived: %zu", _items_count);
log_error(aot)("Too many strings to be archived: %zu", items_count_acquire());
MetaspaceShared::unrecoverable_writing_error();
}
@ -1070,7 +1090,7 @@ oop StringTable::init_shared_strings_array() {
void StringTable::write_shared_table() {
_shared_table.reset();
CompactHashtableWriter writer((int)_items_count, ArchiveBuilder::string_stats());
CompactHashtableWriter writer((int)items_count_acquire(), ArchiveBuilder::string_stats());
int index = 0;
auto copy_into_shared_table = [&] (WeakHandle* val) {
@ -1084,6 +1104,8 @@ void StringTable::write_shared_table() {
};
_local_table->do_safepoint_scan(copy_into_shared_table);
writer.dump(&_shared_table, "string");
DEBUG_ONLY(Atomic::release_store(&_disable_interning_during_cds_dump, false));
}
void StringTable::set_shared_strings_array_index(int root_index) {

View File

@ -40,7 +40,7 @@ class StringTableConfig;
class StringTable : AllStatic {
friend class StringTableConfig;
class VerifyCompStrings;
static volatile bool _has_work;
// Set if one bucket is out of balance due to hash algorithm deficiency
@ -74,6 +74,7 @@ private:
static void item_added();
static void item_removed();
static size_t items_count_acquire();
static oop intern(const StringWrapper& name, TRAPS);
static oop do_intern(const StringWrapper& name, uintx hash, TRAPS);

View File

@ -348,6 +348,13 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) {
}
}
InstanceKlass* nest_host = k->nest_host_or_null();
if (nest_host != nullptr && nest_host != k && check_for_exclusion(nest_host, nullptr)) {
ResourceMark rm;
aot_log_warning(aot)("Skipping %s: nest_host class %s is excluded", k->name()->as_C_string(), nest_host->name()->as_C_string());
return true;
}
return false; // false == k should NOT be excluded
}

View File

@ -1483,6 +1483,9 @@ AOTCodeAddressTable::~AOTCodeAddressTable() {
if (_extrs_addr != nullptr) {
FREE_C_HEAP_ARRAY(address, _extrs_addr);
}
if (_stubs_addr != nullptr) {
FREE_C_HEAP_ARRAY(address, _stubs_addr);
}
if (_shared_blobs_addr != nullptr) {
FREE_C_HEAP_ARRAY(address, _shared_blobs_addr);
}

View File

@ -136,6 +136,7 @@ private:
public:
AOTCodeAddressTable() :
_extrs_addr(nullptr),
_stubs_addr(nullptr),
_shared_blobs_addr(nullptr),
_C1_blobs_addr(nullptr),
_extrs_length(0),

View File

@ -206,6 +206,8 @@ void CodeBlob::purge() {
if (_mutable_data != blob_end()) {
os::free(_mutable_data);
_mutable_data = blob_end(); // Valid not null address
_mutable_data_size = 0;
_relocation_size = 0;
}
if (_oop_maps != nullptr) {
delete _oop_maps;

View File

@ -882,6 +882,7 @@ void CodeCache::do_unloading(bool unloading_occurred) {
void CodeCache::verify_clean_inline_caches() {
#ifdef ASSERT
if (!VerifyInlineCaches) return;
NMethodIterator iter(NMethodIterator::not_unloading);
while(iter.next()) {
nmethod* nm = iter.method();

View File

@ -192,13 +192,13 @@ private:
static inline CompiledDirectCall* before(address return_addr) {
CompiledDirectCall* st = new CompiledDirectCall(nativeCall_before(return_addr));
st->verify();
if (VerifyInlineCaches) st->verify();
return st;
}
static inline CompiledDirectCall* at(address native_call) {
CompiledDirectCall* st = new CompiledDirectCall(nativeCall_at(native_call));
st->verify();
if (VerifyInlineCaches) st->verify();
return st;
}

View File

@ -1935,6 +1935,14 @@ bool nmethod::is_maybe_on_stack() {
void nmethod::inc_decompile_count() {
if (!is_compiled_by_c2() && !is_compiled_by_jvmci()) return;
// Could be gated by ProfileTraps, but do not bother...
#if INCLUDE_JVMCI
// Deoptimization count is used by the CompileBroker to reason about compilations
// it requests so do not pollute the count for deoptimizations in non-default (i.e.
// non-CompilerBroker) compilations.
if (is_jvmci_hosted()) {
return;
}
#endif
Method* m = method();
if (m == nullptr) return;
MethodData* mdo = m->method_data();
@ -2156,6 +2164,7 @@ void nmethod::purge(bool unregister_nmethod) {
}
CodeCache::unregister_old_nmethod(this);
JVMCI_ONLY( _metadata_size = 0; )
CodeBlob::purge();
}
@ -3463,6 +3472,9 @@ void nmethod::decode2(outputStream* ost) const {
if (use_compressed_format && ! compressed_with_comments) {
const_cast<nmethod*>(this)->print_constant_pool(st);
st->bol();
st->cr();
st->print_cr("Loading hsdis library failed, undisassembled code is shown in MachCode section");
//---< Open the output (Marker for post-mortem disassembler) >---
st->print_cr("[MachCode]");
const char* header = nullptr;
@ -3497,6 +3509,9 @@ void nmethod::decode2(outputStream* ost) const {
if (compressed_with_comments) {
const_cast<nmethod*>(this)->print_constant_pool(st);
st->bol();
st->cr();
st->print_cr("Loading hsdis library failed, undisassembled code is shown in MachCode section");
//---< Open the output (Marker for post-mortem disassembler) >---
st->print_cr("[MachCode]");
while ((p < end) && (p != nullptr)) {
@ -4050,4 +4065,8 @@ const char* nmethod::jvmci_name() {
}
return nullptr;
}
bool nmethod::is_jvmci_hosted() const {
return jvmci_nmethod_data() != nullptr && !jvmci_nmethod_data()->is_default();
}
#endif

View File

@ -913,6 +913,10 @@ public:
JVMCINMethodData* jvmci_nmethod_data() const {
return jvmci_data_size() == 0 ? nullptr : (JVMCINMethodData*) jvmci_data_begin();
}
// Returns true if a JVMCI compiled method is non-default,
// i.e., not triggered by CompilerBroker
bool is_jvmci_hosted() const;
#endif
void oops_do(OopClosure* f) { oops_do(f, false); }

View File

@ -350,6 +350,9 @@ void AbstractDisassembler::decode_abstract(address start, address end, outputStr
outputStream* st = (ost == nullptr) ? tty : ost;
st->bol();
st->cr();
st->print_cr("Loading hsdis library failed, undisassembled code is shown in MachCode section");
//---< Open the output (Marker for post-mortem disassembler) >---
st->bol();
st->print_cr("[MachCode]");

View File

@ -1750,6 +1750,10 @@ void CompileBroker::wait_for_completion(CompileTask* task) {
}
}
void CompileBroker::wait_for_no_active_tasks() {
CompileTask::wait_for_no_active_tasks();
}
/**
* Initialize compiler thread(s) + compiler object(s). The postcondition
* of this function is that the compiler runtimes are initialized and that

View File

@ -383,6 +383,9 @@ public:
static bool is_compilation_disabled_forever() {
return _should_compile_new_jobs == shutdown_compilation;
}
static void wait_for_no_active_tasks();
static void handle_full_code_cache(CodeBlobType code_blob_type);
// Ensures that warning is only printed once.
static bool should_print_compiler_warning() {

View File

@ -37,12 +37,13 @@
#include "runtime/mutexLocker.hpp"
CompileTask* CompileTask::_task_free_list = nullptr;
int CompileTask::_active_tasks = 0;
/**
* Allocate a CompileTask, from the free list if possible.
*/
CompileTask* CompileTask::allocate() {
MutexLocker locker(CompileTaskAlloc_lock);
MonitorLocker locker(CompileTaskAlloc_lock);
CompileTask* task = nullptr;
if (_task_free_list != nullptr) {
@ -56,6 +57,7 @@ CompileTask* CompileTask::allocate() {
}
assert(task->is_free(), "Task must be free.");
task->set_is_free(false);
_active_tasks++;
return task;
}
@ -63,7 +65,7 @@ CompileTask* CompileTask::allocate() {
* Add a task to the free list.
*/
void CompileTask::free(CompileTask* task) {
MutexLocker locker(CompileTaskAlloc_lock);
MonitorLocker locker(CompileTaskAlloc_lock);
if (!task->is_free()) {
if ((task->_method_holder != nullptr && JNIHandles::is_weak_global_handle(task->_method_holder))) {
JNIHandles::destroy_weak_global(task->_method_holder);
@ -79,6 +81,17 @@ void CompileTask::free(CompileTask* task) {
task->set_is_free(true);
task->set_next(_task_free_list);
_task_free_list = task;
_active_tasks--;
if (_active_tasks == 0) {
locker.notify_all();
}
}
}
void CompileTask::wait_for_no_active_tasks() {
MonitorLocker locker(CompileTaskAlloc_lock);
while (_active_tasks > 0) {
locker.wait();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2025, 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
@ -83,6 +83,7 @@ class CompileTask : public CHeapObj<mtCompiler> {
private:
static CompileTask* _task_free_list;
static int _active_tasks;
int _compile_id;
Method* _method;
jobject _method_holder;
@ -123,6 +124,7 @@ class CompileTask : public CHeapObj<mtCompiler> {
static CompileTask* allocate();
static void free(CompileTask* task);
static void wait_for_no_active_tasks();
int compile_id() const { return _compile_id; }
Method* method() const { return _method; }

View File

@ -1269,6 +1269,9 @@ jint G1CollectedHeap::initialize_service_thread() {
jint G1CollectedHeap::initialize() {
if (!os::is_thread_cpu_time_supported()) {
vm_exit_during_initialization("G1 requires cpu time gathering support");
}
// Necessary to satisfy locking discipline assertions.
MutexLocker x(Heap_lock);
@ -2234,7 +2237,7 @@ void G1CollectedHeap::gc_epilogue(bool full) {
_free_arena_memory_task->notify_new_stats(&_young_gen_card_set_stats,
&_collection_set_candidates_card_set_stats);
update_parallel_gc_threads_cpu_time();
update_perf_counter_cpu_time();
}
uint G1CollectedHeap::uncommit_regions(uint region_limit) {
@ -2318,10 +2321,10 @@ void G1CollectedHeap::verify_region_attr_remset_is_tracked() {
}
#endif
void G1CollectedHeap::update_parallel_gc_threads_cpu_time() {
void G1CollectedHeap::update_perf_counter_cpu_time() {
assert(Thread::current()->is_VM_thread(),
"Must be called from VM thread to avoid races");
if (!UsePerfData || !os::is_thread_cpu_time_supported()) {
if (!UsePerfData) {
return;
}

View File

@ -262,7 +262,7 @@ public:
void set_collection_set_candidates_stats(G1MonotonicArenaMemoryStats& stats);
void set_young_gen_card_set_stats(const G1MonotonicArenaMemoryStats& stats);
void update_parallel_gc_threads_cpu_time();
void update_perf_counter_cpu_time();
private:
// Return true if an explicit GC should start a concurrent cycle instead

View File

@ -71,6 +71,7 @@
#include "runtime/handles.inline.hpp"
#include "runtime/java.hpp"
#include "runtime/orderAccess.hpp"
#include "runtime/os.hpp"
#include "runtime/prefetch.inline.hpp"
#include "runtime/threads.hpp"
#include "utilities/align.hpp"
@ -507,8 +508,6 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h,
_remark_weak_ref_times(),
_cleanup_times(),
_accum_task_vtime(nullptr),
_concurrent_workers(nullptr),
_num_concurrent_workers(0),
_max_concurrent_workers(0),
@ -542,7 +541,6 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h,
}
_tasks = NEW_C_HEAP_ARRAY(G1CMTask*, _max_num_tasks, mtGC);
_accum_task_vtime = NEW_C_HEAP_ARRAY(double, _max_num_tasks, mtGC);
// so that the assertion in MarkingTaskQueue::task_queue doesn't fail
_num_active_tasks = _max_num_tasks;
@ -552,8 +550,6 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h,
_task_queues->register_queue(i, task_queue);
_tasks[i] = new G1CMTask(i, this, task_queue, _region_mark_stats);
_accum_task_vtime[i] = 0.0;
}
reset_at_marking_complete();
@ -980,30 +976,23 @@ public:
void work(uint worker_id) {
ResourceMark rm;
double start_vtime = os::elapsedVTime();
SuspendibleThreadSetJoiner sts_join;
{
SuspendibleThreadSetJoiner sts_join;
assert(worker_id < _cm->active_tasks(), "invariant");
assert(worker_id < _cm->active_tasks(), "invariant");
G1CMTask* task = _cm->task(worker_id);
task->record_start_time();
if (!_cm->has_aborted()) {
do {
task->do_marking_step(G1ConcMarkStepDurationMillis,
true /* do_termination */,
false /* is_serial*/);
G1CMTask* task = _cm->task(worker_id);
task->record_start_time();
if (!_cm->has_aborted()) {
do {
task->do_marking_step(G1ConcMarkStepDurationMillis,
true /* do_termination */,
false /* is_serial*/);
_cm->do_yield_check();
} while (!_cm->has_aborted() && task->has_aborted());
}
task->record_end_time();
guarantee(!task->has_aborted() || _cm->has_aborted(), "invariant");
_cm->do_yield_check();
} while (!_cm->has_aborted() && task->has_aborted());
}
double end_vtime = os::elapsedVTime();
_cm->update_accum_task_vtime(worker_id, end_vtime - start_vtime);
task->record_end_time();
guarantee(!task->has_aborted() || _cm->has_aborted(), "invariant");
}
G1CMConcurrentMarkingTask(G1ConcurrentMark* cm) :
@ -1496,7 +1485,7 @@ void G1ConcurrentMark::remark() {
_remark_weak_ref_times.add((now - mark_work_end) * 1000.0);
_remark_times.add((now - start) * 1000.0);
_g1h->update_parallel_gc_threads_cpu_time();
_g1h->update_perf_counter_cpu_time();
policy->record_concurrent_mark_remark_end();
}
@ -1704,25 +1693,12 @@ void G1ConcurrentMark::weak_refs_work() {
// Prefer to grow the stack until the max capacity.
_global_mark_stack.set_should_grow();
// We need at least one active thread. If reference processing
// is not multi-threaded we use the current (VMThread) thread,
// otherwise we use the workers from the G1CollectedHeap and
// we utilize all the worker threads we can.
uint active_workers = (ParallelRefProcEnabled ? _g1h->workers()->active_workers() : 1U);
active_workers = clamp(active_workers, 1u, _max_num_tasks);
// Set the degree of MT processing here. If the discovery was done MT,
// the number of threads involved during discovery could differ from
// the number of active workers. This is OK as long as the discovered
// Reference lists are balanced (see balance_all_queues() and balance_queues()).
rp->set_active_mt_degree(active_workers);
// Parallel processing task executor.
G1CMRefProcProxyTask task(rp->max_num_queues(), *_g1h, *this);
ReferenceProcessorPhaseTimes pt(_gc_timer_cm, rp->max_num_queues());
// Process the weak references.
const ReferenceProcessorStats& stats = rp->process_discovered_references(task, pt);
const ReferenceProcessorStats& stats = rp->process_discovered_references(task, _g1h->workers(), pt);
_gc_tracer_cm->report_gc_reference_stats(stats);
pt.print_all_references();
@ -1732,8 +1708,6 @@ void G1ConcurrentMark::weak_refs_work() {
assert(has_overflown() || _global_mark_stack.is_empty(),
"Mark stack should be empty (unless it has overflown)");
assert(rp->num_queues() == active_workers, "why not");
}
if (has_overflown()) {
@ -2090,6 +2064,23 @@ void G1ConcurrentMark::abort_marking_threads() {
_second_overflow_barrier_sync.abort();
}
double G1ConcurrentMark::worker_threads_cpu_time_s() {
class CountCpuTimeThreadClosure : public ThreadClosure {
public:
jlong _total_cpu_time;
CountCpuTimeThreadClosure() : ThreadClosure(), _total_cpu_time(0) { }
void do_thread(Thread* t) {
_total_cpu_time += os::thread_cpu_time(t);
}
} cl;
threads_do(&cl);
return (double)cl._total_cpu_time / NANOSECS_PER_SEC;
}
static void print_ms_time_info(const char* prefix, const char* name,
NumberSeq& ns) {
log_trace(gc, marking)("%s%5d %12s: total time = %8.2f s (avg = %8.2f ms).",
@ -2119,7 +2110,7 @@ void G1ConcurrentMark::print_summary_info() {
log.trace(" Total stop_world time = %8.2f s.",
(_remark_times.sum() + _cleanup_times.sum())/1000.0);
log.trace(" Total concurrent time = %8.2f s (%8.2f s marking).",
cm_thread()->vtime_accum(), cm_thread()->vtime_mark_accum());
cm_thread()->total_mark_cpu_time_s(), cm_thread()->worker_threads_cpu_time_s());
}
void G1ConcurrentMark::threads_do(ThreadClosure* tc) const {
@ -2263,8 +2254,6 @@ bool G1CMTask::regular_clock_call() {
return false;
}
double curr_time_ms = os::elapsedVTime() * 1000.0;
// (4) We check whether we should yield. If we have to, then we abort.
if (SuspendibleThreadSet::should_yield()) {
// We should yield. To do this we abort the task. The caller is
@ -2274,7 +2263,7 @@ bool G1CMTask::regular_clock_call() {
// (5) We check whether we've reached our time quota. If we have,
// then we abort.
double elapsed_time_ms = curr_time_ms - _start_time_ms;
double elapsed_time_ms = (double)(os::current_thread_cpu_time() - _start_cpu_time_ns) / NANOSECS_PER_MILLISEC;
if (elapsed_time_ms > _time_target_ms) {
_has_timed_out = true;
return false;
@ -2789,9 +2778,9 @@ void G1CMTask::handle_abort(bool is_serial, double elapsed_time_ms) {
phase has visited reach a given limit. Additional invocations to
the method clock have been planted in a few other strategic places
too. The initial reason for the clock method was to avoid calling
vtime too regularly, as it is quite expensive. So, once it was in
place, it was natural to piggy-back all the other conditions on it
too and not constantly check them throughout the code.
cpu time gathering too regularly, as it is quite expensive. So,
once it was in place, it was natural to piggy-back all the other
conditions on it too and not constantly check them throughout the code.
If do_termination is true then do_marking_step will enter its
termination protocol.
@ -2814,7 +2803,7 @@ void G1CMTask::do_marking_step(double time_target_ms,
bool is_serial) {
assert(time_target_ms >= 1.0, "minimum granularity is 1ms");
_start_time_ms = os::elapsedVTime() * 1000.0;
_start_cpu_time_ns = os::current_thread_cpu_time();
// If do_stealing is true then do_marking_step will attempt to
// steal work from the other G1CMTasks. It only makes sense to
@ -2908,8 +2897,8 @@ void G1CMTask::do_marking_step(double time_target_ms,
// closure which was statically allocated in this frame doesn't
// escape it by accident.
set_cm_oop_closure(nullptr);
double end_time_ms = os::elapsedVTime() * 1000.0;
double elapsed_time_ms = end_time_ms - _start_time_ms;
jlong end_cpu_time_ns = os::current_thread_cpu_time();
double elapsed_time_ms = (double)(end_cpu_time_ns - _start_cpu_time_ns) / NANOSECS_PER_MILLISEC;
// Update the step history.
_step_times_ms.add(elapsed_time_ms);
@ -2932,7 +2921,7 @@ G1CMTask::G1CMTask(uint worker_id,
_mark_stats_cache(mark_stats, G1RegionMarkStatsCache::RegionMarkStatsCacheSize),
_calls(0),
_time_target_ms(0.0),
_start_time_ms(0.0),
_start_cpu_time_ns(0),
_cm_oop_closure(nullptr),
_curr_region(nullptr),
_finger(nullptr),

View File

@ -446,8 +446,6 @@ class G1ConcurrentMark : public CHeapObj<mtGC> {
NumberSeq _remark_weak_ref_times;
NumberSeq _cleanup_times;
double* _accum_task_vtime; // Accumulated task vtime
WorkerThreads* _concurrent_workers;
uint _num_concurrent_workers; // The number of marking worker threads we're using
uint _max_concurrent_workers; // Maximum number of marking worker threads
@ -612,16 +610,8 @@ public:
// running.
void abort_marking_threads();
void update_accum_task_vtime(uint i, double vtime) {
_accum_task_vtime[i] += vtime;
}
double all_task_accum_vtime() {
double ret = 0.0;
for (uint i = 0; i < _max_num_tasks; ++i)
ret += _accum_task_vtime[i];
return ret;
}
// Total cpu time spent in mark worker threads in seconds.
double worker_threads_cpu_time_s();
// Attempts to steal an object from the task queues of other tasks
bool try_stealing(uint worker_id, G1TaskQueueEntry& task_entry);
@ -753,8 +743,8 @@ private:
// When the virtual timer reaches this time, the marking step should exit
double _time_target_ms;
// Start time of the current marking step
double _start_time_ms;
// Start cpu time of the current marking step
jlong _start_cpu_time_ns;
// Oop closure used for iterations over oops
G1CMOopClosure* _cm_oop_closure;

View File

@ -47,8 +47,6 @@
G1ConcurrentMarkThread::G1ConcurrentMarkThread(G1ConcurrentMark* cm) :
ConcurrentGCThread(),
_vtime_start(0.0),
_vtime_accum(0.0),
_cm(cm),
_state(Idle)
{
@ -113,8 +111,6 @@ class G1ConcPhaseTimer : public GCTraceConcTimeImpl<LogLevel::Info, LOG_TAGS(gc,
};
void G1ConcurrentMarkThread::run_service() {
_vtime_start = os::elapsedVTime();
while (wait_for_next_cycle()) {
assert(in_progress(), "must be");
@ -133,9 +129,7 @@ void G1ConcurrentMarkThread::run_service() {
concurrent_cycle_end(_state == FullMark && !_cm->has_aborted());
_vtime_accum = (os::elapsedVTime() - _vtime_start);
update_threads_cpu_time();
update_perf_counter_cpu_time();
}
_cm->root_regions()->cancel_scan();
}
@ -171,7 +165,7 @@ bool G1ConcurrentMarkThread::phase_clear_cld_claimed_marks() {
bool G1ConcurrentMarkThread::phase_scan_root_regions() {
G1ConcPhaseTimer p(_cm, "Concurrent Scan Root Regions");
_cm->scan_root_regions();
update_threads_cpu_time();
update_perf_counter_cpu_time();
return _cm->has_aborted();
}
@ -231,7 +225,7 @@ bool G1ConcurrentMarkThread::subphase_delay_to_keep_mmu_before_remark() {
bool G1ConcurrentMarkThread::subphase_remark() {
ConcurrentGCBreakpoints::at("BEFORE MARKING COMPLETED");
update_threads_cpu_time();
update_perf_counter_cpu_time();
VM_G1PauseRemark op;
VMThread::execute(&op);
return _cm->has_aborted();
@ -241,7 +235,7 @@ bool G1ConcurrentMarkThread::phase_rebuild_and_scrub() {
ConcurrentGCBreakpoints::at("AFTER REBUILD STARTED");
G1ConcPhaseTimer p(_cm, "Concurrent Rebuild Remembered Sets and Scrub Regions");
_cm->rebuild_and_scrub();
update_threads_cpu_time();
update_perf_counter_cpu_time();
return _cm->has_aborted();
}
@ -342,8 +336,8 @@ void G1ConcurrentMarkThread::concurrent_cycle_end(bool mark_cycle_completed) {
ConcurrentGCBreakpoints::notify_active_to_idle();
}
void G1ConcurrentMarkThread::update_threads_cpu_time() {
if (!UsePerfData || !os::is_thread_cpu_time_supported()) {
void G1ConcurrentMarkThread::update_perf_counter_cpu_time() {
if (!UsePerfData) {
return;
}
ThreadTotalCPUTimeClosure tttc(CPUTimeGroups::CPUTimeType::gc_conc_mark);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2025, 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
@ -35,9 +35,6 @@ class G1Policy;
class G1ConcurrentMarkThread: public ConcurrentGCThread {
friend class VMStructs;
double _vtime_start; // Initial virtual time.
double _vtime_accum; // Accumulated virtual time.
G1ConcurrentMark* _cm;
enum ServiceState : uint {
@ -88,10 +85,11 @@ class G1ConcurrentMarkThread: public ConcurrentGCThread {
// Constructor
G1ConcurrentMarkThread(G1ConcurrentMark* cm);
// Total virtual time so far for this thread and concurrent marking tasks.
double vtime_accum();
// Marking virtual time so far this thread and concurrent marking tasks.
double vtime_mark_accum();
// Total cpu time used by all marking related threads (i.e. this thread and the
// marking worker threads) in seconds.
double total_mark_cpu_time_s();
// Cpu time used by all marking worker threads in seconds.
double worker_threads_cpu_time_s();
G1ConcurrentMark* cm() { return _cm; }
@ -110,7 +108,7 @@ class G1ConcurrentMarkThread: public ConcurrentGCThread {
bool in_undo_mark() const;
// Update the perf data counter for concurrent mark.
void update_threads_cpu_time();
void update_perf_counter_cpu_time();
};
#endif // SHARE_GC_G1_G1CONCURRENTMARKTHREAD_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2025, 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
@ -28,15 +28,16 @@
#include "gc/g1/g1ConcurrentMarkThread.hpp"
#include "gc/g1/g1ConcurrentMark.hpp"
#include "runtime/os.hpp"
// Total virtual time so far.
inline double G1ConcurrentMarkThread::vtime_accum() {
return _vtime_accum + _cm->all_task_accum_vtime();
inline double G1ConcurrentMarkThread::total_mark_cpu_time_s() {
return os::thread_cpu_time(this) + worker_threads_cpu_time_s();
}
// Marking virtual time so far
inline double G1ConcurrentMarkThread::vtime_mark_accum() {
return _cm->all_task_accum_vtime();
inline double G1ConcurrentMarkThread::worker_threads_cpu_time_s() {
return _cm->worker_threads_cpu_time_s();
}
inline void G1ConcurrentMarkThread::set_idle() {

View File

@ -40,8 +40,6 @@
G1ConcurrentRefineThread::G1ConcurrentRefineThread(G1ConcurrentRefine* cr, uint worker_id) :
ConcurrentGCThread(),
_vtime_start(0.0),
_vtime_accum(0.0),
_notifier(Mutex::nosafepoint, FormatBuffer<>("G1 Refine#%d", worker_id), true),
_requested_active(false),
_refinement_stats(),
@ -53,8 +51,6 @@ G1ConcurrentRefineThread::G1ConcurrentRefineThread(G1ConcurrentRefine* cr, uint
}
void G1ConcurrentRefineThread::run_service() {
_vtime_start = os::elapsedVTime();
while (wait_for_completed_buffers()) {
SuspendibleThreadSetJoiner sts_join;
G1ConcurrentRefineStats active_stats_start = _refinement_stats;
@ -74,7 +70,7 @@ void G1ConcurrentRefineThread::run_service() {
}
}
report_inactive("Deactivated", _refinement_stats - active_stats_start);
track_usage();
update_perf_counter_cpu_time();
}
log_debug(gc, refine)("Stopping %d", _worker_id);
@ -128,12 +124,17 @@ void G1ConcurrentRefineThread::stop_service() {
activate();
}
jlong G1ConcurrentRefineThread::cpu_time() {
return os::thread_cpu_time(this);
}
// The (single) primary thread drives the controller for the refinement threads.
class G1PrimaryConcurrentRefineThread final : public G1ConcurrentRefineThread {
bool wait_for_completed_buffers() override;
bool maybe_deactivate() override;
void do_refinement_step() override;
void track_usage() override;
// Updates jstat cpu usage for all refinement threads.
void update_perf_counter_cpu_time() override;
public:
G1PrimaryConcurrentRefineThread(G1ConcurrentRefine* cr) :
@ -179,10 +180,8 @@ void G1PrimaryConcurrentRefineThread::do_refinement_step() {
}
}
void G1PrimaryConcurrentRefineThread::track_usage() {
G1ConcurrentRefineThread::track_usage();
// The primary thread is responsible for updating the CPU time for all workers.
if (UsePerfData && os::is_thread_cpu_time_supported()) {
void G1PrimaryConcurrentRefineThread::update_perf_counter_cpu_time() {
if (UsePerfData) {
ThreadTotalCPUTimeClosure tttc(CPUTimeGroups::CPUTimeType::gc_conc_refine);
cr()->threads_do(&tttc);
}
@ -191,6 +190,7 @@ void G1PrimaryConcurrentRefineThread::track_usage() {
class G1SecondaryConcurrentRefineThread final : public G1ConcurrentRefineThread {
bool wait_for_completed_buffers() override;
void do_refinement_step() override;
void update_perf_counter_cpu_time() override { /* Nothing to do. The primary thread does all the work. */ }
public:
G1SecondaryConcurrentRefineThread(G1ConcurrentRefine* cr, uint worker_id) :

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2025, 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
@ -39,9 +39,6 @@ class G1ConcurrentRefineThread: public ConcurrentGCThread {
friend class VMStructs;
friend class G1CollectedHeap;
double _vtime_start; // Initial virtual time.
double _vtime_accum; // Accumulated virtual time.
Monitor _notifier;
bool _requested_active;
@ -71,15 +68,8 @@ protected:
// precondition: this is the current thread.
virtual void do_refinement_step() = 0;
// Update concurrent refine threads stats.
// If we are in Primary thread, we additionally update CPU time tracking.
virtual void track_usage() {
if (os::supports_vtime()) {
_vtime_accum = (os::elapsedVTime() - _vtime_start);
} else {
_vtime_accum = 0.0;
}
};
// Update concurrent refine threads cpu time stats.
virtual void update_perf_counter_cpu_time() = 0;
// Helper for do_refinement_step implementations. Try to perform some
// refinement work, limited by stop_at. Returns true if any refinement work
@ -113,8 +103,8 @@ public:
return &_refinement_stats;
}
// Total virtual time so far.
double vtime_accum() { return _vtime_accum; }
// Total cpu time spent in this thread so far.
jlong cpu_time();
};
#endif // SHARE_GC_G1_G1CONCURRENTREFINETHREAD_HPP

View File

@ -299,18 +299,14 @@ void G1FullCollector::phase1_mark_live_objects() {
}
{
uint old_active_mt_degree = reference_processor()->num_queues();
reference_processor()->set_active_mt_degree(workers());
GCTraceTime(Debug, gc, phases) debug("Phase 1: Reference Processing", scope()->timer());
// Process reference objects found during marking.
ReferenceProcessorPhaseTimes pt(scope()->timer(), reference_processor()->max_num_queues());
G1FullGCRefProcProxyTask task(*this, reference_processor()->max_num_queues());
const ReferenceProcessorStats& stats = reference_processor()->process_discovered_references(task, pt);
const ReferenceProcessorStats& stats = reference_processor()->process_discovered_references(task, _heap->workers(), pt);
scope()->tracer()->report_gc_reference_stats(stats);
pt.print_all_references();
assert(marker(0)->oop_stack()->is_empty(), "Should be no oops on the stack");
reference_processor()->set_active_mt_degree(old_active_mt_degree);
}
{

View File

@ -44,7 +44,7 @@ void G1RemSetSummary::update() {
CollectData(G1RemSetSummary * summary) : _summary(summary), _counter(0) {}
virtual void do_thread(Thread* t) {
G1ConcurrentRefineThread* crt = static_cast<G1ConcurrentRefineThread*>(t);
_summary->set_rs_thread_vtime(_counter, crt->vtime_accum());
_summary->set_refine_thread_cpu_time(_counter, crt->cpu_time());
_counter++;
}
} collector(this);
@ -53,23 +53,23 @@ void G1RemSetSummary::update() {
g1h->concurrent_refine()->threads_do(&collector);
}
void G1RemSetSummary::set_rs_thread_vtime(uint thread, double value) {
assert(_rs_threads_vtimes != nullptr, "just checking");
assert(thread < _num_vtimes, "just checking");
_rs_threads_vtimes[thread] = value;
void G1RemSetSummary::set_refine_thread_cpu_time(uint thread, jlong value) {
assert(_refine_threads_cpu_times != nullptr, "just checking");
assert(thread < _num_refine_threads, "just checking");
_refine_threads_cpu_times[thread] = value;
}
double G1RemSetSummary::rs_thread_vtime(uint thread) const {
assert(_rs_threads_vtimes != nullptr, "just checking");
assert(thread < _num_vtimes, "just checking");
return _rs_threads_vtimes[thread];
jlong G1RemSetSummary::refine_thread_cpu_time(uint thread) const {
assert(_refine_threads_cpu_times != nullptr, "just checking");
assert(thread < _num_refine_threads, "just checking");
return _refine_threads_cpu_times[thread];
}
G1RemSetSummary::G1RemSetSummary(bool should_update) :
_num_vtimes(G1ConcRefinementThreads),
_rs_threads_vtimes(NEW_C_HEAP_ARRAY(double, _num_vtimes, mtGC)) {
_num_refine_threads(G1ConcRefinementThreads),
_refine_threads_cpu_times(NEW_C_HEAP_ARRAY(jlong, _num_refine_threads, mtGC)) {
memset(_rs_threads_vtimes, 0, sizeof(double) * _num_vtimes);
memset(_refine_threads_cpu_times, 0, sizeof(jlong) * _num_refine_threads);
if (should_update) {
update();
@ -77,26 +77,26 @@ G1RemSetSummary::G1RemSetSummary(bool should_update) :
}
G1RemSetSummary::~G1RemSetSummary() {
FREE_C_HEAP_ARRAY(double, _rs_threads_vtimes);
FREE_C_HEAP_ARRAY(jlong, _refine_threads_cpu_times);
}
void G1RemSetSummary::set(G1RemSetSummary* other) {
assert(other != nullptr, "just checking");
assert(_num_vtimes == other->_num_vtimes, "just checking");
assert(_num_refine_threads == other->_num_refine_threads, "just checking");
memcpy(_rs_threads_vtimes, other->_rs_threads_vtimes, sizeof(double) * _num_vtimes);
memcpy(_refine_threads_cpu_times, other->_refine_threads_cpu_times, sizeof(jlong) * _num_refine_threads);
}
void G1RemSetSummary::subtract_from(G1RemSetSummary* other) {
assert(other != nullptr, "just checking");
assert(_num_vtimes == other->_num_vtimes, "just checking");
assert(_num_refine_threads == other->_num_refine_threads, "just checking");
for (uint i = 0; i < _num_vtimes; i++) {
set_rs_thread_vtime(i, other->rs_thread_vtime(i) - rs_thread_vtime(i));
for (uint i = 0; i < _num_refine_threads; i++) {
set_refine_thread_cpu_time(i, other->refine_thread_cpu_time(i) - refine_thread_cpu_time(i));
}
}
class RegionTypeCounter {
class G1PerRegionTypeRemSetCounters {
private:
const char* _name;
@ -130,7 +130,7 @@ private:
public:
RegionTypeCounter(const char* name) : _name(name), _rs_unused_mem_size(0), _rs_mem_size(0), _cards_occupied(0),
G1PerRegionTypeRemSetCounters(const char* name) : _name(name), _rs_unused_mem_size(0), _rs_mem_size(0), _cards_occupied(0),
_amount(0), _amount_tracked(0), _code_root_mem_size(0), _code_root_elems(0) { }
void add(size_t rs_unused_mem_size, size_t rs_mem_size, size_t cards_occupied,
@ -180,13 +180,12 @@ public:
};
class HRRSStatsIter: public G1HeapRegionClosure {
private:
RegionTypeCounter _young;
RegionTypeCounter _humongous;
RegionTypeCounter _free;
RegionTypeCounter _old;
RegionTypeCounter _all;
class G1HeapRegionStatsClosure: public G1HeapRegionClosure {
G1PerRegionTypeRemSetCounters _young;
G1PerRegionTypeRemSetCounters _humongous;
G1PerRegionTypeRemSetCounters _free;
G1PerRegionTypeRemSetCounters _old;
G1PerRegionTypeRemSetCounters _all;
size_t _max_rs_mem_sz;
G1HeapRegion* _max_rs_mem_sz_region;
@ -214,7 +213,7 @@ private:
G1HeapRegion* max_code_root_mem_sz_region() const { return _max_code_root_mem_sz_region; }
public:
HRRSStatsIter() : _young("Young"), _humongous("Humongous"),
G1HeapRegionStatsClosure() : _young("Young"), _humongous("Humongous"),
_free("Free"), _old("Old"), _all("All"),
_max_rs_mem_sz(0), _max_rs_mem_sz_region(nullptr),
_max_code_root_mem_sz(0), _max_code_root_mem_sz_region(nullptr),
@ -249,7 +248,7 @@ public:
}
size_t code_root_elems = hrrs->code_roots_list_length();
RegionTypeCounter* current = nullptr;
G1PerRegionTypeRemSetCounters* current = nullptr;
if (r->is_free()) {
current = &_free;
} else if (r->is_young()) {
@ -290,7 +289,7 @@ public:
}
RegionTypeCounter* current = &_old;
G1PerRegionTypeRemSetCounters* current = &_old;
for (G1CSetCandidateGroup* group : g1h->policy()->candidates()->from_marking_groups()) {
if (group->length() > 1) {
G1CardSet* group_card_set = group->card_set();
@ -311,7 +310,7 @@ public:
}
void print_summary_on(outputStream* out) {
RegionTypeCounter* counters[] = { &_young, &_humongous, &_free, &_old, nullptr };
G1PerRegionTypeRemSetCounters* counters[] = { &_young, &_humongous, &_free, &_old, nullptr };
out->print_cr(" Current rem set statistics");
out->print_cr(" Total per region rem sets sizes = %zu"
@ -319,13 +318,13 @@ public:
total_rs_mem_sz(),
max_rs_mem_sz(),
total_rs_unused_mem_sz());
for (RegionTypeCounter** current = &counters[0]; *current != nullptr; current++) {
for (G1PerRegionTypeRemSetCounters** current = &counters[0]; *current != nullptr; current++) {
(*current)->print_rs_mem_info_on(out, total_rs_mem_sz());
}
out->print_cr(" %zu occupied cards represented.",
total_cards_occupied());
for (RegionTypeCounter** current = &counters[0]; *current != nullptr; current++) {
for (G1PerRegionTypeRemSetCounters** current = &counters[0]; *current != nullptr; current++) {
(*current)->print_cards_occupied_info_on(out, total_cards_occupied());
}
@ -360,13 +359,13 @@ public:
proper_unit_for_byte_size(total_code_root_mem_sz()),
byte_size_in_proper_unit(max_code_root_rem_set->code_roots_mem_size()),
proper_unit_for_byte_size(max_code_root_rem_set->code_roots_mem_size()));
for (RegionTypeCounter** current = &counters[0]; *current != nullptr; current++) {
for (G1PerRegionTypeRemSetCounters** current = &counters[0]; *current != nullptr; current++) {
(*current)->print_code_root_mem_info_on(out, total_code_root_mem_sz());
}
out->print_cr(" %zu code roots represented.",
total_code_root_elems());
for (RegionTypeCounter** current = &counters[0]; *current != nullptr; current++) {
for (G1PerRegionTypeRemSetCounters** current = &counters[0]; *current != nullptr; current++) {
(*current)->print_code_root_elems_info_on(out, total_code_root_elems());
}
@ -383,12 +382,12 @@ void G1RemSetSummary::print_on(outputStream* out, bool show_thread_times) {
if (show_thread_times) {
out->print_cr(" Concurrent refinement threads times (s)");
out->print(" ");
for (uint i = 0; i < _num_vtimes; i++) {
out->print(" %5.2f", rs_thread_vtime(i));
for (uint i = 0; i < _num_refine_threads; i++) {
out->print(" %5.2f", (double)refine_thread_cpu_time(i) / NANOSECS_PER_SEC);
}
out->cr();
}
HRRSStatsIter blk;
G1HeapRegionStatsClosure blk;
G1CollectedHeap::heap()->heap_region_iterate(&blk);
blk.do_cset_groups();
blk.print_summary_on(out);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2025, 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
@ -31,15 +31,14 @@
class G1RemSet;
// A G1RemSetSummary manages statistical information about the G1RemSet
// A G1RemSetSummary manages statistical information about the remembered set.
class G1RemSetSummary {
size_t _num_vtimes;
double* _rs_threads_vtimes;
size_t _num_refine_threads;
jlong* _refine_threads_cpu_times;
void set_rs_thread_vtime(uint thread, double value);
void set_refine_thread_cpu_time(uint thread, jlong value);
// update this summary with current data from various places
// Update this summary with current data from various places.
void update();
public:
@ -47,14 +46,14 @@ public:
~G1RemSetSummary();
// set the counters in this summary to the values of the others
// Set the counters in this summary to the values of the others.
void set(G1RemSetSummary* other);
// subtract all counters from the other summary, and set them in the current
// Subtract all counters from the other summary, and set them in the current.
void subtract_from(G1RemSetSummary* other);
void print_on(outputStream* out, bool show_thread_times);
double rs_thread_vtime(uint thread) const;
jlong refine_thread_cpu_time(uint thread) const;
};
#endif // SHARE_GC_G1_G1REMSETSUMMARY_HPP

View File

@ -119,7 +119,7 @@ G1ServiceTask* G1ServiceThread::wait_for_task() {
void G1ServiceThread::run_task(G1ServiceTask* task) {
jlong start = os::elapsed_counter();
double vstart = os::elapsedVTime();
jlong start_cpu_time_ns = os::thread_cpu_time(this);
assert(task->time() <= start,
"task run early: " JLONG_FORMAT " > " JLONG_FORMAT,
@ -130,12 +130,12 @@ void G1ServiceThread::run_task(G1ServiceTask* task) {
task->execute();
update_thread_cpu_time();
update_perf_counter_cpu_time();
log_debug(gc, task)("G1 Service Thread (%s) (run: %1.3fms) (cpu: %1.3fms)",
task->name(),
TimeHelper::counter_to_millis(os::elapsed_counter() - start),
(os::elapsedVTime() - vstart) * MILLIUNITS);
(double)(os::thread_cpu_time(this) - start_cpu_time_ns) / NANOSECS_PER_MILLISEC);
}
void G1ServiceThread::run_service() {
@ -153,8 +153,8 @@ void G1ServiceThread::stop_service() {
ml.notify();
}
void G1ServiceThread::update_thread_cpu_time() {
if (UsePerfData && os::is_thread_cpu_time_supported()) {
void G1ServiceThread::update_perf_counter_cpu_time() {
if (UsePerfData) {
ThreadTotalCPUTimeClosure tttc(CPUTimeGroups::CPUTimeType::gc_service);
tttc.do_thread(this);
}

View File

@ -121,7 +121,7 @@ class G1ServiceThread: public ConcurrentGCThread {
void schedule(G1ServiceTask* task, jlong delay, bool notify);
// Update the perf data counter for service thread.
void update_thread_cpu_time();
void update_perf_counter_cpu_time();
public:
G1ServiceThread();

View File

@ -971,12 +971,9 @@ void G1YoungCollector::process_discovered_references(G1ParScanThreadStateSet* pe
ReferenceProcessor* rp = ref_processor_stw();
assert(rp->discovery_enabled(), "should have been enabled");
uint no_of_gc_workers = workers()->active_workers();
rp->set_active_mt_degree(no_of_gc_workers);
G1STWRefProcProxyTask task(rp->max_num_queues(), *_g1h, *per_thread_states, *task_queues());
ReferenceProcessorPhaseTimes& pt = *phase_times()->ref_phase_times();
ReferenceProcessorStats stats = rp->process_discovered_references(task, pt);
ReferenceProcessorStats stats = rp->process_discovered_references(task, _g1h->workers(), pt);
gc_tracer_stw()->report_gc_reference_stats(stats);

View File

@ -41,7 +41,7 @@
"for a system GC") \
\
product(bool, PSChunkLargeArrays, true, \
"Process large arrays in chunks")
"(Deprecated) Process large arrays in chunks")
// end of GC_PARALLEL_FLAGS

View File

@ -1310,9 +1310,8 @@ void PSParallelCompact::marking_phase(ParallelOldTracer *gc_tracer) {
ReferenceProcessorStats stats;
ReferenceProcessorPhaseTimes pt(&_gc_timer, ref_processor()->max_num_queues());
ref_processor()->set_active_mt_degree(active_gc_threads);
ParallelCompactRefProcProxyTask task(ref_processor()->max_num_queues());
stats = ref_processor()->process_discovered_references(task, pt);
stats = ref_processor()->process_discovered_references(task, &ParallelScavengeHeap::heap()->workers(), pt);
gc_tracer->report_gc_reference_stats(stats);
pt.print_all_references();

View File

@ -294,7 +294,7 @@ public:
}
PSThreadRootsTaskClosure closure(worker_id);
Threads::possibly_parallel_threads_do(true /* is_par */, &closure);
Threads::possibly_parallel_threads_do(_active_workers > 1 /* is_par */, &closure);
// Scavenge OopStorages
{
@ -410,12 +410,11 @@ bool PSScavenge::invoke(bool clear_soft_refs) {
{
GCTraceTime(Debug, gc, phases) tm("Reference Processing", &_gc_timer);
reference_processor()->set_active_mt_degree(active_workers);
ReferenceProcessorStats stats;
ReferenceProcessorPhaseTimes pt(&_gc_timer, reference_processor()->max_num_queues());
ParallelScavengeRefProcProxyTask task(reference_processor()->max_num_queues());
stats = reference_processor()->process_discovered_references(task, pt);
stats = reference_processor()->process_discovered_references(task, &ParallelScavengeHeap::heap()->workers(), pt);
_gc_tracer.report_gc_reference_stats(stats);
pt.print_all_references();

View File

@ -631,7 +631,7 @@ bool DefNewGeneration::collect(bool clear_all_soft_refs) {
ReferenceProcessor* rp = ref_processor();
ReferenceProcessorPhaseTimes pt(_gc_timer, rp->max_num_queues());
SerialGCRefProcProxyTask task(is_alive, keep_alive, evacuate_followers);
const ReferenceProcessorStats& stats = rp->process_discovered_references(task, pt);
const ReferenceProcessorStats& stats = rp->process_discovered_references(task, nullptr, pt);
_gc_tracer->report_gc_reference_stats(stats);
_gc_tracer->report_tenuring_threshold(tenuring_threshold());
pt.print_all_references();

View File

@ -498,7 +498,7 @@ void SerialFullGC::phase1_mark(bool clear_all_softrefs) {
ReferenceProcessorPhaseTimes pt(_gc_timer, ref_processor()->max_num_queues());
SerialGCRefProcProxyTask task(is_alive, keep_alive, follow_stack_closure);
const ReferenceProcessorStats& stats = ref_processor()->process_discovered_references(task, pt);
const ReferenceProcessorStats& stats = ref_processor()->process_discovered_references(task, nullptr, pt);
pt.print_all_references();
gc_tracer()->report_gc_reference_stats(stats);
}

View File

@ -179,6 +179,7 @@ void ReferenceProcessor::verify_total_count_zero(DiscoveredList lists[], const c
#endif
ReferenceProcessorStats ReferenceProcessor::process_discovered_references(RefProcProxyTask& proxy_task,
WorkerThreads* workers,
ReferenceProcessorPhaseTimes& phase_times) {
double start_time = os::elapsedTime();
@ -197,17 +198,17 @@ ReferenceProcessorStats ReferenceProcessor::process_discovered_references(RefPro
{
RefProcTotalPhaseTimesTracker tt(SoftWeakFinalRefsPhase, &phase_times);
process_soft_weak_final_refs(proxy_task, phase_times);
process_soft_weak_final_refs(proxy_task, workers, phase_times);
}
{
RefProcTotalPhaseTimesTracker tt(KeepAliveFinalRefsPhase, &phase_times);
process_final_keep_alive(proxy_task, phase_times);
process_final_keep_alive(proxy_task, workers, phase_times);
}
{
RefProcTotalPhaseTimesTracker tt(PhantomRefsPhase, &phase_times);
process_phantom_refs(proxy_task, phase_times);
process_phantom_refs(proxy_task, workers, phase_times);
}
phase_times.set_total_time_ms((os::elapsedTime() - start_time) * 1000);
@ -619,8 +620,7 @@ void ReferenceProcessor::maybe_balance_queues(DiscoveredList refs_lists[]) {
// Move entries from all queues[0, 1, ..., _max_num_q-1] to
// queues[0, 1, ..., _num_q-1] because only the first _num_q
// corresponding to the active workers will be processed.
void ReferenceProcessor::balance_queues(DiscoveredList ref_lists[])
{
void ReferenceProcessor::balance_queues(DiscoveredList ref_lists[]) {
// calculate total length
size_t total_refs = 0;
log_develop_trace(gc, ref)("Balance ref_lists ");
@ -633,60 +633,60 @@ void ReferenceProcessor::balance_queues(DiscoveredList ref_lists[])
size_t avg_refs = total_refs / _num_queues + 1;
uint to_idx = 0;
for (uint from_idx = 0; from_idx < _max_num_queues; from_idx++) {
bool move_all = false;
size_t from_len = ref_lists[from_idx].length();
size_t remaining_to_move;
if (from_idx >= _num_queues) {
move_all = ref_lists[from_idx].length() > 0;
// Move all
remaining_to_move = from_len;
} else {
// Move those above avg_refs
remaining_to_move = from_len > avg_refs
? from_len - avg_refs
: 0;
}
while ((ref_lists[from_idx].length() > avg_refs) ||
move_all) {
while (remaining_to_move > 0) {
assert(to_idx < _num_queues, "Sanity Check!");
if (ref_lists[to_idx].length() < avg_refs) {
// move superfluous refs
size_t refs_to_move;
// Move all the Ref's if the from queue will not be processed.
if (move_all) {
refs_to_move = MIN2(ref_lists[from_idx].length(),
avg_refs - ref_lists[to_idx].length());
} else {
refs_to_move = MIN2(ref_lists[from_idx].length() - avg_refs,
avg_refs - ref_lists[to_idx].length());
}
assert(refs_to_move > 0, "otherwise the code below will fail");
oop move_head = ref_lists[from_idx].head();
oop move_tail = move_head;
oop new_head = move_head;
// find an element to split the list on
for (size_t j = 0; j < refs_to_move; ++j) {
move_tail = new_head;
new_head = java_lang_ref_Reference::discovered(new_head);
}
// Add the chain to the to list.
if (ref_lists[to_idx].head() == nullptr) {
// to list is empty. Make a loop at the end.
java_lang_ref_Reference::set_discovered_raw(move_tail, move_tail);
} else {
java_lang_ref_Reference::set_discovered_raw(move_tail, ref_lists[to_idx].head());
}
ref_lists[to_idx].set_head(move_head);
ref_lists[to_idx].inc_length(refs_to_move);
// Remove the chain from the from list.
if (move_tail == new_head) {
// We found the end of the from list.
ref_lists[from_idx].set_head(nullptr);
} else {
ref_lists[from_idx].set_head(new_head);
}
ref_lists[from_idx].dec_length(refs_to_move);
if (ref_lists[from_idx].length() == 0) {
break;
}
} else {
to_idx = (to_idx + 1) % _num_queues;
size_t to_len = ref_lists[to_idx].length();
if (to_len >= avg_refs) {
// this list is full enough; move on to next
to_idx++;
continue;
}
size_t refs_to_move = MIN2(remaining_to_move, avg_refs - to_len);
assert(refs_to_move > 0, "otherwise the code below will fail");
oop move_head = ref_lists[from_idx].head();
oop move_tail = move_head;
oop new_head = move_head;
// find an element to split the list on
for (size_t j = 0; j < refs_to_move; ++j) {
move_tail = new_head;
new_head = java_lang_ref_Reference::discovered(new_head);
}
// Add the chain to the to list.
if (ref_lists[to_idx].head() == nullptr) {
// to list is empty. Make a loop at the end.
java_lang_ref_Reference::set_discovered_raw(move_tail, move_tail);
} else {
java_lang_ref_Reference::set_discovered_raw(move_tail, ref_lists[to_idx].head());
}
ref_lists[to_idx].set_head(move_head);
ref_lists[to_idx].inc_length(refs_to_move);
// Remove the chain from the from list.
if (move_tail == new_head) {
// We found the end of the from list.
ref_lists[from_idx].set_head(nullptr);
} else {
ref_lists[from_idx].set_head(new_head);
}
ref_lists[from_idx].dec_length(refs_to_move);
remaining_to_move -= refs_to_move;
}
}
#ifdef ASSERT
@ -699,7 +699,7 @@ void ReferenceProcessor::balance_queues(DiscoveredList ref_lists[])
#endif
}
void ReferenceProcessor::run_task(RefProcTask& task, RefProcProxyTask& proxy_task, bool marks_oops_alive) {
void ReferenceProcessor::run_task(RefProcTask& task, RefProcProxyTask& proxy_task, WorkerThreads* workers, bool marks_oops_alive) {
log_debug(gc, ref)("ReferenceProcessor::execute queues: %d, %s, marks_oops_alive: %s",
num_queues(),
processing_is_mt() ? "RefProcThreadModel::Multi" : "RefProcThreadModel::Single",
@ -707,7 +707,6 @@ void ReferenceProcessor::run_task(RefProcTask& task, RefProcProxyTask& proxy_tas
proxy_task.prepare_run_task(task, num_queues(), processing_is_mt() ? RefProcThreadModel::Multi : RefProcThreadModel::Single, marks_oops_alive);
if (processing_is_mt()) {
WorkerThreads* workers = Universe::heap()->safepoint_workers();
assert(workers != nullptr, "can not dispatch multi threaded without workers");
assert(workers->active_workers() >= num_queues(),
"Ergonomically chosen workers(%u) should be less than or equal to active workers(%u)",
@ -720,7 +719,12 @@ void ReferenceProcessor::run_task(RefProcTask& task, RefProcProxyTask& proxy_tas
}
}
static uint num_active_workers(WorkerThreads* workers) {
return workers != nullptr ? workers->active_workers() : 1;
}
void ReferenceProcessor::process_soft_weak_final_refs(RefProcProxyTask& proxy_task,
WorkerThreads* workers,
ReferenceProcessorPhaseTimes& phase_times) {
size_t const num_soft_refs = phase_times.ref_discovered(REF_SOFT);
@ -733,7 +737,7 @@ void ReferenceProcessor::process_soft_weak_final_refs(RefProcProxyTask& proxy_ta
return;
}
RefProcMTDegreeAdjuster a(this, SoftWeakFinalRefsPhase, num_total_refs);
RefProcMTDegreeAdjuster a(this, SoftWeakFinalRefsPhase, num_active_workers(workers), num_total_refs);
if (processing_is_mt()) {
RefProcBalanceQueuesTimeTracker tt(SoftWeakFinalRefsPhase, &phase_times);
@ -747,7 +751,7 @@ void ReferenceProcessor::process_soft_weak_final_refs(RefProcProxyTask& proxy_ta
log_reflist("SoftWeakFinalRefsPhase Final before", _discoveredFinalRefs, _max_num_queues);
RefProcSoftWeakFinalPhaseTask phase_task(*this, &phase_times);
run_task(phase_task, proxy_task, false);
run_task(phase_task, proxy_task, workers, false);
verify_total_count_zero(_discoveredSoftRefs, "SoftReference");
verify_total_count_zero(_discoveredWeakRefs, "WeakReference");
@ -755,6 +759,7 @@ void ReferenceProcessor::process_soft_weak_final_refs(RefProcProxyTask& proxy_ta
}
void ReferenceProcessor::process_final_keep_alive(RefProcProxyTask& proxy_task,
WorkerThreads* workers,
ReferenceProcessorPhaseTimes& phase_times) {
size_t const num_final_refs = phase_times.ref_discovered(REF_FINAL);
@ -764,7 +769,7 @@ void ReferenceProcessor::process_final_keep_alive(RefProcProxyTask& proxy_task,
return;
}
RefProcMTDegreeAdjuster a(this, KeepAliveFinalRefsPhase, num_final_refs);
RefProcMTDegreeAdjuster a(this, KeepAliveFinalRefsPhase, num_active_workers(workers), num_final_refs);
if (processing_is_mt()) {
RefProcBalanceQueuesTimeTracker tt(KeepAliveFinalRefsPhase, &phase_times);
@ -773,12 +778,13 @@ void ReferenceProcessor::process_final_keep_alive(RefProcProxyTask& proxy_task,
// Traverse referents of final references and keep them and followers alive.
RefProcKeepAliveFinalPhaseTask phase_task(*this, &phase_times);
run_task(phase_task, proxy_task, true);
run_task(phase_task, proxy_task, workers, true);
verify_total_count_zero(_discoveredFinalRefs, "FinalReference");
}
void ReferenceProcessor::process_phantom_refs(RefProcProxyTask& proxy_task,
WorkerThreads* workers,
ReferenceProcessorPhaseTimes& phase_times) {
size_t const num_phantom_refs = phase_times.ref_discovered(REF_PHANTOM);
@ -788,7 +794,7 @@ void ReferenceProcessor::process_phantom_refs(RefProcProxyTask& proxy_task,
return;
}
RefProcMTDegreeAdjuster a(this, PhantomRefsPhase, num_phantom_refs);
RefProcMTDegreeAdjuster a(this, PhantomRefsPhase, num_active_workers(workers), num_phantom_refs);
if (processing_is_mt()) {
RefProcBalanceQueuesTimeTracker tt(PhantomRefsPhase, &phase_times);
@ -798,7 +804,7 @@ void ReferenceProcessor::process_phantom_refs(RefProcProxyTask& proxy_task,
log_reflist("PhantomRefsPhase Phantom before", _discoveredPhantomRefs, _max_num_queues);
RefProcPhantomPhaseTask phase_task(*this, &phase_times);
run_task(phase_task, proxy_task, false);
run_task(phase_task, proxy_task, workers, false);
verify_total_count_zero(_discoveredPhantomRefs, "PhantomReference");
}
@ -1137,10 +1143,11 @@ bool RefProcMTDegreeAdjuster::use_max_threads(RefProcPhases phase) const {
RefProcMTDegreeAdjuster::RefProcMTDegreeAdjuster(ReferenceProcessor* rp,
RefProcPhases phase,
uint num_active_workers,
size_t ref_count):
_rp(rp),
_saved_num_queues(_rp->num_queues()) {
uint workers = ergo_proc_thread_count(ref_count, _rp->num_queues(), phase);
uint workers = ergo_proc_thread_count(ref_count, num_active_workers, phase);
_rp->set_active_mt_degree(workers);
}

View File

@ -185,6 +185,7 @@ public:
class ReferenceProcessor : public ReferenceDiscoverer {
friend class RefProcTask;
friend class RefProcKeepAliveFinalPhaseTask;
friend class RefProcMTDegreeAdjuster;
public:
// Names of sub-phases of reference processing. Indicates the type of the reference
// processed and the associated phase number at the end.
@ -253,19 +254,22 @@ private:
DiscoveredList* _discoveredFinalRefs;
DiscoveredList* _discoveredPhantomRefs;
void run_task(RefProcTask& task, RefProcProxyTask& proxy_task, bool marks_oops_alive);
void run_task(RefProcTask& task, RefProcProxyTask& proxy_task, WorkerThreads* threads, bool marks_oops_alive);
// Drop Soft/Weak/Final references with a null or live referent, and clear
// and enqueue non-Final references.
void process_soft_weak_final_refs(RefProcProxyTask& proxy_task,
WorkerThreads* workers,
ReferenceProcessorPhaseTimes& phase_times);
// Keep alive followers of Final references, and enqueue.
void process_final_keep_alive(RefProcProxyTask& proxy_task,
WorkerThreads* workers,
ReferenceProcessorPhaseTimes& phase_times);
// Drop and keep alive live Phantom references, or clear and enqueue if dead.
void process_phantom_refs(RefProcProxyTask& proxy_task,
WorkerThreads* workers,
ReferenceProcessorPhaseTimes& phase_times);
// Work methods used by the process_* methods. All methods return the number of
@ -292,12 +296,14 @@ private:
_always_clear_soft_ref_policy : _default_soft_ref_policy;
_current_soft_ref_policy->setup(); // snapshot the policy threshold
}
void set_active_mt_degree(uint v);
public:
static int number_of_subclasses_of_ref() { return (REF_PHANTOM - REF_NONE); }
uint num_queues() const { return _num_queues; }
uint max_num_queues() const { return _max_num_queues; }
void set_active_mt_degree(uint v);
void start_discovery(bool always_clear) {
enable_discovery();
@ -416,6 +422,7 @@ public:
// Process references found during GC (called by the garbage collector)
ReferenceProcessorStats
process_discovered_references(RefProcProxyTask& proxy_task,
WorkerThreads* workers,
ReferenceProcessorPhaseTimes& phase_times);
// If a discovery is in process that is being superseded, abandon it: all
@ -589,6 +596,7 @@ class RefProcMTDegreeAdjuster : public StackObj {
public:
RefProcMTDegreeAdjuster(ReferenceProcessor* rp,
RefProcPhases phase,
uint num_active_workers,
size_t ref_count);
~RefProcMTDegreeAdjuster();
};

View File

@ -1145,22 +1145,22 @@ void ShenandoahConcurrentGC::op_update_refs() {
ShenandoahHeap::heap()->update_heap_references(true /*concurrent*/);
}
class ShenandoahUpdateThreadClosure : public HandshakeClosure {
class ShenandoahUpdateThreadHandshakeClosure : public HandshakeClosure {
private:
// This closure runs when thread is stopped for handshake, which means
// we can use non-concurrent closure here, as long as it only updates
// locations modified by the thread itself, i.e. stack locations.
ShenandoahNonConcUpdateRefsClosure _cl;
public:
ShenandoahUpdateThreadClosure();
ShenandoahUpdateThreadHandshakeClosure();
void do_thread(Thread* thread);
};
ShenandoahUpdateThreadClosure::ShenandoahUpdateThreadClosure() :
ShenandoahUpdateThreadHandshakeClosure::ShenandoahUpdateThreadHandshakeClosure() :
HandshakeClosure("Shenandoah Update Thread Roots") {
}
void ShenandoahUpdateThreadClosure::do_thread(Thread* thread) {
void ShenandoahUpdateThreadHandshakeClosure::do_thread(Thread* thread) {
if (thread->is_Java_thread()) {
JavaThread* jt = JavaThread::cast(thread);
ResourceMark rm;
@ -1169,7 +1169,7 @@ void ShenandoahUpdateThreadClosure::do_thread(Thread* thread) {
}
void ShenandoahConcurrentGC::op_update_thread_roots() {
ShenandoahUpdateThreadClosure cl;
ShenandoahUpdateThreadHandshakeClosure cl;
Handshake::execute(&cl);
}

View File

@ -1245,9 +1245,9 @@ public:
}
};
class ShenandoahGCStatePropagator : public HandshakeClosure {
class ShenandoahGCStatePropagatorHandshakeClosure : public HandshakeClosure {
public:
explicit ShenandoahGCStatePropagator(char gc_state) :
explicit ShenandoahGCStatePropagatorHandshakeClosure(char gc_state) :
HandshakeClosure("Shenandoah GC State Change"),
_gc_state(gc_state) {}
@ -1258,9 +1258,9 @@ private:
char _gc_state;
};
class ShenandoahPrepareForUpdateRefs : public HandshakeClosure {
class ShenandoahPrepareForUpdateRefsHandshakeClosure : public HandshakeClosure {
public:
explicit ShenandoahPrepareForUpdateRefs(char gc_state) :
explicit ShenandoahPrepareForUpdateRefsHandshakeClosure(char gc_state) :
HandshakeClosure("Shenandoah Prepare for Update Refs"),
_retire(ResizeTLAB), _propagator(gc_state) {}
@ -1272,7 +1272,7 @@ public:
}
private:
ShenandoahRetireGCLABClosure _retire;
ShenandoahGCStatePropagator _propagator;
ShenandoahGCStatePropagatorHandshakeClosure _propagator;
};
void ShenandoahHeap::evacuate_collection_set(bool concurrent) {
@ -1295,7 +1295,7 @@ void ShenandoahHeap::concurrent_prepare_for_update_refs() {
}
// This will propagate the gc state and retire gclabs and plabs for threads that require it.
ShenandoahPrepareForUpdateRefs prepare_for_update_refs(_gc_state.raw_value());
ShenandoahPrepareForUpdateRefsHandshakeClosure prepare_for_update_refs(_gc_state.raw_value());
// The handshake won't touch worker threads (or control thread, or VM thread), so do those separately.
Threads::non_java_threads_do(&prepare_for_update_refs);
@ -1327,7 +1327,7 @@ void ShenandoahHeap::concurrent_final_roots(HandshakeClosure* handshake_closure)
set_gc_state_concurrent(WEAK_ROOTS, false);
}
ShenandoahGCStatePropagator propagator(_gc_state.raw_value());
ShenandoahGCStatePropagatorHandshakeClosure propagator(_gc_state.raw_value());
Threads::non_java_threads_do(&propagator);
if (handshake_closure == nullptr) {
Handshake::execute(&propagator);
@ -2020,14 +2020,14 @@ void ShenandoahHeap::parallel_heap_region_iterate(ShenandoahHeapRegionClosure* b
}
}
class ShenandoahRendezvousClosure : public HandshakeClosure {
class ShenandoahRendezvousHandshakeClosure : public HandshakeClosure {
public:
inline ShenandoahRendezvousClosure(const char* name) : HandshakeClosure(name) {}
inline ShenandoahRendezvousHandshakeClosure(const char* name) : HandshakeClosure(name) {}
inline void do_thread(Thread* thread) {}
};
void ShenandoahHeap::rendezvous_threads(const char* name) {
ShenandoahRendezvousClosure cl(name);
ShenandoahRendezvousHandshakeClosure cl(name);
Handshake::execute(&cl);
}
@ -2069,7 +2069,7 @@ void ShenandoahHeap::prepare_update_heap_references() {
void ShenandoahHeap::propagate_gc_state_to_all_threads() {
assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at Shenandoah safepoint");
if (_gc_state_changed) {
ShenandoahGCStatePropagator propagator(_gc_state.raw_value());
ShenandoahGCStatePropagatorHandshakeClosure propagator(_gc_state.raw_value());
Threads::threads_do(&propagator);
_gc_state_changed = false;
}

View File

@ -532,13 +532,13 @@ bool ZMark::try_steal(ZMarkContext* context) {
return try_steal_local(context) || try_steal_global(context);
}
class ZMarkFlushStacksClosure : public HandshakeClosure {
class ZMarkFlushStacksHandshakeClosure : public HandshakeClosure {
private:
ZMark* const _mark;
bool _flushed;
public:
ZMarkFlushStacksClosure(ZMark* mark)
ZMarkFlushStacksHandshakeClosure(ZMark* mark)
: HandshakeClosure("ZMarkFlushStacks"),
_mark(mark),
_flushed(false) {}
@ -585,7 +585,7 @@ public:
};
bool ZMark::flush() {
ZMarkFlushStacksClosure cl(this);
ZMarkFlushStacksHandshakeClosure cl(this);
VM_ZMarkFlushOperation vm_cl(&cl);
Handshake::execute(&cl);
VMThread::execute(&vm_cl);
@ -956,7 +956,7 @@ bool ZMark::try_end() {
}
// Try end marking
ZMarkFlushStacksClosure cl(this);
ZMarkFlushStacksHandshakeClosure cl(this);
Threads::non_java_threads_do(&cl);
// Check if non-java threads have any pending marking

View File

@ -237,7 +237,7 @@ ClassFileStream* JfrUpcalls::on_method_trace(InstanceKlass* ik, const ClassFileS
ModuleEntry* module_entry = ik->module();
oop module = nullptr;
if (module_entry != nullptr) {
module = module_entry->module();
module = module_entry->module_oop();
}
instanceHandle module_handle(THREAD, (instanceOop)module);

View File

@ -144,7 +144,7 @@ bool JVMCICompiler::force_comp_at_level_simple(const methodHandle& method) {
if (excludeModules.not_null()) {
ModuleEntry* moduleEntry = method->method_holder()->module();
for (int i = 0; i < excludeModules->length(); i++) {
if (excludeModules->obj_at(i) == moduleEntry->module()) {
if (excludeModules->obj_at(i) == moduleEntry->module_oop()) {
return true;
}
}

View File

@ -746,6 +746,7 @@ JVM_END
void JVMCINMethodData::initialize(int nmethod_mirror_index,
int nmethod_entry_patch_offset,
const char* nmethod_mirror_name,
bool is_default,
FailedSpeculation** failed_speculations)
{
_failed_speculations = failed_speculations;
@ -753,16 +754,17 @@ void JVMCINMethodData::initialize(int nmethod_mirror_index,
guarantee(nmethod_entry_patch_offset != -1, "missing entry barrier");
_nmethod_entry_patch_offset = nmethod_entry_patch_offset;
if (nmethod_mirror_name != nullptr) {
_has_name = true;
_properties.bits._has_name = 1;
char* dest = (char*) name();
strcpy(dest, nmethod_mirror_name);
} else {
_has_name = false;
_properties.bits._has_name = 0;
}
_properties.bits._is_default = is_default;
}
void JVMCINMethodData::copy(JVMCINMethodData* data) {
initialize(data->_nmethod_mirror_index, data->_nmethod_entry_patch_offset, data->name(), data->_failed_speculations);
initialize(data->_nmethod_mirror_index, data->_nmethod_entry_patch_offset, data->name(), data->_properties.bits._is_default, data->_failed_speculations);
}
void JVMCINMethodData::add_failed_speculation(nmethod* nm, jlong speculation) {
@ -2130,7 +2132,7 @@ JVMCI::CodeInstallResult JVMCIRuntime::register_method(JVMCIEnv* JVMCIENV,
JVMCICompileState* compile_state = JVMCIENV->compile_state();
bool failing_dep_is_call_site;
result = validate_compile_task_dependencies(dependencies, compile_state, &failure_detail, failing_dep_is_call_site);
if (result != JVMCI::ok) {
if (install_default && result != JVMCI::ok) {
// While not a true deoptimization, it is a preemptive decompile.
MethodData* mdp = method()->method_data();
if (mdp != nullptr && !failing_dep_is_call_site) {
@ -2151,6 +2153,7 @@ JVMCI::CodeInstallResult JVMCIRuntime::register_method(JVMCIEnv* JVMCIENV,
JVMCINMethodData* data = JVMCINMethodData::create(nmethod_mirror_index,
nmethod_entry_patch_offset,
nmethod_mirror_name,
install_default,
failed_speculations);
nm = nmethod::new_nmethod(method,
compile_id,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2025, 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
@ -48,9 +48,19 @@ class MetadataHandles;
class JVMCINMethodData : public ResourceObj {
friend class JVMCIVMStructs;
// Is HotSpotNmethod.name non-null? If so, the value is
// embedded in the end of this object.
bool _has_name;
union JVMCINMethodProperties {
uint8_t value;
struct {
// Is HotSpotNmethod.name non-null? If so, the value is
// embedded in the end of this object.
uint8_t _has_name : 1,
// HotSpotNmethod.isDefault (e.g., compilation scheduled by CompileBroker)
_is_default : 1,
: 6;
} bits;
};
JVMCINMethodProperties _properties;
// Index for the HotSpotNmethod mirror in the nmethod's oops table.
// This is -1 if there is no mirror in the oops table.
@ -76,6 +86,7 @@ class JVMCINMethodData : public ResourceObj {
void initialize(int nmethod_mirror_index,
int nmethod_entry_patch_offset,
const char* nmethod_mirror_name,
bool is_default,
FailedSpeculation** failed_speculations);
void* operator new(size_t size, const char* nmethod_mirror_name) {
@ -88,11 +99,13 @@ public:
static JVMCINMethodData* create(int nmethod_mirror_index,
int nmethod_entry_patch_offset,
const char* nmethod_mirror_name,
bool is_default,
FailedSpeculation** failed_speculations) {
JVMCINMethodData* result = new (nmethod_mirror_name) JVMCINMethodData();
result->initialize(nmethod_mirror_index,
nmethod_entry_patch_offset,
nmethod_mirror_name,
is_default,
failed_speculations);
return result;
}
@ -117,7 +130,7 @@ public:
void add_failed_speculation(nmethod* nm, jlong speculation);
// Gets the JVMCI name of the nmethod (which may be null).
const char* name() { return _has_name ? (char*)(((address) this) + sizeof(JVMCINMethodData)) : nullptr; }
const char* name() { return has_name() ? (char*)(((address) this) + sizeof(JVMCINMethodData)) : nullptr; }
// Clears the HotSpotNmethod.address field in the mirror. If nm
// is dead, the HotSpotNmethod.entryPoint field is also cleared.
@ -132,6 +145,14 @@ public:
int nmethod_entry_patch_offset() {
return _nmethod_entry_patch_offset;
}
bool has_name() {
return _properties.bits._has_name;
}
bool is_default() {
return _properties.bits._is_default;
}
};
// A top level class that represents an initialized JVMCI runtime.

View File

@ -106,7 +106,7 @@ bool JVMCIGlobals::check_jvmci_flags_are_consistent() {
}
if (BootstrapJVMCI && (TieredStopAtLevel < CompLevel_full_optimization)) {
jio_fprintf(defaultStream::error_stream(),
"-XX:+BootstrapJVMCI is not compatible with -XX:TieredStopAtLevel=%d\n", TieredStopAtLevel);
"-XX:+BootstrapJVMCI is not compatible with -XX:TieredStopAtLevel=%zd\n", TieredStopAtLevel);
return false;
}
}

View File

@ -22,7 +22,6 @@
*
*/
#include "jvm.h"
#include "logging/log.hpp"
#include "memory/memoryReserver.hpp"
#include "oops/compressedOops.hpp"
@ -65,11 +64,9 @@ static void log_on_large_pages_failure(char* req_addr, size_t bytes) {
// Compressed oops logging.
log_debug(gc, heap, coops)("Reserve regular memory without large pages");
// JVM style warning that we did not succeed in using large pages.
char msg[128];
jio_snprintf(msg, sizeof(msg), "Failed to reserve and commit memory using large pages. "
"req_addr: " PTR_FORMAT " bytes: %zu",
req_addr, bytes);
warning("%s", msg);
warning("Failed to reserve and commit memory using large pages. "
"req_addr: " PTR_FORMAT " bytes: %zu",
p2i(req_addr), bytes);
}
}

View File

@ -120,8 +120,8 @@ void ArrayKlass::complete_create_array_klass(ArrayKlass* k, Klass* super_klass,
// java.base is defined.
assert((module_entry != nullptr) || ((module_entry == nullptr) && !ModuleEntryTable::javabase_defined()),
"module entry not available post " JAVA_BASE_NAME " definition");
oop module = (module_entry != nullptr) ? module_entry->module() : (oop)nullptr;
java_lang_Class::create_mirror(k, Handle(THREAD, k->class_loader()), Handle(THREAD, module), Handle(), Handle(), CHECK);
oop module_oop = (module_entry != nullptr) ? module_entry->module_oop() : (oop)nullptr;
java_lang_Class::create_mirror(k, Handle(THREAD, k->class_loader()), Handle(THREAD, module_oop), Handle(), Handle(), CHECK);
}
ArrayKlass* ArrayKlass::array_klass(int n, TRAPS) {

View File

@ -444,6 +444,9 @@ public:
assert(_nest_host != nullptr, "must be");
return _nest_host;
}
InstanceKlass* nest_host_or_null() {
return _nest_host;
}
// Used to construct informative IllegalAccessError messages at a higher level,
// if there was an issue resolving or validating the nest host.
// Returns null if there was no error.

View File

@ -896,7 +896,7 @@ void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protec
module_entry = ModuleEntryTable::javabase_moduleEntry();
}
// Obtain java.lang.Module, if available
Handle module_handle(THREAD, ((module_entry != nullptr) ? module_entry->module() : (oop)nullptr));
Handle module_handle(THREAD, ((module_entry != nullptr) ? module_entry->module_oop() : (oop)nullptr));
if (this->has_archived_mirror_index()) {
ResourceMark rm(THREAD);

View File

@ -58,6 +58,9 @@
product(bool, StressMacroExpansion, false, DIAGNOSTIC, \
"Randomize macro node expansion order") \
\
product(bool, StressMacroElimination, false, DIAGNOSTIC, \
"Randomize macro node elimination order") \
\
product(bool, StressUnstableIfTraps, false, DIAGNOSTIC, \
"Randomly take unstable if traps") \
\

View File

@ -736,8 +736,9 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci,
}
if (StressLCM || StressGCM || StressIGVN || StressCCP ||
StressIncrementalInlining || StressMacroExpansion || StressUnstableIfTraps || StressBailout ||
StressLoopPeeling) {
StressIncrementalInlining || StressMacroExpansion ||
StressMacroElimination || StressUnstableIfTraps ||
StressBailout || StressLoopPeeling) {
initialize_stress_seed(directive);
}
@ -2421,6 +2422,7 @@ void Compile::Optimize() {
PhaseMacroExpand mexp(igvn);
mexp.eliminate_macro_nodes();
if (failing()) return;
print_method(PHASE_AFTER_MACRO_ELIMINATION, 2);
igvn.set_delay_transform(false);
igvn.optimize();
@ -2520,6 +2522,18 @@ void Compile::Optimize() {
TracePhase tp(_t_macroExpand);
print_method(PHASE_BEFORE_MACRO_EXPANSION, 3);
PhaseMacroExpand mex(igvn);
// Do not allow new macro nodes once we start to eliminate and expand
C->reset_allow_macro_nodes();
// Last attempt to eliminate macro nodes before expand
mex.eliminate_macro_nodes();
if (failing()) {
return;
}
mex.eliminate_opaque_looplimit_macro_nodes();
if (failing()) {
return;
}
print_method(PHASE_AFTER_MACRO_ELIMINATION, 2);
if (mex.expand_macro_nodes()) {
assert(failing(), "must bail out w/ explicit message");
return;

View File

@ -825,6 +825,29 @@ const Type* DivHFNode::Value(PhaseGVN* phase) const {
if (t1->base() == Type::HalfFloatCon &&
t2->base() == Type::HalfFloatCon) {
// IEEE 754 floating point comparison treats 0.0 and -0.0 as equals.
// Division of a zero by a zero results in NaN.
if (t1->getf() == 0.0f && t2->getf() == 0.0f) {
return TypeH::make(NAN);
}
// As per C++ standard section 7.6.5 (expr.mul), behavior is undefined only if
// the second operand is 0.0. In all other situations, we can expect a standard-compliant
// C++ compiler to generate code following IEEE 754 semantics.
if (t2->getf() == 0.0) {
// If either operand is NaN, the result is NaN
if (g_isnan(t1->getf())) {
return TypeH::make(NAN);
} else {
// Division of a nonzero finite value by a zero results in a signed infinity. Also,
// division of an infinity by a finite value results in a signed infinity.
bool res_sign_neg = (jint_cast(t1->getf()) < 0) ^ (jint_cast(t2->getf()) < 0);
const TypeF* res = res_sign_neg ? TypeF::NEG_INF : TypeF::POS_INF;
return TypeH::make(res->getf());
}
}
return TypeH::make(t1->getf() / t2->getf());
}

View File

@ -2365,6 +2365,10 @@ void PhaseMacroExpand::refine_strip_mined_loop_macro_nodes() {
void PhaseMacroExpand::eliminate_macro_nodes() {
if (C->macro_count() == 0)
return;
if (StressMacroElimination) {
C->shuffle_macro_nodes();
}
NOT_PRODUCT(int membar_before = count_MemBar(C);)
// Before elimination may re-mark (change to Nested or NonEscObj)
@ -2404,6 +2408,9 @@ void PhaseMacroExpand::eliminate_macro_nodes() {
}
assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count");
progress = progress || success;
if (success) {
C->print_method(PHASE_AFTER_MACRO_ELIMINATION_STEP, 5, n);
}
}
}
// Next, attempt to eliminate allocations
@ -2452,6 +2459,9 @@ void PhaseMacroExpand::eliminate_macro_nodes() {
}
assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count");
progress = progress || success;
if (success) {
C->print_method(PHASE_AFTER_MACRO_ELIMINATION_STEP, 5, n);
}
}
}
#ifndef PRODUCT
@ -2462,19 +2472,11 @@ void PhaseMacroExpand::eliminate_macro_nodes() {
#endif
}
//------------------------------expand_macro_nodes----------------------
// Returns true if a failure occurred.
bool PhaseMacroExpand::expand_macro_nodes() {
refine_strip_mined_loop_macro_nodes();
// Do not allow new macro nodes once we started to expand
C->reset_allow_macro_nodes();
if (StressMacroExpansion) {
C->shuffle_macro_nodes();
void PhaseMacroExpand::eliminate_opaque_looplimit_macro_nodes() {
if (C->macro_count() == 0) {
return;
}
// Last attempt to eliminate macro nodes.
eliminate_macro_nodes();
if (C->failing()) return true;
refine_strip_mined_loop_macro_nodes();
// Eliminate Opaque and LoopLimit nodes. Do it after all loop optimizations.
bool progress = true;
while (progress) {
@ -2536,10 +2538,18 @@ bool PhaseMacroExpand::expand_macro_nodes() {
assert(!success || (C->macro_count() == (old_macro_count - 1)), "elimination must have deleted one node from macro list");
progress = progress || success;
if (success) {
C->print_method(PHASE_AFTER_MACRO_EXPANSION_STEP, 5, n);
C->print_method(PHASE_AFTER_MACRO_ELIMINATION_STEP, 5, n);
}
}
}
}
//------------------------------expand_macro_nodes----------------------
// Returns true if a failure occurred.
bool PhaseMacroExpand::expand_macro_nodes() {
if (StressMacroExpansion) {
C->shuffle_macro_nodes();
}
// Clean up the graph so we're less likely to hit the maximum node
// limit

View File

@ -203,6 +203,7 @@ public:
void refine_strip_mined_loop_macro_nodes();
void eliminate_macro_nodes();
bool expand_macro_nodes();
void eliminate_opaque_looplimit_macro_nodes();
SafePointScalarObjectNode* create_scalarized_object_description(AllocateNode *alloc, SafePointNode* sfpt);
static bool can_eliminate_allocation(PhaseIterGVN *igvn, AllocateNode *alloc, GrowableArray <SafePointNode *> *safepoints);

View File

@ -3121,6 +3121,7 @@ Node *PhaseCCP::transform_once( Node *n ) {
hash_delete(n); // changing bottom type may force a rehash
n->raise_bottom_type(t);
_worklist.push(n); // n re-enters the hash table via the worklist
add_users_to_worklist(n); // if ideal or identity optimizations depend on the input type, users need to be notified
}
// TEMPORARY fix to ensure that 2nd GVN pass eliminates null checks

View File

@ -91,6 +91,8 @@
flags(PHASEIDEALLOOP_ITERATIONS, "PhaseIdealLoop iterations") \
flags(AFTER_LOOP_OPTS, "After Loop Optimizations") \
flags(AFTER_MERGE_STORES, "After Merge Stores") \
flags(AFTER_MACRO_ELIMINATION_STEP, "After Macro Elimination Step") \
flags(AFTER_MACRO_ELIMINATION, "After Macro Elimination") \
flags(BEFORE_MACRO_EXPANSION , "Before Macro Expansion") \
flags(AFTER_MACRO_EXPANSION_STEP, "After Macro Expansion Step") \
flags(AFTER_MACRO_EXPANSION, "After Macro Expansion") \

View File

@ -2966,7 +2966,7 @@ JVM_ENTRY(jobject, JVM_CreateThreadSnapshot(JNIEnv* env, jobject jthread))
oop snapshot = ThreadSnapshotFactory::get_thread_snapshot(jthread, THREAD);
return JNIHandles::make_local(THREAD, snapshot);
#else
return nullptr;
THROW_NULL(vmSymbols::java_lang_UnsupportedOperationException());
#endif
JVM_END

View File

@ -943,12 +943,12 @@ class JvmtiClassFileLoadHookPoster : public StackObj {
ModuleEntry* module_entry = InstanceKlass::cast(klass)->module();
assert(module_entry != nullptr, "module_entry should always be set");
if (module_entry->is_named() &&
module_entry->module() != nullptr &&
module_entry->module_oop() != nullptr &&
!module_entry->has_default_read_edges()) {
if (!module_entry->set_has_default_read_edges()) {
// We won a potential race.
// Add read edges to the unnamed modules of the bootstrap and app class loaders
Handle class_module(_thread, module_entry->module()); // Obtain j.l.r.Module
Handle class_module(_thread, module_entry->module_oop()); // Obtain j.l.r.Module
JvmtiExport::add_default_read_edges(class_module, _thread);
}
}

View File

@ -120,6 +120,7 @@ address JvmtiBreakpoint::getBcp() const {
}
void JvmtiBreakpoint::each_method_version_do(method_action meth_act) {
assert(!_method->is_old(), "the breakpoint method shouldn't be old");
((Method*)_method->*meth_act)(_bci);
// add/remove breakpoint to/from versions of the method that are EMCP.
@ -183,8 +184,16 @@ void JvmtiBreakpoint::print_on(outputStream* out) const {
//
// Modify the Breakpoints data structure at a safepoint
//
// The caller of VM_ChangeBreakpoints operation should ensure that
// _bp.method is preserved until VM_ChangeBreakpoints is processed.
void VM_ChangeBreakpoints::doit() {
if (_bp->method()->is_old()) {
// The bp->_method became old because VMOp with class redefinition happened for this class
// after JvmtiBreakpoint was created but before JVM_ChangeBreakpoints started.
// All class breakpoints are cleared during redefinition, so don't set/clear this breakpoint.
return;
}
switch (_operation) {
case SET_BREAKPOINT:
_breakpoints->set_at_safepoint(*_bp);
@ -249,6 +258,9 @@ int JvmtiBreakpoints::set(JvmtiBreakpoint& bp) {
if (find(bp) != -1) {
return JVMTI_ERROR_DUPLICATE;
}
// Ensure that bp._method is not deallocated before VM_ChangeBreakpoints::doit().
methodHandle mh(Thread::current(), bp.method());
VM_ChangeBreakpoints set_breakpoint(VM_ChangeBreakpoints::SET_BREAKPOINT, &bp);
VMThread::execute(&set_breakpoint);
return JVMTI_ERROR_NONE;
@ -259,6 +271,8 @@ int JvmtiBreakpoints::clear(JvmtiBreakpoint& bp) {
return JVMTI_ERROR_NOT_FOUND;
}
// Ensure that bp._method is not deallocated before VM_ChangeBreakpoints::doit().
methodHandle mh(Thread::current(), bp.method());
VM_ChangeBreakpoints clear_breakpoint(VM_ChangeBreakpoints::CLEAR_BREAKPOINT, &bp);
VMThread::execute(&clear_breakpoint);
return JVMTI_ERROR_NONE;

View File

@ -105,15 +105,15 @@ static frame get_last_frame(JavaThread* jt) {
return last_frame;
}
class ScopedAsyncExceptionHandshake : public AsyncExceptionHandshake {
class ScopedAsyncExceptionHandshakeClosure : public AsyncExceptionHandshakeClosure {
OopHandle _session;
public:
ScopedAsyncExceptionHandshake(OopHandle& session, OopHandle& error)
: AsyncExceptionHandshake(error),
ScopedAsyncExceptionHandshakeClosure(OopHandle& session, OopHandle& error)
: AsyncExceptionHandshakeClosure(error),
_session(session) {}
~ScopedAsyncExceptionHandshake() {
~ScopedAsyncExceptionHandshakeClosure() {
_session.release(Universe::vm_global());
}
@ -122,17 +122,17 @@ public:
bool ignored;
if (is_accessing_session(jt, _session.resolve(), ignored)) {
// Throw exception to unwind out from the scoped access
AsyncExceptionHandshake::do_thread(thread);
AsyncExceptionHandshakeClosure::do_thread(thread);
}
}
};
class CloseScopedMemoryClosure : public HandshakeClosure {
class CloseScopedMemoryHandshakeClosure : public HandshakeClosure {
jobject _session;
jobject _error;
public:
CloseScopedMemoryClosure(jobject session, jobject error)
CloseScopedMemoryHandshakeClosure(jobject session, jobject error)
: HandshakeClosure("CloseScopedMemory")
, _session(session)
, _error(error) {}
@ -159,7 +159,7 @@ public:
// the scoped access.
OopHandle session(Universe::vm_global(), JNIHandles::resolve(_session));
OopHandle error(Universe::vm_global(), JNIHandles::resolve(_error));
jt->install_async_exception(new ScopedAsyncExceptionHandshake(session, error));
jt->install_async_exception(new ScopedAsyncExceptionHandshakeClosure(session, error));
} else if (!in_scoped) {
frame last_frame = get_last_frame(jt);
if (last_frame.is_compiled_frame() && last_frame.can_be_deoptimized()) {
@ -213,7 +213,7 @@ public:
* closed (deopt), this method returns false, signalling that the session cannot be closed safely.
*/
JVM_ENTRY(void, ScopedMemoryAccess_closeScope(JNIEnv *env, jobject receiver, jobject session, jobject error))
CloseScopedMemoryClosure cl(session, error);
CloseScopedMemoryHandshakeClosure cl(session, error);
Handshake::execute(&cl);
JVM_END

View File

@ -2246,7 +2246,7 @@ WB_END
#endif // INCLUDE_CDS
WB_ENTRY(jboolean, WB_HandshakeReadMonitors(JNIEnv* env, jobject wb, jobject thread_handle))
class ReadMonitorsClosure : public HandshakeClosure {
class ReadMonitorsHandshakeClosure : public HandshakeClosure {
jboolean _executed;
void do_thread(Thread* th) {
@ -2281,24 +2281,24 @@ WB_ENTRY(jboolean, WB_HandshakeReadMonitors(JNIEnv* env, jobject wb, jobject thr
}
public:
ReadMonitorsClosure() : HandshakeClosure("WB_HandshakeReadMonitors"), _executed(false) {}
ReadMonitorsHandshakeClosure() : HandshakeClosure("WB_HandshakeReadMonitors"), _executed(false) {}
jboolean executed() const { return _executed; }
};
ReadMonitorsClosure rmc;
ReadMonitorsHandshakeClosure rmhc;
if (thread_handle != nullptr) {
ThreadsListHandle tlh;
JavaThread* target = nullptr;
bool is_alive = tlh.cv_internal_thread_to_JavaThread(thread_handle, &target, nullptr);
if (is_alive) {
Handshake::execute(&rmc, &tlh, target);
Handshake::execute(&rmhc, &tlh, target);
}
}
return rmc.executed();
return rmhc.executed();
WB_END
WB_ENTRY(jint, WB_HandshakeWalkStack(JNIEnv* env, jobject wb, jobject thread_handle, jboolean all_threads))
class TraceSelfClosure : public HandshakeClosure {
class TraceSelfHandshakeClosure : public HandshakeClosure {
jint _num_threads_completed;
void do_thread(Thread* th) {
@ -2312,27 +2312,27 @@ WB_ENTRY(jint, WB_HandshakeWalkStack(JNIEnv* env, jobject wb, jobject thread_han
}
public:
TraceSelfClosure(Thread* thread) : HandshakeClosure("WB_TraceSelf"), _num_threads_completed(0) {}
TraceSelfHandshakeClosure(Thread* thread) : HandshakeClosure("WB_TraceSelf"), _num_threads_completed(0) {}
jint num_threads_completed() const { return _num_threads_completed; }
};
TraceSelfClosure tsc(Thread::current());
TraceSelfHandshakeClosure tshc(Thread::current());
if (all_threads) {
Handshake::execute(&tsc);
Handshake::execute(&tshc);
} else if (thread_handle != nullptr) {
ThreadsListHandle tlh;
JavaThread* target = nullptr;
bool is_alive = tlh.cv_internal_thread_to_JavaThread(thread_handle, &target, nullptr);
if (is_alive) {
Handshake::execute(&tsc, &tlh, target);
Handshake::execute(&tshc, &tlh, target);
}
}
return tsc.num_threads_completed();
return tshc.num_threads_completed();
WB_END
WB_ENTRY(void, WB_AsyncHandshakeWalkStack(JNIEnv* env, jobject wb, jobject thread_handle))
class TraceSelfClosure : public AsyncHandshakeClosure {
class TraceSelfHandshakeClosure : public AsyncHandshakeClosure {
JavaThread* _self;
void do_thread(Thread* th) {
assert(th->is_Java_thread(), "sanity");
@ -2347,15 +2347,15 @@ WB_ENTRY(void, WB_AsyncHandshakeWalkStack(JNIEnv* env, jobject wb, jobject threa
}
public:
TraceSelfClosure(JavaThread* self_target) : AsyncHandshakeClosure("WB_TraceSelf"), _self(self_target) {}
TraceSelfHandshakeClosure(JavaThread* self_target) : AsyncHandshakeClosure("WB_TraceSelf"), _self(self_target) {}
};
if (thread_handle != nullptr) {
ThreadsListHandle tlh;
JavaThread* target = nullptr;
bool is_alive = tlh.cv_internal_thread_to_JavaThread(thread_handle, &target, nullptr);
if (is_alive) {
TraceSelfClosure* tsc = new TraceSelfClosure(target);
Handshake::execute(tsc, target);
TraceSelfHandshakeClosure* tshc = new TraceSelfHandshakeClosure(target);
Handshake::execute(tshc, target);
}
}
WB_END

View File

@ -534,6 +534,7 @@ static SpecialFlag const special_jvm_flags[] = {
#endif
{ "ParallelRefProcEnabled", JDK_Version::jdk(26), JDK_Version::jdk(27), JDK_Version::jdk(28) },
{ "ParallelRefProcBalancingEnabled", JDK_Version::jdk(26), JDK_Version::jdk(27), JDK_Version::jdk(28) },
{ "PSChunkLargeArrays", JDK_Version::jdk(26), JDK_Version::jdk(27), JDK_Version::jdk(28) },
// --- Deprecated alias flags (see also aliased_jvm_flags) - sorted by obsolete_in then expired_in:
{ "CreateMinidumpOnCrash", JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::undefined() },

View File

@ -1049,9 +1049,9 @@ JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_m
return bt;
JRT_END
class DeoptimizeMarkedClosure : public HandshakeClosure {
class DeoptimizeMarkedHandshakeClosure : public HandshakeClosure {
public:
DeoptimizeMarkedClosure() : HandshakeClosure("Deoptimize") {}
DeoptimizeMarkedHandshakeClosure() : HandshakeClosure("Deoptimize") {}
void do_thread(Thread* thread) {
JavaThread* jt = JavaThread::cast(thread);
jt->deoptimize_marked_methods();
@ -1064,7 +1064,7 @@ void Deoptimization::deoptimize_all_marked() {
// Make the dependent methods not entrant
CodeCache::make_marked_nmethods_deoptimized();
DeoptimizeMarkedClosure deopt;
DeoptimizeMarkedHandshakeClosure deopt;
if (SafepointSynchronize::is_at_safepoint()) {
Threads::java_threads_do(&deopt);
} else {
@ -2363,6 +2363,14 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* current, jint tr
ShouldNotReachHere();
}
#if INCLUDE_JVMCI
// Deoptimization count is used by the CompileBroker to reason about compilations
// it requests so do not pollute the count for deoptimizations in non-default (i.e.
// non-CompilerBroker) compilations.
if (nm->is_jvmci_hosted()) {
update_trap_state = false;
}
#endif
// Setting +ProfileTraps fixes the following, on all platforms:
// The result is infinite heroic-opt-uncommon-trap/deopt/recompile cycles, since the
// recompile relies on a MethodData* to record heroic opt failures.
@ -2473,7 +2481,6 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* current, jint tr
trap_mdo->inc_tenure_traps();
}
}
if (inc_recompile_count) {
trap_mdo->inc_overflow_recompile_count();
if ((uint)trap_mdo->overflow_recompile_count() >

View File

@ -165,9 +165,9 @@ bool EscapeBarrier::deoptimize_objects_all_threads() {
bool EscapeBarrier::_deoptimizing_objects_for_all_threads = false;
bool EscapeBarrier::_self_deoptimization_in_progress = false;
class EscapeBarrierSuspendHandshake : public HandshakeClosure {
class EscapeBarrierSuspendHandshakeClosure : public HandshakeClosure {
public:
EscapeBarrierSuspendHandshake(const char* name) :
EscapeBarrierSuspendHandshakeClosure(const char* name) :
HandshakeClosure(name) { }
void do_thread(Thread* th) { }
};
@ -196,7 +196,7 @@ void EscapeBarrier::sync_and_suspend_one() {
}
// Use a handshake to synchronize with the target thread.
EscapeBarrierSuspendHandshake sh("EscapeBarrierSuspendOne");
EscapeBarrierSuspendHandshakeClosure sh("EscapeBarrierSuspendOne");
Handshake::execute(&sh, _deoptee_thread);
assert(!_deoptee_thread->has_last_Java_frame() || _deoptee_thread->frame_anchor()->walkable(),
"stack should be walkable now");
@ -242,7 +242,7 @@ void EscapeBarrier::sync_and_suspend_all() {
}
// Use a handshake to synchronize with the other threads.
EscapeBarrierSuspendHandshake sh("EscapeBarrierSuspendAll");
EscapeBarrierSuspendHandshakeClosure sh("EscapeBarrierSuspendAll");
Handshake::execute(&sh);
#ifdef ASSERT
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {

View File

@ -293,6 +293,9 @@ const int ObjectAlignmentInBytes = 8;
product(bool, UseInlineCaches, true, \
"Use Inline Caches for virtual calls ") \
\
develop(bool, VerifyInlineCaches, true, \
"Verify Inline Caches") \
\
product(bool, InlineArrayCopy, true, DIAGNOSTIC, \
"Inline arraycopy native that is known to be part of " \
"base library DLL") \

View File

@ -705,7 +705,7 @@ void HandshakeState::handle_unsafe_access_error() {
// back to Java until resumed we cannot create the exception
// object yet. Add a new unsafe access error operation to
// the end of the queue and try again in the next attempt.
Handshake::execute(new UnsafeAccessErrorHandshake(), _handshakee);
Handshake::execute(new UnsafeAccessErrorHandshakeClosure(), _handshakee);
log_info(handshake)("JavaThread " INTPTR_FORMAT " skipping unsafe access processing due to suspend.", p2i(_handshakee));
return;
}

View File

@ -35,7 +35,7 @@
class HandshakeOperation;
class AsyncHandshakeOperation;
class JavaThread;
class UnsafeAccessErrorHandshake;
class UnsafeAccessErrorHandshakeClosure;
class ThreadsListHandle;
// A handshake closure is a callback that is executed for a JavaThread
@ -86,7 +86,7 @@ class JvmtiRawMonitor;
// operation is only done by either VMThread/Handshaker on behalf of the
// JavaThread or by the target JavaThread itself.
class HandshakeState {
friend UnsafeAccessErrorHandshake;
friend UnsafeAccessErrorHandshakeClosure;
friend JavaThread;
// This a back reference to the JavaThread,
// the target for all operation in the queue.

View File

@ -471,6 +471,7 @@ void before_exit(JavaThread* thread, bool halt) {
NativeHeapTrimmer::cleanup();
Universe::heap()->print_tracing_info();
// Stop concurrent GC threads
Universe::heap()->stop();
@ -513,7 +514,6 @@ void before_exit(JavaThread* thread, bool halt) {
os::terminate_signal_thread();
print_statistics();
Universe::heap()->print_tracing_info();
{ MutexLocker ml(BeforeExit_lock);
_before_exit_status = BEFORE_EXIT_DONE;

Some files were not shown because too many files have changed in this diff Show More