mirror of
https://github.com/openjdk/jdk.git
synced 2026-06-15 06:52:26 +00:00
Merge branch 'shenandoah-allocator-interface' into shenandoah-per-partition-allocator
# Conflicts: # src/hotspot/share/gc/shenandoah/shenandoahSerialAllocator.cpp
This commit is contained in:
commit
25af3cc308
@ -1111,7 +1111,7 @@ void ShenandoahBarrierStubC2::keepalive(MacroAssembler& masm, Label* L_done) {
|
||||
|
||||
// Go to runtime and handle the rest there.
|
||||
__ mov(c_rarg0, _obj);
|
||||
__ mov(lr, keepalive_runtime_entry_addr());
|
||||
__ lea(lr, RuntimeAddress(keepalive_runtime_entry_addr()));
|
||||
__ blr(lr);
|
||||
}
|
||||
if (L_done != nullptr) {
|
||||
@ -1197,7 +1197,7 @@ void ShenandoahBarrierStubC2::lrb(MacroAssembler& masm) {
|
||||
}
|
||||
|
||||
// Go to runtime and handle the rest there.
|
||||
__ mov(lr, lrb_runtime_entry_addr());
|
||||
__ lea(lr, RuntimeAddress(lrb_runtime_entry_addr()));
|
||||
__ blr(lr);
|
||||
|
||||
// Save the result where needed. Narrow entries return narrowOop (32 bits)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2025 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2012, 2026 SAP SE. 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
|
||||
@ -81,7 +81,7 @@ inline void frame::setup(kind knd) {
|
||||
// Continuation frames on the java heap are not aligned.
|
||||
// When thawing interpreted frames the sp can be unaligned (see new_stack_frame()).
|
||||
assert(_on_heap ||
|
||||
((is_aligned(_sp, alignment_in_bytes) || is_interpreted_frame()) &&
|
||||
((is_aligned(_sp, alignment_in_bytes) || is_interpreted_frame() || is_deoptimized_frame()) &&
|
||||
(is_aligned(_fp, alignment_in_bytes) || !is_fully_initialized())),
|
||||
"invalid alignment sp:" PTR_FORMAT " unextended_sp:" PTR_FORMAT " fp:" PTR_FORMAT, p2i(_sp), p2i(_unextended_sp), p2i(_fp));
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2025 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2012, 2026 SAP SE. 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
|
||||
@ -2346,11 +2346,25 @@ void InterpreterMacroAssembler::notify_method_exit(bool is_native_method, TosSta
|
||||
// depth. If it is possible to enter interp_only_mode we add
|
||||
// the code to check if the event should be sent.
|
||||
if (mode == NotifyJVMTI && (JvmtiExport::can_post_interpreter_events() || JvmtiExport::can_post_frame_pop())) {
|
||||
Label jvmti_post_done;
|
||||
|
||||
// if (thread->jvmti_thread_state() == nullptr) exit;
|
||||
ld(R11_scratch1, in_bytes(JavaThread::jvmti_thread_state_offset()), R16_thread);
|
||||
cmpdi(CR0, R11_scratch1, 0);
|
||||
beq(CR0, jvmti_post_done);
|
||||
|
||||
// if (interp_only_mode() == false && frame_pop_cnt() == 0) exit;
|
||||
lwz(R12_scratch2, in_bytes(JavaThread::interp_only_mode_offset()), R16_thread);
|
||||
lwz(R11_scratch1, in_bytes(JvmtiThreadState::frame_pop_cnt_offset()), R11_scratch1);
|
||||
or_(R0, R11_scratch1, R12_scratch2);
|
||||
beq(CR0, jvmti_post_done);
|
||||
|
||||
if (!is_native_method) { push(state); } // Expose tos to GC.
|
||||
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_exit), check_exceptions);
|
||||
if (!is_native_method) { pop(state); }
|
||||
|
||||
align(32, 12);
|
||||
bind(jvmti_post_done);
|
||||
}
|
||||
|
||||
// Dtrace support not implemented.
|
||||
|
||||
@ -985,7 +985,8 @@ void ShenandoahBarrierStubC2::keepalive(MacroAssembler& masm, Label* L_done) {
|
||||
|
||||
// Go to runtime and handle the rest there.
|
||||
__ mv(c_rarg0, _obj);
|
||||
__ rt_call(keepalive_runtime_entry_addr());
|
||||
__ la(ra, RuntimeAddress(keepalive_runtime_entry_addr()));
|
||||
__ jalr(ra);
|
||||
}
|
||||
if (L_done != nullptr) {
|
||||
__ j(*L_done);
|
||||
@ -1056,7 +1057,8 @@ void ShenandoahBarrierStubC2::lrb(MacroAssembler& masm) {
|
||||
}
|
||||
|
||||
// Go to runtime and handle the rest there.
|
||||
__ rt_call(lrb_runtime_entry_addr());
|
||||
__ la(ra, RuntimeAddress(lrb_runtime_entry_addr()));
|
||||
__ jalr(ra);
|
||||
|
||||
// Save the result where needed. Narrow entries return narrowOop (32 bits)
|
||||
// we need to zero the upper 32 bits of x10.
|
||||
|
||||
@ -3439,6 +3439,16 @@ void Assembler::movdqa(XMMRegister dst, Address src) {
|
||||
emit_operand(dst, src, 0);
|
||||
}
|
||||
|
||||
void Assembler::movdqa(Address dst, XMMRegister src) {
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit);
|
||||
attributes.reset_is_clear_context();
|
||||
simd_prefix(src, xnoreg, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
|
||||
emit_int8(0x7F);
|
||||
emit_operand(src, dst, 0);
|
||||
}
|
||||
|
||||
void Assembler::movdqu(XMMRegister dst, Address src) {
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
@ -3848,6 +3858,26 @@ void Assembler::evmovdqaq(XMMRegister dst, KRegister mask, Address src, bool mer
|
||||
emit_operand(dst, src, 0);
|
||||
}
|
||||
|
||||
void Assembler::evmovdqaq(Address dst, XMMRegister src, int vector_len) {
|
||||
// Unmasked instruction
|
||||
evmovdqaq(dst, k0, src, /*merge*/ false, vector_len);
|
||||
}
|
||||
|
||||
void Assembler::evmovdqaq(Address dst, KRegister mask, XMMRegister src, bool merge, int vector_len) {
|
||||
assert(VM_Version::supports_evex(), "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit);
|
||||
attributes.set_embedded_opmask_register_specifier(mask);
|
||||
attributes.set_is_evex_instruction();
|
||||
if (merge) {
|
||||
attributes.reset_is_clear_context();
|
||||
}
|
||||
vex_prefix(dst, 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
|
||||
emit_int8(0x7F);
|
||||
emit_operand(src, dst, 0);
|
||||
}
|
||||
|
||||
void Assembler::evmovntdquq(Address dst, XMMRegister src, int vector_len) {
|
||||
// Unmasked instruction
|
||||
evmovntdquq(dst, k0, src, /*merge*/ true, vector_len);
|
||||
@ -9481,6 +9511,20 @@ void Assembler::vpsllq(XMMRegister dst, XMMRegister src, XMMRegister shift, int
|
||||
emit_int16((unsigned char)0xF3, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::vpsllq(XMMRegister dst, XMMRegister src, Address shift, int vector_len) {
|
||||
assert(UseAVX > 0, "requires some form of AVX");
|
||||
assert(vector_len == AVX_128bit ? VM_Version::supports_avx() :
|
||||
vector_len == AVX_256bit ? VM_Version::supports_avx2() :
|
||||
vector_len == AVX_512bit ? VM_Version::supports_evex() : 0, "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
attributes.set_rex_vex_w_reverted();
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_M128, /* input_size_in_bits */ EVEX_NObit);
|
||||
vex_prefix(shift, src->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
|
||||
emit_int8((unsigned char)0xF3);
|
||||
emit_operand(dst, shift, 0);
|
||||
}
|
||||
|
||||
// Shift packed integers logically right by specified number of bits.
|
||||
void Assembler::psrlw(XMMRegister dst, int shift) {
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
@ -9572,6 +9616,20 @@ void Assembler::vpsrlq(XMMRegister dst, XMMRegister src, XMMRegister shift, int
|
||||
emit_int16((unsigned char)0xD3, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::vpsrlq(XMMRegister dst, XMMRegister src, Address shift, int vector_len) {
|
||||
assert(UseAVX > 0, "requires some form of AVX");
|
||||
assert(vector_len == AVX_128bit ? VM_Version::supports_avx() :
|
||||
vector_len == AVX_256bit ? VM_Version::supports_avx2() :
|
||||
vector_len == AVX_512bit ? VM_Version::supports_evex() : 0, "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
attributes.set_rex_vex_w_reverted();
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_M128, /* input_size_in_bits */ EVEX_NObit);
|
||||
vex_prefix(shift, src->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
|
||||
emit_int8((unsigned char)0xD3);
|
||||
emit_operand(dst, shift, 0);
|
||||
}
|
||||
|
||||
void Assembler::evpsrlvw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
|
||||
assert(VM_Version::supports_avx512bw(), "");
|
||||
InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
@ -9712,6 +9770,18 @@ void Assembler::vpsllvq(XMMRegister dst, XMMRegister src, XMMRegister shift, int
|
||||
emit_int16(0x47, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::vpsllvq(XMMRegister dst, XMMRegister src, Address shift, int vector_len) {
|
||||
assert(vector_len == AVX_128bit ? VM_Version::supports_avx2() :
|
||||
vector_len == AVX_256bit ? VM_Version::supports_avx2() :
|
||||
vector_len == AVX_512bit ? VM_Version::supports_evex() : 0, "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
|
||||
vex_prefix(shift, src->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
|
||||
emit_int8((unsigned char)0x47);
|
||||
emit_operand(dst, shift, 0);
|
||||
}
|
||||
|
||||
//Variable Shift packed integers logically right.
|
||||
void Assembler::vpsrlvd(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len) {
|
||||
assert(UseAVX > 1, "requires AVX2");
|
||||
@ -9727,6 +9797,18 @@ void Assembler::vpsrlvq(XMMRegister dst, XMMRegister src, XMMRegister shift, int
|
||||
emit_int16(0x45, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::vpsrlvq(XMMRegister dst, XMMRegister src, Address shift, int vector_len) {
|
||||
assert(vector_len == AVX_128bit ? VM_Version::supports_avx2() :
|
||||
vector_len == AVX_256bit ? VM_Version::supports_avx2() :
|
||||
vector_len == AVX_512bit ? VM_Version::supports_evex() : 0, "");
|
||||
InstructionMark im(this);
|
||||
InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
|
||||
vex_prefix(shift, src->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
|
||||
emit_int8((unsigned char)0x45);
|
||||
emit_operand(dst, shift, 0);
|
||||
}
|
||||
|
||||
//Variable right Shift arithmetic packed integers .
|
||||
void Assembler::vpsravd(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len) {
|
||||
assert(UseAVX > 1, "requires AVX2");
|
||||
|
||||
@ -1612,6 +1612,7 @@ private:
|
||||
// Move Aligned Double Quadword
|
||||
void movdqa(XMMRegister dst, XMMRegister src);
|
||||
void movdqa(XMMRegister dst, Address src);
|
||||
void movdqa(Address dst, XMMRegister src);
|
||||
|
||||
// Move Unaligned Double Quadword
|
||||
void movdqu(Address dst, XMMRegister src);
|
||||
@ -1661,8 +1662,10 @@ private:
|
||||
void evmovdquq(Address dst, KRegister mask, XMMRegister src, bool merge, int vector_len);
|
||||
|
||||
// Move Aligned 512bit Vector
|
||||
void evmovdqaq(XMMRegister dst, Address src, int vector_len);
|
||||
void evmovdqaq(XMMRegister dst, KRegister mask, Address src, bool merge, int vector_len);
|
||||
void evmovdqaq(XMMRegister dst, Address src, int vector_len);
|
||||
void evmovdqaq(Address dst, XMMRegister src, int vector_len);
|
||||
void evmovdqaq(XMMRegister dst, KRegister mask, Address src, bool merge, int vector_len);
|
||||
void evmovdqaq(Address dst, KRegister mask, XMMRegister src, bool merge, int vector_len);
|
||||
|
||||
void vmovsldup(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
void vmovshdup(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
@ -2860,6 +2863,7 @@ private:
|
||||
void vpsllw(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len);
|
||||
void vpslld(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len);
|
||||
void vpsllq(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len);
|
||||
void vpsllq(XMMRegister dst, XMMRegister src, Address shift, int vector_len);
|
||||
void vpslldq(XMMRegister dst, XMMRegister src, int shift, int vector_len);
|
||||
|
||||
// Logical shift right packed integers
|
||||
@ -2875,6 +2879,7 @@ private:
|
||||
void vpsrlw(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len);
|
||||
void vpsrld(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len);
|
||||
void vpsrlq(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len);
|
||||
void vpsrlq(XMMRegister dst, XMMRegister src, Address shift, int vector_len);
|
||||
void vpsrldq(XMMRegister dst, XMMRegister src, int shift, int vector_len);
|
||||
void evpsrlvw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
|
||||
void evpsllvw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
|
||||
@ -2895,10 +2900,12 @@ private:
|
||||
// Variable shift left packed integers
|
||||
void vpsllvd(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len);
|
||||
void vpsllvq(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len);
|
||||
void vpsllvq(XMMRegister dst, XMMRegister src, Address shift, int vector_len);
|
||||
|
||||
// Variable shift right packed integers
|
||||
void vpsrlvd(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len);
|
||||
void vpsrlvq(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len);
|
||||
void vpsrlvq(XMMRegister dst, XMMRegister src, Address shift, int vector_len);
|
||||
|
||||
// Variable shift right arithmetic packed integers
|
||||
void vpsravd(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len);
|
||||
|
||||
@ -1137,7 +1137,8 @@ void ShenandoahBarrierStubC2::keepalive(MacroAssembler& masm, Label* L_done) {
|
||||
}
|
||||
|
||||
// Go to runtime and handle the rest there.
|
||||
__ call(RuntimeAddress(keepalive_runtime_entry_addr()));
|
||||
// Use rax as scratch, as it will be saved if live.
|
||||
__ call(RuntimeAddress(keepalive_runtime_entry_addr()), rax);
|
||||
}
|
||||
if (L_done != nullptr) {
|
||||
__ jmp(*L_done);
|
||||
@ -1260,7 +1261,8 @@ void ShenandoahBarrierStubC2::lrb(MacroAssembler& masm) {
|
||||
}
|
||||
|
||||
// Go to runtime and handle the rest there.
|
||||
__ call(RuntimeAddress(lrb_runtime_entry_addr()));
|
||||
// Use rax as scratch, as it will be clobbered by result anyway.
|
||||
__ call(RuntimeAddress(lrb_runtime_entry_addr()), rax);
|
||||
|
||||
// Save the result where needed.
|
||||
if (_narrow) {
|
||||
|
||||
@ -2124,6 +2124,26 @@ void MacroAssembler::vmovdqa(XMMRegister dst, AddressLiteral src, int vector_len
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::vmovdqa(XMMRegister dst, Address src, int vector_len) {
|
||||
if (vector_len == AVX_512bit) {
|
||||
Assembler::evmovdqaq(dst, src, AVX_512bit);
|
||||
} else if (vector_len == AVX_256bit) {
|
||||
Assembler::vmovdqa(dst, src);
|
||||
} else {
|
||||
Assembler::movdqa(dst, src);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::vmovdqa(Address dst, XMMRegister src, int vector_len) {
|
||||
if (vector_len == AVX_512bit) {
|
||||
Assembler::evmovdqaq(dst, src, AVX_512bit);
|
||||
} else if (vector_len == AVX_256bit) {
|
||||
Assembler::vmovdqa(dst, src);
|
||||
} else {
|
||||
Assembler::movdqa(dst, src);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::kmov(KRegister dst, Address src) {
|
||||
if (VM_Version::supports_avx512bw()) {
|
||||
kmovql(dst, src);
|
||||
|
||||
@ -1181,6 +1181,8 @@ public:
|
||||
using Assembler::vmovdqa;
|
||||
void vmovdqa(XMMRegister dst, AddressLiteral src, Register rscratch = noreg);
|
||||
void vmovdqa(XMMRegister dst, AddressLiteral src, int vector_len, Register rscratch = noreg);
|
||||
void vmovdqa(XMMRegister dst, Address src, int vector_len);
|
||||
void vmovdqa(Address dst, XMMRegister src, int vector_len);
|
||||
|
||||
// AVX512 Unaligned
|
||||
void evmovdqu(BasicType type, KRegister kmask, Address dst, XMMRegister src, bool merge, int vector_len);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1323,7 +1323,8 @@ void VM_Version::get_processor_features() {
|
||||
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
|
||||
}
|
||||
|
||||
if (UseSHA && supports_evex() && supports_avx512bw()) {
|
||||
if (UseSHA && ((supports_evex() && supports_avx512vlbw()) ||
|
||||
(EnableX86ECoreOpts && !supports_hybrid()))) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA3Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA3Intrinsics, true);
|
||||
}
|
||||
|
||||
@ -1742,14 +1742,10 @@ static inline void movfp(MacroAssembler* masm, enum FP_PREC pt,
|
||||
// ja -> b # a
|
||||
// jp -> NaN # NaN
|
||||
// jb -> a # b
|
||||
// je #
|
||||
// |-jz -> a | b # a & b
|
||||
// | -> a #
|
||||
// je -> a | b # a & b
|
||||
static void emit_fp_min_max(MacroAssembler* masm, XMMRegister dst,
|
||||
XMMRegister a, XMMRegister b,
|
||||
XMMRegister xmmt, Register rt,
|
||||
XMMRegister a, XMMRegister b, Register rt,
|
||||
bool min, enum FP_PREC pt) {
|
||||
|
||||
Label nan, zero, below, above, done;
|
||||
|
||||
emit_fp_ucom(masm, pt, a, b);
|
||||
@ -1759,31 +1755,26 @@ static void emit_fp_min_max(MacroAssembler* masm, XMMRegister dst,
|
||||
} else {
|
||||
__ jccb(Assembler::above, done);
|
||||
}
|
||||
|
||||
__ jccb(Assembler::parity, nan); // PF=1
|
||||
__ jccb(Assembler::below, below); // CF=1
|
||||
|
||||
// equal
|
||||
__ vpxor(xmmt, xmmt, xmmt, Assembler::AVX_128bit);
|
||||
emit_fp_ucom(masm, pt, a, xmmt);
|
||||
|
||||
__ jccb(Assembler::equal, zero);
|
||||
movfp(masm, pt, dst, a, rt);
|
||||
|
||||
__ jmp(done);
|
||||
|
||||
__ bind(zero);
|
||||
// Using bitwise operations is a low cost way to compute the correct result
|
||||
// for zero and non-zero inputs in this scenario except for NaN, which is
|
||||
// handled separately. The mantissa and exponent are valid with either
|
||||
// bitwise operation. For zero inputs, the sign bit is chosen according to
|
||||
// whether a minimum or maximum value is required.
|
||||
if (min) {
|
||||
// Negative sign preserved when available (e.g., min(+0, -0) -> -0)
|
||||
__ vpor(dst, a, b, Assembler::AVX_128bit);
|
||||
} else {
|
||||
// Positive sign preserved when available (e.g., max(+0, -0) -> +0)
|
||||
__ vpand(dst, a, b, Assembler::AVX_128bit);
|
||||
}
|
||||
|
||||
__ jmp(done);
|
||||
|
||||
__ bind(above);
|
||||
movfp(masm, pt, dst, min ? b : a, rt);
|
||||
|
||||
__ jmp(done);
|
||||
|
||||
__ bind(nan);
|
||||
@ -7376,18 +7367,18 @@ instruct minmaxF_reg_avx10_2(regF dst, regF a, regF b)
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
instruct minmaxF_reduction_reg_avx10_2(regF dst, regF a, regF b, regF xtmp, rRegI rtmp, rFlagsReg cr)
|
||||
instruct minmaxF_reduction_reg_avx10_2(regF dst, regF a, regF b, rRegI rtmp, rFlagsReg cr)
|
||||
%{
|
||||
predicate(VM_Version::supports_avx10_2() && VLoopReductions::is_reduction(n));
|
||||
match(Set dst (MaxF a b));
|
||||
match(Set dst (MinF a b));
|
||||
effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr);
|
||||
effect(USE a, USE b, TEMP rtmp, KILL cr);
|
||||
|
||||
format %{ "minmaxF_reduction $dst, $a, $b \t! using $xtmp and $rtmp as TEMP" %}
|
||||
format %{ "minmaxF_reduction $dst, $a, $b \t! using $rtmp as TEMP" %}
|
||||
ins_encode %{
|
||||
int opcode = this->ideal_Opcode();
|
||||
bool min = (opcode == Op_MinF) ? true : false;
|
||||
emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register,
|
||||
emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $rtmp$$Register,
|
||||
min, fp_prec_flt /*pt*/);
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
@ -7412,18 +7403,18 @@ instruct minmaxF_reg(legRegF dst, legRegF a, legRegF b, legRegF tmp, legRegF atm
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
instruct minmaxF_reduction_reg(legRegF dst, legRegF a, legRegF b, legRegF xtmp, rRegI rtmp, rFlagsReg cr)
|
||||
instruct minmaxF_reduction_reg(legRegF dst, legRegF a, legRegF b, rRegI rtmp, rFlagsReg cr)
|
||||
%{
|
||||
predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n));
|
||||
match(Set dst (MaxF a b));
|
||||
match(Set dst (MinF a b));
|
||||
effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr);
|
||||
effect(USE a, USE b, TEMP rtmp, KILL cr);
|
||||
|
||||
format %{ "minmaxF_reduction $dst, $a, $b \t!using $xtmp and $rtmp as TEMP" %}
|
||||
format %{ "minmaxF_reduction $dst, $a, $b \t!using $rtmp as TEMP" %}
|
||||
ins_encode %{
|
||||
int opcode = this->ideal_Opcode();
|
||||
bool min = (opcode == Op_MinF) ? true : false;
|
||||
emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register,
|
||||
emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $rtmp$$Register,
|
||||
min, fp_prec_flt /*pt*/);
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
@ -7445,18 +7436,18 @@ instruct minmaxD_reg_avx10_2(regD dst, regD a, regD b)
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
instruct minmaxD_reduction_reg_avx10_2(regD dst, regD a, regD b, regD xtmp, rRegI rtmp, rFlagsReg cr)
|
||||
instruct minmaxD_reduction_reg_avx10_2(regD dst, regD a, regD b, rRegI rtmp, rFlagsReg cr)
|
||||
%{
|
||||
predicate(VM_Version::supports_avx10_2() && VLoopReductions::is_reduction(n));
|
||||
match(Set dst (MaxD a b));
|
||||
match(Set dst (MinD a b));
|
||||
effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr);
|
||||
effect(USE a, USE b, TEMP rtmp, KILL cr);
|
||||
|
||||
format %{ "minmaxD_reduction $dst, $a, $b \t! using $xtmp and $rtmp as TEMP" %}
|
||||
format %{ "minmaxD_reduction $dst, $a, $b \t! using $rtmp as TEMP" %}
|
||||
ins_encode %{
|
||||
int opcode = this->ideal_Opcode();
|
||||
bool min = (opcode == Op_MinD) ? true : false;
|
||||
emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register,
|
||||
emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $rtmp$$Register,
|
||||
min, fp_prec_dbl /*pt*/);
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
@ -7481,18 +7472,18 @@ instruct minmaxD_reg(legRegD dst, legRegD a, legRegD b, legRegD tmp, legRegD atm
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
instruct minmaxD_reduction_reg(legRegD dst, legRegD a, legRegD b, legRegD xtmp, rRegL rtmp, rFlagsReg cr)
|
||||
instruct minmaxD_reduction_reg(legRegD dst, legRegD a, legRegD b, rRegL rtmp, rFlagsReg cr)
|
||||
%{
|
||||
predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n));
|
||||
match(Set dst (MaxD a b));
|
||||
match(Set dst (MinD a b));
|
||||
effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr);
|
||||
effect(USE a, USE b, TEMP rtmp, KILL cr);
|
||||
|
||||
format %{ "minmaxD_reduction $dst, $a, $b \t! using $xtmp and $rtmp as TEMP" %}
|
||||
format %{ "minmaxD_reduction $dst, $a, $b \t! using $rtmp as TEMP" %}
|
||||
ins_encode %{
|
||||
int opcode = this->ideal_Opcode();
|
||||
bool min = (opcode == Op_MinD) ? true : false;
|
||||
emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register,
|
||||
emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $rtmp$$Register,
|
||||
min, fp_prec_dbl /*pt*/);
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
|
||||
@ -132,6 +132,7 @@ class java_lang_String : AllStatic {
|
||||
static inline bool is_latin1(oop java_string);
|
||||
static inline bool deduplication_forbidden(oop java_string);
|
||||
static inline bool deduplication_requested(oop java_string);
|
||||
static inline bool deduplication_requested_or_forbidden(oop java_string);
|
||||
static inline int length(oop java_string);
|
||||
static inline int length(oop java_string, typeArrayOop string_value);
|
||||
static size_t utf8_length(oop java_string);
|
||||
|
||||
@ -91,6 +91,10 @@ bool java_lang_String::deduplication_requested(oop java_string) {
|
||||
return is_flag_set(java_string, _deduplication_requested_mask);
|
||||
}
|
||||
|
||||
bool java_lang_String::deduplication_requested_or_forbidden(oop java_string) {
|
||||
return is_flag_set(java_string, _deduplication_requested_mask | _deduplication_forbidden_mask);
|
||||
}
|
||||
|
||||
void java_lang_String::set_deduplication_forbidden(oop java_string) {
|
||||
test_and_set_flag(java_string, _deduplication_forbidden_mask);
|
||||
}
|
||||
|
||||
@ -487,6 +487,7 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) {
|
||||
if (!UseSHA512Intrinsics) return true;
|
||||
break;
|
||||
case vmIntrinsics::_double_keccak:
|
||||
case vmIntrinsics::_quad_keccak:
|
||||
case vmIntrinsics::_sha3_implCompress:
|
||||
if (!UseSHA3Intrinsics) return true;
|
||||
break;
|
||||
|
||||
@ -526,9 +526,12 @@ class methodHandle;
|
||||
\
|
||||
/* support for sun.security.provider.SHAKE128Parallel */ \
|
||||
do_class(sun_security_provider_sha3_parallel, "sun/security/provider/SHA3Parallel") \
|
||||
do_intrinsic(_double_keccak, sun_security_provider_sha3_parallel, double_keccak_name, double_keccak_signature, F_S) \
|
||||
do_intrinsic(_double_keccak, sun_security_provider_sha3_parallel, double_keccak_name, double_keccak_signature, F_S) \
|
||||
do_name( double_keccak_name, "doubleKeccak") \
|
||||
do_signature(double_keccak_signature, "([J[J)I") \
|
||||
do_intrinsic(_quad_keccak, sun_security_provider_sha3_parallel, quad_keccak_name, quad_keccak_signature, F_S) \
|
||||
do_name( quad_keccak_name, "quadKeccak") \
|
||||
do_signature(quad_keccak_signature, "([J[J[J[J)I") \
|
||||
\
|
||||
/* support for sun.security.provider.DigestBase */ \
|
||||
do_class(sun_security_provider_digestbase, "sun/security/provider/DigestBase") \
|
||||
|
||||
@ -991,7 +991,7 @@ public:
|
||||
// state is cached, therefore, during concurrent class unloading phase,
|
||||
// we will not touch the metadata of unloading nmethods
|
||||
{
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCache, worker_id);
|
||||
ShenandoahIsNMethodAliveClosure is_nmethod_alive;
|
||||
_nmethod_itr.nmethods_do(&is_nmethod_alive);
|
||||
}
|
||||
@ -1004,9 +1004,8 @@ void ShenandoahConcurrentGC::op_weak_roots() {
|
||||
assert(heap->is_concurrent_weak_root_in_progress(), "Only during this phase");
|
||||
{
|
||||
// Concurrent weak root processing
|
||||
ShenandoahTimingsTracker t(ShenandoahPhaseTimings::conc_weak_roots_work);
|
||||
ShenandoahGCWorkerPhase worker_phase(ShenandoahPhaseTimings::conc_weak_roots_work);
|
||||
ShenandoahConcurrentWeakRootsEvacUpdateTask task(_generation, ShenandoahPhaseTimings::conc_weak_roots_work);
|
||||
ShenandoahGCWorkerPhase worker_phase(ShenandoahPhaseTimings::conc_weak_roots);
|
||||
ShenandoahConcurrentWeakRootsEvacUpdateTask task(_generation, ShenandoahPhaseTimings::conc_weak_roots);
|
||||
heap->workers()->run_task(&task);
|
||||
}
|
||||
|
||||
@ -1080,7 +1079,7 @@ public:
|
||||
}
|
||||
|
||||
if (!ShenandoahHeap::heap()->unload_classes()) {
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCache, worker_id);
|
||||
ShenandoahEvacUpdateCodeCacheClosure cl;
|
||||
_nmethod_itr.nmethods_do(&cl);
|
||||
}
|
||||
|
||||
@ -36,7 +36,6 @@
|
||||
#include "gc/shenandoah/shenandoahReferenceProcessor.hpp"
|
||||
#include "gc/shenandoah/shenandoahRootProcessor.inline.hpp"
|
||||
#include "gc/shenandoah/shenandoahScanRemembered.inline.hpp"
|
||||
#include "gc/shenandoah/shenandoahStringDedup.hpp"
|
||||
#include "gc/shenandoah/shenandoahTaskqueue.inline.hpp"
|
||||
#include "gc/shenandoah/shenandoahUtils.hpp"
|
||||
#include "memory/iterator.inline.hpp"
|
||||
@ -57,12 +56,9 @@ public:
|
||||
|
||||
void work(uint worker_id) {
|
||||
ShenandoahConcurrentWorkerSession worker_session(worker_id);
|
||||
ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::conc_mark, ShenandoahPhaseTimings::ParallelMark, worker_id, true);
|
||||
ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::conc_mark, ShenandoahPhaseTimings::Work, worker_id, true);
|
||||
SuspendibleThreadSetJoiner stsj;
|
||||
StringDedup::Requests requests;
|
||||
_cm->mark_loop(worker_id, _terminator, GENERATION, true /*cancellable*/,
|
||||
ShenandoahStringDedup::is_enabled() ? ENQUEUE_DEDUP : NO_DEDUP,
|
||||
&requests);
|
||||
_cm->mark_loop(worker_id, _terminator, GENERATION, true /*cancellable*/);
|
||||
}
|
||||
};
|
||||
|
||||
@ -71,20 +67,19 @@ class ShenandoahFinalMarkingTask : public WorkerTask {
|
||||
private:
|
||||
ShenandoahConcurrentMark* _cm;
|
||||
TaskTerminator* _terminator;
|
||||
bool _dedup_string;
|
||||
ThreadsClaimTokenScope _threads_claim_token_scope; // needed for Threads::possibly_parallel_threads_do
|
||||
|
||||
public:
|
||||
ShenandoahFinalMarkingTask(ShenandoahConcurrentMark* cm, TaskTerminator* terminator, bool dedup_string) :
|
||||
WorkerTask("Shenandoah Final Mark"), _cm(cm), _terminator(terminator), _dedup_string(dedup_string),
|
||||
ShenandoahFinalMarkingTask(ShenandoahConcurrentMark* cm, TaskTerminator* terminator) :
|
||||
WorkerTask("Shenandoah Final Mark"), _cm(cm), _terminator(terminator),
|
||||
_threads_claim_token_scope() {
|
||||
}
|
||||
|
||||
void work(uint worker_id) {
|
||||
ShenandoahHeap* heap = ShenandoahHeap::heap();
|
||||
|
||||
ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::finish_mark, ShenandoahPhaseTimings::Work, worker_id, true);
|
||||
ShenandoahParallelWorkerSession worker_session(worker_id);
|
||||
StringDedup::Requests requests;
|
||||
// First drain remaining SATB buffers.
|
||||
{
|
||||
ShenandoahObjToScanQueue* q = _cm->get_queue(worker_id);
|
||||
@ -98,9 +93,7 @@ public:
|
||||
ShenandoahFlushSATB tc(satb_mq_set);
|
||||
Threads::possibly_parallel_threads_do(true /* is_par */, &tc);
|
||||
}
|
||||
_cm->mark_loop(worker_id, _terminator, GENERATION, false /*not cancellable*/,
|
||||
_dedup_string ? ENQUEUE_DEDUP : NO_DEDUP,
|
||||
&requests);
|
||||
_cm->mark_loop(worker_id, _terminator, GENERATION, false /*not cancellable*/);
|
||||
assert(_cm->task_queues()->is_empty(), "Should be empty");
|
||||
}
|
||||
};
|
||||
@ -278,22 +271,22 @@ void ShenandoahConcurrentMark::finish_mark_work() {
|
||||
|
||||
switch (_generation->type()) {
|
||||
case YOUNG:{
|
||||
ShenandoahFinalMarkingTask<YOUNG> task(this, &terminator, ShenandoahStringDedup::is_enabled());
|
||||
ShenandoahFinalMarkingTask<YOUNG> task(this, &terminator);
|
||||
heap->workers()->run_task(&task);
|
||||
break;
|
||||
}
|
||||
case OLD:{
|
||||
ShenandoahFinalMarkingTask<OLD> task(this, &terminator, ShenandoahStringDedup::is_enabled());
|
||||
ShenandoahFinalMarkingTask<OLD> task(this, &terminator);
|
||||
heap->workers()->run_task(&task);
|
||||
break;
|
||||
}
|
||||
case GLOBAL:{
|
||||
ShenandoahFinalMarkingTask<GLOBAL> task(this, &terminator, ShenandoahStringDedup::is_enabled());
|
||||
ShenandoahFinalMarkingTask<GLOBAL> task(this, &terminator);
|
||||
heap->workers()->run_task(&task);
|
||||
break;
|
||||
}
|
||||
case NON_GEN:{
|
||||
ShenandoahFinalMarkingTask<NON_GEN> task(this, &terminator, ShenandoahStringDedup::is_enabled());
|
||||
ShenandoahFinalMarkingTask<NON_GEN> task(this, &terminator);
|
||||
heap->workers()->run_task(&task);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -347,7 +347,7 @@ void ShenandoahDegenGC::op_reset() {
|
||||
|
||||
void ShenandoahDegenGC::op_mark() {
|
||||
assert(!_generation->is_concurrent_mark_in_progress(), "Should be reset");
|
||||
ShenandoahGCPhase phase(ShenandoahPhaseTimings::degen_gc_stw_mark);
|
||||
ShenandoahGCPhase phase(ShenandoahPhaseTimings::degen_gc_mark);
|
||||
ShenandoahSTWMark mark(_generation, false /*full gc*/);
|
||||
mark.mark();
|
||||
}
|
||||
@ -410,7 +410,7 @@ void ShenandoahDegenGC::op_cleanup_early() {
|
||||
}
|
||||
|
||||
void ShenandoahDegenGC::op_evacuate() {
|
||||
ShenandoahGCPhase phase(ShenandoahPhaseTimings::degen_gc_stw_evac);
|
||||
ShenandoahGCPhase phase(ShenandoahPhaseTimings::degen_gc_evac);
|
||||
ShenandoahHeap::heap()->evacuate_collection_set(_generation, false /* concurrent*/);
|
||||
}
|
||||
|
||||
|
||||
@ -669,7 +669,7 @@ void ShenandoahGenerationalHeap::coalesce_and_fill_old_regions(bool concurrent)
|
||||
|
||||
void work(uint worker_id) override {
|
||||
ShenandoahWorkerTimingsTracker timer(_phase,
|
||||
ShenandoahPhaseTimings::ScanClusters,
|
||||
ShenandoahPhaseTimings::Work,
|
||||
worker_id, true);
|
||||
ShenandoahHeapRegion* region;
|
||||
while ((region = _regions.next()) != nullptr) {
|
||||
|
||||
@ -1127,10 +1127,12 @@ public:
|
||||
|
||||
void work(uint worker_id) {
|
||||
if (_concurrent) {
|
||||
ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::conc_evac, ShenandoahPhaseTimings::Work, worker_id, true);
|
||||
ShenandoahConcurrentWorkerSession worker_session(worker_id);
|
||||
SuspendibleThreadSetJoiner stsj;
|
||||
do_work();
|
||||
} else {
|
||||
ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::degen_gc_evac, ShenandoahPhaseTimings::Work, worker_id, true);
|
||||
ShenandoahParallelWorkerSession worker_session(worker_id);
|
||||
do_work();
|
||||
}
|
||||
@ -2533,10 +2535,12 @@ public:
|
||||
|
||||
void work(uint worker_id) {
|
||||
if (CONCURRENT) {
|
||||
ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::conc_update_refs, ShenandoahPhaseTimings::Work, worker_id, true);
|
||||
ShenandoahConcurrentWorkerSession worker_session(worker_id);
|
||||
SuspendibleThreadSetJoiner stsj;
|
||||
do_work<ShenandoahConcUpdateRefsClosure>(worker_id);
|
||||
} else {
|
||||
ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::degen_gc_update_refs, ShenandoahPhaseTimings::Work, worker_id, true);
|
||||
ShenandoahParallelWorkerSession worker_session(worker_id);
|
||||
do_work<ShenandoahNonConcUpdateRefsClosure>(worker_id);
|
||||
}
|
||||
|
||||
@ -51,10 +51,11 @@ void ShenandoahMark::end_mark() {
|
||||
ShenandoahMark::ShenandoahMark(ShenandoahGeneration* generation) :
|
||||
_generation(generation),
|
||||
_task_queues(generation->task_queues()),
|
||||
_old_gen_task_queues(generation->old_gen_task_queues()) {
|
||||
_old_gen_task_queues(generation->old_gen_task_queues()),
|
||||
_string_dedup(StringDedup::is_enabled()) {
|
||||
}
|
||||
|
||||
template <ShenandoahGenerationType GENERATION, bool CANCELLABLE, StringDedupMode STRING_DEDUP>
|
||||
template <ShenandoahGenerationType GENERATION, bool CANCELLABLE, bool STRING_DEDUP>
|
||||
void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, StringDedup::Requests* const req, bool update_refs) {
|
||||
ShenandoahObjToScanQueue* q = get_queue(w);
|
||||
ShenandoahObjToScanQueue* old_q = get_old_queue(w);
|
||||
@ -77,7 +78,7 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, StringDedup::R
|
||||
heap->flush_liveness_cache(w);
|
||||
}
|
||||
|
||||
template<bool CANCELLABLE, StringDedupMode STRING_DEDUP>
|
||||
template<bool CANCELLABLE, bool STRING_DEDUP>
|
||||
void ShenandoahMark::mark_loop(uint worker_id, TaskTerminator* terminator,
|
||||
ShenandoahGenerationType generation_type, StringDedup::Requests* const req) {
|
||||
bool update_refs = ShenandoahHeap::heap()->has_forwarded_objects();
|
||||
@ -102,35 +103,24 @@ void ShenandoahMark::mark_loop(uint worker_id, TaskTerminator* terminator,
|
||||
}
|
||||
|
||||
void ShenandoahMark::mark_loop(uint worker_id, TaskTerminator* terminator, ShenandoahGenerationType generation_type,
|
||||
bool cancellable, StringDedupMode dedup_mode, StringDedup::Requests* const req) {
|
||||
if (cancellable) {
|
||||
switch(dedup_mode) {
|
||||
case NO_DEDUP:
|
||||
mark_loop<true, NO_DEDUP>(worker_id, terminator, generation_type, req);
|
||||
break;
|
||||
case ENQUEUE_DEDUP:
|
||||
mark_loop<true, ENQUEUE_DEDUP>(worker_id, terminator, generation_type, req);
|
||||
break;
|
||||
case ALWAYS_DEDUP:
|
||||
mark_loop<true, ALWAYS_DEDUP>(worker_id, terminator, generation_type, req);
|
||||
break;
|
||||
bool cancellable) {
|
||||
if (_string_dedup) {
|
||||
StringDedup::Requests req;
|
||||
if (cancellable) {
|
||||
mark_loop<true, true>(worker_id, terminator, generation_type, &req);
|
||||
} else {
|
||||
mark_loop<false, true>(worker_id, terminator, generation_type, &req);
|
||||
}
|
||||
} else {
|
||||
switch(dedup_mode) {
|
||||
case NO_DEDUP:
|
||||
mark_loop<false, NO_DEDUP>(worker_id, terminator, generation_type, req);
|
||||
break;
|
||||
case ENQUEUE_DEDUP:
|
||||
mark_loop<false, ENQUEUE_DEDUP>(worker_id, terminator, generation_type, req);
|
||||
break;
|
||||
case ALWAYS_DEDUP:
|
||||
mark_loop<false, ALWAYS_DEDUP>(worker_id, terminator, generation_type, req);
|
||||
break;
|
||||
if (cancellable) {
|
||||
mark_loop<true, false>(worker_id, terminator, generation_type, nullptr);
|
||||
} else {
|
||||
mark_loop<false, false>(worker_id, terminator, generation_type, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, ShenandoahGenerationType GENERATION, bool CANCELLABLE, StringDedupMode STRING_DEDUP>
|
||||
template <class T, ShenandoahGenerationType GENERATION, bool CANCELLABLE, bool STRING_DEDUP>
|
||||
void ShenandoahMark::mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint worker_id, TaskTerminator *terminator, StringDedup::Requests* const req) {
|
||||
uintx stride = ShenandoahMarkLoopStride;
|
||||
|
||||
|
||||
@ -34,12 +34,6 @@
|
||||
#include "gc/shenandoah/shenandoahHeap.hpp"
|
||||
#include "gc/shenandoah/shenandoahTaskqueue.hpp"
|
||||
|
||||
enum StringDedupMode {
|
||||
NO_DEDUP, // Do not do anything for String deduplication
|
||||
ENQUEUE_DEDUP, // Enqueue candidate Strings for deduplication, if meet age threshold
|
||||
ALWAYS_DEDUP // Enqueue Strings for deduplication
|
||||
};
|
||||
|
||||
class ShenandoahMarkingContext;
|
||||
|
||||
// Base class for mark
|
||||
@ -50,6 +44,7 @@ protected:
|
||||
ShenandoahGeneration* const _generation;
|
||||
ShenandoahObjToScanQueueSet* const _task_queues;
|
||||
ShenandoahObjToScanQueueSet* const _old_gen_task_queues;
|
||||
bool const _string_dedup;
|
||||
|
||||
protected:
|
||||
ShenandoahMark(ShenandoahGeneration* generation);
|
||||
@ -76,7 +71,7 @@ public:
|
||||
private:
|
||||
// ---------- Marking loop and tasks
|
||||
|
||||
template <class T, ShenandoahGenerationType GENERATION, StringDedupMode STRING_DEDUP>
|
||||
template <class T, ShenandoahGenerationType GENERATION, bool STRING_DEDUP>
|
||||
inline void do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveData* live_data, StringDedup::Requests* const req, ShenandoahMarkTask* task, uint worker_id);
|
||||
|
||||
template <class T>
|
||||
@ -88,10 +83,10 @@ private:
|
||||
template <ShenandoahGenerationType GENERATION>
|
||||
inline void count_liveness(ShenandoahLiveData* live_data, oop obj, Klass* klass, uint worker_id);
|
||||
|
||||
template <class T, ShenandoahGenerationType GENERATION, bool CANCELLABLE, StringDedupMode STRING_DEDUP>
|
||||
template <class T, ShenandoahGenerationType GENERATION, bool CANCELLABLE, bool STRING_DEDUP>
|
||||
void mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint worker_id, TaskTerminator *t, StringDedup::Requests* const req);
|
||||
|
||||
template <ShenandoahGenerationType GENERATION, bool CANCELLABLE, StringDedupMode STRING_DEDUP>
|
||||
template <ShenandoahGenerationType GENERATION, bool CANCELLABLE, bool STRING_DEDUP>
|
||||
void mark_loop_prework(uint worker_id, TaskTerminator *terminator, StringDedup::Requests* const req, bool update_refs);
|
||||
|
||||
template <ShenandoahGenerationType GENERATION>
|
||||
@ -104,15 +99,14 @@ private:
|
||||
ShenandoahMarkingContext* const mark_context,
|
||||
bool weak, oop obj);
|
||||
|
||||
template <StringDedupMode STRING_DEDUP>
|
||||
inline void dedup_string(oop obj, StringDedup::Requests* const req);
|
||||
static inline void dedup_string(oop obj, StringDedup::Requests* const req);
|
||||
protected:
|
||||
template<bool CANCELLABLE, StringDedupMode STRING_DEDUP>
|
||||
template<bool CANCELLABLE, bool STRING_DEDUP>
|
||||
void mark_loop(uint worker_id, TaskTerminator* terminator, ShenandoahGenerationType generation_type,
|
||||
StringDedup::Requests* const req);
|
||||
|
||||
void mark_loop(uint worker_id, TaskTerminator* terminator, ShenandoahGenerationType generation_type,
|
||||
bool cancellable, StringDedupMode dedup_mode, StringDedup::Requests* const req);
|
||||
bool cancellable);
|
||||
};
|
||||
|
||||
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHMARK_HPP
|
||||
|
||||
@ -38,7 +38,6 @@
|
||||
#include "gc/shenandoah/shenandoahMarkingContext.inline.hpp"
|
||||
#include "gc/shenandoah/shenandoahOldGeneration.hpp"
|
||||
#include "gc/shenandoah/shenandoahScanRemembered.inline.hpp"
|
||||
#include "gc/shenandoah/shenandoahStringDedup.inline.hpp"
|
||||
#include "gc/shenandoah/shenandoahTaskqueue.inline.hpp"
|
||||
#include "gc/shenandoah/shenandoahUtils.hpp"
|
||||
#include "memory/iterator.inline.hpp"
|
||||
@ -48,21 +47,7 @@
|
||||
#include "utilities/devirtualizer.inline.hpp"
|
||||
#include "utilities/powerOfTwo.hpp"
|
||||
|
||||
template <StringDedupMode STRING_DEDUP>
|
||||
void ShenandoahMark::dedup_string(oop obj, StringDedup::Requests* const req) {
|
||||
if (STRING_DEDUP == ENQUEUE_DEDUP) {
|
||||
if (ShenandoahStringDedup::is_candidate(obj)) {
|
||||
req->add(obj);
|
||||
}
|
||||
} else if (STRING_DEDUP == ALWAYS_DEDUP) {
|
||||
if (ShenandoahStringDedup::is_string_candidate(obj) &&
|
||||
!ShenandoahStringDedup::dedup_requested(obj)) {
|
||||
req->add(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, ShenandoahGenerationType GENERATION, StringDedupMode STRING_DEDUP>
|
||||
template <class T, ShenandoahGenerationType GENERATION, bool STRING_DEDUP>
|
||||
void ShenandoahMark::do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveData* live_data, StringDedup::Requests* const req, ShenandoahMarkTask* task, uint worker_id) {
|
||||
oop obj = task->obj();
|
||||
|
||||
@ -78,13 +63,14 @@ void ShenandoahMark::do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveD
|
||||
Klass* klass = obj->klass();
|
||||
if (klass->is_instance_klass()) {
|
||||
// Case 1: Normal oop, process as usual.
|
||||
if (STRING_DEDUP && (klass == vmClasses::String_klass())) {
|
||||
dedup_string(obj, req);
|
||||
}
|
||||
if (klass->is_stack_chunk_instance_klass()) {
|
||||
// Loom doesn't support mixing of weak marking and strong marking of stack chunks.
|
||||
cl->set_weak(false);
|
||||
}
|
||||
|
||||
obj->oop_iterate(cl);
|
||||
dedup_string<STRING_DEDUP>(obj, req);
|
||||
} else if (klass->is_objArray_klass()) {
|
||||
// Case 2: Object array instance and no chunk is set. Must be the first
|
||||
// time we visit it, start the chunked processing.
|
||||
@ -108,6 +94,22 @@ void ShenandoahMark::do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveD
|
||||
}
|
||||
}
|
||||
|
||||
void ShenandoahMark::dedup_string(oop obj, StringDedup::Requests* const req) {
|
||||
assert(req != nullptr, "Should be available if dedup is enabled");
|
||||
|
||||
// Skip if already requested or dedup is forbidden.
|
||||
// The overwhelming majority of Strings would be filtered here.
|
||||
// These bits are also sticky, so older Strings would be filtered here too.
|
||||
if (java_lang_String::deduplication_requested_or_forbidden(obj)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Accept deduplication request.
|
||||
if (!java_lang_String::test_and_set_deduplication_requested(obj)) {
|
||||
req->add(obj);
|
||||
}
|
||||
}
|
||||
|
||||
template <ShenandoahGenerationType GENERATION>
|
||||
inline void ShenandoahMark::count_liveness(ShenandoahLiveData* live_data, oop obj, Klass* klass, uint worker_id) {
|
||||
const ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
|
||||
@ -78,7 +78,7 @@ public:
|
||||
}
|
||||
|
||||
void work(uint worker_id) override {
|
||||
ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::conc_coalesce_and_fill, ShenandoahPhaseTimings::ScanClusters, worker_id);
|
||||
ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::conc_coalesce_and_fill, ShenandoahPhaseTimings::Work, worker_id);
|
||||
for (uint region_idx = worker_id; region_idx < _coalesce_and_fill_region_count; region_idx += _nworkers) {
|
||||
ShenandoahHeapRegion* r = _coalesce_and_fill_region_array[region_idx];
|
||||
if (r->is_humongous()) {
|
||||
|
||||
@ -41,14 +41,14 @@ ShenandoahClassUnloadingTask::ShenandoahClassUnloadingTask(ShenandoahPhaseTiming
|
||||
|
||||
void ShenandoahClassUnloadingTask::work(uint worker_id) {
|
||||
{
|
||||
ShenandoahWorkerTimingsTracker x(_phase, ShenandoahPhaseTimings::CodeCacheUnload, worker_id);
|
||||
ShenandoahWorkerTimingsTracker x(_phase, ShenandoahPhaseTimings::CodeCache, worker_id);
|
||||
_code_cache_task.work(worker_id);
|
||||
}
|
||||
// Clean all klasses that were not unloaded.
|
||||
// The weak metadata in klass doesn't need to be
|
||||
// processed if there was no unloading.
|
||||
if (_unloading_occurred) {
|
||||
ShenandoahWorkerTimingsTracker x(_phase, ShenandoahPhaseTimings::CLDUnlink, worker_id);
|
||||
ShenandoahWorkerTimingsTracker x(_phase, ShenandoahPhaseTimings::Classes, worker_id);
|
||||
_klass_cleaning_task.work();
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ ShenandoahParallelWeakRootsCleaningTask<IsAlive, KeepAlive>::~ShenandoahParallel
|
||||
template<typename IsAlive, typename KeepAlive>
|
||||
void ShenandoahParallelWeakRootsCleaningTask<IsAlive, KeepAlive>::work(uint worker_id) {
|
||||
{
|
||||
ShenandoahWorkerTimingsTracker x(_phase, ShenandoahPhaseTimings::VMWeakRoots, worker_id);
|
||||
ShenandoahWorkerTimingsTracker x(_phase, ShenandoahPhaseTimings::VMWeaks, worker_id);
|
||||
_weak_processing_task.work<IsAlive, KeepAlive>(worker_id, _is_alive, _keep_alive);
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,14 +40,19 @@
|
||||
#define SHENANDOAH_US_WORKER_NOTIME_FORMAT "%3s"
|
||||
#define SHENANDOAH_PARALLELISM_FORMAT "%4.2lf"
|
||||
|
||||
#define SHENANDOAH_PHASE_DECLARE_NAME(type, title) \
|
||||
title,
|
||||
#define SHENANDOAH_PHASE_DECLARE_DESC(name, desc, has_worker_phase) desc,
|
||||
#define SHENANDOAH_PHASE_DECLARE_HAS_WORKER_PHASE(name, desc, has_worker_phase) has_worker_phase,
|
||||
|
||||
const char* ShenandoahPhaseTimings::_phase_names[] = {
|
||||
SHENANDOAH_PHASE_DO(SHENANDOAH_PHASE_DECLARE_NAME)
|
||||
const char* ShenandoahPhaseTimings::_desc[] = {
|
||||
SHENANDOAH_PHASE_DO(SHENANDOAH_PHASE_DECLARE_DESC)
|
||||
};
|
||||
|
||||
#undef SHENANDOAH_PHASE_DECLARE_NAME
|
||||
bool ShenandoahPhaseTimings::_has_worker_phase[] = {
|
||||
SHENANDOAH_PHASE_DO(SHENANDOAH_PHASE_DECLARE_HAS_WORKER_PHASE)
|
||||
};
|
||||
|
||||
#undef SHENANDOAH_PHASE_DECLARE_DESC
|
||||
#undef SHENANDOAH_PHASE_DECLARE_HAS_WORKER_PHASE
|
||||
|
||||
ShenandoahPhaseTimings::ShenandoahPhaseTimings(uint max_workers) :
|
||||
_max_workers(max_workers) {
|
||||
@ -55,22 +60,17 @@ ShenandoahPhaseTimings::ShenandoahPhaseTimings(uint max_workers) :
|
||||
|
||||
// Initialize everything to sane defaults
|
||||
for (uint i = 0; i < _num_phases; i++) {
|
||||
#define SHENANDOAH_WORKER_DATA_NULL(type, title) \
|
||||
_worker_data[i] = nullptr;
|
||||
SHENANDOAH_PAR_PHASE_DO(,, SHENANDOAH_WORKER_DATA_NULL)
|
||||
#undef SHENANDOAH_WORKER_DATA_NULL
|
||||
_cycle_data[i] = uninitialized();
|
||||
}
|
||||
|
||||
// Then punch in the worker-related data.
|
||||
// Every worker phase get a bunch of internal objects, except
|
||||
// the very first slot, which is "<total>" and is not populated.
|
||||
for (uint i = 0; i < _num_phases; i++) {
|
||||
if (is_worker_phase(Phase(i))) {
|
||||
int c = 0;
|
||||
#define SHENANDOAH_WORKER_DATA_INIT(type, title) \
|
||||
if (c++ != 0) _worker_data[i + c] = new ShenandoahWorkerData(nullptr, title, _max_workers);
|
||||
SHENANDOAH_PAR_PHASE_DO(,, SHENANDOAH_WORKER_DATA_INIT)
|
||||
if (has_worker_phases(Phase(i))) {
|
||||
int c = i + 1;
|
||||
#define SHENANDOAH_WORKER_DATA_INIT(name, desc, has_worker_phase) \
|
||||
_worker_data[c++] = new ShenandoahWorkerData(nullptr, desc, _max_workers);
|
||||
SHENANDOAH_WORKER_PHASE_DO(,, SHENANDOAH_WORKER_DATA_INIT)
|
||||
#undef SHENANDOAH_WORKER_DATA_INIT
|
||||
}
|
||||
}
|
||||
@ -79,59 +79,23 @@ ShenandoahPhaseTimings::ShenandoahPhaseTimings(uint max_workers) :
|
||||
assert(_policy != nullptr, "Can not be null");
|
||||
}
|
||||
|
||||
ShenandoahPhaseTimings::Phase ShenandoahPhaseTimings::worker_par_phase(Phase phase, ParPhase par_phase) {
|
||||
assert(is_worker_phase(phase), "Phase should accept worker phase times: %s", phase_name(phase));
|
||||
Phase p = Phase(phase + 1 + par_phase);
|
||||
assert(p >= 0 && p < _num_phases, "Out of bound for: %s", phase_name(phase));
|
||||
ShenandoahPhaseTimings::Phase ShenandoahPhaseTimings::compute_phase_slot(Phase phase, WorkerPhase worker_phase) {
|
||||
assert(has_worker_phases(phase), "Phase should accept worker phase times: %s", phase_desc(phase));
|
||||
Phase p = Phase(phase + 1 + worker_phase);
|
||||
assert(p >= 0 && p < _num_phases, "Out of bound for: %s", phase_desc(phase));
|
||||
return p;
|
||||
}
|
||||
|
||||
ShenandoahWorkerData* ShenandoahPhaseTimings::worker_data(Phase phase, ParPhase par_phase) {
|
||||
Phase p = worker_par_phase(phase, par_phase);
|
||||
ShenandoahWorkerData* ShenandoahPhaseTimings::worker_data(Phase phase, WorkerPhase worker_phase) {
|
||||
Phase p = compute_phase_slot(phase, worker_phase);
|
||||
ShenandoahWorkerData* wd = _worker_data[p];
|
||||
assert(wd != nullptr, "Counter initialized: %s", phase_name(p));
|
||||
assert(wd != nullptr, "Counter initialized: %s", phase_desc(p));
|
||||
return wd;
|
||||
}
|
||||
|
||||
bool ShenandoahPhaseTimings::is_worker_phase(Phase phase) {
|
||||
assert(phase >= 0 && phase < _num_phases, "Out of bounds");
|
||||
switch (phase) {
|
||||
case init_evac:
|
||||
case init_scan_rset:
|
||||
case finish_mark:
|
||||
case purge_weak_par:
|
||||
case full_gc_mark:
|
||||
case full_gc_update_roots:
|
||||
case full_gc_adjust_roots:
|
||||
case degen_gc_stw_mark:
|
||||
case degen_gc_mark:
|
||||
case degen_gc_update_roots:
|
||||
case full_gc_weakrefs:
|
||||
case full_gc_purge_class_unload:
|
||||
case full_gc_purge_weak_par:
|
||||
case degen_gc_coalesce_and_fill:
|
||||
case degen_gc_weakrefs:
|
||||
case degen_gc_purge_class_unload:
|
||||
case degen_gc_purge_weak_par:
|
||||
case heap_iteration_roots:
|
||||
case conc_mark:
|
||||
case conc_mark_roots:
|
||||
case conc_thread_roots:
|
||||
case conc_weak_roots_work:
|
||||
case conc_weak_refs:
|
||||
case conc_strong_roots:
|
||||
case conc_coalesce_and_fill:
|
||||
case promote_in_place:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ShenandoahPhaseTimings::is_root_work_phase(Phase phase) {
|
||||
switch (phase) {
|
||||
case finish_mark:
|
||||
case init_evac:
|
||||
case degen_gc_update_roots:
|
||||
case full_gc_mark:
|
||||
case full_gc_update_roots:
|
||||
@ -147,9 +111,7 @@ void ShenandoahPhaseTimings::set_cycle_data(Phase phase, double time, bool shoul
|
||||
if (should_aggregate) {
|
||||
_cycle_data[phase] = (cycle_data == uninitialized()) ? time : (cycle_data + time);
|
||||
} else {
|
||||
#ifdef ASSERT
|
||||
assert(cycle_data == uninitialized(), "Should not be set yet: %s, current value: %lf", phase_name(phase), cycle_data);
|
||||
#endif
|
||||
assert(cycle_data == uninitialized(), "Should not be set yet: %s, current value: %lf", phase_desc(phase), cycle_data);
|
||||
_cycle_data[phase] = time;
|
||||
}
|
||||
}
|
||||
@ -161,38 +123,37 @@ void ShenandoahPhaseTimings::record_phase_time(Phase phase, double time, bool sh
|
||||
}
|
||||
|
||||
void ShenandoahPhaseTimings::record_workers_start(Phase phase) {
|
||||
assert(is_worker_phase(phase), "Phase should accept worker phase times: %s", phase_name(phase));
|
||||
assert(has_worker_phases(phase), "Phase should accept worker phase times: %s", phase_desc(phase));
|
||||
|
||||
// Special case: these phases can enter multiple times, need to reset
|
||||
// their worker data every time.
|
||||
if (phase == heap_iteration_roots) {
|
||||
for (uint i = 1; i < _num_par_phases; i++) {
|
||||
worker_data(phase, ParPhase(i))->reset();
|
||||
for (uint i = 0; i < _num_par_phases; i++) {
|
||||
worker_data(phase, WorkerPhase(i))->reset();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
for (uint i = 1; i < _num_par_phases; i++) {
|
||||
ShenandoahWorkerData* wd = worker_data(phase, ParPhase(i));
|
||||
for (uint i = 0; i < _num_par_phases; i++) {
|
||||
ShenandoahWorkerData* wd = worker_data(phase, WorkerPhase(i));
|
||||
for (uint c = 0; c < _max_workers; c++) {
|
||||
assert(wd->get(c) == ShenandoahWorkerData::uninitialized(),
|
||||
"Should not be set: %s", phase_name(worker_par_phase(phase, ParPhase(i))));
|
||||
"Should not be set: %s", phase_desc(compute_phase_slot(phase, WorkerPhase(i))));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ShenandoahPhaseTimings::record_workers_end(Phase phase) {
|
||||
assert(is_worker_phase(phase), "Phase should accept worker phase times: %s", phase_name(phase));
|
||||
assert(has_worker_phases(phase), "Phase should accept worker phase times: %s", phase_desc(phase));
|
||||
}
|
||||
|
||||
void ShenandoahPhaseTimings::flush_par_workers_to_cycle() {
|
||||
for (uint pi = 0; pi < _num_phases; pi++) {
|
||||
Phase phase = Phase(pi);
|
||||
if (is_worker_phase(phase)) {
|
||||
double sum = uninitialized();
|
||||
for (uint i = 1; i < _num_par_phases; i++) {
|
||||
ShenandoahWorkerData* wd = worker_data(phase, ParPhase(i));
|
||||
if (has_worker_phases(phase)) {
|
||||
for (uint i = 0; i < _num_par_phases; i++) {
|
||||
ShenandoahWorkerData* wd = worker_data(phase, WorkerPhase(i));
|
||||
double worker_sum = uninitialized();
|
||||
for (uint c = 0; c < _max_workers; c++) {
|
||||
double worker_time = wd->get(c);
|
||||
@ -207,17 +168,8 @@ void ShenandoahPhaseTimings::flush_par_workers_to_cycle() {
|
||||
if (worker_sum != uninitialized()) {
|
||||
// add to each line in phase
|
||||
set_cycle_data(Phase(phase + i + 1), worker_sum);
|
||||
if (sum == uninitialized()) {
|
||||
sum = worker_sum;
|
||||
} else {
|
||||
sum += worker_sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sum != uninitialized()) {
|
||||
// add to total for phase
|
||||
set_cycle_data(Phase(phase + 1), sum);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -237,23 +189,29 @@ void ShenandoahPhaseTimings::flush_cycle_to_global() {
|
||||
|
||||
void ShenandoahPhaseTimings::print_cycle_on(outputStream* out) const {
|
||||
out->cr();
|
||||
out->print_cr("All times are wall-clock times, except per-root-class counters, that are sum over");
|
||||
out->print_cr("all workers. Dividing the <total> over the root stage time estimates parallelism.");
|
||||
out->print_cr(" All times are wall-clock times, except for ones explicitly marked as \"total\", those are");
|
||||
out->print_cr(" sum over all workers. Dividing the total over the root stage time estimates parallelism.");
|
||||
out->cr();
|
||||
for (uint i = 0; i < _num_phases; i++) {
|
||||
double v = _cycle_data[i] * 1000000.0;
|
||||
if (v > 0) {
|
||||
out->print(SHENANDOAH_PHASE_NAME_FORMAT " " SHENANDOAH_US_TIME_FORMAT " us", _phase_names[i], v);
|
||||
out->print(SHENANDOAH_PHASE_NAME_FORMAT " " SHENANDOAH_US_TIME_FORMAT " us", _desc[i], v);
|
||||
|
||||
if (is_worker_phase(Phase(i))) {
|
||||
double total = _cycle_data[i + 1] * 1000000.0;
|
||||
if (has_worker_phases(Phase(i))) {
|
||||
double total = 0;
|
||||
for (uint pi = 0; pi < _num_par_phases; pi++) {
|
||||
uint idx = i + 1 + pi;
|
||||
if (_cycle_data[idx] != uninitialized()) {
|
||||
total += _cycle_data[idx];
|
||||
}
|
||||
}
|
||||
if (total > 0) {
|
||||
out->print(", parallelism: " SHENANDOAH_PARALLELISM_FORMAT "x", total / v);
|
||||
out->print(" with " SHENANDOAH_PARALLELISM_FORMAT "x parallelism", total * 1000000.0 / v);
|
||||
}
|
||||
}
|
||||
|
||||
if (_worker_data[i] != nullptr) {
|
||||
out->print(", workers (us): ");
|
||||
out->print(" total, per worker: ");
|
||||
for (uint c = 0; c < _max_workers; c++) {
|
||||
double tv = _worker_data[i]->get(c);
|
||||
if (tv != ShenandoahWorkerData::uninitialized()) {
|
||||
@ -277,8 +235,8 @@ void ShenandoahPhaseTimings::print_global_on(outputStream* out) const {
|
||||
out->print_cr(" \"a\" is average time for each phase, look at levels to see if average makes sense.");
|
||||
out->print_cr(" \"lvls\" are quantiles: 0%% (minimum), 25%%, 50%% (median), 75%%, 100%% (maximum).");
|
||||
out->cr();
|
||||
out->print_cr(" All times are wall-clock times, except per-root-class counters, that are sum over");
|
||||
out->print_cr(" all workers. Dividing the <total> over the root stage time estimates parallelism.");
|
||||
out->print_cr(" All times are wall-clock times, except for ones explicitly marked as \"total\", those are");
|
||||
out->print_cr(" sum over all workers. Dividing the total over the root stage time estimates parallelism.");
|
||||
out->cr();
|
||||
|
||||
for (uint i = 0; i < _num_phases; i++) {
|
||||
@ -291,7 +249,7 @@ void ShenandoahPhaseTimings::print_global_on(outputStream* out) const {
|
||||
SHENANDOAH_US_TIME_FORMAT ", "
|
||||
SHENANDOAH_US_TIME_FORMAT ", "
|
||||
SHENANDOAH_US_TIME_FORMAT ")",
|
||||
_phase_names[i],
|
||||
_desc[i],
|
||||
_global_data[i].sum(),
|
||||
_global_data[i].avg() * 1000000.0,
|
||||
_global_data[i].num(),
|
||||
@ -306,21 +264,21 @@ void ShenandoahPhaseTimings::print_global_on(outputStream* out) const {
|
||||
}
|
||||
|
||||
ShenandoahWorkerTimingsTracker::ShenandoahWorkerTimingsTracker(ShenandoahPhaseTimings::Phase phase,
|
||||
ShenandoahPhaseTimings::ParPhase par_phase, uint worker_id, bool cumulative) :
|
||||
ShenandoahPhaseTimings::WorkerPhase worker_phase, uint worker_id, bool cumulative) :
|
||||
_timings(ShenandoahHeap::heap()->phase_timings()),
|
||||
_phase(phase), _par_phase(par_phase), _worker_id(worker_id) {
|
||||
_phase(phase), _worker_phase(worker_phase), _worker_id(worker_id) {
|
||||
|
||||
assert(_timings->worker_data(_phase, _par_phase)->get(_worker_id) == ShenandoahWorkerData::uninitialized() || cumulative,
|
||||
"Should not be set yet: %s", ShenandoahPhaseTimings::phase_name(_timings->worker_par_phase(_phase, _par_phase)));
|
||||
assert(_timings->worker_data(_phase, _worker_phase)->get(_worker_id) == ShenandoahWorkerData::uninitialized() || cumulative,
|
||||
"Should not be set yet: %s", ShenandoahPhaseTimings::phase_desc(_timings->compute_phase_slot(_phase, _worker_phase)));
|
||||
_start_time = os::elapsedTime();
|
||||
}
|
||||
|
||||
ShenandoahWorkerTimingsTracker::~ShenandoahWorkerTimingsTracker() {
|
||||
_timings->worker_data(_phase, _par_phase)->set_or_add(_worker_id, os::elapsedTime() - _start_time);
|
||||
_timings->worker_data(_phase, _worker_phase)->set_or_add(_worker_id, os::elapsedTime() - _start_time);
|
||||
|
||||
if (ShenandoahPhaseTimings::is_root_work_phase(_phase)) {
|
||||
ShenandoahPhaseTimings::Phase root_phase = _phase;
|
||||
ShenandoahPhaseTimings::Phase cur_phase = _timings->worker_par_phase(root_phase, _par_phase);
|
||||
_event.commit(GCId::current(), _worker_id, ShenandoahPhaseTimings::phase_name(cur_phase));
|
||||
ShenandoahPhaseTimings::Phase cur_phase = _timings->compute_phase_slot(root_phase, _worker_phase);
|
||||
_event.commit(GCId::current(), _worker_id, ShenandoahPhaseTimings::phase_desc(cur_phase));
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,177 +34,171 @@
|
||||
class ShenandoahCollectorPolicy;
|
||||
class outputStream;
|
||||
|
||||
#define SHENANDOAH_PAR_PHASE_DO(CNT_PREFIX, DESC_PREFIX, f) \
|
||||
f(CNT_PREFIX ## TotalWork, DESC_PREFIX "<total>") \
|
||||
f(CNT_PREFIX ## ThreadRoots, DESC_PREFIX "Thread Roots") \
|
||||
f(CNT_PREFIX ## CodeCacheRoots, DESC_PREFIX "Code Cache Roots") \
|
||||
f(CNT_PREFIX ## VMStrongRoots, DESC_PREFIX "VM Strong Roots") \
|
||||
f(CNT_PREFIX ## VMWeakRoots, DESC_PREFIX "VM Weak Roots") \
|
||||
f(CNT_PREFIX ## CLDGRoots, DESC_PREFIX "CLDG Roots") \
|
||||
f(CNT_PREFIX ## CodeCacheUnload, DESC_PREFIX "Unload Code Caches") \
|
||||
f(CNT_PREFIX ## CLDUnlink, DESC_PREFIX "Unlink CLDs") \
|
||||
f(CNT_PREFIX ## WeakRefProc, DESC_PREFIX "Weak References") \
|
||||
f(CNT_PREFIX ## ParallelMark, DESC_PREFIX "Parallel Mark") \
|
||||
f(CNT_PREFIX ## ScanClusters, DESC_PREFIX "Scan Clusters") \
|
||||
// end
|
||||
#define SHENANDOAH_WORKER_PHASE_DO(NAME_PREFIX, DESC_PREFIX, f) \
|
||||
f(NAME_PREFIX ## Work, DESC_PREFIX "Work", false) \
|
||||
f(NAME_PREFIX ## Threads, DESC_PREFIX "Threads", false) \
|
||||
f(NAME_PREFIX ## CodeCache, DESC_PREFIX "Code Cache", false) \
|
||||
f(NAME_PREFIX ## VMStrongs, DESC_PREFIX "VM Strongs", false) \
|
||||
f(NAME_PREFIX ## VMWeaks, DESC_PREFIX "VM Weaks", false) \
|
||||
f(NAME_PREFIX ## Classes, DESC_PREFIX "Classes", false) \
|
||||
// END
|
||||
|
||||
#define SHENANDOAH_PHASE_DO(f) \
|
||||
f(conc_reset, "Concurrent Reset") \
|
||||
f(conc_reset_after_collect, "Concurrent Reset After Collect") \
|
||||
f(conc_reset_old, "Concurrent Reset (OLD)") \
|
||||
f(init_mark_gross, "Pause Init Mark (G)") \
|
||||
f(init_mark, "Pause Init Mark (N)") \
|
||||
f(init_mark_verify, " Verify") \
|
||||
f(init_manage_tlabs, " Manage TLABs") \
|
||||
f(init_swap_rset, " Swap Remembered Set") \
|
||||
f(init_transfer_satb, " Transfer Old From SATB") \
|
||||
f(init_update_region_states, " Update Region States") \
|
||||
f(init_propagate_gc_state, " Propagate GC State") \
|
||||
\
|
||||
f(init_scan_rset, "Concurrent Scan Remembered Set") \
|
||||
SHENANDOAH_PAR_PHASE_DO(init_scan_rset_, " RS: ", f) \
|
||||
\
|
||||
f(conc_mark_roots, "Concurrent Mark Roots ") \
|
||||
SHENANDOAH_PAR_PHASE_DO(conc_mark_roots, " CMR: ", f) \
|
||||
f(conc_mark, "Concurrent Marking") \
|
||||
SHENANDOAH_PAR_PHASE_DO(conc_mark, " CM: ", f) \
|
||||
f(conc_mark_satb_flush, " Flush SATB") \
|
||||
\
|
||||
f(final_mark_gross, "Pause Final Mark (G)") \
|
||||
f(final_mark, "Pause Final Mark (N)") \
|
||||
f(final_mark_verify, " Verify") \
|
||||
f(finish_mark, " Finish Mark") \
|
||||
f(final_mark_propagate_gc_state, " Propagate GC State") \
|
||||
SHENANDOAH_PAR_PHASE_DO(finish_mark_, " FM: ", f) \
|
||||
f(purge, " System Purge") \
|
||||
SHENANDOAH_PAR_PHASE_DO(purge_cu_par_, " CU: ", f) \
|
||||
f(purge_weak_par, " Weak Roots") \
|
||||
SHENANDOAH_PAR_PHASE_DO(purge_weak_par_, " WR: ", f) \
|
||||
f(final_update_region_states, " Update Region States") \
|
||||
f(final_manage_labs, " Manage GC/TLABs") \
|
||||
f(choose_cset, " Choose Collection Set") \
|
||||
f(final_rebuild_freeset, " Rebuild Free Set") \
|
||||
f(init_evac, " Initial Evacuation") \
|
||||
SHENANDOAH_PAR_PHASE_DO(evac_, " E: ", f) \
|
||||
\
|
||||
f(conc_thread_roots, "Concurrent Thread Roots") \
|
||||
SHENANDOAH_PAR_PHASE_DO(conc_thread_roots_, " CTR: ", f) \
|
||||
f(conc_weak_refs, "Concurrent Weak References") \
|
||||
SHENANDOAH_PAR_PHASE_DO(conc_weak_refs_, " CWRF: ", f) \
|
||||
f(conc_weak_roots, "Concurrent Weak Roots") \
|
||||
f(conc_weak_roots_work, " Roots") \
|
||||
SHENANDOAH_PAR_PHASE_DO(conc_weak_roots_work_, " CWR: ", f) \
|
||||
f(conc_weak_roots_rendezvous, " Rendezvous") \
|
||||
f(conc_cleanup_early, "Concurrent Cleanup") \
|
||||
f(conc_class_unload, "Concurrent Class Unloading") \
|
||||
f(conc_class_unload_unlink, " Unlink Stale") \
|
||||
f(conc_class_unload_unlink_sd, " System Dictionary") \
|
||||
f(conc_class_unload_unlink_weak_klass, " Weak Class Links") \
|
||||
f(conc_class_unload_unlink_code_roots, " Code Roots") \
|
||||
f(conc_class_unload_rendezvous, " Rendezvous") \
|
||||
f(conc_class_unload_purge, " Purge Unlinked") \
|
||||
f(conc_class_unload_purge_coderoots, " Code Roots") \
|
||||
f(conc_class_unload_purge_cldg, " CLDG") \
|
||||
f(conc_class_unload_purge_ec, " Exception Caches") \
|
||||
f(conc_strong_roots, "Concurrent Strong Roots") \
|
||||
SHENANDOAH_PAR_PHASE_DO(conc_strong_roots_, " CSR: ", f) \
|
||||
f(conc_evac, "Concurrent Evacuation") \
|
||||
f(conc_update_card_table, "Concurrent Update Cards") \
|
||||
f(conc_final_roots, "Concurrent Final Roots") \
|
||||
f(promote_in_place, " Promote Regions") \
|
||||
f(final_verify_gross, "Pause Final Verify (G)") \
|
||||
f(final_verify, "Pause Final Verify (N)") \
|
||||
\
|
||||
f(init_update_refs_gross, "Pause Init Update Refs (G)") \
|
||||
f(init_update_refs, "Pause Init Update Refs (N)") \
|
||||
f(init_update_refs_verify, " Verify") \
|
||||
\
|
||||
f(conc_update_refs_prepare, "Concurrent Update Refs Prepare") \
|
||||
f(conc_update_refs, "Concurrent Update Refs") \
|
||||
f(conc_update_thread_roots, "Concurrent Update Thread Roots") \
|
||||
\
|
||||
f(final_update_refs_gross, "Pause Final Update Refs (G)") \
|
||||
f(final_update_refs, "Pause Final Update Refs (N)") \
|
||||
f(final_update_refs_verify, " Verify") \
|
||||
f(final_update_refs_update_region_states, " Update Region States") \
|
||||
f(final_update_refs_transfer_satb, " Transfer Old From SATB") \
|
||||
f(final_update_refs_trash_cset, " Trash Collection Set") \
|
||||
f(final_update_refs_rebuild_freeset, " Rebuild Free Set") \
|
||||
f(final_update_refs_propagate_gc_state, " Propagate GC State") \
|
||||
\
|
||||
f(conc_cleanup_complete, "Concurrent Cleanup") \
|
||||
f(conc_coalesce_and_fill, "Concurrent Coalesce and Fill") \
|
||||
SHENANDOAH_PAR_PHASE_DO(conc_coalesce_, " CC&F: ", f) \
|
||||
\
|
||||
f(degen_gc_gross, "Pause Degenerated GC (G)") \
|
||||
f(degen_gc, "Pause Degenerated GC (N)") \
|
||||
f(degen_gc_un_self_forward, " Un-Self-Forward") \
|
||||
f(degen_gc_stw_mark, " Degen STW Mark") \
|
||||
SHENANDOAH_PAR_PHASE_DO(degen_gc_stw_mark_, " DSM: ", f) \
|
||||
f(degen_gc_mark, " Degen Mark") \
|
||||
SHENANDOAH_PAR_PHASE_DO(degen_gc_mark_, " DM: ", f) \
|
||||
f(degen_gc_purge, " System Purge") \
|
||||
f(degen_gc_weakrefs, " Weak References") \
|
||||
SHENANDOAH_PAR_PHASE_DO(degen_gc_weakrefs_p_, " WRP: ", f) \
|
||||
f(degen_gc_purge_class_unload, " Unload Classes") \
|
||||
SHENANDOAH_PAR_PHASE_DO(degen_gc_purge_cu_par_, " DCU: ", f) \
|
||||
f(degen_gc_purge_weak_par, " Weak Roots") \
|
||||
SHENANDOAH_PAR_PHASE_DO(degen_gc_purge_weak_p_, " DWR: ", f) \
|
||||
f(degen_gc_purge_cldg, " CLDG") \
|
||||
f(degen_gc_final_update_region_states, " Update Region States") \
|
||||
f(degen_gc_final_manage_labs, " Manage GC/TLABs") \
|
||||
f(degen_gc_choose_cset, " Choose Collection Set") \
|
||||
f(degen_gc_final_rebuild_freeset, " Rebuild Free Set") \
|
||||
f(degen_gc_stw_evac, " Evacuation") \
|
||||
f(degen_gc_init_update_refs_manage_gclabs, " Manage GCLABs") \
|
||||
f(degen_gc_update_refs, " Update References") \
|
||||
f(degen_gc_final_update_refs_update_region_states," Update Region States") \
|
||||
f(degen_gc_final_update_refs_trash_cset, " Trash Collection Set") \
|
||||
f(degen_gc_final_update_refs_rebuild_freeset, " Rebuild Free Set") \
|
||||
f(degen_gc_update_roots, " Degen Update Roots") \
|
||||
SHENANDOAH_PAR_PHASE_DO(degen_gc_update_, " DU: ", f) \
|
||||
f(degen_gc_cleanup_complete, " Cleanup") \
|
||||
f(degen_gc_promote_regions, " Degen Promote Regions") \
|
||||
f(degen_gc_coalesce_and_fill, " Degen Coalesce and Fill") \
|
||||
SHENANDOAH_PAR_PHASE_DO(degen_coalesce_, " DC&F", f) \
|
||||
f(degen_gc_propagate_gc_state, " Propagate GC State") \
|
||||
\
|
||||
f(full_gc_gross, "Pause Full GC (G)") \
|
||||
f(full_gc, "Pause Full GC (N)") \
|
||||
f(full_gc_un_self_forward, " Un-Self-Forward") \
|
||||
f(full_gc_heapdump_pre, " Pre Heap Dump") \
|
||||
f(full_gc_prepare, " Prepare") \
|
||||
f(full_gc_update_roots, " Update Roots") \
|
||||
SHENANDOAH_PAR_PHASE_DO(full_gc_update_roots_, " FU: ", f) \
|
||||
f(full_gc_mark, " Mark") \
|
||||
SHENANDOAH_PAR_PHASE_DO(full_gc_mark_, " FM: ", f) \
|
||||
f(full_gc_purge, " System Purge") \
|
||||
f(full_gc_weakrefs, " Weak References") \
|
||||
SHENANDOAH_PAR_PHASE_DO(full_gc_weakrefs_p_, " WRP: ", f) \
|
||||
f(full_gc_purge_class_unload, " Unload Classes") \
|
||||
SHENANDOAH_PAR_PHASE_DO(full_gc_purge_cu_par_, " CU: ", f) \
|
||||
f(full_gc_purge_weak_par, " Weak Roots") \
|
||||
SHENANDOAH_PAR_PHASE_DO(full_gc_purge_weak_p_, " WR: ", f) \
|
||||
f(full_gc_purge_cldg, " CLDG") \
|
||||
f(full_gc_calculate_addresses, " Calculate Addresses") \
|
||||
f(full_gc_calculate_addresses_regular, " Regular Objects") \
|
||||
f(full_gc_calculate_addresses_humong, " Humongous Objects") \
|
||||
f(full_gc_adjust_pointers, " Adjust Pointers") \
|
||||
f(full_gc_adjust_roots, " Adjust Roots") \
|
||||
SHENANDOAH_PAR_PHASE_DO(full_gc_adjust_roots_, " FA: ", f) \
|
||||
f(full_gc_copy_objects, " Copy Objects") \
|
||||
f(full_gc_copy_objects_regular, " Regular Objects") \
|
||||
f(full_gc_copy_objects_humong, " Humongous Objects") \
|
||||
f(full_gc_recompute_generation_usage, " Recompute generation usage") \
|
||||
f(full_gc_copy_objects_reset_complete, " Reset Complete Bitmap") \
|
||||
f(full_gc_copy_objects_rebuild, " Rebuild Region Sets") \
|
||||
f(full_gc_reconstruct_remembered_set, " Reconstruct Remembered Set") \
|
||||
f(full_gc_heapdump_post, " Post Heap Dump") \
|
||||
f(full_gc_propagate_gc_state, " Propagate GC State") \
|
||||
\
|
||||
f(heap_iteration_roots, "Heap Iteration") \
|
||||
SHENANDOAH_PAR_PHASE_DO(heap_iteration_roots_, " HI: ", f) \
|
||||
// end
|
||||
#define SHENANDOAH_SIMPLE_PHASE_DEF(f, NAME, DESC) \
|
||||
f(NAME, DESC, false)
|
||||
|
||||
#define SHENANDOAH_WORKER_PHASE_DEF(f, NAME_PREFIX, MAIN_DESC, DESC_PREFIX) \
|
||||
f(NAME_PREFIX, MAIN_DESC, true) \
|
||||
SHENANDOAH_WORKER_PHASE_DO(NAME_PREFIX, DESC_PREFIX, f)
|
||||
|
||||
#define SHENANDOAH_PHASE_DO(f) \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_reset, "Concurrent Reset") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, init_mark_gross, "Pause Init Mark (G)") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, init_mark, "Pause Init Mark (N)") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, init_mark_verify, " Verify") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, init_manage_tlabs, " Manage TLABs") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, init_swap_rset, " Swap Remembered Set") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, init_transfer_satb, " Transfer Old From SATB") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, init_update_region_states, " Update Region States") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, init_propagate_gc_state, " Propagate GC State") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, init_scan_rset, "Concurrent Scan Remembered Set", \
|
||||
" RS: ") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, conc_mark_roots, "Concurrent Mark Roots", \
|
||||
" CMR: ") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, conc_mark, "Concurrent Marking", \
|
||||
" CM: ") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_mark_satb_flush, " Flush SATB") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, final_mark_gross, "Pause Final Mark (G)") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, final_mark, "Pause Final Mark (N)") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, final_mark_verify, " Verify") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, finish_mark, " Finish Mark", \
|
||||
" FM: ") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, final_mark_propagate_gc_state, " Propagate GC State") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, purge, " System Purge", \
|
||||
" CU: ") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, purge_weak_par, " Weak Roots", \
|
||||
" WR: ") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, final_update_region_states, " Update Region States") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, final_manage_labs, " Manage GC/TLABs") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, choose_cset, " Choose Collection Set") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, final_rebuild_freeset, " Rebuild Free Set") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, conc_thread_roots, "Concurrent Thread Roots", \
|
||||
" CTR: ") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, conc_weak_refs, "Concurrent Weak References", \
|
||||
" CWRF: ") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, conc_weak_roots, "Concurrent Weak Roots", \
|
||||
" CWR: ") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_weak_roots_rendezvous, " Rendezvous") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_cleanup_early, "Concurrent Cleanup, Early") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_class_unload, "Concurrent Class Unloading") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_class_unload_unlink, " Unlink Stale") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_class_unload_unlink_sd, " System Dictionary") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_class_unload_unlink_weak_klass, " Weak Class Links") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_class_unload_unlink_code_roots, " Code Roots") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_class_unload_rendezvous, " Rendezvous") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_class_unload_purge, " Purge Unlinked") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_class_unload_purge_coderoots, " Code Roots") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_class_unload_purge_cldg, " CLDG") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_class_unload_purge_ec, " Exception Caches") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, conc_strong_roots, "Concurrent Strong Roots", \
|
||||
" CSR: ") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, conc_evac, "Concurrent Evacuation", \
|
||||
" CE: ") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_update_card_table, "Concurrent Update Cards") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_final_roots, "Concurrent Final Roots") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, promote_in_place, " Promote Regions", \
|
||||
" PIP: ") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, final_verify_gross, "Pause Final Verify (G)") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, final_verify, "Pause Final Verify (N)") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, init_update_refs_gross, "Pause Init Update Refs (G)") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, init_update_refs, "Pause Init Update Refs (N)") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, init_update_refs_verify, " Verify") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_update_refs_prepare, "Concurrent Update Refs Prepare") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, conc_update_refs, "Concurrent Update Refs", \
|
||||
" CUR: ") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_update_thread_roots, "Concurrent Update Thread Roots") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, final_update_refs_gross, "Pause Final Update Refs (G)") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, final_update_refs, "Pause Final Update Refs (N)") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, final_update_refs_verify, " Verify") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, final_update_refs_update_region_states, " Update Region States") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, final_update_refs_transfer_satb, " Transfer Old From SATB") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, final_update_refs_trash_cset, " Trash Collection Set") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, final_update_refs_rebuild_freeset, " Rebuild Free Set") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, final_update_refs_propagate_gc_state, " Propagate GC State") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_cleanup_complete, "Concurrent Cleanup, Complete") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, conc_coalesce_and_fill, "Concurrent Coalesce and Fill", \
|
||||
" CC&F: ") \
|
||||
\
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_gross, "Pause Degenerated GC (G)") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc, "Pause Degenerated GC (N)") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_un_self_forward, " Un-Self-Forward") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, degen_gc_mark, " Mark", \
|
||||
" DM: ") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_purge, " System Purge") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, degen_gc_weakrefs, " Weak References", \
|
||||
" WRP: ") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, degen_gc_purge_class_unload, " Unload Classes", \
|
||||
" DCU: ") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, degen_gc_purge_weak_par, " Weak Roots", \
|
||||
" DWR: ") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_purge_cldg, " CLDG") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_final_update_region_states, " Update Region States") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_final_manage_labs, " Manage GC/TLABs") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_choose_cset, " Choose Collection Set") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_final_rebuild_freeset, " Rebuild Free Set") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, degen_gc_evac, " Evacuation", \
|
||||
" DE: ") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_init_update_refs_manage_gclabs, " Manage GCLABs") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, degen_gc_update_refs, " Update References", \
|
||||
" DUR: ") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_final_update_refs_update_region_states, " Update Region States") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_final_update_refs_trash_cset, " Trash Collection Set") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_final_update_refs_rebuild_freeset, " Rebuild Free Set") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, degen_gc_update_roots, " Degen Update Roots", \
|
||||
" DU: ") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_cleanup_complete, " Cleanup") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_promote_regions, " Degen Promote Regions") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, degen_gc_coalesce_and_fill, " Degen Coalesce and Fill", \
|
||||
" DC&F") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, degen_gc_propagate_gc_state, " Propagate GC State") \
|
||||
\
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_gross, "Pause Full GC (G)") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc, "Pause Full GC (N)") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_un_self_forward, " Un-Self-Forward") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_heapdump_pre, " Pre Heap Dump") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_prepare, " Prepare") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, full_gc_update_roots, " Update Roots", \
|
||||
" FU: ") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, full_gc_mark, " Mark", \
|
||||
" FM: ") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_purge, " System Purge") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, full_gc_weakrefs, " Weak References", \
|
||||
" WRP: ") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, full_gc_purge_class_unload, " Unload Classes", \
|
||||
" CU: ") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, full_gc_purge_weak_par, " Weak Roots", \
|
||||
" WR: ") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_purge_cldg, " CLDG") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_calculate_addresses, " Calculate Addresses") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_calculate_addresses_regular, " Regular Objects") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_calculate_addresses_humong, " Humongous Objects") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_adjust_pointers, " Adjust Pointers") \
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, full_gc_adjust_roots, " Adjust Roots", \
|
||||
" FA: ") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_copy_objects, " Copy Objects") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_copy_objects_regular, " Regular Objects") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_copy_objects_humong, " Humongous Objects") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_recompute_generation_usage, " Recompute generation usage") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_copy_objects_reset_complete, " Reset Complete Bitmap") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_copy_objects_rebuild, " Rebuild Region Sets") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_reconstruct_remembered_set, " Reconstruct Remembered Set") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_heapdump_post, " Post Heap Dump") \
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, full_gc_propagate_gc_state, " Propagate GC State") \
|
||||
\
|
||||
SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_reset_after_collect, "Concurrent Reset After Collect") \
|
||||
\
|
||||
SHENANDOAH_WORKER_PHASE_DEF(f, heap_iteration_roots, "Heap Iteration", \
|
||||
" HI: ") \
|
||||
// END
|
||||
|
||||
typedef WorkerDataArray<double> ShenandoahWorkerData;
|
||||
|
||||
@ -212,7 +206,7 @@ class ShenandoahPhaseTimings : public CHeapObj<mtGC> {
|
||||
friend class ShenandoahGCPhase;
|
||||
friend class ShenandoahWorkerTimingsTracker;
|
||||
public:
|
||||
#define SHENANDOAH_PHASE_DECLARE_ENUM(type, title) type,
|
||||
#define SHENANDOAH_PHASE_DECLARE_ENUM(name, desc, has_worker_phase) name,
|
||||
|
||||
enum Phase {
|
||||
SHENANDOAH_PHASE_DO(SHENANDOAH_PHASE_DECLARE_ENUM)
|
||||
@ -220,8 +214,8 @@ public:
|
||||
_invalid_phase = _num_phases
|
||||
};
|
||||
|
||||
enum ParPhase {
|
||||
SHENANDOAH_PAR_PHASE_DO(,, SHENANDOAH_PHASE_DECLARE_ENUM)
|
||||
enum WorkerPhase {
|
||||
SHENANDOAH_WORKER_PHASE_DO(,, SHENANDOAH_PHASE_DECLARE_ENUM)
|
||||
_num_par_phases
|
||||
};
|
||||
|
||||
@ -231,16 +225,16 @@ private:
|
||||
uint _max_workers;
|
||||
double _cycle_data[_num_phases];
|
||||
HdrSeq _global_data[_num_phases];
|
||||
static const char* _phase_names[_num_phases];
|
||||
static const char* _desc[_num_phases];
|
||||
static bool _has_worker_phase[_num_phases];
|
||||
|
||||
ShenandoahWorkerData* _worker_data[_num_phases];
|
||||
ShenandoahCollectorPolicy* _policy;
|
||||
|
||||
static bool is_worker_phase(Phase phase);
|
||||
static bool is_root_work_phase(Phase phase);
|
||||
|
||||
ShenandoahWorkerData* worker_data(Phase phase, ParPhase par_phase);
|
||||
Phase worker_par_phase(Phase phase, ParPhase par_phase);
|
||||
ShenandoahWorkerData* worker_data(Phase phase, WorkerPhase par_phase);
|
||||
static Phase compute_phase_slot(Phase phase, WorkerPhase worker_phase);
|
||||
|
||||
void set_cycle_data(Phase phase, double time, bool should_aggregate = false);
|
||||
static double uninitialized() { return -1; }
|
||||
@ -256,9 +250,14 @@ public:
|
||||
void flush_par_workers_to_cycle();
|
||||
void flush_cycle_to_global();
|
||||
|
||||
static const char* phase_name(Phase phase) {
|
||||
static const char* phase_desc(Phase phase) {
|
||||
assert(phase >= 0 && phase < _num_phases, "Out of bounds: %d", phase);
|
||||
return _phase_names[phase];
|
||||
return _desc[phase];
|
||||
}
|
||||
|
||||
static bool has_worker_phases(Phase phase) {
|
||||
assert(phase >= 0 && phase < _num_phases, "Out of bounds: %d", phase);
|
||||
return _has_worker_phase[phase];
|
||||
}
|
||||
|
||||
void print_cycle_on(outputStream* out) const;
|
||||
@ -269,14 +268,14 @@ class ShenandoahWorkerTimingsTracker : public StackObj {
|
||||
private:
|
||||
ShenandoahPhaseTimings* const _timings;
|
||||
ShenandoahPhaseTimings::Phase const _phase;
|
||||
ShenandoahPhaseTimings::ParPhase const _par_phase;
|
||||
ShenandoahPhaseTimings::WorkerPhase const _worker_phase;
|
||||
uint const _worker_id;
|
||||
|
||||
double _start_time;
|
||||
EventGCPhaseParallel _event;
|
||||
public:
|
||||
ShenandoahWorkerTimingsTracker(ShenandoahPhaseTimings::Phase phase,
|
||||
ShenandoahPhaseTimings::ParPhase par_phase,
|
||||
ShenandoahPhaseTimings::WorkerPhase worker_phase,
|
||||
uint worker_id,
|
||||
bool cumulative = false);
|
||||
~ShenandoahWorkerTimingsTracker();
|
||||
|
||||
@ -547,11 +547,11 @@ public:
|
||||
virtual void work(uint worker_id) {
|
||||
if (_concurrent) {
|
||||
ShenandoahConcurrentWorkerSession worker_session(worker_id);
|
||||
ShenandoahWorkerTimingsTracker x(_phase, ShenandoahPhaseTimings::WeakRefProc, worker_id);
|
||||
ShenandoahWorkerTimingsTracker x(_phase, ShenandoahPhaseTimings::Work, worker_id);
|
||||
_reference_processor->work();
|
||||
} else {
|
||||
ShenandoahParallelWorkerSession worker_session(worker_id);
|
||||
ShenandoahWorkerTimingsTracker x(_phase, ShenandoahPhaseTimings::WeakRefProc, worker_id);
|
||||
ShenandoahWorkerTimingsTracker x(_phase, ShenandoahPhaseTimings::Work, worker_id);
|
||||
_reference_processor->work();
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ uint ShenandoahJavaThreadsIterator::claim() {
|
||||
}
|
||||
|
||||
void ShenandoahJavaThreadsIterator::threads_do(ThreadClosure* cl, uint worker_id) {
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::ThreadRoots, worker_id);
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::Threads, worker_id);
|
||||
for (uint i = claim(); i < _length; i = claim()) {
|
||||
for (uint t = i; t < MIN2(_length, i + _stride); t++) {
|
||||
cl->do_thread(thread_at(t));
|
||||
@ -63,13 +63,13 @@ ShenandoahThreadRoots::ShenandoahThreadRoots(ShenandoahPhaseTimings::Phase phase
|
||||
_threads_claim_token_scope() {}
|
||||
|
||||
void ShenandoahThreadRoots::oops_do(OopClosure* oops_cl, NMethodClosure* code_cl, uint worker_id) {
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::ThreadRoots, worker_id);
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::Threads, worker_id);
|
||||
ResourceMark rm;
|
||||
Threads::possibly_parallel_oops_do(_is_par, oops_cl, code_cl);
|
||||
}
|
||||
|
||||
void ShenandoahThreadRoots::threads_do(ThreadClosure* tc, uint worker_id) {
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::ThreadRoots, worker_id);
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::Threads, worker_id);
|
||||
ResourceMark rm;
|
||||
Threads::possibly_parallel_threads_do(_is_par, tc);
|
||||
}
|
||||
@ -78,7 +78,7 @@ ShenandoahCodeCacheRoots::ShenandoahCodeCacheRoots(ShenandoahPhaseTimings::Phase
|
||||
}
|
||||
|
||||
void ShenandoahCodeCacheRoots::nmethods_do(NMethodClosure* nmethod_cl, uint worker_id) {
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCache, worker_id);
|
||||
_coderoots_iterator.possibly_parallel_nmethods_do(nmethod_cl);
|
||||
}
|
||||
|
||||
@ -153,7 +153,7 @@ void ShenandoahConcurrentRootScanner::roots_do(OopClosure* oops, uint worker_id)
|
||||
_cld_roots.cld_do(&clds_cl, worker_id);
|
||||
|
||||
{
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCache, worker_id);
|
||||
NMethodToOopClosure nmethods(oops, !NMethodToOopClosure::FixRelocations);
|
||||
_codecache_snapshot->parallel_nmethods_do(&nmethods);
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ ShenandoahVMWeakRoots<CONCURRENT>::ShenandoahVMWeakRoots(ShenandoahPhaseTimings:
|
||||
template <bool CONCURRENT>
|
||||
template <typename T>
|
||||
void ShenandoahVMWeakRoots<CONCURRENT>::oops_do(T* cl, uint worker_id) {
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::VMWeakRoots, worker_id);
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::VMWeaks, worker_id);
|
||||
_weak_roots.oops_do(cl);
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ template <bool CONCURRENT>
|
||||
template <typename IsAlive, typename KeepAlive>
|
||||
void ShenandoahVMWeakRoots<CONCURRENT>::weak_oops_do(IsAlive* is_alive, KeepAlive* keep_alive, uint worker_id) {
|
||||
ShenandoahCleanUpdateWeakOopsClosure<CONCURRENT, IsAlive, KeepAlive> cl(is_alive, keep_alive);
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::VMWeakRoots, worker_id);
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::VMWeaks, worker_id);
|
||||
_weak_roots.oops_do(&cl);
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ ShenandoahVMRoots<CONCURRENT>::ShenandoahVMRoots(ShenandoahPhaseTimings::Phase p
|
||||
template <bool CONCURRENT>
|
||||
template <typename T>
|
||||
void ShenandoahVMRoots<CONCURRENT>::oops_do(T* cl, uint worker_id) {
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::VMStrongRoots, worker_id);
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::VMStrongs, worker_id);
|
||||
_strong_roots.oops_do(cl);
|
||||
}
|
||||
|
||||
@ -104,12 +104,12 @@ template <bool CONCURRENT>
|
||||
void ShenandoahClassLoaderDataRoots<CONCURRENT>::cld_do_impl(CldDo f, CLDClosure* clds, uint worker_id) {
|
||||
if (CONCURRENT) {
|
||||
if (_semaphore.try_acquire()) {
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CLDGRoots, worker_id);
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::Classes, worker_id);
|
||||
f(clds);
|
||||
_semaphore.claim_all();
|
||||
}
|
||||
} else {
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CLDGRoots, worker_id);
|
||||
ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::Classes, worker_id);
|
||||
f(clds);
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,7 +36,6 @@
|
||||
#include "gc/shenandoah/shenandoahPhaseTimings.hpp"
|
||||
#include "gc/shenandoah/shenandoahRootVerifier.hpp"
|
||||
#include "gc/shenandoah/shenandoahScanRemembered.inline.hpp"
|
||||
#include "gc/shenandoah/shenandoahStringDedup.hpp"
|
||||
#include "gc/shenandoah/shenandoahUtils.hpp"
|
||||
#include "runtime/javaThread.hpp"
|
||||
#include "runtime/jniHandles.hpp"
|
||||
|
||||
@ -63,7 +63,7 @@ void ShenandoahSTWMarkTask::work(uint worker_id) {
|
||||
|
||||
ShenandoahSTWMark::ShenandoahSTWMark(ShenandoahGeneration* generation, bool full_gc) :
|
||||
ShenandoahMark(generation),
|
||||
_root_scanner(full_gc ? ShenandoahPhaseTimings::full_gc_mark : ShenandoahPhaseTimings::degen_gc_stw_mark),
|
||||
_root_scanner(full_gc ? ShenandoahPhaseTimings::full_gc_mark : ShenandoahPhaseTimings::degen_gc_mark),
|
||||
_terminator(ShenandoahHeap::heap()->workers()->active_workers(), task_queues()),
|
||||
_full_gc(full_gc) {
|
||||
assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a Shenandoah safepoint");
|
||||
@ -151,10 +151,8 @@ void ShenandoahSTWMark::mark_roots(uint worker_id) {
|
||||
}
|
||||
|
||||
void ShenandoahSTWMark::finish_mark(uint worker_id) {
|
||||
ShenandoahPhaseTimings::Phase phase = _full_gc ? ShenandoahPhaseTimings::full_gc_mark : ShenandoahPhaseTimings::degen_gc_stw_mark;
|
||||
ShenandoahWorkerTimingsTracker timer(phase, ShenandoahPhaseTimings::ParallelMark, worker_id);
|
||||
StringDedup::Requests requests;
|
||||
ShenandoahPhaseTimings::Phase phase = _full_gc ? ShenandoahPhaseTimings::full_gc_mark : ShenandoahPhaseTimings::degen_gc_mark;
|
||||
ShenandoahWorkerTimingsTracker timer(phase, ShenandoahPhaseTimings::Work, worker_id);
|
||||
|
||||
mark_loop(worker_id, &_terminator, _generation->type(), false /* not cancellable */,
|
||||
ShenandoahStringDedup::is_enabled() ? ALWAYS_DEDUP : NO_DEDUP, &requests);
|
||||
mark_loop(worker_id, &_terminator, _generation->type(), false /* not cancellable */);
|
||||
}
|
||||
|
||||
@ -808,7 +808,7 @@ void ShenandoahScanRememberedTask::work(uint worker_id) {
|
||||
}
|
||||
|
||||
void ShenandoahScanRememberedTask::do_work(uint worker_id) {
|
||||
ShenandoahWorkerTimingsTracker x(ShenandoahPhaseTimings::init_scan_rset, ShenandoahPhaseTimings::ScanClusters, worker_id);
|
||||
ShenandoahWorkerTimingsTracker x(ShenandoahPhaseTimings::init_scan_rset, ShenandoahPhaseTimings::Work, worker_id);
|
||||
|
||||
ShenandoahObjToScanQueue* q = _queue_set->queue(worker_id);
|
||||
ShenandoahObjToScanQueue* old = _old_queue_set == nullptr ? nullptr : _old_queue_set->queue(worker_id);
|
||||
|
||||
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2021, Red Hat, Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHSTRINGDEDUP_INLINE_HPP
|
||||
#define SHARE_GC_SHENANDOAH_SHENANDOAHSTRINGDEDUP_INLINE_HPP
|
||||
|
||||
#include "gc/shenandoah/shenandoahStringDedup.hpp"
|
||||
|
||||
#include "classfile/javaClasses.inline.hpp"
|
||||
#include "gc/shenandoah/shenandoahHeap.inline.hpp"
|
||||
#include "oops/markWord.hpp"
|
||||
|
||||
bool ShenandoahStringDedup::is_string_candidate(oop obj) {
|
||||
assert(Thread::current()->is_Worker_thread(),
|
||||
"Only from a GC worker thread");
|
||||
return java_lang_String::is_instance(obj) &&
|
||||
java_lang_String::value(obj) != nullptr;
|
||||
}
|
||||
|
||||
bool ShenandoahStringDedup::dedup_requested(oop obj) {
|
||||
return java_lang_String::test_and_set_deduplication_requested(obj);
|
||||
}
|
||||
|
||||
bool ShenandoahStringDedup::is_candidate(oop obj) {
|
||||
if (!is_string_candidate(obj)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint age = ShenandoahHeap::get_object_age(obj);
|
||||
return (age <= markWord::max_age) &&
|
||||
StringDedup::is_below_threshold_age(age) &&
|
||||
!dedup_requested(obj);
|
||||
}
|
||||
|
||||
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHSTRINGDEDUP_INLINE_HPP
|
||||
@ -143,7 +143,7 @@ bool ShenandoahTimingsTracker::is_current_phase_valid() {
|
||||
ShenandoahGCPhase::ShenandoahGCPhase(ShenandoahPhaseTimings::Phase phase) :
|
||||
ShenandoahTimingsTracker(phase),
|
||||
_timer(ShenandoahHeap::heap()->gc_timer()) {
|
||||
_timer->register_gc_phase_start(ShenandoahPhaseTimings::phase_name(phase), Ticks::now());
|
||||
_timer->register_gc_phase_start(ShenandoahPhaseTimings::phase_desc(phase), Ticks::now());
|
||||
}
|
||||
|
||||
ShenandoahGCPhase::~ShenandoahGCPhase() {
|
||||
@ -164,9 +164,9 @@ ShenandoahWorkerSession::ShenandoahWorkerSession(uint worker_id) {
|
||||
}
|
||||
|
||||
ShenandoahConcurrentWorkerSession::~ShenandoahConcurrentWorkerSession() {
|
||||
_event.commit(GCId::current(), ShenandoahPhaseTimings::phase_name(ShenandoahGCPhase::current_phase()));
|
||||
_event.commit(GCId::current(), ShenandoahPhaseTimings::phase_desc(ShenandoahGCPhase::current_phase()));
|
||||
}
|
||||
|
||||
ShenandoahParallelWorkerSession::~ShenandoahParallelWorkerSession() {
|
||||
_event.commit(GCId::current(), WorkerThread::worker_id(), ShenandoahPhaseTimings::phase_name(ShenandoahGCPhase::current_phase()));
|
||||
_event.commit(GCId::current(), WorkerThread::worker_id(), ShenandoahPhaseTimings::phase_desc(ShenandoahGCPhase::current_phase()));
|
||||
}
|
||||
|
||||
@ -792,6 +792,7 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) {
|
||||
case vmIntrinsics::_sha5_implCompress:
|
||||
case vmIntrinsics::_sha3_implCompress:
|
||||
case vmIntrinsics::_double_keccak:
|
||||
case vmIntrinsics::_quad_keccak:
|
||||
case vmIntrinsics::_digestBase_implCompressMB:
|
||||
case vmIntrinsics::_multiplyToLen:
|
||||
case vmIntrinsics::_squareToLen:
|
||||
|
||||
@ -505,19 +505,19 @@ bool ConnectionGraph::can_reduce_phi_check_inputs(PhiNode* ophi) const {
|
||||
// We can reduce the Cmp if it's a comparison between the Phi and a constant.
|
||||
// I require the 'other' input to be a constant so that I can move the Cmp
|
||||
// around safely.
|
||||
bool ConnectionGraph::can_reduce_cmp(Node* n, Node* cmp) const {
|
||||
bool ConnectionGraph::can_reduce_cmp(PhiNode* phi, Node* cmp) const {
|
||||
assert(cmp->Opcode() == Op_CmpP || cmp->Opcode() == Op_CmpN, "not expected node: %s", cmp->Name());
|
||||
Node* left = cmp->in(1);
|
||||
Node* right = cmp->in(2);
|
||||
|
||||
return (left == n || right == n) &&
|
||||
return (left == phi || right == phi) &&
|
||||
(left->is_Con() || right->is_Con()) &&
|
||||
cmp->outcnt() == 1;
|
||||
}
|
||||
|
||||
// We are going to check if any of the SafePointScalarMerge entries
|
||||
// in the SafePoint reference the Phi that we are checking.
|
||||
bool ConnectionGraph::has_been_reduced(PhiNode* n, SafePointNode* sfpt) const {
|
||||
bool ConnectionGraph::has_been_reduced(PhiNode* phi, SafePointNode* sfpt) const {
|
||||
JVMState *jvms = sfpt->jvms();
|
||||
|
||||
for (uint i = jvms->debug_start(); i < jvms->debug_end(); i++) {
|
||||
@ -525,7 +525,7 @@ bool ConnectionGraph::has_been_reduced(PhiNode* n, SafePointNode* sfpt) const {
|
||||
if (sfpt_in->is_SafePointScalarMerge()) {
|
||||
SafePointScalarMergeNode* smerge = sfpt_in->as_SafePointScalarMerge();
|
||||
Node* nsr_ptr = sfpt->in(smerge->merge_pointer_idx(jvms));
|
||||
if (nsr_ptr == n) {
|
||||
if (nsr_ptr == phi) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -542,6 +542,8 @@ bool ConnectionGraph::has_been_reduced(PhiNode* n, SafePointNode* sfpt) const {
|
||||
// - Phi -> CastPP -> SafePoints
|
||||
// - Phi -> CastPP -> AddP -> Load
|
||||
bool ConnectionGraph::can_reduce_check_users(Node* n, uint nesting) const {
|
||||
assert((n->is_Phi() && nesting == 0) || (n->is_CastPP() && nesting > 0),
|
||||
"invalid node class %s and nesting %d combination", n->Name(), nesting);
|
||||
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
|
||||
Node* use = n->fast_out(i);
|
||||
|
||||
@ -582,37 +584,21 @@ bool ConnectionGraph::can_reduce_check_users(Node* n, uint nesting) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_trivial_control = use->in(0) == nullptr || use->in(0) == n->in(0);
|
||||
if (!is_trivial_control) {
|
||||
// If it's not a trivial control then we check if we can reduce the
|
||||
// CmpP/N used by the If controlling the cast.
|
||||
if (use->in(0)->is_IfTrue() || use->in(0)->is_IfFalse()) {
|
||||
Node* iff = use->in(0)->in(0);
|
||||
// We may have an OpaqueConstantBool node between If and Bool nodes. But we could also have a sub class of IfNode,
|
||||
// for example, an OuterStripMinedLoopEnd or a Parse Predicate. Bail out in all these cases.
|
||||
bool can_reduce = (iff->Opcode() == Op_If) && iff->in(1)->is_Bool() && iff->in(1)->in(1)->is_Cmp();
|
||||
if (can_reduce) {
|
||||
Node* iff_cmp = iff->in(1)->in(1);
|
||||
int opc = iff_cmp->Opcode();
|
||||
can_reduce = (opc == Op_CmpP || opc == Op_CmpN) && can_reduce_cmp(n, iff_cmp);
|
||||
}
|
||||
if (!can_reduce) {
|
||||
#ifndef PRODUCT
|
||||
if (TraceReduceAllocationMerges) {
|
||||
tty->print_cr("Can NOT reduce Phi %d on invocation %d. CastPP %d doesn't have simple control.", n->_idx, _invocation, use->_idx);
|
||||
n->dump(5);
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
if (!can_reduce_phi_at_castpp(n->as_Phi(), use->as_CastPP())) {
|
||||
#ifdef ASSERT
|
||||
if (TraceReduceAllocationMerges) {
|
||||
tty->print_cr("Can NOT reduce Phi %d on invocation %d. CastPP %d doesn't have simple control.", n->_idx, _invocation, use->_idx);
|
||||
n->dump(5);
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!can_reduce_check_users(use, nesting+1)) {
|
||||
return false;
|
||||
}
|
||||
} else if (use->Opcode() == Op_CmpP || use->Opcode() == Op_CmpN) {
|
||||
if (!can_reduce_cmp(n, use)) {
|
||||
if (!can_reduce_cmp(n->as_Phi(), use)) {
|
||||
NOT_PRODUCT(if (TraceReduceAllocationMerges) tty->print_cr("Can NOT reduce Phi %d on invocation %d. CmpP/N %d isn't reducible.", n->_idx, _invocation, use->_idx);)
|
||||
return false;
|
||||
}
|
||||
@ -625,6 +611,33 @@ bool ConnectionGraph::can_reduce_check_users(Node* n, uint nesting) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true if the CastPP's control is simple enough to reduce the Phi:
|
||||
// 1) no control,
|
||||
// 2) control is the same Region as the Phi, or
|
||||
// 3) an IfTrue/IfFalse coming from an CmpP/N between the phi and a constant.
|
||||
bool ConnectionGraph::can_reduce_phi_at_castpp(PhiNode* phi, CastPPNode* castpp) const {
|
||||
if (castpp->in(0) == nullptr || castpp->in(0) == phi->in(0)) {
|
||||
return true;
|
||||
}
|
||||
// If it's not a trivial control then we check if we can reduce the
|
||||
// CmpP/N used by the If controlling the cast.
|
||||
if (!(castpp->in(0)->is_IfTrue() || castpp->in(0)->is_IfFalse())) {
|
||||
return false; // Only If control is considered
|
||||
} else {
|
||||
Node* iff = castpp->in(0)->in(0);
|
||||
// We may have an OpaqueConstantBool node between If and Bool nodes. But we could also have a sub class of IfNode,
|
||||
// for example, an OuterStripMinedLoopEnd or a Parse Predicate. Bail out in all these cases.
|
||||
if (iff->Opcode() == Op_If && iff->in(1)->is_Bool() && iff->in(1)->in(1)->is_Cmp()) {
|
||||
Node* iff_cmp = iff->in(1)->in(1);
|
||||
int opc = iff_cmp->Opcode();
|
||||
if ((opc == Op_CmpP || opc == Op_CmpN) && can_reduce_cmp(phi, iff_cmp)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns true if: 1) It's profitable to reduce the merge, and 2) The Phi is
|
||||
// only used in some certain code shapes. Check comments in
|
||||
// 'can_reduce_phi_inputs' and 'can_reduce_phi_users' for more
|
||||
@ -878,9 +891,9 @@ Node* ConnectionGraph::split_castpp_load_through_phi(Node* curr_addp, Node* curr
|
||||
// \|/
|
||||
// Phi # "Field" Phi
|
||||
//
|
||||
void ConnectionGraph::reduce_phi_on_castpp_field_load(Node* curr_castpp, GrowableArray<Node*> &alloc_worklist) {
|
||||
Node* ophi = curr_castpp->in(1);
|
||||
assert(ophi->is_Phi(), "Expected this to be a Phi node.");
|
||||
void ConnectionGraph::reduce_phi_on_castpp_field_load(CastPPNode* curr_castpp, GrowableArray<Node*> &alloc_worklist) {
|
||||
PhiNode* ophi = curr_castpp->in(1)->as_Phi();
|
||||
precond(can_reduce_phi_at_castpp(ophi, curr_castpp));
|
||||
|
||||
// Identify which base should be used for AddP->Load later when spliting the
|
||||
// CastPP->Loads through ophi. Three kind of values may be stored in this
|
||||
@ -1374,7 +1387,7 @@ void ConnectionGraph::reduce_phi(PhiNode* ophi, GrowableArray<Node*> &alloc_work
|
||||
// splitting CastPPs we make reference to the inputs of the Cmp that is used
|
||||
// by the If controlling the CastPP.
|
||||
for (uint i = 0; i < castpps.size(); i++) {
|
||||
reduce_phi_on_castpp_field_load(castpps.at(i), alloc_worklist);
|
||||
reduce_phi_on_castpp_field_load(castpps.at(i)->as_CastPP(), alloc_worklist);
|
||||
_compile->print_method(PHASE_EA_AFTER_PHI_CASTPP_REDUCTION, 6, castpps.at(i));
|
||||
}
|
||||
|
||||
@ -2285,6 +2298,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call) {
|
||||
strcmp(call->as_CallLeaf()->_name, "sha512_implCompressMB") == 0 ||
|
||||
strcmp(call->as_CallLeaf()->_name, "sha3_implCompress") == 0 ||
|
||||
strcmp(call->as_CallLeaf()->_name, "double_keccak") == 0 ||
|
||||
strcmp(call->as_CallLeaf()->_name, "quad_keccak") == 0 ||
|
||||
strcmp(call->as_CallLeaf()->_name, "sha3_implCompressMB") == 0 ||
|
||||
strcmp(call->as_CallLeaf()->_name, "multiplyToLen") == 0 ||
|
||||
strcmp(call->as_CallLeaf()->_name, "squareToLen") == 0 ||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -609,14 +609,15 @@ private:
|
||||
Node* specialize_cmp(Node* base, Node* curr_ctrl);
|
||||
Node* specialize_castpp(Node* castpp, Node* base, Node* current_control);
|
||||
|
||||
bool can_reduce_cmp(Node* n, Node* cmp) const;
|
||||
bool can_reduce_cmp(PhiNode* n, Node* cmp) const;
|
||||
bool has_been_reduced(PhiNode* n, SafePointNode* sfpt) const;
|
||||
bool can_reduce_phi(PhiNode* ophi) const;
|
||||
bool can_reduce_check_users(Node* n, uint nesting) const;
|
||||
bool can_reduce_phi_check_inputs(PhiNode* ophi) const;
|
||||
bool can_reduce_phi_at_castpp(PhiNode* phi, CastPPNode* castpp) const;
|
||||
|
||||
void reduce_phi_on_field_access(Node* previous_addp, GrowableArray<Node *> &alloc_worklist);
|
||||
void reduce_phi_on_castpp_field_load(Node* castpp, GrowableArray<Node*> &alloc_worklist);
|
||||
void reduce_phi_on_castpp_field_load(CastPPNode* castpp, GrowableArray<Node*> &alloc_worklist);
|
||||
void reduce_phi_on_cmp(Node* cmp);
|
||||
bool reduce_phi_on_safepoints(PhiNode* ophi);
|
||||
bool reduce_phi_on_safepoints_helper(Node* ophi, Node* cast, Node* selector, Unique_Node_List& safepoints);
|
||||
|
||||
@ -600,7 +600,8 @@ bool LibraryCallKit::try_to_inline(int predicate) {
|
||||
case vmIntrinsics::_sha3_implCompress:
|
||||
return inline_digestBase_implCompress(intrinsic_id());
|
||||
case vmIntrinsics::_double_keccak:
|
||||
return inline_double_keccak();
|
||||
case vmIntrinsics::_quad_keccak:
|
||||
return inline_keccak(intrinsic_id());
|
||||
|
||||
case vmIntrinsics::_digestBase_implCompressMB:
|
||||
return inline_digestBase_implCompressMB(predicate);
|
||||
@ -8471,33 +8472,60 @@ bool LibraryCallKit::inline_digestBase_implCompress(vmIntrinsics::ID id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------inline_double_keccak
|
||||
bool LibraryCallKit::inline_double_keccak() {
|
||||
address stubAddr;
|
||||
//------------------------------inline_keccak
|
||||
bool LibraryCallKit::inline_keccak(vmIntrinsics::ID id) {
|
||||
address stubAddr = nullptr;
|
||||
const char *stubName;
|
||||
assert(UseSHA3Intrinsics, "need SHA3 intrinsics support");
|
||||
assert(callee()->signature()->size() == 2, "double_keccak has 2 parameters");
|
||||
assert((id == vmIntrinsics::_double_keccak && callee()->signature()->size() == 2) ||
|
||||
(id == vmIntrinsics::_quad_keccak && callee()->signature()->size() == 4),
|
||||
"double_keccak wrong number of parameters");
|
||||
|
||||
int parmCnt = 0;
|
||||
switch (id) {
|
||||
case vmIntrinsics::_double_keccak:
|
||||
stubAddr = StubRoutines::double_keccak();
|
||||
stubName = "double_keccak";
|
||||
parmCnt = 2;
|
||||
break;
|
||||
case vmIntrinsics::_quad_keccak:
|
||||
stubAddr = StubRoutines::quad_keccak();
|
||||
stubName = "quad_keccak";
|
||||
parmCnt = 4;
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
stubAddr = StubRoutines::double_keccak();
|
||||
stubName = "double_keccak";
|
||||
if (!stubAddr) return false;
|
||||
|
||||
Node* status0 = argument(0);
|
||||
Node* status1 = argument(1);
|
||||
Node* state[4];
|
||||
for (int i = 0; i<parmCnt; i++) {
|
||||
state[i] = must_be_not_null(argument(i), true);
|
||||
state[i] = array_element_address(state[i], intcon(0), T_LONG);
|
||||
assert(state[i], "state[%d] is null", i);
|
||||
}
|
||||
|
||||
status0 = must_be_not_null(status0, true);
|
||||
status1 = must_be_not_null(status1, true);
|
||||
|
||||
Node* status0_start = array_element_address(status0, intcon(0), T_LONG);
|
||||
assert(status0_start, "status0 is null");
|
||||
Node* status1_start = array_element_address(status1, intcon(0), T_LONG);
|
||||
assert(status1_start, "status1 is null");
|
||||
Node* double_keccak = make_runtime_call(RC_LEAF|RC_NO_FP,
|
||||
Node* keccak;
|
||||
switch (id) {
|
||||
case vmIntrinsics::_double_keccak:
|
||||
keccak = make_runtime_call(RC_LEAF|RC_NO_FP,
|
||||
OptoRuntime::double_keccak_Type(),
|
||||
stubAddr, stubName, TypePtr::BOTTOM,
|
||||
status0_start, status1_start);
|
||||
state[0], state[1]);
|
||||
break;
|
||||
case vmIntrinsics::_quad_keccak:
|
||||
keccak = make_runtime_call(RC_LEAF|RC_NO_FP,
|
||||
OptoRuntime::quad_keccak_Type(),
|
||||
stubAddr, stubName, TypePtr::BOTTOM,
|
||||
state[0], state[1], state[2], state[3]);
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
// return an int
|
||||
Node* retvalue = _gvn.transform(new ProjNode(double_keccak, TypeFunc::Parms));
|
||||
Node* retvalue = _gvn.transform(new ProjNode(keccak, TypeFunc::Parms));
|
||||
set_result(retvalue);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -344,7 +344,7 @@ class LibraryCallKit : public GraphKit {
|
||||
bool inline_intpoly_montgomeryMult_P256();
|
||||
bool inline_intpoly_assign();
|
||||
bool inline_digestBase_implCompress(vmIntrinsics::ID id);
|
||||
bool inline_double_keccak();
|
||||
bool inline_keccak(vmIntrinsics::ID id);
|
||||
bool inline_digestBase_implCompressMB(int predicate);
|
||||
bool inline_digestBase_implCompressMB(Node* digestBaseObj, ciInstanceKlass* instklass,
|
||||
BasicType elem_type, address stubAddr, const char *stubName,
|
||||
|
||||
@ -2741,29 +2741,30 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) {
|
||||
}
|
||||
|
||||
// Need to find the main-loop zero-trip guard
|
||||
Node *ctrl = cl->skip_assertion_predicates_with_halt();
|
||||
Node *iffm = ctrl->in(0);
|
||||
Node *opqzm = iffm->in(1)->in(1)->in(2);
|
||||
assert(opqzm->in(1) == main_limit, "do not understand situation");
|
||||
Node* const zero_trip_guard_success_proj = cl->skip_assertion_predicates_with_halt();
|
||||
DEBUG_ONLY(ensure_zero_trip_guard_proj(zero_trip_guard_success_proj, true));
|
||||
Node* const zero_trip_guard = zero_trip_guard_success_proj->in(0);
|
||||
Node* const opaque_zero_trip_guard = zero_trip_guard->in(1)->in(1)->in(2);
|
||||
assert(opaque_zero_trip_guard->in(1) == main_limit, "unexpected limit node: %s", opaque_zero_trip_guard->in(1)->Name());
|
||||
|
||||
// Find the pre-loop limit; we will expand its iterations to
|
||||
// not ever trip low tests.
|
||||
Node *p_f = iffm->in(0);
|
||||
Node* pre_loop_exit_proj = zero_trip_guard->in(0);
|
||||
// pre loop may have been optimized out
|
||||
if (p_f->Opcode() != Op_IfFalse) {
|
||||
if (!pre_loop_exit_proj->is_IfFalse()) {
|
||||
return;
|
||||
}
|
||||
CountedLoopEndNode *pre_end = p_f->in(0)->as_CountedLoopEnd();
|
||||
assert(pre_end->loopnode()->is_pre_loop(), "");
|
||||
Node *pre_opaq1 = pre_end->limit();
|
||||
CountedLoopEndNode* pre_end = pre_loop_exit_proj->in(0)->as_CountedLoopEnd();
|
||||
assert(pre_end->loopnode()->is_pre_loop(), "not a pre loop");
|
||||
Node* pre_loop_limit = pre_end->limit();
|
||||
// Occasionally it's possible for a pre-loop Opaque1 node to be
|
||||
// optimized away and then another round of loop opts attempted.
|
||||
// We can not optimize this particular loop in that case.
|
||||
if (pre_opaq1->Opcode() != Op_Opaque1) {
|
||||
if (pre_loop_limit->Opcode() != Op_Opaque1) {
|
||||
return;
|
||||
}
|
||||
Opaque1Node *pre_opaq = (Opaque1Node*)pre_opaq1;
|
||||
Node *pre_limit = pre_opaq->in(1);
|
||||
Opaque1Node* pre_loop_limit_opaque = pre_loop_limit->as_Opaque1();
|
||||
Node* pre_limit = pre_loop_limit_opaque->in(1);
|
||||
Node* pre_limit_ctrl = get_ctrl(pre_limit);
|
||||
|
||||
// Where do we put new limit calculations
|
||||
@ -2777,7 +2778,7 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) {
|
||||
|
||||
// Ensure the original loop limit is available from the
|
||||
// pre-loop Opaque1 node.
|
||||
Node *orig_limit = pre_opaq->original_loop_limit();
|
||||
Node *orig_limit = pre_loop_limit_opaque->original_loop_limit();
|
||||
if (orig_limit == nullptr || _igvn.type(orig_limit) == Type::TOP) {
|
||||
return;
|
||||
}
|
||||
@ -2846,7 +2847,7 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) {
|
||||
// 'limit' maybe pinned below the zero trip test (probably from a
|
||||
// previous round of rce), in which case, it can't be used in the
|
||||
// zero trip test expression which must occur before the zero test's if.
|
||||
if (is_dominator(ctrl, limit_ctrl)) {
|
||||
if (is_dominator(zero_trip_guard_success_proj, limit_ctrl)) {
|
||||
continue; // Don't rce this check but continue looking for other candidates.
|
||||
}
|
||||
|
||||
@ -2867,7 +2868,7 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) {
|
||||
|
||||
// As above for the 'limit', the 'offset' maybe pinned below the
|
||||
// zero trip test.
|
||||
if (is_dominator(ctrl, offset_ctrl)) {
|
||||
if (is_dominator(zero_trip_guard_success_proj, offset_ctrl)) {
|
||||
continue; // Don't rce this check but continue looking for other candidates.
|
||||
}
|
||||
|
||||
@ -2902,16 +2903,15 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) {
|
||||
Node* int_limit = limit;
|
||||
limit = new ConvI2LNode(limit);
|
||||
register_new_node(limit, next_limit_ctrl);
|
||||
Node* ctrl_target_for_data_rewire = zero_trip_guard_success_proj;
|
||||
|
||||
// Adjust pre and main loop limits to guard the correct iteration set
|
||||
if (cmp->Opcode() == Op_CmpU) { // Unsigned compare is really 2 tests
|
||||
if (b_test._test == BoolTest::lt) { // Range checks always use lt
|
||||
if (b_test._test == BoolTest::lt) {
|
||||
// Range checks always use lt
|
||||
// The underflow and overflow limits: 0 <= scale*I+offset < limit
|
||||
add_constraint(stride_con, lscale_con, offset, zero, limit, next_limit_ctrl, &pre_limit, &main_limit);
|
||||
Node* init = cl->uncasted_init_trip(true);
|
||||
|
||||
Node* opaque_init = new OpaqueLoopInitNode(C, init);
|
||||
register_new_node(opaque_init, loop_entry);
|
||||
|
||||
InitializedAssertionPredicateCreator initialized_assertion_predicate_creator(this);
|
||||
if (abs_stride_is_one) {
|
||||
@ -2938,12 +2938,15 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) {
|
||||
TemplateAssertionPredicateCreator template_assertion_predicate_creator(cl, scale_con , int_offset, int_limit,
|
||||
this);
|
||||
loop_entry = template_assertion_predicate_creator.create(loop_entry);
|
||||
// Make sure to rewire data dependencies on the removed check to the Template Assertion Predicate in order
|
||||
// to update them correctly when further splitting the main loop later.
|
||||
ctrl_target_for_data_rewire = loop_entry;
|
||||
|
||||
// Initialized Assertion Predicate for the value of the initial main-loop.
|
||||
Node* init = cl->uncasted_init_trip(true);
|
||||
loop_entry = initialized_assertion_predicate_creator.create(init, loop_entry, stride_con, scale_con,
|
||||
int_offset, int_limit,
|
||||
AssertionPredicateType::InitValue);
|
||||
|
||||
} else {
|
||||
if (PrintOpto) {
|
||||
tty->print_cr("missed RCE opportunity");
|
||||
@ -2982,6 +2985,7 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) {
|
||||
continue; // Unhandled case
|
||||
}
|
||||
}
|
||||
|
||||
// Only update variable tracking control for new nodes if it's indeed a range check that can be eliminated (and
|
||||
// limits are updated)
|
||||
new_limit_ctrl = next_limit_ctrl;
|
||||
@ -2996,10 +3000,10 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) {
|
||||
// Find loads off the surviving projection; remove their control edge
|
||||
for (DUIterator_Fast imax, i = dp->fast_outs(imax); i < imax; i++) {
|
||||
Node* cd = dp->fast_out(i); // Control-dependent node
|
||||
if (cd->is_Load() && cd->depends_only_on_test()) { // Loads can now float around in the loop
|
||||
// Allow the load to float around in the loop, or before it
|
||||
// but NOT before the pre-loop.
|
||||
_igvn.replace_input_of(cd, 0, ctrl); // ctrl, not null
|
||||
if (cd->is_Load() && cd->depends_only_on_test()) {
|
||||
// Allow a load to float around in the loop, or before it but after this loop's Template Assertion Predicates
|
||||
// or when absent after the loop's zero trip guard.
|
||||
_igvn.replace_input_of(cd, 0, ctrl_target_for_data_rewire);
|
||||
--i;
|
||||
--imax;
|
||||
}
|
||||
@ -3020,13 +3024,13 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) {
|
||||
}
|
||||
// new pre_limit can push Bool/Cmp/Opaque nodes down (when one of the eliminated condition has parameters that are not
|
||||
// loop invariant in the pre loop.
|
||||
set_ctrl(pre_opaq, new_limit_ctrl);
|
||||
set_ctrl(pre_loop_limit_opaque, new_limit_ctrl);
|
||||
// Can't use new_limit_ctrl for Bool/Cmp because it can be out of loop while they are loop variant. Conservatively set
|
||||
// control to latest possible one.
|
||||
set_ctrl(pre_end->cmp_node(), pre_end->in(0));
|
||||
set_ctrl(pre_end->in(1), pre_end->in(0));
|
||||
|
||||
_igvn.replace_input_of(pre_opaq, 1, pre_limit);
|
||||
_igvn.replace_input_of(pre_loop_limit_opaque, 1, pre_limit);
|
||||
|
||||
// Note:: we are making the main loop limit no longer precise;
|
||||
// need to round up based on stride.
|
||||
@ -3062,14 +3066,14 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) {
|
||||
_igvn.replace_node(final_iv_placeholder, final_iv);
|
||||
}
|
||||
// The OpaqueNode is unshared by design
|
||||
assert(opqzm->outcnt() == 1, "cannot hack shared node");
|
||||
_igvn.replace_input_of(opqzm, 1, main_limit);
|
||||
assert(opaque_zero_trip_guard->outcnt() == 1, "cannot hack shared node");
|
||||
_igvn.replace_input_of(opaque_zero_trip_guard, 1, main_limit);
|
||||
// new main_limit can push opaque node for zero trip guard down (when one of the eliminated condition has parameters
|
||||
// that are not loop invariant in the pre loop).
|
||||
set_ctrl(opqzm, new_limit_ctrl);
|
||||
set_ctrl(opaque_zero_trip_guard, new_limit_ctrl);
|
||||
// Bool/Cmp nodes for zero trip guard should have been assigned control between the main and pre loop (because zero
|
||||
// trip guard depends on induction variable value out of pre loop) so shouldn't need to be adjusted
|
||||
assert(is_dominator(new_limit_ctrl, get_ctrl(iffm->in(1)->in(1))), "control of cmp should be below control of updated input");
|
||||
assert(is_dominator(new_limit_ctrl, get_ctrl(zero_trip_guard->in(1)->in(1))), "control of cmp should be below control of updated input");
|
||||
|
||||
C->print_method(PHASE_AFTER_RANGE_CHECK_ELIMINATION, 4, cl);
|
||||
}
|
||||
|
||||
@ -209,6 +209,7 @@ const TypeFunc* OptoRuntime::_digestBase_implCompress_without_sha3_Type = null
|
||||
const TypeFunc* OptoRuntime::_digestBase_implCompressMB_with_sha3_Type = nullptr;
|
||||
const TypeFunc* OptoRuntime::_digestBase_implCompressMB_without_sha3_Type = nullptr;
|
||||
const TypeFunc* OptoRuntime::_double_keccak_Type = nullptr;
|
||||
const TypeFunc* OptoRuntime::_quad_keccak_Type = nullptr;
|
||||
const TypeFunc* OptoRuntime::_multiplyToLen_Type = nullptr;
|
||||
const TypeFunc* OptoRuntime::_montgomeryMultiply_Type = nullptr;
|
||||
const TypeFunc* OptoRuntime::_montgomerySquare_Type = nullptr;
|
||||
@ -1221,6 +1222,26 @@ static const TypeFunc* make_double_keccak_Type() {
|
||||
return TypeFunc::make(domain, range);
|
||||
}
|
||||
|
||||
static const TypeFunc* make_quad_keccak_Type() {
|
||||
int argcnt = 4;
|
||||
|
||||
const Type** fields = TypeTuple::fields(argcnt);
|
||||
int argp = TypeFunc::Parms;
|
||||
fields[argp++] = TypePtr::NOTNULL; // status0
|
||||
fields[argp++] = TypePtr::NOTNULL; // status1
|
||||
fields[argp++] = TypePtr::NOTNULL; // status2
|
||||
fields[argp++] = TypePtr::NOTNULL; // status3
|
||||
|
||||
assert(argp == TypeFunc::Parms + argcnt, "correct decoding");
|
||||
const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields);
|
||||
|
||||
// result type needed
|
||||
fields = TypeTuple::fields(1);
|
||||
fields[TypeFunc::Parms + 0] = TypeInt::INT;
|
||||
const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields);
|
||||
return TypeFunc::make(domain, range);
|
||||
}
|
||||
|
||||
static const TypeFunc* make_multiplyToLen_Type() {
|
||||
// create input type (domain)
|
||||
int num_args = 5;
|
||||
@ -2305,6 +2326,7 @@ void OptoRuntime::initialize_types() {
|
||||
_digestBase_implCompressMB_with_sha3_Type = make_digestBase_implCompressMB_Type(/* is_sha3= */ true);
|
||||
_digestBase_implCompressMB_without_sha3_Type = make_digestBase_implCompressMB_Type(/* is_sha3= */ false);
|
||||
_double_keccak_Type = make_double_keccak_Type();
|
||||
_quad_keccak_Type = make_quad_keccak_Type();
|
||||
_multiplyToLen_Type = make_multiplyToLen_Type();
|
||||
_montgomeryMultiply_Type = make_montgomeryMultiply_Type();
|
||||
_montgomerySquare_Type = make_montgomerySquare_Type();
|
||||
|
||||
@ -162,6 +162,7 @@ class OptoRuntime : public AllStatic {
|
||||
static const TypeFunc* _digestBase_implCompressMB_with_sha3_Type;
|
||||
static const TypeFunc* _digestBase_implCompressMB_without_sha3_Type;
|
||||
static const TypeFunc* _double_keccak_Type;
|
||||
static const TypeFunc* _quad_keccak_Type;
|
||||
static const TypeFunc* _multiplyToLen_Type;
|
||||
static const TypeFunc* _montgomeryMultiply_Type;
|
||||
static const TypeFunc* _montgomerySquare_Type;
|
||||
@ -537,6 +538,11 @@ private:
|
||||
return _double_keccak_Type;
|
||||
}
|
||||
|
||||
static inline const TypeFunc* quad_keccak_Type() {
|
||||
assert(_quad_keccak_Type != nullptr, "should be initialized");
|
||||
return _quad_keccak_Type;
|
||||
}
|
||||
|
||||
static inline const TypeFunc* multiplyToLen_Type() {
|
||||
assert(_multiplyToLen_Type != nullptr, "should be initialized");
|
||||
return _multiplyToLen_Type;
|
||||
|
||||
@ -830,6 +830,8 @@
|
||||
sha3_implCompress) \
|
||||
do_stub(compiler, double_keccak) \
|
||||
do_entry(compiler, double_keccak, double_keccak, double_keccak) \
|
||||
do_stub(compiler, quad_keccak) \
|
||||
do_entry(compiler, quad_keccak, quad_keccak, quad_keccak) \
|
||||
do_stub(compiler, sha3_implCompressMB) \
|
||||
do_entry(compiler, sha3_implCompressMB, sha3_implCompressMB, \
|
||||
sha3_implCompressMB) \
|
||||
|
||||
@ -827,7 +827,7 @@ public final class ML_KEM {
|
||||
private short[][][] generateA(byte[] rho, Boolean transposed) {
|
||||
short[][][] a = new short[mlKem_k][mlKem_k][];
|
||||
|
||||
int nrPar = 2;
|
||||
int nrPar = 4;
|
||||
int rhoLen = rho.length;
|
||||
byte[] seedBuf = new byte[XOF_BLOCK_LEN];
|
||||
System.arraycopy(rho, 0, seedBuf, 0, rho.length);
|
||||
|
||||
@ -1146,7 +1146,7 @@ public class ML_DSA {
|
||||
a[i] = new int[mlDsa_l][];
|
||||
}
|
||||
|
||||
int nrPar = 2;
|
||||
int nrPar = 4;
|
||||
int rhoLen = seed.length;
|
||||
byte[] seedBuf = new byte[SHAKE128_BLOCK_SIZE];
|
||||
System.arraycopy(seed, 0, seedBuf, 0, seed.length);
|
||||
|
||||
@ -97,6 +97,7 @@ public abstract class SHA3 extends DigestBase {
|
||||
private SHA3(String name, int digestLength, byte suffix, int c) {
|
||||
super(name, digestLength, (WIDTH - c));
|
||||
this.suffix = suffix;
|
||||
blockSizeCheck();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -113,6 +114,14 @@ public abstract class SHA3 extends DigestBase {
|
||||
Preconditions.checkIndex(ofs + blockSize - 1, b.length, Preconditions.AIOOBE_FORMATTER);
|
||||
}
|
||||
|
||||
private void blockSizeCheck() {
|
||||
switch(blockSize) {
|
||||
case 72, 104, 136, 144, 168: break;
|
||||
default:
|
||||
throw new ProviderException("Invalid SHA3 blocksize:" + blockSize);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Core compression function. Processes blockSize bytes at a time
|
||||
* and updates the state of this object.
|
||||
|
||||
@ -36,7 +36,7 @@ import static sun.security.provider.ByteArrayAccess.l2bLittle;
|
||||
import static sun.security.provider.SHA3.keccak;
|
||||
|
||||
/*
|
||||
* This class is for making it possible that NRPAR (= 2) (rather restricted)
|
||||
* This class is for making it possible that NRPAR (= 4) (rather restricted)
|
||||
* SHAKE computations execute in parallel.
|
||||
* The restrictions are:
|
||||
* 1. The messages processed should be such that the absorb phase should
|
||||
@ -54,7 +54,7 @@ public class SHA3Parallel {
|
||||
private static final int DM = 5; // dimension of lanesArr
|
||||
private byte[][] buffers;
|
||||
private long[][] lanesArr;
|
||||
private static final int NRPAR = 2;
|
||||
private static final int NRPAR = 4;
|
||||
|
||||
private SHA3Parallel(byte[][] buffers, int blockSize) throws InvalidAlgorithmParameterException {
|
||||
if ((buffers.length != NRPAR) || (buffers[0].length < blockSize)) {
|
||||
@ -81,13 +81,20 @@ public class SHA3Parallel {
|
||||
}
|
||||
|
||||
public int squeezeBlock() {
|
||||
int retVal = doubleKeccak(lanesArr[0], lanesArr[1]);
|
||||
int retVal = quadKeccak(lanesArr[0], lanesArr[1], lanesArr[2], lanesArr[3]);
|
||||
for (int i = 0; i < NRPAR; i++) {
|
||||
l2bLittle(lanesArr[i], 0, buffers[i], 0, blockSize);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@IntrinsicCandidate
|
||||
private static int quadKeccak(long[] lanes0, long[] lanes1, long[] lanes2, long[] lanes3) {
|
||||
doubleKeccak(lanes0, lanes1);
|
||||
doubleKeccak(lanes2, lanes3);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@IntrinsicCandidate
|
||||
private static int doubleKeccak(long[] lanes0, long[] lanes1) {
|
||||
doubleKeccakJava(lanes0, lanes1);
|
||||
|
||||
@ -853,8 +853,10 @@ public class EventQueue {
|
||||
newEventQueue.previousQueue = topQueue;
|
||||
topQueue.nextQueue = newEventQueue;
|
||||
|
||||
if (SunToolkit.currentEventQueue == topQueue) {
|
||||
SunToolkit.currentEventQueue = newEventQueue;
|
||||
synchronized (SunToolkit.class) {
|
||||
if (SunToolkit.getSystemEventQueueImplPP() == topQueue) {
|
||||
SunToolkit.currentEventQueue = newEventQueue;
|
||||
}
|
||||
}
|
||||
|
||||
pushPopCond.signalAll();
|
||||
@ -913,8 +915,10 @@ public class EventQueue {
|
||||
topQueue.dispatchThread.setEventQueue(prevQueue);
|
||||
}
|
||||
|
||||
if (SunToolkit.currentEventQueue == this) {
|
||||
SunToolkit.currentEventQueue = prevQueue;
|
||||
synchronized (SunToolkit.class) {
|
||||
if (SunToolkit.getSystemEventQueueImplPP() == this) {
|
||||
SunToolkit.currentEventQueue = prevQueue;
|
||||
}
|
||||
}
|
||||
|
||||
// Wake up EDT waiting in getNextEvent(), so it can
|
||||
|
||||
@ -125,7 +125,6 @@ public class TrayIcon {
|
||||
if (!SystemTray.isSupported()) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
SunToolkit.insertTargetMapping(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -99,22 +99,39 @@ public class MultiPixelPackedSampleModel extends SampleModel
|
||||
* either {@code DataBuffer.TYPE_BYTE},
|
||||
* {@code DataBuffer.TYPE_USHORT}, or
|
||||
* {@code DataBuffer.TYPE_INT}
|
||||
* @throws IllegalArgumentException if either {@code w} or {@code h}
|
||||
* is less than or equal to 0
|
||||
* @throws RasterFormatException if the number of bits per pixel
|
||||
* is not a power of 2 or if a power of 2 number of
|
||||
* pixels do not fit in one data element.
|
||||
*/
|
||||
public MultiPixelPackedSampleModel(int dataType,
|
||||
int w,
|
||||
int h,
|
||||
int numberOfBits) {
|
||||
this(dataType,w,h,
|
||||
numberOfBits,
|
||||
(w*numberOfBits+DataBuffer.getDataTypeSize(dataType)-1)/
|
||||
DataBuffer.getDataTypeSize(dataType),
|
||||
0);
|
||||
long size = (long)w * h;
|
||||
if (w <= 0 || h <= 0) {
|
||||
throw new IllegalArgumentException("Width ("+w+") and height ("+
|
||||
h+") must be > 0");
|
||||
}
|
||||
if (size > Integer.MAX_VALUE) {
|
||||
throw new IllegalArgumentException("Dimensions (width="+w+
|
||||
" height="+h+") are too large");
|
||||
}
|
||||
|
||||
if (dataType != DataBuffer.TYPE_BYTE &&
|
||||
dataType != DataBuffer.TYPE_USHORT &&
|
||||
dataType != DataBuffer.TYPE_INT) {
|
||||
throw new IllegalArgumentException("Unsupported data type "+
|
||||
dataType != DataBuffer.TYPE_INT)
|
||||
{
|
||||
throw new IllegalArgumentException("Unsupported dataType: "+
|
||||
dataType);
|
||||
}
|
||||
long sls = ((long)w*numberOfBits+DataBuffer.getDataTypeSize(dataType)-1)/
|
||||
DataBuffer.getDataTypeSize(dataType);
|
||||
if (sls > Integer.MAX_VALUE) {
|
||||
throw new RasterFormatException("Pixels do not fit");
|
||||
}
|
||||
this(dataType, w, h, numberOfBits, (int)sls, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,15 +147,23 @@ public class MultiPixelPackedSampleModel extends SampleModel
|
||||
* @param scanlineStride the line stride of the image data
|
||||
* @param dataBitOffset the data bit offset for the region of image
|
||||
* data described
|
||||
* @throws RasterFormatException if the number of bits per pixel
|
||||
* is not a power of 2 or if a power of 2 number of
|
||||
* pixels do not fit in one data element.
|
||||
* @throws IllegalArgumentException if {@code w} or
|
||||
* {@code h} is not greater than 0
|
||||
* @throws IllegalArgumentException if {@code dataType} is not
|
||||
* either {@code DataBuffer.TYPE_BYTE},
|
||||
* {@code DataBuffer.TYPE_USHORT}, or
|
||||
* {@code DataBuffer.TYPE_INT}
|
||||
* @throws IllegalArgumentException if either {@code w} or {@code h}
|
||||
* is less than or equal to 0
|
||||
* @throws IllegalArgumentException if {@code scanlineStride}
|
||||
* is less than or equal to 0
|
||||
* @throws RasterFormatException if
|
||||
* {@code ((numberOfBits * (long)w) + DataBuffer.getDataTypeSize(dataType) - 1)
|
||||
* / DataBuffer.getDataTypeSize(dataType)}
|
||||
* is greater than {@code scanlineStride}
|
||||
* @throws RasterFormatException if the number of bits per pixel
|
||||
* is not a power of 2 or if a power of 2 number of
|
||||
* pixels do not fit in one data element.
|
||||
* @throws IllegalArgumentException if {@code dataBitOffset} is less than zero,
|
||||
* or not a multiple of {@code numberOfBits}.
|
||||
*/
|
||||
public MultiPixelPackedSampleModel(int dataType, int w, int h,
|
||||
int numberOfBits,
|
||||
@ -151,11 +176,27 @@ public class MultiPixelPackedSampleModel extends SampleModel
|
||||
throw new IllegalArgumentException("Unsupported data type "+
|
||||
dataType);
|
||||
}
|
||||
if ((numberOfBits <= 0) || ((numberOfBits & (numberOfBits - 1)) != 0)) {
|
||||
throw new RasterFormatException("numberOfBits per pixel must be a power of 2");
|
||||
}
|
||||
if (scanlineStride <= 0) {
|
||||
throw new IllegalArgumentException("scanlineStride must be > 0");
|
||||
}
|
||||
int dataTypeSize = DataBuffer.getDataTypeSize(dataType);
|
||||
if ((((numberOfBits * (long)w) + dataTypeSize - 1) / dataTypeSize) > scanlineStride) {
|
||||
throw new RasterFormatException("scanlineStride is too small for width");
|
||||
}
|
||||
if (dataBitOffset < 0) {
|
||||
throw new IllegalArgumentException("dataBitOffset must be >= 0");
|
||||
}
|
||||
if ((dataBitOffset % numberOfBits) != 0) {
|
||||
throw new IllegalArgumentException("dataBitOffset must be a multiple of bits per pixel");
|
||||
}
|
||||
this.dataType = dataType;
|
||||
this.pixelBitStride = numberOfBits;
|
||||
this.scanlineStride = scanlineStride;
|
||||
this.dataBitOffset = dataBitOffset;
|
||||
this.dataElementSize = DataBuffer.getDataTypeSize(dataType);
|
||||
this.dataElementSize = dataTypeSize;
|
||||
this.pixelsPerDataElement = dataElementSize/numberOfBits;
|
||||
if (pixelsPerDataElement*numberOfBits != dataElementSize) {
|
||||
throw new RasterFormatException("MultiPixelPackedSampleModel " +
|
||||
@ -320,22 +361,12 @@ public class MultiPixelPackedSampleModel extends SampleModel
|
||||
* subset of the bands of this
|
||||
* {@code MultiPixelPackedSampleModel}. Since a
|
||||
* {@code MultiPixelPackedSampleModel} only has one band, the
|
||||
* bands argument must have a length of one and indicate the zeroth
|
||||
* band.
|
||||
* @param bands the specified bands
|
||||
* @return a new {@code SampleModel} with a subset of bands of
|
||||
* bands argument is ignored.
|
||||
* @param bands the specified bands (ignored)
|
||||
* @return a new {@code SampleModel} with the same bands as
|
||||
* this {@code MultiPixelPackedSampleModel}.
|
||||
* @throws RasterFormatException if the number of bands requested
|
||||
* is not one.
|
||||
* @throws IllegalArgumentException if {@code w} or
|
||||
* {@code h} is not greater than 0
|
||||
*/
|
||||
public SampleModel createSubsetSampleModel(int[] bands) {
|
||||
if (bands != null) {
|
||||
if (bands.length != 1)
|
||||
throw new RasterFormatException("MultiPixelPackedSampleModel has "
|
||||
+ "only one band.");
|
||||
}
|
||||
SampleModel sm = createCompatibleSampleModel(width, height);
|
||||
return sm;
|
||||
}
|
||||
|
||||
@ -200,8 +200,8 @@ public class Raster {
|
||||
* @throws IllegalArgumentException if {@code bands} is less than 1
|
||||
* @throws IllegalArgumentException if {@code w} and {@code h} are not
|
||||
* both > 0
|
||||
* @throws IllegalArgumentException if the product of {@code w}
|
||||
* and {@code h} is greater than {@code Integer.MAX_VALUE}
|
||||
* @throws IllegalArgumentException if the product of {@code w},
|
||||
* {@code h} and {@code bands} is greater than {@code Integer.MAX_VALUE}
|
||||
* @throws RasterFormatException if computing either
|
||||
* {@code location.x + w} or
|
||||
* {@code location.y + h} results in integer overflow
|
||||
@ -218,6 +218,14 @@ public class Raster {
|
||||
throw new IllegalArgumentException("Dimensions (width="+w+
|
||||
" height="+h+") are too large");
|
||||
}
|
||||
if (bands < 1) {
|
||||
throw new IllegalArgumentException("Number of bands ("+
|
||||
bands+") must be greater than 0");
|
||||
}
|
||||
long slsz = (long)w * bands;
|
||||
if (slsz > Integer.MAX_VALUE) {
|
||||
throw new IllegalArgumentException("width * bands is too large");
|
||||
}
|
||||
int[] bandOffsets = new int[bands];
|
||||
for (int i = 0; i < bands; i++) {
|
||||
bandOffsets[i] = i;
|
||||
|
||||
@ -1,692 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.awt;
|
||||
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Window;
|
||||
import java.awt.SystemTray;
|
||||
import java.awt.TrayIcon;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.event.InvocationEvent;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.beans.PropertyChangeSupport;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.lang.ref.SoftReference;
|
||||
|
||||
import sun.util.logging.PlatformLogger;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* The AppContext is a table referenced by ThreadGroup which stores
|
||||
* application service instances. (If you are not writing an application
|
||||
* service, or don't know what one is, please do not use this class.)
|
||||
* The AppContext allows a context access to what would otherwise be
|
||||
* potentially dangerous services, such as the ability to peek at
|
||||
* EventQueues or change the look-and-feel of a Swing application.<p>
|
||||
*
|
||||
* Most application services use a singleton object to provide their
|
||||
* services, either as a default (such as getSystemEventQueue or
|
||||
* getDefaultToolkit) or as static methods with class data (System).
|
||||
* The AppContext works with the former method by extending the concept
|
||||
* of "default" to be ThreadGroup-specific. Application services
|
||||
* lookup their singleton in the AppContext.<p>
|
||||
*
|
||||
* For example, here we have a Foo service, with its pre-AppContext
|
||||
* code:<p>
|
||||
* <pre>{@code
|
||||
* public class Foo {
|
||||
* private static Foo defaultFoo = new Foo();
|
||||
*
|
||||
* public static Foo getDefaultFoo() {
|
||||
* return defaultFoo;
|
||||
* }
|
||||
*
|
||||
* ... Foo service methods
|
||||
* }
|
||||
* }</pre><p>
|
||||
*
|
||||
* The problem with the above is that the Foo service is global in scope,
|
||||
* so that untrusted code can execute methods on the
|
||||
* single, shared Foo instance. The Foo service therefore either needs
|
||||
* to block its use by untrusted code using a SecurityManager test, or
|
||||
* restrict its capabilities so that it doesn't matter if untrusted code
|
||||
* executes it.<p>
|
||||
*
|
||||
* Here's the Foo class written to use the AppContext:<p>
|
||||
* <pre>{@code
|
||||
* public class Foo {
|
||||
* public static Foo getDefaultFoo() {
|
||||
* Foo foo = (Foo)AppContext.getAppContext().get(Foo.class);
|
||||
* if (foo == null) {
|
||||
* foo = new Foo();
|
||||
* getAppContext().put(Foo.class, foo);
|
||||
* }
|
||||
* return foo;
|
||||
* }
|
||||
*
|
||||
* ... Foo service methods
|
||||
* }
|
||||
* }</pre><p>
|
||||
*
|
||||
* Since a separate AppContext can exist for each ThreadGroup, trusted
|
||||
* and untrusted code have access to different Foo instances. This allows
|
||||
* untrusted code access to "system-wide" services -- the service remains
|
||||
* within the AppContext "sandbox". For example, say malicious code
|
||||
* wants to peek all of the key events on the EventQueue to listen for
|
||||
* passwords; if separate EventQueues are used for each ThreadGroup
|
||||
* using AppContexts, the only key events that code will be able to
|
||||
* listen to are its own. A more reasonable request would be to
|
||||
* change the Swing default look-and-feel; with that default stored in
|
||||
* an AppContext, the look-and-feel will change without
|
||||
* disrupting other contexts.
|
||||
*
|
||||
* @author Thomas Ball
|
||||
* @author Fred Ecks
|
||||
*/
|
||||
public final class AppContext {
|
||||
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.AppContext");
|
||||
|
||||
/* Since the contents of an AppContext are unique to each Java
|
||||
* session, this class should never be serialized. */
|
||||
|
||||
/* A map of AppContexts, referenced by ThreadGroup.
|
||||
*/
|
||||
private static final Map<ThreadGroup, AppContext> threadGroup2appContext =
|
||||
Collections.synchronizedMap(new IdentityHashMap<ThreadGroup, AppContext>());
|
||||
|
||||
/**
|
||||
* Returns a set containing all {@code AppContext}s.
|
||||
*/
|
||||
public static Set<AppContext> getAppContexts() {
|
||||
synchronized (threadGroup2appContext) {
|
||||
return new HashSet<AppContext>(threadGroup2appContext.values());
|
||||
}
|
||||
}
|
||||
|
||||
/* The main "system" AppContext, used by everything not otherwise
|
||||
contained in another AppContext. It is implicitly created for
|
||||
standalone apps only.
|
||||
*/
|
||||
private static volatile AppContext mainAppContext;
|
||||
|
||||
private static class GetAppContextLock {}
|
||||
private static final Object getAppContextLock = new GetAppContextLock();
|
||||
|
||||
/*
|
||||
* The hash map associated with this AppContext. A private delegate
|
||||
* is used instead of subclassing HashMap so as to avoid all of
|
||||
* HashMap's potentially risky methods, such as clear(), elements(),
|
||||
* putAll(), etc.
|
||||
*/
|
||||
private final Map<Object, Object> table = new HashMap<>();
|
||||
|
||||
private final ThreadGroup threadGroup;
|
||||
|
||||
/**
|
||||
* If any {@code PropertyChangeListeners} have been registered,
|
||||
* the {@code changeSupport} field describes them.
|
||||
*
|
||||
* @see #addPropertyChangeListener
|
||||
* @see #removePropertyChangeListener
|
||||
* @see PropertyChangeSupport#firePropertyChange
|
||||
*/
|
||||
private PropertyChangeSupport changeSupport = null;
|
||||
|
||||
public static final String DISPOSED_PROPERTY_NAME = "disposed";
|
||||
public static final String GUI_DISPOSED = "guidisposed";
|
||||
|
||||
private enum State {
|
||||
VALID,
|
||||
BEING_DISPOSED,
|
||||
DISPOSED
|
||||
}
|
||||
|
||||
private volatile State state = State.VALID;
|
||||
|
||||
public boolean isDisposed() {
|
||||
return state == State.DISPOSED;
|
||||
}
|
||||
|
||||
/*
|
||||
* The total number of AppContexts, system-wide. This number is
|
||||
* incremented at the beginning of the constructor, and decremented
|
||||
* at the end of dispose(). getAppContext() checks to see if this
|
||||
* number is 1. If so, it returns the sole AppContext without
|
||||
* checking Thread.currentThread().
|
||||
*/
|
||||
private static final AtomicInteger numAppContexts = new AtomicInteger();
|
||||
|
||||
|
||||
/*
|
||||
* The context ClassLoader that was used to create this AppContext.
|
||||
*/
|
||||
private final ClassLoader contextClassLoader;
|
||||
|
||||
/**
|
||||
* Constructor for AppContext. This method is <i>not</i> public,
|
||||
* nor should it ever be used as such. The proper way to construct
|
||||
* an AppContext is through the use of SunToolkit.createNewAppContext.
|
||||
* A ThreadGroup is created for the new AppContext, a Thread is
|
||||
* created within that ThreadGroup, and that Thread calls
|
||||
* SunToolkit.createNewAppContext before calling anything else.
|
||||
* That creates both the new AppContext and its EventQueue.
|
||||
*
|
||||
* @param threadGroup The ThreadGroup for the new AppContext
|
||||
* @see sun.awt.SunToolkit
|
||||
* @since 1.2
|
||||
*/
|
||||
AppContext(ThreadGroup threadGroup) {
|
||||
numAppContexts.incrementAndGet();
|
||||
|
||||
this.threadGroup = threadGroup;
|
||||
threadGroup2appContext.put(threadGroup, this);
|
||||
|
||||
this.contextClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
}
|
||||
|
||||
private static final ThreadLocal<AppContext> threadAppContext =
|
||||
new ThreadLocal<AppContext>();
|
||||
|
||||
private static void initMainAppContext() {
|
||||
// On the main Thread, we get the ThreadGroup, make a corresponding
|
||||
// AppContext, and instantiate the Java EventQueue. This way, legacy
|
||||
// code is unaffected by the move to multiple AppContext ability.
|
||||
ThreadGroup currentThreadGroup = Thread.currentThread().getThreadGroup();
|
||||
ThreadGroup parentThreadGroup = currentThreadGroup.getParent();
|
||||
while (parentThreadGroup != null) {
|
||||
// Find the root ThreadGroup to construct our main AppContext
|
||||
currentThreadGroup = parentThreadGroup;
|
||||
parentThreadGroup = currentThreadGroup.getParent();
|
||||
}
|
||||
|
||||
mainAppContext = SunToolkit.createNewAppContext(currentThreadGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the appropriate AppContext for the caller,
|
||||
* as determined by its ThreadGroup.
|
||||
*
|
||||
* @return the AppContext for the caller.
|
||||
* @see java.lang.ThreadGroup
|
||||
* @since 1.2
|
||||
*/
|
||||
public static AppContext getAppContext() {
|
||||
// we are standalone app, return the main app context
|
||||
if (numAppContexts.get() == 1 && mainAppContext != null) {
|
||||
return mainAppContext;
|
||||
}
|
||||
|
||||
AppContext appContext = threadAppContext.get();
|
||||
|
||||
if (null == appContext) {
|
||||
// Get the current ThreadGroup, and look for it and its
|
||||
// parents in the hash from ThreadGroup to AppContext --
|
||||
// it should be found, because we use createNewContext()
|
||||
// when new AppContext objects are created.
|
||||
ThreadGroup currentThreadGroup = Thread.currentThread().getThreadGroup();
|
||||
ThreadGroup threadGroup = currentThreadGroup;
|
||||
|
||||
// Special case: we implicitly create the main app context
|
||||
// if no contexts have been created yet.
|
||||
synchronized (getAppContextLock) {
|
||||
if (numAppContexts.get() == 0) {
|
||||
if (System.getProperty("javaplugin.version") == null &&
|
||||
System.getProperty("javawebstart.version") == null) {
|
||||
initMainAppContext();
|
||||
} else if (System.getProperty("javafx.version") != null &&
|
||||
threadGroup.getParent() != null) {
|
||||
// Swing inside JavaFX case
|
||||
SunToolkit.createNewAppContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AppContext context = threadGroup2appContext.get(threadGroup);
|
||||
while (context == null) {
|
||||
threadGroup = threadGroup.getParent();
|
||||
if (threadGroup == null) {
|
||||
// We've got up to the root thread group and did not find an AppContext
|
||||
// We have nowhere else to look, and this is not supposed to happen.
|
||||
// return null from this whole method.
|
||||
return null;
|
||||
}
|
||||
context = threadGroup2appContext.get(threadGroup);
|
||||
}
|
||||
|
||||
// In case we did anything in the above while loop, we add
|
||||
// all the intermediate ThreadGroups to threadGroup2appContext
|
||||
// so we won't spin again.
|
||||
for (ThreadGroup tg = currentThreadGroup; tg != threadGroup; tg = tg.getParent()) {
|
||||
threadGroup2appContext.put(tg, context);
|
||||
}
|
||||
|
||||
// Now we're done, so we cache the latest key/value pair.
|
||||
threadAppContext.set(context);
|
||||
|
||||
appContext = context;
|
||||
}
|
||||
|
||||
return appContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified AppContext is the main AppContext.
|
||||
*
|
||||
* @param ctx the context to compare with the main context
|
||||
* @return true if the specified AppContext is the main AppContext.
|
||||
* @since 1.8
|
||||
*/
|
||||
public static boolean isMainContext(AppContext ctx) {
|
||||
return (ctx != null && ctx == mainAppContext);
|
||||
}
|
||||
|
||||
private long DISPOSAL_TIMEOUT = 5000; // Default to 5-second timeout
|
||||
// for disposal of all Frames
|
||||
// (we wait for this time twice,
|
||||
// once for dispose(), and once
|
||||
// to clear the EventQueue).
|
||||
|
||||
private long THREAD_INTERRUPT_TIMEOUT = 1000;
|
||||
// Default to 1-second timeout for all
|
||||
// interrupted Threads to exit, and another
|
||||
// 1 second for all stopped Threads to die.
|
||||
|
||||
/**
|
||||
* Disposes of this AppContext, all of its top-level Frames, and
|
||||
* all Threads and ThreadGroups contained within it.
|
||||
*
|
||||
* This method must be called from a Thread which is not contained
|
||||
* within this AppContext.
|
||||
*
|
||||
* @throws IllegalThreadStateException if the current thread is
|
||||
* contained within this AppContext
|
||||
* @since 1.2
|
||||
*/
|
||||
public void dispose() throws IllegalThreadStateException {
|
||||
System.err.println(
|
||||
"""
|
||||
WARNING: sun.awt.AppContext.dispose() no longer stops threads.
|
||||
Additionally AppContext will be removed in a future release.
|
||||
Remove all uses of this internal class as soon as possible.
|
||||
There is no replacement.
|
||||
""");
|
||||
// Check to be sure that the current Thread isn't in this AppContext
|
||||
if (this.threadGroup.parentOf(Thread.currentThread().getThreadGroup())) {
|
||||
throw new IllegalThreadStateException(
|
||||
"Current Thread is contained within AppContext to be disposed."
|
||||
);
|
||||
}
|
||||
|
||||
synchronized(this) {
|
||||
if (this.state != State.VALID) {
|
||||
return; // If already disposed or being disposed, bail.
|
||||
}
|
||||
|
||||
this.state = State.BEING_DISPOSED;
|
||||
}
|
||||
|
||||
final PropertyChangeSupport changeSupport = this.changeSupport;
|
||||
if (changeSupport != null) {
|
||||
changeSupport.firePropertyChange(DISPOSED_PROPERTY_NAME, false, true);
|
||||
}
|
||||
|
||||
// First, we post an InvocationEvent to be run on the
|
||||
// EventDispatchThread which disposes of all top-level Frames and TrayIcons
|
||||
|
||||
final Object notificationLock = new Object();
|
||||
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
Window[] windowsToDispose = Window.getOwnerlessWindows();
|
||||
for (Window w : windowsToDispose) {
|
||||
try {
|
||||
w.dispose();
|
||||
} catch (Throwable t) {
|
||||
log.finer("exception occurred while disposing app context", t);
|
||||
}
|
||||
}
|
||||
if (!GraphicsEnvironment.isHeadless() && SystemTray.isSupported()) {
|
||||
SystemTray systemTray = SystemTray.getSystemTray();
|
||||
TrayIcon[] trayIconsToDispose = systemTray.getTrayIcons();
|
||||
for (TrayIcon ti : trayIconsToDispose) {
|
||||
systemTray.remove(ti);
|
||||
}
|
||||
}
|
||||
// Alert PropertyChangeListeners that the GUI has been disposed.
|
||||
if (changeSupport != null) {
|
||||
changeSupport.firePropertyChange(GUI_DISPOSED, false, true);
|
||||
}
|
||||
synchronized(notificationLock) {
|
||||
notificationLock.notifyAll(); // Notify caller that we're done
|
||||
}
|
||||
}
|
||||
};
|
||||
synchronized(notificationLock) {
|
||||
SunToolkit.postEvent(this,
|
||||
new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
|
||||
try {
|
||||
notificationLock.wait(DISPOSAL_TIMEOUT);
|
||||
} catch (InterruptedException e) { }
|
||||
}
|
||||
|
||||
// Next, we post another InvocationEvent to the end of the
|
||||
// EventQueue. When it's executed, we know we've executed all
|
||||
// events in the queue.
|
||||
|
||||
runnable = new Runnable() { public void run() {
|
||||
synchronized(notificationLock) {
|
||||
notificationLock.notifyAll(); // Notify caller that we're done
|
||||
}
|
||||
} };
|
||||
synchronized(notificationLock) {
|
||||
SunToolkit.postEvent(this,
|
||||
new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
|
||||
try {
|
||||
notificationLock.wait(DISPOSAL_TIMEOUT);
|
||||
} catch (InterruptedException e) { }
|
||||
}
|
||||
|
||||
// We are done with posting events, so change the state to disposed
|
||||
synchronized(this) {
|
||||
this.state = State.DISPOSED;
|
||||
}
|
||||
|
||||
// Next, we interrupt all Threads in the ThreadGroup
|
||||
this.threadGroup.interrupt();
|
||||
// Note, the EventDispatchThread we've interrupted may dump an
|
||||
// InterruptedException to the console here. This needs to be
|
||||
// fixed in the EventDispatchThread, not here.
|
||||
|
||||
// Next, we sleep 10ms at a time, waiting for all of the active
|
||||
// Threads in the ThreadGroup to exit.
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
long endTime = startTime + THREAD_INTERRUPT_TIMEOUT;
|
||||
while ((this.threadGroup.activeCount() > 0) &&
|
||||
(System.currentTimeMillis() < endTime)) {
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
} catch (InterruptedException e) { }
|
||||
}
|
||||
|
||||
// Next, we remove this and all subThreadGroups from threadGroup2appContext
|
||||
int numSubGroups = this.threadGroup.activeGroupCount();
|
||||
if (numSubGroups > 0) {
|
||||
ThreadGroup [] subGroups = new ThreadGroup[numSubGroups];
|
||||
numSubGroups = this.threadGroup.enumerate(subGroups);
|
||||
for (int subGroup = 0; subGroup < numSubGroups; subGroup++) {
|
||||
threadGroup2appContext.remove(subGroups[subGroup]);
|
||||
}
|
||||
}
|
||||
threadGroup2appContext.remove(this.threadGroup);
|
||||
|
||||
threadAppContext.set(null);
|
||||
|
||||
synchronized (table) {
|
||||
this.table.clear(); // Clear out the Hashtable to ease garbage collection
|
||||
}
|
||||
|
||||
numAppContexts.decrementAndGet();
|
||||
|
||||
mostRecentKeyValue = null;
|
||||
}
|
||||
|
||||
private MostRecentKeyValue mostRecentKeyValue = null;
|
||||
private MostRecentKeyValue shadowMostRecentKeyValue = null;
|
||||
|
||||
/**
|
||||
* Returns the value to which the specified key is mapped in this context.
|
||||
*
|
||||
* @param key a key in the AppContext.
|
||||
* @return the value to which the key is mapped in this AppContext;
|
||||
* {@code null} if the key is not mapped to any value.
|
||||
* @see #put(Object, Object)
|
||||
* @since 1.2
|
||||
*/
|
||||
public Object get(Object key) {
|
||||
/*
|
||||
* The most recent reference should be updated inside a synchronized
|
||||
* block to avoid a race when put() and get() are executed in
|
||||
* parallel on different threads.
|
||||
*/
|
||||
synchronized (table) {
|
||||
// Note: this most recent key/value caching is thread-hot.
|
||||
// A simple test using SwingSet found that 72% of lookups
|
||||
// were matched using the most recent key/value. By instantiating
|
||||
// a simple MostRecentKeyValue object on cache misses, the
|
||||
// cache hits can be processed without synchronization.
|
||||
|
||||
MostRecentKeyValue recent = mostRecentKeyValue;
|
||||
if ((recent != null) && (recent.key == key)) {
|
||||
return recent.value;
|
||||
}
|
||||
|
||||
Object value = table.get(key);
|
||||
if(mostRecentKeyValue == null) {
|
||||
mostRecentKeyValue = new MostRecentKeyValue(key, value);
|
||||
shadowMostRecentKeyValue = new MostRecentKeyValue(key, value);
|
||||
} else {
|
||||
MostRecentKeyValue auxKeyValue = mostRecentKeyValue;
|
||||
shadowMostRecentKeyValue.setPair(key, value);
|
||||
mostRecentKeyValue = shadowMostRecentKeyValue;
|
||||
shadowMostRecentKeyValue = auxKeyValue;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the specified {@code key} to the specified
|
||||
* {@code value} in this AppContext. Neither the key nor the
|
||||
* value can be {@code null}.
|
||||
* <p>
|
||||
* The value can be retrieved by calling the {@code get} method
|
||||
* with a key that is equal to the original key.
|
||||
*
|
||||
* @param key the AppContext key.
|
||||
* @param value the value.
|
||||
* @return the previous value of the specified key in this
|
||||
* AppContext, or {@code null} if it did not have one.
|
||||
* @throws NullPointerException if the key or value is
|
||||
* {@code null}.
|
||||
* @see #get(Object)
|
||||
* @since 1.2
|
||||
*/
|
||||
public Object put(Object key, Object value) {
|
||||
synchronized (table) {
|
||||
MostRecentKeyValue recent = mostRecentKeyValue;
|
||||
if ((recent != null) && (recent.key == key))
|
||||
recent.value = value;
|
||||
return table.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the key (and its corresponding value) from this
|
||||
* AppContext. This method does nothing if the key is not in the
|
||||
* AppContext.
|
||||
*
|
||||
* @param key the key that needs to be removed.
|
||||
* @return the value to which the key had been mapped in this AppContext,
|
||||
* or {@code null} if the key did not have a mapping.
|
||||
* @since 1.2
|
||||
*/
|
||||
public Object remove(Object key) {
|
||||
synchronized (table) {
|
||||
MostRecentKeyValue recent = mostRecentKeyValue;
|
||||
if ((recent != null) && (recent.key == key))
|
||||
recent.value = null;
|
||||
return table.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the root ThreadGroup for all Threads contained within
|
||||
* this AppContext.
|
||||
* @since 1.2
|
||||
*/
|
||||
public ThreadGroup getThreadGroup() {
|
||||
return threadGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the context ClassLoader that was used to create this
|
||||
* AppContext.
|
||||
*
|
||||
* @see java.lang.Thread#getContextClassLoader
|
||||
*/
|
||||
public ClassLoader getContextClassLoader() {
|
||||
return contextClassLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this AppContext.
|
||||
* @since 1.2
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + "[threadGroup=" + threadGroup.getName() + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all the property change listeners
|
||||
* registered on this component.
|
||||
*
|
||||
* @return all of this component's {@code PropertyChangeListener}s
|
||||
* or an empty array if no property change
|
||||
* listeners are currently registered
|
||||
*
|
||||
* @see #addPropertyChangeListener
|
||||
* @see #removePropertyChangeListener
|
||||
* @see #getPropertyChangeListeners(java.lang.String)
|
||||
* @see java.beans.PropertyChangeSupport#getPropertyChangeListeners
|
||||
* @since 1.4
|
||||
*/
|
||||
public synchronized PropertyChangeListener[] getPropertyChangeListeners() {
|
||||
if (changeSupport == null) {
|
||||
return new PropertyChangeListener[0];
|
||||
}
|
||||
return changeSupport.getPropertyChangeListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a PropertyChangeListener to the listener list for a specific
|
||||
* property. The specified property may be one of the following:
|
||||
* <ul>
|
||||
* <li>if this AppContext is disposed ("disposed")</li>
|
||||
* </ul>
|
||||
* <ul>
|
||||
* <li>if this AppContext's unowned Windows have been disposed
|
||||
* ("guidisposed"). Code to cleanup after the GUI is disposed
|
||||
* (such as LookAndFeel.uninitialize()) should execute in response to
|
||||
* this property being fired. Notifications for the "guidisposed"
|
||||
* property are sent on the event dispatch thread.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* If listener is null, no exception is thrown and no action is performed.
|
||||
*
|
||||
* @param propertyName one of the property names listed above
|
||||
* @param listener the PropertyChangeListener to be added
|
||||
*
|
||||
* @see #removePropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
|
||||
* @see #getPropertyChangeListeners(java.lang.String)
|
||||
* @see #addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
|
||||
*/
|
||||
public synchronized void addPropertyChangeListener(
|
||||
String propertyName,
|
||||
PropertyChangeListener listener) {
|
||||
if (listener == null) {
|
||||
return;
|
||||
}
|
||||
if (changeSupport == null) {
|
||||
changeSupport = new PropertyChangeSupport(this);
|
||||
}
|
||||
changeSupport.addPropertyChangeListener(propertyName, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a PropertyChangeListener from the listener list for a specific
|
||||
* property. This method should be used to remove PropertyChangeListeners
|
||||
* that were registered for a specific bound property.
|
||||
* <p>
|
||||
* If listener is null, no exception is thrown and no action is performed.
|
||||
*
|
||||
* @param propertyName a valid property name
|
||||
* @param listener the PropertyChangeListener to be removed
|
||||
*
|
||||
* @see #addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
|
||||
* @see #getPropertyChangeListeners(java.lang.String)
|
||||
* @see PropertyChangeSupport#removePropertyChangeListener(java.beans.PropertyChangeListener)
|
||||
*/
|
||||
public synchronized void removePropertyChangeListener(
|
||||
String propertyName,
|
||||
PropertyChangeListener listener) {
|
||||
if (listener == null || changeSupport == null) {
|
||||
return;
|
||||
}
|
||||
changeSupport.removePropertyChangeListener(propertyName, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all the listeners which have been associated
|
||||
* with the named property.
|
||||
*
|
||||
* @return all of the {@code PropertyChangeListeners} associated with
|
||||
* the named property or an empty array if no listeners have
|
||||
* been added
|
||||
*
|
||||
* @see #addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
|
||||
* @see #removePropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
|
||||
* @see #getPropertyChangeListeners
|
||||
* @since 1.4
|
||||
*/
|
||||
public synchronized PropertyChangeListener[] getPropertyChangeListeners(
|
||||
String propertyName) {
|
||||
if (changeSupport == null) {
|
||||
return new PropertyChangeListener[0];
|
||||
}
|
||||
return changeSupport.getPropertyChangeListeners(propertyName);
|
||||
}
|
||||
}
|
||||
|
||||
final class MostRecentKeyValue {
|
||||
Object key;
|
||||
Object value;
|
||||
MostRecentKeyValue(Object k, Object v) {
|
||||
key = k;
|
||||
value = v;
|
||||
}
|
||||
void setPair(Object k, Object v) {
|
||||
key = k;
|
||||
value = v;
|
||||
}
|
||||
}
|
||||
@ -166,6 +166,7 @@ public abstract class SunToolkit extends Toolkit
|
||||
}
|
||||
|
||||
public SunToolkit() {
|
||||
initEQ();
|
||||
}
|
||||
|
||||
public boolean useBufferPerWindow() {
|
||||
@ -258,24 +259,6 @@ public abstract class SunToolkit extends Toolkit
|
||||
return AWT_LOCK.isHeldByCurrentThread();
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new AppContext, along with its EventQueue, for a
|
||||
* new ThreadGroup.
|
||||
*/
|
||||
public static AppContext createNewAppContext() {
|
||||
ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
|
||||
return createNewAppContext(threadGroup);
|
||||
}
|
||||
|
||||
static final AppContext createNewAppContext(ThreadGroup threadGroup) {
|
||||
// Create appContext before initialization of EventQueue, so all
|
||||
// the calls to AppContext.getAppContext() from EventQueue ctor
|
||||
// return correct values
|
||||
AppContext appContext = new AppContext(threadGroup);
|
||||
initEQ();
|
||||
return appContext;
|
||||
}
|
||||
|
||||
static void wakeupEventQueue(EventQueue q, boolean isShutdown){
|
||||
AWTAccessor.getEventQueueAccessor().wakeup(q, isShutdown);
|
||||
}
|
||||
@ -311,52 +294,6 @@ public abstract class SunToolkit extends Toolkit
|
||||
}
|
||||
}
|
||||
|
||||
// Maps from non-Component/MenuComponent to AppContext.
|
||||
// WeakHashMap<Component,AppContext>
|
||||
private static final Map<Object, AppContext> appContextMap =
|
||||
Collections.synchronizedMap(new WeakIdentityHashMap<Object, AppContext>());
|
||||
|
||||
/**
|
||||
* Sets the appContext field of target. If target is not a Component or
|
||||
* MenuComponent, this returns false.
|
||||
*/
|
||||
private static boolean setAppContext(Object target,
|
||||
AppContext context) {
|
||||
return (target instanceof Component);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the appContext field for target. If target is not a
|
||||
* Component or MenuComponent this returns null.
|
||||
*/
|
||||
private static AppContext getAppContext(Object target) {
|
||||
if ((target instanceof Component) ||
|
||||
(target instanceof MenuComponent)) {
|
||||
return AppContext.getAppContext();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch the AppContext associated with the given target.
|
||||
* This can be used to determine things like which EventQueue
|
||||
* to use for posting events to a Component. If the target is
|
||||
* null or the target can't be found, a null with be returned.
|
||||
*/
|
||||
public static AppContext targetToAppContext(Object target) {
|
||||
if (target == null) {
|
||||
return null;
|
||||
}
|
||||
AppContext context = getAppContext(target);
|
||||
if (context == null) {
|
||||
// target is not a Component/MenuComponent, try the
|
||||
// appContextMap.
|
||||
context = appContextMap.get(target);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the synchronous status of focus requests on lightweight
|
||||
* components in the specified window to the specified value.
|
||||
@ -394,34 +331,6 @@ public abstract class SunToolkit extends Toolkit
|
||||
cont.setFocusTraversalPolicy(defaultPolicy);
|
||||
}
|
||||
|
||||
/* This method should be removed at the same time as targetToAppContext() */
|
||||
public static void insertTargetMapping(Object target) {
|
||||
insertTargetMapping(target, AppContext.getAppContext());
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a mapping from target to AppContext, for later retrieval
|
||||
* via targetToAppContext() above.
|
||||
*/
|
||||
public static void insertTargetMapping(Object target, AppContext appContext) {
|
||||
if (!setAppContext(target, appContext)) {
|
||||
// Target is not a Component/MenuComponent, use the private Map
|
||||
// instead.
|
||||
appContextMap.put(target, appContext);
|
||||
}
|
||||
}
|
||||
|
||||
public static void postEvent(AWTEvent event) {
|
||||
/* Adding AppContext is temporary to help migrate away from using app contexts
|
||||
* It is used by code which has already been subject to that migration.
|
||||
* However until that is complete, there is a single main app context we
|
||||
* can retrieve to use which would be the same as if the code had
|
||||
* not been migrated.
|
||||
* The overload which accepts the AppContext will eventually be replaced by this.
|
||||
*/
|
||||
postEvent(AppContext.getAppContext(), event);
|
||||
}
|
||||
|
||||
/*
|
||||
* Post an AWTEvent to the Java EventQueue, using the PostEventQueue
|
||||
* to avoid possibly calling client code (EventQueueSubclass.postEvent())
|
||||
@ -429,7 +338,7 @@ public abstract class SunToolkit extends Toolkit
|
||||
* not be called under another lock since it locks the EventQueue.
|
||||
* See bugids 4632918, 4526597.
|
||||
*/
|
||||
public static void postEvent(AppContext appContext, AWTEvent event) {
|
||||
public static void postEvent(AWTEvent event) {
|
||||
if (event == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
@ -468,7 +377,7 @@ public abstract class SunToolkit extends Toolkit
|
||||
((Component)e.getSource()).dispatchEvent(e);
|
||||
}
|
||||
}, PeerEvent.ULTIMATE_PRIORITY_EVENT);
|
||||
postEvent(targetToAppContext(e.getSource()), pe);
|
||||
postEvent(pe);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -513,25 +422,18 @@ public abstract class SunToolkit extends Toolkit
|
||||
* returning to the caller.
|
||||
*/
|
||||
public static void executeOnEventHandlerThread(PeerEvent peerEvent) {
|
||||
postEvent(targetToAppContext(peerEvent.getSource()), peerEvent);
|
||||
postEvent(peerEvent);
|
||||
}
|
||||
|
||||
public static void invokeLater(Runnable dispatcher) {
|
||||
invokeLaterOnAppContext(AppContext.getAppContext(), dispatcher);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute a chunk of code on the Java event handler thread. The
|
||||
* method takes into account provided AppContext and sets
|
||||
* {@code SunToolkit.getDefaultToolkit()} as a target of the
|
||||
* method sets {@code SunToolkit.getDefaultToolkit()} as a target of the
|
||||
* event. See 6451487 for details.
|
||||
* Does not wait for the execution to occur before returning to
|
||||
* the caller.
|
||||
*/
|
||||
public static void invokeLaterOnAppContext(
|
||||
AppContext appContext, Runnable dispatcher)
|
||||
{
|
||||
postEvent(appContext,
|
||||
public static void invokeLater(Runnable dispatcher) {
|
||||
postEvent(
|
||||
new PeerEvent(Toolkit.getDefaultToolkit(), dispatcher,
|
||||
PeerEvent.PRIORITY_EVENT));
|
||||
}
|
||||
@ -1479,8 +1381,7 @@ public abstract class SunToolkit extends Toolkit
|
||||
final AtomicBoolean eventDispatched = new AtomicBoolean();
|
||||
synchronized (waitLock) {
|
||||
queueWasEmpty = isEQEmpty();
|
||||
postEvent(AppContext.getAppContext(),
|
||||
new PeerEvent(getSystemEventQueueImpl(), null, PeerEvent.LOW_PRIORITY_EVENT) {
|
||||
postEvent(new PeerEvent(getSystemEventQueueImpl(), null, PeerEvent.LOW_PRIORITY_EVENT) {
|
||||
@Override
|
||||
public void dispatch() {
|
||||
// Here we block EDT. It could have some
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
## The FreeType Project: Freetype v2.14.2
|
||||
## The FreeType Project: Freetype v2.14.3
|
||||
|
||||
|
||||
### FreeType Notice
|
||||
@ -21,24 +21,24 @@ which fits your needs best.
|
||||
### FreeType License
|
||||
```
|
||||
|
||||
Copyright (C) 1996-2025 by David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
Copyright (C) 2007-2025 by Dereg Clegg and Michael Toftdal.
|
||||
Copyright (C) 1996-2025 by Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
Copyright (C) 2022-2025 by David Turner, Robert Wilhelm, Werner Lemberg, George Williams, and
|
||||
Copyright (C) 2004-2025 by Masatake YAMATO and Redhat K.K.
|
||||
Copyright (C) 2007-2025 by Derek Clegg and Michael Toftdal.
|
||||
Copyright (C) 2003-2025 by Masatake YAMATO, Red Hat K.K.,
|
||||
Copyright (C) 1996-2025 by David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches.
|
||||
Copyright (C) 2007-2025 by David Turner.
|
||||
Copyright (C) 2022-2025 by David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti.
|
||||
Copyright (C) 2007-2025 by Rahul Bhalerao <rahul.bhalerao@redhat.com>, <b.rahul.pm@gmail.com>.
|
||||
Copyright (C) 2025 by Behdad Esfahbod.
|
||||
Copyright (C) 2008-2025 by David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya.
|
||||
Copyright (C) 2013-2025 by Google, Inc.
|
||||
Copyright (C) 2019-2025 by Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
Copyright (C) 2009-2025 by Oran Agra and Mickey Gabel.
|
||||
Copyright (C) 2018-2025 by David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg.
|
||||
Copyright (C) 2004-2025 by David Turner, Robert Wilhelm, Werner Lemberg, and George Williams.
|
||||
Copyright (C) 1996-2026 by David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
Copyright (C) 2007-2026 by Dereg Clegg and Michael Toftdal.
|
||||
Copyright (C) 1996-2026 by Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
Copyright (C) 2022-2026 by David Turner, Robert Wilhelm, Werner Lemberg, George Williams, and
|
||||
Copyright (C) 2004-2026 by Masatake YAMATO and Redhat K.K.
|
||||
Copyright (C) 2007-2026 by Derek Clegg and Michael Toftdal.
|
||||
Copyright (C) 2003-2026 by Masatake YAMATO, Red Hat K.K.,
|
||||
Copyright (C) 1996-2026 by David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches.
|
||||
Copyright (C) 2007-2026 by David Turner.
|
||||
Copyright (C) 2022-2026 by David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti.
|
||||
Copyright (C) 2007-2026 by Rahul Bhalerao <rahul.bhalerao@redhat.com>, <b.rahul.pm@gmail.com>.
|
||||
Copyright (C) 2025-2026 by Behdad Esfahbod.
|
||||
Copyright (C) 2008-2026 by David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya.
|
||||
Copyright (C) 2013-2026 by Google, Inc.
|
||||
Copyright (C) 2019-2026 by Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
Copyright (C) 2009-2026 by Oran Agra and Mickey Gabel.
|
||||
Copyright (C) 2018-2026 by David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg.
|
||||
Copyright (C) 2004-2026 by David Turner, Robert Wilhelm, Werner Lemberg, and George Williams.
|
||||
The FreeType Project LICENSE
|
||||
----------------------------
|
||||
|
||||
@ -90,7 +90,7 @@ Introduction
|
||||
|
||||
"""
|
||||
Portions of this software are copyright © <year> The FreeType
|
||||
Project (www.freetype.org). All rights reserved.
|
||||
Project (https://freetype.org). All rights reserved.
|
||||
"""
|
||||
|
||||
Please replace <year> with the value from the FreeType version you
|
||||
@ -204,7 +204,7 @@ Legal Terms
|
||||
|
||||
Our home page can be found at
|
||||
|
||||
https://www.freetype.org
|
||||
https://freetype.org
|
||||
|
||||
|
||||
```
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* ANSI-specific configuration file (specification only).
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* Build macros of the FreeType 2 library.
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* User-selectable configuration macros (specification only).
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
* ANSI-specific library and header configuration file (specification
|
||||
* only).
|
||||
*
|
||||
* Copyright (C) 2002-2025 by
|
||||
* Copyright (C) 2002-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType integer types definitions.
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* Mac/OS X support configuration header.
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* Define a set of compiler macros used in public FreeType headers.
|
||||
*
|
||||
* Copyright (C) 2020-2025 by
|
||||
* Copyright (C) 2020-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType high-level API and common types (specification only).
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
@ -5169,7 +5169,7 @@ FT_BEGIN_HEADER
|
||||
*/
|
||||
#define FREETYPE_MAJOR 2
|
||||
#define FREETYPE_MINOR 14
|
||||
#define FREETYPE_PATCH 2
|
||||
#define FREETYPE_PATCH 3
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* Quick computation of advance widths (specification only).
|
||||
*
|
||||
* Copyright (C) 2008-2025 by
|
||||
* Copyright (C) 2008-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType exact bbox computation (specification).
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType API for accessing BDF-specific strings (specification).
|
||||
*
|
||||
* Copyright (C) 2002-2025 by
|
||||
* Copyright (C) 2002-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType utility functions for bitmaps (specification).
|
||||
*
|
||||
* Copyright (C) 2004-2025 by
|
||||
* Copyright (C) 2004-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType API for accessing CID font information (specification).
|
||||
*
|
||||
* Copyright (C) 2007-2025 by
|
||||
* Copyright (C) 2007-2026 by
|
||||
* Dereg Clegg and Michael Toftdal.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType's glyph color management (specification).
|
||||
*
|
||||
* Copyright (C) 2018-2025 by
|
||||
* Copyright (C) 2018-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType API for controlling driver modules (specification only).
|
||||
*
|
||||
* Copyright (C) 2017-2025 by
|
||||
* Copyright (C) 2017-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType error codes (specification).
|
||||
*
|
||||
* Copyright (C) 2002-2025 by
|
||||
* Copyright (C) 2002-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType error code handling (specification).
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* Support functions for font formats.
|
||||
*
|
||||
* Copyright (C) 2002-2025 by
|
||||
* Copyright (C) 2002-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* Access of TrueType's 'gasp' table (specification).
|
||||
*
|
||||
* Copyright (C) 2007-2025 by
|
||||
* Copyright (C) 2007-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType convenience functions to handle glyphs (specification).
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* Gzip-compressed stream support.
|
||||
*
|
||||
* Copyright (C) 2002-2025 by
|
||||
* Copyright (C) 2002-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
* FreeType glyph image formats and default raster interface
|
||||
* (specification).
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType incremental loading (specification).
|
||||
*
|
||||
* Copyright (C) 2002-2025 by
|
||||
* Copyright (C) 2002-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
* FreeType API for color filtering of subpixel bitmap glyphs
|
||||
* (specification).
|
||||
*
|
||||
* Copyright (C) 2006-2025 by
|
||||
* Copyright (C) 2006-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* Generic list support for FreeType (specification).
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* Additional debugging APIs.
|
||||
*
|
||||
* Copyright (C) 2020-2025 by
|
||||
* Copyright (C) 2020-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* Additional Mac-specific API.
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType variation font interface (specification).
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType modules public interface (specification).
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType module error offsets (specification).
|
||||
*
|
||||
* Copyright (C) 2001-2025 by
|
||||
* Copyright (C) 2001-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
* Support for the FT_Outline type used to store glyph shapes of
|
||||
* most scalable font formats (specification).
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType API for possible FT_Parameter tags (specification only).
|
||||
*
|
||||
* Copyright (C) 2017-2025 by
|
||||
* Copyright (C) 2017-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType renderer modules public interface (specification).
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType size objects management (specification).
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
*
|
||||
* This is _not_ used to retrieve glyph names!
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType path stroker (specification).
|
||||
*
|
||||
* Copyright (C) 2002-2025 by
|
||||
* Copyright (C) 2002-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
* FreeType synthesizing code for emboldening and slanting
|
||||
* (specification).
|
||||
*
|
||||
* Copyright (C) 2000-2025 by
|
||||
* Copyright (C) 2000-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType low-level system interface definition (specification).
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType trigonometric functions (specification).
|
||||
*
|
||||
* Copyright (C) 2001-2025 by
|
||||
* Copyright (C) 2001-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* FreeType simple types definitions (specification only).
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* High-level 'autohint' module-specific interface (specification).
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* Basic OpenType/CFF object type definitions (specification).
|
||||
*
|
||||
* Copyright (C) 2017-2025 by
|
||||
* Copyright (C) 2017-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
* Basic OpenType/CFF type definitions and interface (specification
|
||||
* only).
|
||||
*
|
||||
* Copyright (C) 1996-2025 by
|
||||
* Copyright (C) 1996-2026 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user