mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-19 15:59:40 +01:00
Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a84946dde4 | ||
|
|
fdb3e37c71 | ||
|
|
80cb773b7e | ||
|
|
a576952039 | ||
|
|
b89f364842 | ||
|
|
0694cc1d52 | ||
|
|
a3abaadc15 | ||
|
|
7cc1f82b84 | ||
|
|
636b56374e | ||
|
|
fe9efb75b0 | ||
|
|
ca6b165003 | ||
|
|
d5aa225451 | ||
|
|
79a85df074 | ||
|
|
41928aed7d | ||
|
|
3f6b0c69c3 | ||
|
|
36b185a930 | ||
|
|
c832f001e4 | ||
|
|
e5ac75a35b | ||
|
|
b79ca5f03b | ||
|
|
5bcea92eaa | ||
|
|
cc4e9716ac | ||
|
|
46cfc1e194 | ||
|
|
ae71782e77 | ||
|
|
753700182d | ||
|
|
eb727dcb51 | ||
|
|
b6cacfcbc8 | ||
|
|
d870a48880 | ||
|
|
2ea2f74f92 | ||
|
|
077ce2edc7 | ||
|
|
2a3294571a | ||
|
|
3877746eb9 | ||
|
|
3bd80fe3ba | ||
|
|
03232d4a5d | ||
|
|
4111730845 | ||
|
|
74ea38e406 | ||
|
|
839a91e14b | ||
|
|
aa4f79eaec | ||
|
|
c7df72ff0f | ||
|
|
80e066e733 |
4
.github/workflows/main.yml
vendored
4
.github/workflows/main.yml
vendored
@@ -310,7 +310,7 @@ jobs:
|
||||
uses: ./.github/workflows/build-windows.yml
|
||||
with:
|
||||
platform: windows-x64
|
||||
msvc-toolset-version: '14.43'
|
||||
msvc-toolset-version: '14.44'
|
||||
msvc-toolset-architecture: 'x86.x64'
|
||||
configure-arguments: ${{ github.event.inputs.configure-arguments }}
|
||||
make-arguments: ${{ github.event.inputs.make-arguments }}
|
||||
@@ -322,7 +322,7 @@ jobs:
|
||||
uses: ./.github/workflows/build-windows.yml
|
||||
with:
|
||||
platform: windows-aarch64
|
||||
msvc-toolset-version: '14.43'
|
||||
msvc-toolset-version: '14.44'
|
||||
msvc-toolset-architecture: 'arm64'
|
||||
make-target: 'hotspot'
|
||||
extra-conf-options: '--openjdk-target=aarch64-unknown-cygwin'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[general]
|
||||
project=jdk
|
||||
jbs=JDK
|
||||
version=26
|
||||
version=25
|
||||
|
||||
[checks]
|
||||
error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace,problemlists,copyright
|
||||
|
||||
4
make/autoconf/configure
vendored
4
make/autoconf/configure
vendored
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@@ -366,7 +366,7 @@ EOT
|
||||
|
||||
# Print additional help, e.g. a list of toolchains and JVM features.
|
||||
# This must be done by the autoconf script.
|
||||
( CONFIGURE_PRINT_ADDITIONAL_HELP=true . $generated_script PRINTF=printf )
|
||||
( CONFIGURE_PRINT_ADDITIONAL_HELP=true . $generated_script PRINTF=printf ECHO=echo )
|
||||
|
||||
cat <<EOT
|
||||
|
||||
|
||||
@@ -26,17 +26,17 @@
|
||||
# Default version, product, and vendor information to use,
|
||||
# unless overridden by configure
|
||||
|
||||
DEFAULT_VERSION_FEATURE=26
|
||||
DEFAULT_VERSION_FEATURE=25
|
||||
DEFAULT_VERSION_INTERIM=0
|
||||
DEFAULT_VERSION_UPDATE=0
|
||||
DEFAULT_VERSION_PATCH=0
|
||||
DEFAULT_VERSION_EXTRA1=0
|
||||
DEFAULT_VERSION_EXTRA2=0
|
||||
DEFAULT_VERSION_EXTRA3=0
|
||||
DEFAULT_VERSION_DATE=2026-03-17
|
||||
DEFAULT_VERSION_CLASSFILE_MAJOR=70 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`"
|
||||
DEFAULT_VERSION_DATE=2025-09-16
|
||||
DEFAULT_VERSION_CLASSFILE_MAJOR=69 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`"
|
||||
DEFAULT_VERSION_CLASSFILE_MINOR=0
|
||||
DEFAULT_VERSION_DOCS_API_SINCE=11
|
||||
DEFAULT_ACCEPTABLE_BOOT_VERSIONS="24 25 26"
|
||||
DEFAULT_JDK_SOURCE_TARGET_VERSION=26
|
||||
DEFAULT_ACCEPTABLE_BOOT_VERSIONS="24 25"
|
||||
DEFAULT_JDK_SOURCE_TARGET_VERSION=25
|
||||
DEFAULT_PROMOTED_VERSION_PRE=ea
|
||||
|
||||
@@ -2170,15 +2170,13 @@ void C2_MacroAssembler::enc_cmove_cmp_fp(int cmpFlag, FloatRegister op1, FloatRe
|
||||
cmov_cmp_fp_le(op1, op2, dst, src, is_single);
|
||||
break;
|
||||
case BoolTest::ge:
|
||||
assert(false, "Should go to BoolTest::le case");
|
||||
ShouldNotReachHere();
|
||||
cmov_cmp_fp_ge(op1, op2, dst, src, is_single);
|
||||
break;
|
||||
case BoolTest::lt:
|
||||
cmov_cmp_fp_lt(op1, op2, dst, src, is_single);
|
||||
break;
|
||||
case BoolTest::gt:
|
||||
assert(false, "Should go to BoolTest::lt case");
|
||||
ShouldNotReachHere();
|
||||
cmov_cmp_fp_gt(op1, op2, dst, src, is_single);
|
||||
break;
|
||||
default:
|
||||
assert(false, "unsupported compare condition");
|
||||
|
||||
@@ -1268,12 +1268,19 @@ void MacroAssembler::cmov_gtu(Register cmp1, Register cmp2, Register dst, Regist
|
||||
}
|
||||
|
||||
// ----------- cmove, compare float -----------
|
||||
//
|
||||
// For CmpF/D + CMoveI/L, ordered ones are quite straight and simple,
|
||||
// so, just list behaviour of unordered ones as follow.
|
||||
//
|
||||
// Set dst (CMoveI (Binary cop (CmpF/D op1 op2)) (Binary dst src))
|
||||
// (If one or both inputs to the compare are NaN, then)
|
||||
// 1. (op1 lt op2) => true => CMove: dst = src
|
||||
// 2. (op1 le op2) => true => CMove: dst = src
|
||||
// 3. (op1 gt op2) => false => CMove: dst = dst
|
||||
// 4. (op1 ge op2) => false => CMove: dst = dst
|
||||
// 5. (op1 eq op2) => false => CMove: dst = dst
|
||||
// 6. (op1 ne op2) => true => CMove: dst = src
|
||||
|
||||
// Move src to dst only if cmp1 == cmp2,
|
||||
// otherwise leave dst unchanged, including the case where one of them is NaN.
|
||||
// Clarification:
|
||||
// java code : cmp1 != cmp2 ? dst : src
|
||||
// transformed to : CMove dst, (cmp1 eq cmp2), dst, src
|
||||
void MacroAssembler::cmov_cmp_fp_eq(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single) {
|
||||
if (UseZicond) {
|
||||
if (is_single) {
|
||||
@@ -1289,7 +1296,7 @@ void MacroAssembler::cmov_cmp_fp_eq(FloatRegister cmp1, FloatRegister cmp2, Regi
|
||||
Label no_set;
|
||||
if (is_single) {
|
||||
// jump if cmp1 != cmp2, including the case of NaN
|
||||
// not jump (i.e. move src to dst) if cmp1 == cmp2
|
||||
// fallthrough (i.e. move src to dst) if cmp1 == cmp2
|
||||
float_bne(cmp1, cmp2, no_set);
|
||||
} else {
|
||||
double_bne(cmp1, cmp2, no_set);
|
||||
@@ -1298,11 +1305,6 @@ void MacroAssembler::cmov_cmp_fp_eq(FloatRegister cmp1, FloatRegister cmp2, Regi
|
||||
bind(no_set);
|
||||
}
|
||||
|
||||
// Keep dst unchanged only if cmp1 == cmp2,
|
||||
// otherwise move src to dst, including the case where one of them is NaN.
|
||||
// Clarification:
|
||||
// java code : cmp1 == cmp2 ? dst : src
|
||||
// transformed to : CMove dst, (cmp1 ne cmp2), dst, src
|
||||
void MacroAssembler::cmov_cmp_fp_ne(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single) {
|
||||
if (UseZicond) {
|
||||
if (is_single) {
|
||||
@@ -1318,7 +1320,7 @@ void MacroAssembler::cmov_cmp_fp_ne(FloatRegister cmp1, FloatRegister cmp2, Regi
|
||||
Label no_set;
|
||||
if (is_single) {
|
||||
// jump if cmp1 == cmp2
|
||||
// not jump (i.e. move src to dst) if cmp1 != cmp2, including the case of NaN
|
||||
// fallthrough (i.e. move src to dst) if cmp1 != cmp2, including the case of NaN
|
||||
float_beq(cmp1, cmp2, no_set);
|
||||
} else {
|
||||
double_beq(cmp1, cmp2, no_set);
|
||||
@@ -1327,14 +1329,6 @@ void MacroAssembler::cmov_cmp_fp_ne(FloatRegister cmp1, FloatRegister cmp2, Regi
|
||||
bind(no_set);
|
||||
}
|
||||
|
||||
// When cmp1 <= cmp2 or any of them is NaN then dst = src, otherwise, dst = dst
|
||||
// Clarification
|
||||
// scenario 1:
|
||||
// java code : cmp2 < cmp1 ? dst : src
|
||||
// transformed to : CMove dst, (cmp1 le cmp2), dst, src
|
||||
// scenario 2:
|
||||
// java code : cmp1 > cmp2 ? dst : src
|
||||
// transformed to : CMove dst, (cmp1 le cmp2), dst, src
|
||||
void MacroAssembler::cmov_cmp_fp_le(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single) {
|
||||
if (UseZicond) {
|
||||
if (is_single) {
|
||||
@@ -1350,7 +1344,7 @@ void MacroAssembler::cmov_cmp_fp_le(FloatRegister cmp1, FloatRegister cmp2, Regi
|
||||
Label no_set;
|
||||
if (is_single) {
|
||||
// jump if cmp1 > cmp2
|
||||
// not jump (i.e. move src to dst) if cmp1 <= cmp2 or either is NaN
|
||||
// fallthrough (i.e. move src to dst) if cmp1 <= cmp2 or either is NaN
|
||||
float_bgt(cmp1, cmp2, no_set);
|
||||
} else {
|
||||
double_bgt(cmp1, cmp2, no_set);
|
||||
@@ -1359,14 +1353,30 @@ void MacroAssembler::cmov_cmp_fp_le(FloatRegister cmp1, FloatRegister cmp2, Regi
|
||||
bind(no_set);
|
||||
}
|
||||
|
||||
// When cmp1 < cmp2 or any of them is NaN then dst = src, otherwise, dst = dst
|
||||
// Clarification
|
||||
// scenario 1:
|
||||
// java code : cmp2 <= cmp1 ? dst : src
|
||||
// transformed to : CMove dst, (cmp1 lt cmp2), dst, src
|
||||
// scenario 2:
|
||||
// java code : cmp1 >= cmp2 ? dst : src
|
||||
// transformed to : CMove dst, (cmp1 lt cmp2), dst, src
|
||||
void MacroAssembler::cmov_cmp_fp_ge(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single) {
|
||||
if (UseZicond) {
|
||||
if (is_single) {
|
||||
fle_s(t0, cmp2, cmp1);
|
||||
} else {
|
||||
fle_d(t0, cmp2, cmp1);
|
||||
}
|
||||
czero_nez(dst, dst, t0);
|
||||
czero_eqz(t0 , src, t0);
|
||||
orr(dst, dst, t0);
|
||||
return;
|
||||
}
|
||||
Label no_set;
|
||||
if (is_single) {
|
||||
// jump if cmp1 < cmp2 or either is NaN
|
||||
// fallthrough (i.e. move src to dst) if cmp1 >= cmp2
|
||||
float_blt(cmp1, cmp2, no_set, false, true);
|
||||
} else {
|
||||
double_blt(cmp1, cmp2, no_set, false, true);
|
||||
}
|
||||
mv(dst, src);
|
||||
bind(no_set);
|
||||
}
|
||||
|
||||
void MacroAssembler::cmov_cmp_fp_lt(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single) {
|
||||
if (UseZicond) {
|
||||
if (is_single) {
|
||||
@@ -1382,7 +1392,7 @@ void MacroAssembler::cmov_cmp_fp_lt(FloatRegister cmp1, FloatRegister cmp2, Regi
|
||||
Label no_set;
|
||||
if (is_single) {
|
||||
// jump if cmp1 >= cmp2
|
||||
// not jump (i.e. move src to dst) if cmp1 < cmp2 or either is NaN
|
||||
// fallthrough (i.e. move src to dst) if cmp1 < cmp2 or either is NaN
|
||||
float_bge(cmp1, cmp2, no_set);
|
||||
} else {
|
||||
double_bge(cmp1, cmp2, no_set);
|
||||
@@ -1391,6 +1401,30 @@ void MacroAssembler::cmov_cmp_fp_lt(FloatRegister cmp1, FloatRegister cmp2, Regi
|
||||
bind(no_set);
|
||||
}
|
||||
|
||||
void MacroAssembler::cmov_cmp_fp_gt(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single) {
|
||||
if (UseZicond) {
|
||||
if (is_single) {
|
||||
flt_s(t0, cmp2, cmp1);
|
||||
} else {
|
||||
flt_d(t0, cmp2, cmp1);
|
||||
}
|
||||
czero_nez(dst, dst, t0);
|
||||
czero_eqz(t0 , src, t0);
|
||||
orr(dst, dst, t0);
|
||||
return;
|
||||
}
|
||||
Label no_set;
|
||||
if (is_single) {
|
||||
// jump if cmp1 <= cmp2 or either is NaN
|
||||
// fallthrough (i.e. move src to dst) if cmp1 > cmp2
|
||||
float_ble(cmp1, cmp2, no_set, false, true);
|
||||
} else {
|
||||
double_ble(cmp1, cmp2, no_set, false, true);
|
||||
}
|
||||
mv(dst, src);
|
||||
bind(no_set);
|
||||
}
|
||||
|
||||
// Float compare branch instructions
|
||||
|
||||
#define INSN(NAME, FLOATCMP, BRANCH) \
|
||||
|
||||
@@ -660,7 +660,9 @@ class MacroAssembler: public Assembler {
|
||||
void cmov_cmp_fp_eq(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single);
|
||||
void cmov_cmp_fp_ne(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single);
|
||||
void cmov_cmp_fp_le(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single);
|
||||
void cmov_cmp_fp_ge(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single);
|
||||
void cmov_cmp_fp_lt(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single);
|
||||
void cmov_cmp_fp_gt(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single);
|
||||
|
||||
public:
|
||||
// We try to follow risc-v asm menomics.
|
||||
|
||||
@@ -4655,6 +4655,7 @@ static void convertF2I_slowpath(C2_MacroAssembler& masm, C2GeneralStub<Register,
|
||||
__ subptr(rsp, 8);
|
||||
__ movdbl(Address(rsp), src);
|
||||
__ call(RuntimeAddress(target));
|
||||
// APX REX2 encoding for pop(dst) increases the stub size by 1 byte.
|
||||
__ pop(dst);
|
||||
__ jmp(stub.continuation());
|
||||
#undef __
|
||||
@@ -4687,7 +4688,9 @@ void C2_MacroAssembler::convertF2I(BasicType dst_bt, BasicType src_bt, Register
|
||||
}
|
||||
}
|
||||
|
||||
auto stub = C2CodeStub::make<Register, XMMRegister, address>(dst, src, slowpath_target, 23, convertF2I_slowpath);
|
||||
// Using the APX extended general purpose registers increases the instruction encoding size by 1 byte.
|
||||
int max_size = 23 + (UseAPX ? 1 : 0);
|
||||
auto stub = C2CodeStub::make<Register, XMMRegister, address>(dst, src, slowpath_target, max_size, convertF2I_slowpath);
|
||||
jcc(Assembler::equal, stub->entry());
|
||||
bind(stub->continuation());
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@
|
||||
do_arch_blob, \
|
||||
do_arch_entry, \
|
||||
do_arch_entry_init) \
|
||||
do_arch_blob(final, 31000 \
|
||||
do_arch_blob(final, 33000 \
|
||||
WINDOWS_ONLY(+22000) ZGC_ONLY(+20000)) \
|
||||
|
||||
#endif // CPU_X86_STUBDECLARATIONS_HPP
|
||||
|
||||
@@ -2111,7 +2111,7 @@ bool VM_Version::is_intel_cascade_lake() {
|
||||
// has improved implementation of 64-byte load/stores and so the default
|
||||
// threshold is set to 0 for these platforms.
|
||||
int VM_Version::avx3_threshold() {
|
||||
return (is_intel_family_core() &&
|
||||
return (is_intel_server_family() &&
|
||||
supports_serialize() &&
|
||||
FLAG_IS_DEFAULT(AVX3Threshold)) ? 0 : AVX3Threshold;
|
||||
}
|
||||
|
||||
@@ -10527,7 +10527,8 @@ instruct xorI_rReg_im1_ndd(rRegI dst, rRegI src, immI_M1 imm)
|
||||
// Xor Register with Immediate
|
||||
instruct xorI_rReg_imm(rRegI dst, immI src, rFlagsReg cr)
|
||||
%{
|
||||
predicate(!UseAPX);
|
||||
// Strict predicate check to make selection of xorI_rReg_im1 cost agnostic if immI src is -1.
|
||||
predicate(!UseAPX && n->in(2)->bottom_type()->is_int()->get_con() != -1);
|
||||
match(Set dst (XorI dst src));
|
||||
effect(KILL cr);
|
||||
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
|
||||
@@ -10541,7 +10542,8 @@ instruct xorI_rReg_imm(rRegI dst, immI src, rFlagsReg cr)
|
||||
|
||||
instruct xorI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr)
|
||||
%{
|
||||
predicate(UseAPX);
|
||||
// Strict predicate check to make selection of xorI_rReg_im1_ndd cost agnostic if immI src2 is -1.
|
||||
predicate(UseAPX && n->in(2)->bottom_type()->is_int()->get_con() != -1);
|
||||
match(Set dst (XorI src1 src2));
|
||||
effect(KILL cr);
|
||||
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
|
||||
@@ -10559,6 +10561,7 @@ instruct xorI_rReg_mem_imm_ndd(rRegI dst, memory src1, immI src2, rFlagsReg cr)
|
||||
predicate(UseAPX);
|
||||
match(Set dst (XorI (LoadI src1) src2));
|
||||
effect(KILL cr);
|
||||
ins_cost(150);
|
||||
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
|
||||
|
||||
format %{ "exorl $dst, $src1, $src2\t# int ndd" %}
|
||||
@@ -11201,7 +11204,8 @@ instruct xorL_rReg_im1_ndd(rRegL dst,rRegL src, immL_M1 imm)
|
||||
// Xor Register with Immediate
|
||||
instruct xorL_rReg_imm(rRegL dst, immL32 src, rFlagsReg cr)
|
||||
%{
|
||||
predicate(!UseAPX);
|
||||
// Strict predicate check to make selection of xorL_rReg_im1 cost agnostic if immL32 src is -1.
|
||||
predicate(!UseAPX && n->in(2)->bottom_type()->is_long()->get_con() != -1L);
|
||||
match(Set dst (XorL dst src));
|
||||
effect(KILL cr);
|
||||
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
|
||||
@@ -11215,7 +11219,8 @@ instruct xorL_rReg_imm(rRegL dst, immL32 src, rFlagsReg cr)
|
||||
|
||||
instruct xorL_rReg_rReg_imm(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr)
|
||||
%{
|
||||
predicate(UseAPX);
|
||||
// Strict predicate check to make selection of xorL_rReg_im1_ndd cost agnostic if immL32 src2 is -1.
|
||||
predicate(UseAPX && n->in(2)->bottom_type()->is_long()->get_con() != -1L);
|
||||
match(Set dst (XorL src1 src2));
|
||||
effect(KILL cr);
|
||||
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
|
||||
@@ -11234,6 +11239,7 @@ instruct xorL_rReg_mem_imm(rRegL dst, memory src1, immL32 src2, rFlagsReg cr)
|
||||
match(Set dst (XorL (LoadL src1) src2));
|
||||
effect(KILL cr);
|
||||
flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag);
|
||||
ins_cost(150);
|
||||
|
||||
format %{ "exorq $dst, $src1, $src2\t# long ndd" %}
|
||||
ins_encode %{
|
||||
|
||||
@@ -818,7 +818,7 @@ JRT_ENTRY(void, Runtime1::deoptimize(JavaThread* current, jint trap_request))
|
||||
Deoptimization::DeoptReason reason = Deoptimization::trap_request_reason(trap_request);
|
||||
|
||||
if (action == Deoptimization::Action_make_not_entrant) {
|
||||
if (nm->make_not_entrant(nmethod::ChangeReason::C1_deoptimize)) {
|
||||
if (nm->make_not_entrant("C1 deoptimize")) {
|
||||
if (reason == Deoptimization::Reason_tenured) {
|
||||
MethodData* trap_mdo = Deoptimization::get_method_data(current, method, true /*create_if_missing*/);
|
||||
if (trap_mdo != nullptr) {
|
||||
@@ -1110,7 +1110,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, C1StubId stub_id ))
|
||||
// safepoint, but if it's still alive then make it not_entrant.
|
||||
nmethod* nm = CodeCache::find_nmethod(caller_frame.pc());
|
||||
if (nm != nullptr) {
|
||||
nm->make_not_entrant(nmethod::ChangeReason::C1_codepatch);
|
||||
nm->make_not_entrant("C1 code patch");
|
||||
}
|
||||
|
||||
Deoptimization::deoptimize_frame(current, caller_frame.id());
|
||||
@@ -1358,7 +1358,7 @@ void Runtime1::patch_code(JavaThread* current, C1StubId stub_id) {
|
||||
// Make sure the nmethod is invalidated, i.e. made not entrant.
|
||||
nmethod* nm = CodeCache::find_nmethod(caller_frame.pc());
|
||||
if (nm != nullptr) {
|
||||
nm->make_not_entrant(nmethod::ChangeReason::C1_deoptimize_for_patching);
|
||||
nm->make_not_entrant("C1 deoptimize for patching");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1486,7 +1486,7 @@ JRT_ENTRY(void, Runtime1::predicate_failed_trap(JavaThread* current))
|
||||
|
||||
nmethod* nm = CodeCache::find_nmethod(caller_frame.pc());
|
||||
assert (nm != nullptr, "no more nmethod?");
|
||||
nm->make_not_entrant(nmethod::ChangeReason::C1_predicate_failed_trap);
|
||||
nm->make_not_entrant("C1 predicate failed trap");
|
||||
|
||||
methodHandle m(current, nm->method());
|
||||
MethodData* mdo = m->method_data();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -187,7 +187,13 @@ class ValueNumberingVisitor: public InstructionVisitor {
|
||||
void do_Convert (Convert* x) { /* nothing to do */ }
|
||||
void do_NullCheck (NullCheck* x) { /* nothing to do */ }
|
||||
void do_TypeCast (TypeCast* x) { /* nothing to do */ }
|
||||
void do_NewInstance (NewInstance* x) { /* nothing to do */ }
|
||||
void do_NewInstance (NewInstance* x) {
|
||||
ciInstanceKlass* c = x->klass();
|
||||
if (c != nullptr && !c->is_initialized() &&
|
||||
(!c->is_loaded() || c->has_class_initializer())) {
|
||||
kill_memory();
|
||||
}
|
||||
}
|
||||
void do_NewTypeArray (NewTypeArray* x) { /* nothing to do */ }
|
||||
void do_NewObjectArray (NewObjectArray* x) { /* nothing to do */ }
|
||||
void do_NewMultiArray (NewMultiArray* x) { /* nothing to do */ }
|
||||
|
||||
@@ -549,6 +549,11 @@ bool ciInstanceKlass::compute_has_trusted_loader() {
|
||||
return java_lang_ClassLoader::is_trusted_loader(loader_oop);
|
||||
}
|
||||
|
||||
bool ciInstanceKlass::has_class_initializer() {
|
||||
VM_ENTRY_MARK;
|
||||
return get_instanceKlass()->class_initializer() != nullptr;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciInstanceKlass::find_method
|
||||
//
|
||||
|
||||
@@ -231,6 +231,8 @@ public:
|
||||
ciInstanceKlass* unique_concrete_subklass();
|
||||
bool has_finalizable_subclass();
|
||||
|
||||
bool has_class_initializer();
|
||||
|
||||
bool contains_field_offset(int offset);
|
||||
|
||||
// Get the instance of java.lang.Class corresponding to
|
||||
|
||||
@@ -802,7 +802,7 @@ class CompileReplay : public StackObj {
|
||||
// Make sure the existence of a prior compile doesn't stop this one
|
||||
nmethod* nm = (entry_bci != InvocationEntryBci) ? method->lookup_osr_nmethod_for(entry_bci, comp_level, true) : method->code();
|
||||
if (nm != nullptr) {
|
||||
nm->make_not_entrant(nmethod::ChangeReason::CI_replay);
|
||||
nm->make_not_entrant("CI replay");
|
||||
}
|
||||
replay_state = this;
|
||||
CompileBroker::compile_method(methodHandle(THREAD, method), entry_bci, comp_level,
|
||||
|
||||
@@ -154,8 +154,6 @@
|
||||
|
||||
#define JAVA_25_VERSION 69
|
||||
|
||||
#define JAVA_26_VERSION 70
|
||||
|
||||
void ClassFileParser::set_class_bad_constant_seen(short bad_constant) {
|
||||
assert((bad_constant == JVM_CONSTANT_Module ||
|
||||
bad_constant == JVM_CONSTANT_Package) && _major_version >= JAVA_9_VERSION,
|
||||
@@ -3740,6 +3738,7 @@ void ClassFileParser::apply_parsed_class_metadata(
|
||||
_cp->set_pool_holder(this_klass);
|
||||
this_klass->set_constants(_cp);
|
||||
this_klass->set_fieldinfo_stream(_fieldinfo_stream);
|
||||
this_klass->set_fieldinfo_search_table(_fieldinfo_search_table);
|
||||
this_klass->set_fields_status(_fields_status);
|
||||
this_klass->set_methods(_methods);
|
||||
this_klass->set_inner_classes(_inner_classes);
|
||||
@@ -3749,6 +3748,8 @@ void ClassFileParser::apply_parsed_class_metadata(
|
||||
this_klass->set_permitted_subclasses(_permitted_subclasses);
|
||||
this_klass->set_record_components(_record_components);
|
||||
|
||||
DEBUG_ONLY(FieldInfoStream::validate_search_table(_cp, _fieldinfo_stream, _fieldinfo_search_table));
|
||||
|
||||
// Delay the setting of _local_interfaces and _transitive_interfaces until after
|
||||
// initialize_supers() in fill_instance_klass(). It is because the _local_interfaces could
|
||||
// be shared with _transitive_interfaces and _transitive_interfaces may be shared with
|
||||
@@ -5056,6 +5057,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
|
||||
// note that is not safe to use the fields in the parser from this point on
|
||||
assert(nullptr == _cp, "invariant");
|
||||
assert(nullptr == _fieldinfo_stream, "invariant");
|
||||
assert(nullptr == _fieldinfo_search_table, "invariant");
|
||||
assert(nullptr == _fields_status, "invariant");
|
||||
assert(nullptr == _methods, "invariant");
|
||||
assert(nullptr == _inner_classes, "invariant");
|
||||
@@ -5276,6 +5278,7 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
|
||||
_super_klass(),
|
||||
_cp(nullptr),
|
||||
_fieldinfo_stream(nullptr),
|
||||
_fieldinfo_search_table(nullptr),
|
||||
_fields_status(nullptr),
|
||||
_methods(nullptr),
|
||||
_inner_classes(nullptr),
|
||||
@@ -5352,6 +5355,7 @@ void ClassFileParser::clear_class_metadata() {
|
||||
// deallocated if classfile parsing returns an error.
|
||||
_cp = nullptr;
|
||||
_fieldinfo_stream = nullptr;
|
||||
_fieldinfo_search_table = nullptr;
|
||||
_fields_status = nullptr;
|
||||
_methods = nullptr;
|
||||
_inner_classes = nullptr;
|
||||
@@ -5374,6 +5378,7 @@ ClassFileParser::~ClassFileParser() {
|
||||
if (_fieldinfo_stream != nullptr) {
|
||||
MetadataFactory::free_array<u1>(_loader_data, _fieldinfo_stream);
|
||||
}
|
||||
MetadataFactory::free_array<u1>(_loader_data, _fieldinfo_search_table);
|
||||
|
||||
if (_fields_status != nullptr) {
|
||||
MetadataFactory::free_array<FieldStatus>(_loader_data, _fields_status);
|
||||
@@ -5774,6 +5779,7 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st
|
||||
_fieldinfo_stream =
|
||||
FieldInfoStream::create_FieldInfoStream(_temp_field_info, _java_fields_count,
|
||||
injected_fields_count, loader_data(), CHECK);
|
||||
_fieldinfo_search_table = FieldInfoStream::create_search_table(_cp, _fieldinfo_stream, _loader_data, CHECK);
|
||||
_fields_status =
|
||||
MetadataFactory::new_array<FieldStatus>(_loader_data, _temp_field_info->length(),
|
||||
FieldStatus(0), CHECK);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -123,6 +123,7 @@ class ClassFileParser {
|
||||
const InstanceKlass* _super_klass;
|
||||
ConstantPool* _cp;
|
||||
Array<u1>* _fieldinfo_stream;
|
||||
Array<u1>* _fieldinfo_search_table;
|
||||
Array<FieldStatus>* _fields_status;
|
||||
Array<Method*>* _methods;
|
||||
Array<u2>* _inner_classes;
|
||||
|
||||
@@ -301,7 +301,7 @@ void FieldLayout::reconstruct_layout(const InstanceKlass* ik, bool& has_instance
|
||||
BasicType last_type;
|
||||
int last_offset = -1;
|
||||
while (ik != nullptr) {
|
||||
for (AllFieldStream fs(ik->fieldinfo_stream(), ik->constants()); !fs.done(); fs.next()) {
|
||||
for (AllFieldStream fs(ik); !fs.done(); fs.next()) {
|
||||
BasicType type = Signature::basic_type(fs.signature());
|
||||
// distinction between static and non-static fields is missing
|
||||
if (fs.access_flags().is_static()) continue;
|
||||
@@ -461,7 +461,7 @@ void FieldLayout::print(outputStream* output, bool is_static, const InstanceKlas
|
||||
bool found = false;
|
||||
const InstanceKlass* ik = super;
|
||||
while (!found && ik != nullptr) {
|
||||
for (AllFieldStream fs(ik->fieldinfo_stream(), ik->constants()); !fs.done(); fs.next()) {
|
||||
for (AllFieldStream fs(ik); !fs.done(); fs.next()) {
|
||||
if (fs.offset() == b->offset()) {
|
||||
output->print_cr(" @%d \"%s\" %s %d/%d %s",
|
||||
b->offset(),
|
||||
|
||||
@@ -967,6 +967,13 @@ void java_lang_Class::fixup_mirror(Klass* k, TRAPS) {
|
||||
Array<u1>* new_fis = FieldInfoStream::create_FieldInfoStream(fields, java_fields, injected_fields, k->class_loader_data(), CHECK);
|
||||
ik->set_fieldinfo_stream(new_fis);
|
||||
MetadataFactory::free_array<u1>(k->class_loader_data(), old_stream);
|
||||
|
||||
Array<u1>* old_table = ik->fieldinfo_search_table();
|
||||
Array<u1>* search_table = FieldInfoStream::create_search_table(ik->constants(), new_fis, k->class_loader_data(), CHECK);
|
||||
ik->set_fieldinfo_search_table(search_table);
|
||||
MetadataFactory::free_array<u1>(k->class_loader_data(), old_table);
|
||||
|
||||
DEBUG_ONLY(FieldInfoStream::validate_search_table(ik->constants(), new_fis, search_table));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -344,6 +344,7 @@ AOTCodeCache::~AOTCodeCache() {
|
||||
_store_buffer = nullptr;
|
||||
}
|
||||
if (_table != nullptr) {
|
||||
MutexLocker ml(AOTCodeCStrings_lock, Mutex::_no_safepoint_check_flag);
|
||||
delete _table;
|
||||
_table = nullptr;
|
||||
}
|
||||
@@ -774,6 +775,9 @@ bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind
|
||||
// we need to take a lock to prevent race between compiler threads generating AOT code
|
||||
// and the main thread generating adapter
|
||||
MutexLocker ml(Compile_lock);
|
||||
if (!is_on()) {
|
||||
return false; // AOT code cache was already dumped and closed.
|
||||
}
|
||||
if (!cache->align_write()) {
|
||||
return false;
|
||||
}
|
||||
@@ -1485,6 +1489,7 @@ void AOTCodeCache::load_strings() {
|
||||
|
||||
int AOTCodeCache::store_strings() {
|
||||
if (_C_strings_used > 0) {
|
||||
MutexLocker ml(AOTCodeCStrings_lock, Mutex::_no_safepoint_check_flag);
|
||||
uint offset = _write_position;
|
||||
uint length = 0;
|
||||
uint* lengths = (uint *)reserve_bytes(sizeof(uint) * _C_strings_used);
|
||||
@@ -1510,15 +1515,17 @@ int AOTCodeCache::store_strings() {
|
||||
|
||||
const char* AOTCodeCache::add_C_string(const char* str) {
|
||||
if (is_on_for_dump() && str != nullptr) {
|
||||
return _cache->_table->add_C_string(str);
|
||||
MutexLocker ml(AOTCodeCStrings_lock, Mutex::_no_safepoint_check_flag);
|
||||
AOTCodeAddressTable* table = addr_table();
|
||||
if (table != nullptr) {
|
||||
return table->add_C_string(str);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
const char* AOTCodeAddressTable::add_C_string(const char* str) {
|
||||
if (_extrs_complete) {
|
||||
LogStreamHandle(Trace, aot, codecache, stringtable) log; // ctor outside lock
|
||||
MutexLocker ml(AOTCodeCStrings_lock, Mutex::_no_safepoint_check_flag);
|
||||
// Check previous strings address
|
||||
for (int i = 0; i < _C_strings_count; i++) {
|
||||
if (_C_strings_in[i] == str) {
|
||||
@@ -1535,9 +1542,7 @@ const char* AOTCodeAddressTable::add_C_string(const char* str) {
|
||||
_C_strings_in[_C_strings_count] = str;
|
||||
const char* dup = os::strdup(str);
|
||||
_C_strings[_C_strings_count++] = dup;
|
||||
if (log.is_enabled()) {
|
||||
log.print_cr("add_C_string: [%d] " INTPTR_FORMAT " '%s'", _C_strings_count, p2i(dup), dup);
|
||||
}
|
||||
log_trace(aot, codecache, stringtable)("add_C_string: [%d] " INTPTR_FORMAT " '%s'", _C_strings_count, p2i(dup), dup);
|
||||
return dup;
|
||||
} else {
|
||||
assert(false, "Number of C strings >= MAX_STR_COUNT");
|
||||
|
||||
@@ -1361,7 +1361,7 @@ void CodeCache::make_marked_nmethods_deoptimized() {
|
||||
while(iter.next()) {
|
||||
nmethod* nm = iter.method();
|
||||
if (nm->is_marked_for_deoptimization() && !nm->has_been_deoptimized() && nm->can_be_deoptimized()) {
|
||||
nm->make_not_entrant(nmethod::ChangeReason::marked_for_deoptimization);
|
||||
nm->make_not_entrant("marked for deoptimization");
|
||||
nm->make_deoptimized();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1975,12 +1975,14 @@ void nmethod::invalidate_osr_method() {
|
||||
}
|
||||
}
|
||||
|
||||
void nmethod::log_state_change(ChangeReason change_reason) const {
|
||||
void nmethod::log_state_change(const char* reason) const {
|
||||
assert(reason != nullptr, "Must provide a reason");
|
||||
|
||||
if (LogCompilation) {
|
||||
if (xtty != nullptr) {
|
||||
ttyLocker ttyl; // keep the following output all in one block
|
||||
xtty->begin_elem("make_not_entrant thread='%zu' reason='%s'",
|
||||
os::current_thread_id(), change_reason_to_string(change_reason));
|
||||
os::current_thread_id(), reason);
|
||||
log_identity(xtty);
|
||||
xtty->stamp();
|
||||
xtty->end_elem();
|
||||
@@ -1989,7 +1991,7 @@ void nmethod::log_state_change(ChangeReason change_reason) const {
|
||||
|
||||
ResourceMark rm;
|
||||
stringStream ss(NEW_RESOURCE_ARRAY(char, 256), 256);
|
||||
ss.print("made not entrant: %s", change_reason_to_string(change_reason));
|
||||
ss.print("made not entrant: %s", reason);
|
||||
|
||||
CompileTask::print_ul(this, ss.freeze());
|
||||
if (PrintCompilation) {
|
||||
@@ -2004,7 +2006,9 @@ void nmethod::unlink_from_method() {
|
||||
}
|
||||
|
||||
// Invalidate code
|
||||
bool nmethod::make_not_entrant(ChangeReason change_reason) {
|
||||
bool nmethod::make_not_entrant(const char* reason) {
|
||||
assert(reason != nullptr, "Must provide a reason");
|
||||
|
||||
// This can be called while the system is already at a safepoint which is ok
|
||||
NoSafepointVerifier nsv;
|
||||
|
||||
@@ -2073,7 +2077,7 @@ bool nmethod::make_not_entrant(ChangeReason change_reason) {
|
||||
assert(success, "Transition can't fail");
|
||||
|
||||
// Log the transition once
|
||||
log_state_change(change_reason);
|
||||
log_state_change(reason);
|
||||
|
||||
// Remove nmethod from method.
|
||||
unlink_from_method();
|
||||
|
||||
@@ -471,85 +471,6 @@ class nmethod : public CodeBlob {
|
||||
void oops_do_set_strong_done(nmethod* old_head);
|
||||
|
||||
public:
|
||||
enum class ChangeReason : u1 {
|
||||
C1_codepatch,
|
||||
C1_deoptimize,
|
||||
C1_deoptimize_for_patching,
|
||||
C1_predicate_failed_trap,
|
||||
CI_replay,
|
||||
JVMCI_invalidate_nmethod,
|
||||
JVMCI_invalidate_nmethod_mirror,
|
||||
JVMCI_materialize_virtual_object,
|
||||
JVMCI_new_installation,
|
||||
JVMCI_register_method,
|
||||
JVMCI_replacing_with_new_code,
|
||||
JVMCI_reprofile,
|
||||
marked_for_deoptimization,
|
||||
missing_exception_handler,
|
||||
not_used,
|
||||
OSR_invalidation_back_branch,
|
||||
OSR_invalidation_for_compiling_with_C1,
|
||||
OSR_invalidation_of_lower_level,
|
||||
set_native_function,
|
||||
uncommon_trap,
|
||||
whitebox_deoptimization,
|
||||
zombie,
|
||||
};
|
||||
|
||||
|
||||
static const char* change_reason_to_string(ChangeReason change_reason) {
|
||||
switch (change_reason) {
|
||||
case ChangeReason::C1_codepatch:
|
||||
return "C1 code patch";
|
||||
case ChangeReason::C1_deoptimize:
|
||||
return "C1 deoptimized";
|
||||
case ChangeReason::C1_deoptimize_for_patching:
|
||||
return "C1 deoptimize for patching";
|
||||
case ChangeReason::C1_predicate_failed_trap:
|
||||
return "C1 predicate failed trap";
|
||||
case ChangeReason::CI_replay:
|
||||
return "CI replay";
|
||||
case ChangeReason::JVMCI_invalidate_nmethod:
|
||||
return "JVMCI invalidate nmethod";
|
||||
case ChangeReason::JVMCI_invalidate_nmethod_mirror:
|
||||
return "JVMCI invalidate nmethod mirror";
|
||||
case ChangeReason::JVMCI_materialize_virtual_object:
|
||||
return "JVMCI materialize virtual object";
|
||||
case ChangeReason::JVMCI_new_installation:
|
||||
return "JVMCI new installation";
|
||||
case ChangeReason::JVMCI_register_method:
|
||||
return "JVMCI register method";
|
||||
case ChangeReason::JVMCI_replacing_with_new_code:
|
||||
return "JVMCI replacing with new code";
|
||||
case ChangeReason::JVMCI_reprofile:
|
||||
return "JVMCI reprofile";
|
||||
case ChangeReason::marked_for_deoptimization:
|
||||
return "marked for deoptimization";
|
||||
case ChangeReason::missing_exception_handler:
|
||||
return "missing exception handler";
|
||||
case ChangeReason::not_used:
|
||||
return "not used";
|
||||
case ChangeReason::OSR_invalidation_back_branch:
|
||||
return "OSR invalidation back branch";
|
||||
case ChangeReason::OSR_invalidation_for_compiling_with_C1:
|
||||
return "OSR invalidation for compiling with C1";
|
||||
case ChangeReason::OSR_invalidation_of_lower_level:
|
||||
return "OSR invalidation of lower level";
|
||||
case ChangeReason::set_native_function:
|
||||
return "set native function";
|
||||
case ChangeReason::uncommon_trap:
|
||||
return "uncommon trap";
|
||||
case ChangeReason::whitebox_deoptimization:
|
||||
return "whitebox deoptimization";
|
||||
case ChangeReason::zombie:
|
||||
return "zombie";
|
||||
default: {
|
||||
assert(false, "Unhandled reason");
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create nmethod with entry_bci
|
||||
static nmethod* new_nmethod(const methodHandle& method,
|
||||
int compile_id,
|
||||
@@ -712,8 +633,8 @@ public:
|
||||
// alive. It is used when an uncommon trap happens. Returns true
|
||||
// if this thread changed the state of the nmethod or false if
|
||||
// another thread performed the transition.
|
||||
bool make_not_entrant(ChangeReason change_reason);
|
||||
bool make_not_used() { return make_not_entrant(ChangeReason::not_used); }
|
||||
bool make_not_entrant(const char* reason);
|
||||
bool make_not_used() { return make_not_entrant("not used"); }
|
||||
|
||||
bool is_marked_for_deoptimization() const { return deoptimization_status() != not_marked; }
|
||||
bool has_been_deoptimized() const { return deoptimization_status() == deoptimize_done; }
|
||||
@@ -1026,7 +947,7 @@ public:
|
||||
// Logging
|
||||
void log_identity(xmlStream* log) const;
|
||||
void log_new_nmethod() const;
|
||||
void log_state_change(ChangeReason change_reason) const;
|
||||
void log_state_change(const char* reason) const;
|
||||
|
||||
// Prints block-level comments, including nmethod specific block labels:
|
||||
void print_nmethod_labels(outputStream* stream, address block_begin, bool print_section_labels=true) const;
|
||||
|
||||
@@ -924,7 +924,7 @@ void CompilationPolicy::compile(const methodHandle& mh, int bci, CompLevel level
|
||||
nmethod* osr_nm = mh->lookup_osr_nmethod_for(bci, CompLevel_simple, false);
|
||||
if (osr_nm != nullptr && osr_nm->comp_level() > CompLevel_simple) {
|
||||
// Invalidate the existing OSR nmethod so that a compile at CompLevel_simple is permitted.
|
||||
osr_nm->make_not_entrant(nmethod::ChangeReason::OSR_invalidation_for_compiling_with_C1);
|
||||
osr_nm->make_not_entrant("OSR invalidation for compiling with C1");
|
||||
}
|
||||
compile(mh, bci, CompLevel_simple, THREAD);
|
||||
}
|
||||
@@ -1516,7 +1516,7 @@ void CompilationPolicy::method_back_branch_event(const methodHandle& mh, const m
|
||||
int osr_bci = nm->is_osr_method() ? nm->osr_entry_bci() : InvocationEntryBci;
|
||||
print_event(MAKE_NOT_ENTRANT, mh(), mh(), osr_bci, level);
|
||||
}
|
||||
nm->make_not_entrant(nmethod::ChangeReason::OSR_invalidation_back_branch);
|
||||
nm->make_not_entrant("OSR invalidation, back branch");
|
||||
}
|
||||
}
|
||||
// Fix up next_level if necessary to avoid deopts
|
||||
|
||||
@@ -625,6 +625,34 @@ void ShenandoahBarrierC2Support::verify(RootNode* root) {
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ShenandoahBarrierC2Support::is_anti_dependent_load_at_control(PhaseIdealLoop* phase, Node* maybe_load, Node* store,
|
||||
Node* control) {
|
||||
return maybe_load->is_Load() && phase->C->can_alias(store->adr_type(), phase->C->get_alias_index(maybe_load->adr_type())) &&
|
||||
phase->ctrl_or_self(maybe_load) == control;
|
||||
}
|
||||
|
||||
void ShenandoahBarrierC2Support::maybe_push_anti_dependent_loads(PhaseIdealLoop* phase, Node* maybe_store, Node* control, Unique_Node_List &wq) {
|
||||
if (!maybe_store->is_Store() && !maybe_store->is_LoadStore()) {
|
||||
return;
|
||||
}
|
||||
Node* mem = maybe_store->in(MemNode::Memory);
|
||||
for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) {
|
||||
Node* u = mem->fast_out(i);
|
||||
if (is_anti_dependent_load_at_control(phase, u, maybe_store, control)) {
|
||||
wq.push(u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShenandoahBarrierC2Support::push_data_inputs_at_control(PhaseIdealLoop* phase, Node* n, Node* ctrl, Unique_Node_List &wq) {
|
||||
for (uint i = 0; i < n->req(); i++) {
|
||||
Node* in = n->in(i);
|
||||
if (in != nullptr && phase->has_ctrl(in) && phase->get_ctrl(in) == ctrl) {
|
||||
wq.push(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ShenandoahBarrierC2Support::is_dominator_same_ctrl(Node* c, Node* d, Node* n, PhaseIdealLoop* phase) {
|
||||
// That both nodes have the same control is not sufficient to prove
|
||||
// domination, verify that there's no path from d to n
|
||||
@@ -639,22 +667,9 @@ bool ShenandoahBarrierC2Support::is_dominator_same_ctrl(Node* c, Node* d, Node*
|
||||
if (m->is_Phi() && m->in(0)->is_Loop()) {
|
||||
assert(phase->ctrl_or_self(m->in(LoopNode::EntryControl)) != c, "following loop entry should lead to new control");
|
||||
} else {
|
||||
if (m->is_Store() || m->is_LoadStore()) {
|
||||
// Take anti-dependencies into account
|
||||
Node* mem = m->in(MemNode::Memory);
|
||||
for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) {
|
||||
Node* u = mem->fast_out(i);
|
||||
if (u->is_Load() && phase->C->can_alias(m->adr_type(), phase->C->get_alias_index(u->adr_type())) &&
|
||||
phase->ctrl_or_self(u) == c) {
|
||||
wq.push(u);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (uint i = 0; i < m->req(); i++) {
|
||||
if (m->in(i) != nullptr && phase->ctrl_or_self(m->in(i)) == c) {
|
||||
wq.push(m->in(i));
|
||||
}
|
||||
}
|
||||
// Take anti-dependencies into account
|
||||
maybe_push_anti_dependent_loads(phase, m, c, wq);
|
||||
push_data_inputs_at_control(phase, m, c, wq);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -1006,7 +1021,20 @@ void ShenandoahBarrierC2Support::call_lrb_stub(Node*& ctrl, Node*& val, Node* lo
|
||||
phase->register_new_node(val, ctrl);
|
||||
}
|
||||
|
||||
void ShenandoahBarrierC2Support::fix_ctrl(Node* barrier, Node* region, const MemoryGraphFixer& fixer, Unique_Node_List& uses, Unique_Node_List& uses_to_ignore, uint last, PhaseIdealLoop* phase) {
|
||||
void ShenandoahBarrierC2Support::collect_nodes_above_barrier(Unique_Node_List &nodes_above_barrier, PhaseIdealLoop* phase, Node* ctrl, Node* init_raw_mem) {
|
||||
nodes_above_barrier.clear();
|
||||
if (phase->has_ctrl(init_raw_mem) && phase->get_ctrl(init_raw_mem) == ctrl && !init_raw_mem->is_Phi()) {
|
||||
nodes_above_barrier.push(init_raw_mem);
|
||||
}
|
||||
for (uint next = 0; next < nodes_above_barrier.size(); next++) {
|
||||
Node* n = nodes_above_barrier.at(next);
|
||||
// Take anti-dependencies into account
|
||||
maybe_push_anti_dependent_loads(phase, n, ctrl, nodes_above_barrier);
|
||||
push_data_inputs_at_control(phase, n, ctrl, nodes_above_barrier);
|
||||
}
|
||||
}
|
||||
|
||||
void ShenandoahBarrierC2Support::fix_ctrl(Node* barrier, Node* region, const MemoryGraphFixer& fixer, Unique_Node_List& uses, Unique_Node_List& nodes_above_barrier, uint last, PhaseIdealLoop* phase) {
|
||||
Node* ctrl = phase->get_ctrl(barrier);
|
||||
Node* init_raw_mem = fixer.find_mem(ctrl, barrier);
|
||||
|
||||
@@ -1017,30 +1045,17 @@ void ShenandoahBarrierC2Support::fix_ctrl(Node* barrier, Node* region, const Mem
|
||||
// control will be after the expanded barrier. The raw memory (if
|
||||
// its memory is control dependent on the barrier's input control)
|
||||
// must stay above the barrier.
|
||||
uses_to_ignore.clear();
|
||||
if (phase->has_ctrl(init_raw_mem) && phase->get_ctrl(init_raw_mem) == ctrl && !init_raw_mem->is_Phi()) {
|
||||
uses_to_ignore.push(init_raw_mem);
|
||||
}
|
||||
for (uint next = 0; next < uses_to_ignore.size(); next++) {
|
||||
Node *n = uses_to_ignore.at(next);
|
||||
for (uint i = 0; i < n->req(); i++) {
|
||||
Node* in = n->in(i);
|
||||
if (in != nullptr && phase->has_ctrl(in) && phase->get_ctrl(in) == ctrl) {
|
||||
uses_to_ignore.push(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
collect_nodes_above_barrier(nodes_above_barrier, phase, ctrl, init_raw_mem);
|
||||
for (DUIterator_Fast imax, i = ctrl->fast_outs(imax); i < imax; i++) {
|
||||
Node* u = ctrl->fast_out(i);
|
||||
if (u->_idx < last &&
|
||||
u != barrier &&
|
||||
!u->depends_only_on_test() && // preserve dependency on test
|
||||
!uses_to_ignore.member(u) &&
|
||||
!nodes_above_barrier.member(u) &&
|
||||
(u->in(0) != ctrl || (!u->is_Region() && !u->is_Phi())) &&
|
||||
(ctrl->Opcode() != Op_CatchProj || u->Opcode() != Op_CreateEx)) {
|
||||
Node* old_c = phase->ctrl_or_self(u);
|
||||
Node* c = old_c;
|
||||
if (c != ctrl ||
|
||||
if (old_c != ctrl ||
|
||||
is_dominator_same_ctrl(old_c, barrier, u, phase) ||
|
||||
ShenandoahBarrierSetC2::is_shenandoah_state_load(u)) {
|
||||
phase->igvn().rehash_node_delayed(u);
|
||||
@@ -1315,7 +1330,7 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) {
|
||||
|
||||
// Expand load-reference-barriers
|
||||
MemoryGraphFixer fixer(Compile::AliasIdxRaw, true, phase);
|
||||
Unique_Node_List uses_to_ignore;
|
||||
Unique_Node_List nodes_above_barriers;
|
||||
for (int i = state->load_reference_barriers_count() - 1; i >= 0; i--) {
|
||||
ShenandoahLoadReferenceBarrierNode* lrb = state->load_reference_barrier(i);
|
||||
uint last = phase->C->unique();
|
||||
@@ -1410,7 +1425,7 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) {
|
||||
Node* out_val = val_phi;
|
||||
phase->register_new_node(val_phi, region);
|
||||
|
||||
fix_ctrl(lrb, region, fixer, uses, uses_to_ignore, last, phase);
|
||||
fix_ctrl(lrb, region, fixer, uses, nodes_above_barriers, last, phase);
|
||||
|
||||
ctrl = orig_ctrl;
|
||||
|
||||
|
||||
@@ -62,8 +62,12 @@ private:
|
||||
PhaseIdealLoop* phase, int flags);
|
||||
static void call_lrb_stub(Node*& ctrl, Node*& val, Node* load_addr,
|
||||
DecoratorSet decorators, PhaseIdealLoop* phase);
|
||||
|
||||
static void collect_nodes_above_barrier(Unique_Node_List &nodes_above_barrier, PhaseIdealLoop* phase, Node* ctrl,
|
||||
Node* init_raw_mem);
|
||||
|
||||
static void test_in_cset(Node*& ctrl, Node*& not_cset_ctrl, Node* val, Node* raw_mem, PhaseIdealLoop* phase);
|
||||
static void fix_ctrl(Node* barrier, Node* region, const MemoryGraphFixer& fixer, Unique_Node_List& uses, Unique_Node_List& uses_to_ignore, uint last, PhaseIdealLoop* phase);
|
||||
static void fix_ctrl(Node* barrier, Node* region, const MemoryGraphFixer& fixer, Unique_Node_List& uses, Unique_Node_List& nodes_above_barrier, uint last, PhaseIdealLoop* phase);
|
||||
|
||||
static Node* get_load_addr(PhaseIdealLoop* phase, VectorSet& visited, Node* lrb);
|
||||
public:
|
||||
@@ -76,6 +80,11 @@ public:
|
||||
static bool expand(Compile* C, PhaseIterGVN& igvn);
|
||||
static void pin_and_expand(PhaseIdealLoop* phase);
|
||||
|
||||
static void push_data_inputs_at_control(PhaseIdealLoop* phase, Node* n, Node* ctrl,
|
||||
Unique_Node_List &wq);
|
||||
static bool is_anti_dependent_load_at_control(PhaseIdealLoop* phase, Node* maybe_load, Node* store, Node* control);
|
||||
|
||||
static void maybe_push_anti_dependent_loads(PhaseIdealLoop* phase, Node* maybe_store, Node* control, Unique_Node_List &wq);
|
||||
#ifdef ASSERT
|
||||
static void verify(RootNode* root);
|
||||
#endif
|
||||
|
||||
@@ -183,6 +183,29 @@ void ShenandoahGenerationalHeap::stop() {
|
||||
regulator_thread()->stop();
|
||||
}
|
||||
|
||||
bool ShenandoahGenerationalHeap::requires_barriers(stackChunkOop obj) const {
|
||||
if (is_idle()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_concurrent_young_mark_in_progress() && is_in_young(obj) && !marking_context()->allocated_after_mark_start(obj)) {
|
||||
// We are marking young, this object is in young, and it is below the TAMS
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_in_old(obj)) {
|
||||
// Card marking barriers are required for objects in the old generation
|
||||
return true;
|
||||
}
|
||||
|
||||
if (has_forwarded_objects()) {
|
||||
// Object may have pointers that need to be updated
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ShenandoahGenerationalHeap::evacuate_collection_set(bool concurrent) {
|
||||
ShenandoahRegionIterator regions;
|
||||
ShenandoahGenerationalEvacuationTask task(this, ®ions, concurrent, false /* only promote regions */);
|
||||
|
||||
@@ -128,6 +128,8 @@ public:
|
||||
|
||||
void stop() override;
|
||||
|
||||
bool requires_barriers(stackChunkOop obj) const override;
|
||||
|
||||
// Used for logging the result of a region transfer outside the heap lock
|
||||
struct TransferResult {
|
||||
bool success;
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/vmClasses.hpp"
|
||||
#include "code/nmethod.hpp"
|
||||
#include "code/scopeDesc.hpp"
|
||||
#include "compiler/compileBroker.hpp"
|
||||
#include "compiler/compilerEvent.hpp"
|
||||
@@ -1207,7 +1206,7 @@ C2V_VMENTRY_0(jint, installCode0, (JNIEnv *env, jobject,
|
||||
assert(JVMCIENV->isa_HotSpotNmethod(installed_code_handle), "wrong type");
|
||||
// Clear the link to an old nmethod first
|
||||
JVMCIObject nmethod_mirror = installed_code_handle;
|
||||
JVMCIENV->invalidate_nmethod_mirror(nmethod_mirror, true, nmethod::ChangeReason::JVMCI_replacing_with_new_code, JVMCI_CHECK_0);
|
||||
JVMCIENV->invalidate_nmethod_mirror(nmethod_mirror, true, JVMCI_CHECK_0);
|
||||
} else {
|
||||
assert(JVMCIENV->isa_InstalledCode(installed_code_handle), "wrong type");
|
||||
}
|
||||
@@ -1383,7 +1382,7 @@ C2V_VMENTRY(void, reprofile, (JNIEnv* env, jobject, ARGUMENT_PAIR(method)))
|
||||
|
||||
nmethod* code = method->code();
|
||||
if (code != nullptr) {
|
||||
code->make_not_entrant(nmethod::ChangeReason::JVMCI_reprofile);
|
||||
code->make_not_entrant("JVMCI reprofile");
|
||||
}
|
||||
|
||||
MethodData* method_data = method->method_data();
|
||||
@@ -1398,7 +1397,7 @@ C2V_END
|
||||
|
||||
C2V_VMENTRY(void, invalidateHotSpotNmethod, (JNIEnv* env, jobject, jobject hs_nmethod, jboolean deoptimize))
|
||||
JVMCIObject nmethod_mirror = JVMCIENV->wrap(hs_nmethod);
|
||||
JVMCIENV->invalidate_nmethod_mirror(nmethod_mirror, deoptimize, nmethod::ChangeReason::JVMCI_invalidate_nmethod, JVMCI_CHECK);
|
||||
JVMCIENV->invalidate_nmethod_mirror(nmethod_mirror, deoptimize, JVMCI_CHECK);
|
||||
C2V_END
|
||||
|
||||
C2V_VMENTRY_NULL(jlongArray, collectCounters, (JNIEnv* env, jobject))
|
||||
@@ -1823,7 +1822,7 @@ C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv* env, jobject, jobject _hs_
|
||||
if (!fst.current()->is_compiled_frame()) {
|
||||
JVMCI_THROW_MSG(IllegalStateException, "compiled stack frame expected");
|
||||
}
|
||||
fst.current()->cb()->as_nmethod()->make_not_entrant(nmethod::ChangeReason::JVMCI_materialize_virtual_object);
|
||||
fst.current()->cb()->as_nmethod()->make_not_entrant("JVMCI materialize virtual objects");
|
||||
}
|
||||
Deoptimization::deoptimize(thread, *fst.current(), Deoptimization::Reason_none);
|
||||
// look for the frame again as it has been updated by deopt (pc, deopt state...)
|
||||
|
||||
@@ -1750,7 +1750,7 @@ void JVMCIEnv::initialize_installed_code(JVMCIObject installed_code, CodeBlob* c
|
||||
}
|
||||
|
||||
|
||||
void JVMCIEnv::invalidate_nmethod_mirror(JVMCIObject mirror, bool deoptimize, nmethod::ChangeReason change_reason, JVMCI_TRAPS) {
|
||||
void JVMCIEnv::invalidate_nmethod_mirror(JVMCIObject mirror, bool deoptimize, JVMCI_TRAPS) {
|
||||
if (mirror.is_null()) {
|
||||
JVMCI_THROW(NullPointerException);
|
||||
}
|
||||
@@ -1773,7 +1773,7 @@ void JVMCIEnv::invalidate_nmethod_mirror(JVMCIObject mirror, bool deoptimize, nm
|
||||
|
||||
if (!deoptimize) {
|
||||
// Prevent future executions of the nmethod but let current executions complete.
|
||||
nm->make_not_entrant(change_reason);
|
||||
nm->make_not_entrant("JVMCI invalidate nmethod mirror");
|
||||
|
||||
// Do not clear the address field here as the Java code may still
|
||||
// want to later call this method with deoptimize == true. That requires
|
||||
@@ -1782,7 +1782,7 @@ void JVMCIEnv::invalidate_nmethod_mirror(JVMCIObject mirror, bool deoptimize, nm
|
||||
// Deoptimize the nmethod immediately.
|
||||
DeoptimizationScope deopt_scope;
|
||||
deopt_scope.mark(nm);
|
||||
nm->make_not_entrant(change_reason);
|
||||
nm->make_not_entrant("JVMCI invalidate nmethod mirror");
|
||||
nm->make_deoptimized();
|
||||
deopt_scope.deoptimize_marked();
|
||||
|
||||
|
||||
@@ -462,7 +462,7 @@ public:
|
||||
// field of `mirror` to prevent it from being called.
|
||||
// If `deoptimize` is true, the nmethod is immediately deoptimized.
|
||||
// The HotSpotNmethod.address field is zero upon returning.
|
||||
void invalidate_nmethod_mirror(JVMCIObject mirror, bool deoptimze, nmethod::ChangeReason change_reason, JVMCI_TRAPS);
|
||||
void invalidate_nmethod_mirror(JVMCIObject mirror, bool deoptimze, JVMCI_TRAPS);
|
||||
|
||||
void initialize_installed_code(JVMCIObject installed_code, CodeBlob* cb, JVMCI_TRAPS);
|
||||
|
||||
|
||||
@@ -2184,7 +2184,7 @@ JVMCI::CodeInstallResult JVMCIRuntime::register_method(JVMCIEnv* JVMCIENV,
|
||||
tty->print_cr("Replacing method %s", method_name);
|
||||
}
|
||||
if (old != nullptr) {
|
||||
old->make_not_entrant(nmethod::ChangeReason::JVMCI_register_method);
|
||||
old->make_not_entrant("JVMCI register method");
|
||||
}
|
||||
|
||||
LogTarget(Info, nmethod, install) lt;
|
||||
|
||||
@@ -47,7 +47,6 @@ void VectorSet::init(Arena* arena) {
|
||||
|
||||
// Expand the existing set to a bigger size
|
||||
void VectorSet::grow(uint new_word_capacity) {
|
||||
_nesting.check(_set_arena); // Check if a potential reallocation in the arena is safe
|
||||
assert(new_word_capacity >= _size, "Should have been checked before, use maybe_grow?");
|
||||
assert(new_word_capacity < (1U << 30), "");
|
||||
uint x = next_power_of_2(new_word_capacity);
|
||||
|
||||
@@ -52,6 +52,7 @@ private:
|
||||
|
||||
// Grow vector to required word capacity
|
||||
void maybe_grow(uint new_word_capacity) {
|
||||
_nesting.check(_set_arena); // Check if a potential reallocation in the arena is safe
|
||||
if (new_word_capacity >= _size) {
|
||||
grow(new_word_capacity);
|
||||
}
|
||||
|
||||
@@ -22,8 +22,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "cds/cdsConfig.hpp"
|
||||
#include "oops/fieldInfo.inline.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "utilities/packedTable.hpp"
|
||||
|
||||
void FieldInfo::print(outputStream* os, ConstantPool* cp) {
|
||||
os->print_cr("index=%d name_index=%d name=%s signature_index=%d signature=%s offset=%d "
|
||||
@@ -37,8 +40,10 @@ void FieldInfo::print(outputStream* os, ConstantPool* cp) {
|
||||
field_flags().as_uint(),
|
||||
initializer_index(),
|
||||
generic_signature_index(),
|
||||
_field_flags.is_injected() ? lookup_symbol(generic_signature_index())->as_utf8() : cp->symbol_at(generic_signature_index())->as_utf8(),
|
||||
contended_group());
|
||||
_field_flags.is_generic() ? (_field_flags.is_injected() ?
|
||||
lookup_symbol(generic_signature_index())->as_utf8() : cp->symbol_at(generic_signature_index())->as_utf8()
|
||||
) : "",
|
||||
is_contended() ? contended_group() : 0);
|
||||
}
|
||||
|
||||
void FieldInfo::print_from_growable_array(outputStream* os, GrowableArray<FieldInfo>* array, ConstantPool* cp) {
|
||||
@@ -62,13 +67,17 @@ Array<u1>* FieldInfoStream::create_FieldInfoStream(GrowableArray<FieldInfo>* fie
|
||||
StreamSizer s;
|
||||
StreamFieldSizer sizer(&s);
|
||||
|
||||
assert(fields->length() == java_fields + injected_fields, "must be");
|
||||
|
||||
sizer.consumer()->accept_uint(java_fields);
|
||||
sizer.consumer()->accept_uint(injected_fields);
|
||||
for (int i = 0; i < fields->length(); i++) {
|
||||
FieldInfo* fi = fields->adr_at(i);
|
||||
sizer.map_field_info(*fi);
|
||||
}
|
||||
int storage_size = sizer.consumer()->position() + 1;
|
||||
// Originally there was an extra byte with 0 terminating the reading;
|
||||
// now we check limits instead.
|
||||
int storage_size = sizer.consumer()->position();
|
||||
Array<u1>* const fis = MetadataFactory::new_array<u1>(loader_data, storage_size, CHECK_NULL);
|
||||
|
||||
using StreamWriter = UNSIGNED5::Writer<Array<u1>*, int, ArrayHelper<Array<u1>*, int>>;
|
||||
@@ -79,15 +88,14 @@ Array<u1>* FieldInfoStream::create_FieldInfoStream(GrowableArray<FieldInfo>* fie
|
||||
writer.consumer()->accept_uint(java_fields);
|
||||
writer.consumer()->accept_uint(injected_fields);
|
||||
for (int i = 0; i < fields->length(); i++) {
|
||||
FieldInfo* fi = fields->adr_at(i);
|
||||
writer.map_field_info(*fi);
|
||||
writer.map_field_info(fields->at(i));
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
FieldInfoReader r(fis);
|
||||
int jfc = r.next_uint();
|
||||
int jfc, ifc;
|
||||
r.read_field_counts(&jfc, &ifc);
|
||||
assert(jfc == java_fields, "Must be");
|
||||
int ifc = r.next_uint();
|
||||
assert(ifc == injected_fields, "Must be");
|
||||
for (int i = 0; i < jfc + ifc; i++) {
|
||||
FieldInfo fi;
|
||||
@@ -113,30 +121,221 @@ Array<u1>* FieldInfoStream::create_FieldInfoStream(GrowableArray<FieldInfo>* fie
|
||||
return fis;
|
||||
}
|
||||
|
||||
GrowableArray<FieldInfo>* FieldInfoStream::create_FieldInfoArray(const Array<u1>* fis, int* java_fields_count, int* injected_fields_count) {
|
||||
int length = FieldInfoStream::num_total_fields(fis);
|
||||
GrowableArray<FieldInfo>* array = new GrowableArray<FieldInfo>(length);
|
||||
int FieldInfoStream::compare_name_and_sig(const Symbol* n1, const Symbol* s1, const Symbol* n2, const Symbol* s2) {
|
||||
int cmp = n1->fast_compare(n2);
|
||||
return cmp != 0 ? cmp : s1->fast_compare(s2);
|
||||
}
|
||||
|
||||
|
||||
// We use both name and signature during the comparison; while JLS require unique
|
||||
// names for fields, JVMS requires only unique name + signature combination.
|
||||
struct field_pos {
|
||||
Symbol* _name;
|
||||
Symbol* _signature;
|
||||
int _index;
|
||||
int _position;
|
||||
};
|
||||
|
||||
class FieldInfoSupplier: public PackedTableBuilder::Supplier {
|
||||
const field_pos* _positions;
|
||||
size_t _elements;
|
||||
|
||||
public:
|
||||
FieldInfoSupplier(const field_pos* positions, size_t elements): _positions(positions), _elements(elements) {}
|
||||
|
||||
bool next(uint32_t* key, uint32_t* value) override {
|
||||
if (_elements == 0) {
|
||||
return false;
|
||||
}
|
||||
*key = _positions->_position;
|
||||
*value = _positions->_index;
|
||||
++_positions;
|
||||
--_elements;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
Array<u1>* FieldInfoStream::create_search_table(ConstantPool* cp, const Array<u1>* fis, ClassLoaderData* loader_data, TRAPS) {
|
||||
if (CDSConfig::is_dumping_dynamic_archive()) {
|
||||
// We cannot use search table; in case of dynamic archives it should be sorted by "requested" addresses,
|
||||
// but Symbol* addresses are coming from _constants, which has "buffered" addresses.
|
||||
// For background, see new comments inside allocate_node_impl in symbolTable.cpp
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FieldInfoReader r(fis);
|
||||
*java_fields_count = r.next_uint();
|
||||
*injected_fields_count = r.next_uint();
|
||||
int java_fields;
|
||||
int injected_fields;
|
||||
r.read_field_counts(&java_fields, &injected_fields);
|
||||
assert(java_fields >= 0, "must be");
|
||||
if (java_fields == 0 || fis->length() == 0 || static_cast<uint>(java_fields) < BinarySearchThreshold) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ResourceMark rm;
|
||||
field_pos* positions = NEW_RESOURCE_ARRAY(field_pos, java_fields);
|
||||
for (int i = 0; i < java_fields; ++i) {
|
||||
assert(r.has_next(), "number of fields must match");
|
||||
|
||||
positions[i]._position = r.position();
|
||||
FieldInfo fi;
|
||||
r.read_field_info(fi);
|
||||
|
||||
positions[i]._name = fi.name(cp);
|
||||
positions[i]._signature = fi.signature(cp);
|
||||
positions[i]._index = i;
|
||||
}
|
||||
auto compare_pair = [](const void* v1, const void* v2) {
|
||||
const field_pos* p1 = reinterpret_cast<const field_pos*>(v1);
|
||||
const field_pos* p2 = reinterpret_cast<const field_pos*>(v2);
|
||||
return compare_name_and_sig(p1->_name, p1->_signature, p2->_name, p2->_signature);
|
||||
};
|
||||
qsort(positions, java_fields, sizeof(field_pos), compare_pair);
|
||||
|
||||
PackedTableBuilder builder(fis->length() - 1, java_fields - 1);
|
||||
Array<u1>* table = MetadataFactory::new_array<u1>(loader_data, java_fields * builder.element_bytes(), CHECK_NULL);
|
||||
FieldInfoSupplier supplier(positions, java_fields);
|
||||
builder.fill(table->data(), static_cast<size_t>(table->length()), supplier);
|
||||
return table;
|
||||
}
|
||||
|
||||
GrowableArray<FieldInfo>* FieldInfoStream::create_FieldInfoArray(const Array<u1>* fis, int* java_fields_count, int* injected_fields_count) {
|
||||
FieldInfoReader r(fis);
|
||||
r.read_field_counts(java_fields_count, injected_fields_count);
|
||||
int length = *java_fields_count + *injected_fields_count;
|
||||
|
||||
GrowableArray<FieldInfo>* array = new GrowableArray<FieldInfo>(length);
|
||||
while (r.has_next()) {
|
||||
FieldInfo fi;
|
||||
r.read_field_info(fi);
|
||||
array->append(fi);
|
||||
}
|
||||
assert(array->length() == length, "Must be");
|
||||
assert(array->length() == *java_fields_count + *injected_fields_count, "Must be");
|
||||
return array;
|
||||
}
|
||||
|
||||
void FieldInfoStream::print_from_fieldinfo_stream(Array<u1>* fis, outputStream* os, ConstantPool* cp) {
|
||||
int length = FieldInfoStream::num_total_fields(fis);
|
||||
FieldInfoReader r(fis);
|
||||
int java_field_count = r.next_uint();
|
||||
int injected_fields_count = r.next_uint();
|
||||
int java_fields_count;
|
||||
int injected_fields_count;
|
||||
r.read_field_counts(&java_fields_count, &injected_fields_count);
|
||||
while (r.has_next()) {
|
||||
FieldInfo fi;
|
||||
r.read_field_info(fi);
|
||||
fi.print(os, cp);
|
||||
}
|
||||
}
|
||||
|
||||
class FieldInfoComparator: public PackedTableLookup::Comparator {
|
||||
const FieldInfoReader* _reader;
|
||||
ConstantPool* _cp;
|
||||
const Symbol* _name;
|
||||
const Symbol* _signature;
|
||||
|
||||
public:
|
||||
FieldInfoComparator(const FieldInfoReader* reader, ConstantPool* cp, const Symbol* name, const Symbol* signature):
|
||||
_reader(reader), _cp(cp), _name(name), _signature(signature) {}
|
||||
|
||||
int compare_to(uint32_t position) override {
|
||||
FieldInfoReader r2(*_reader);
|
||||
r2.set_position_and_next_index(position, -1);
|
||||
u2 name_index, sig_index;
|
||||
r2.read_name_and_signature(&name_index, &sig_index);
|
||||
Symbol* mid_name = _cp->symbol_at(name_index);
|
||||
Symbol* mid_sig = _cp->symbol_at(sig_index);
|
||||
|
||||
return FieldInfoStream::compare_name_and_sig(_name, _signature, mid_name, mid_sig);
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
void reset(uint32_t position) override {
|
||||
FieldInfoReader r2(*_reader);
|
||||
r2.set_position_and_next_index(position, -1);
|
||||
u2 name_index, signature_index;
|
||||
r2.read_name_and_signature(&name_index, &signature_index);
|
||||
_name = _cp->symbol_at(name_index);
|
||||
_signature = _cp->symbol_at(signature_index);
|
||||
}
|
||||
#endif // ASSERT
|
||||
};
|
||||
|
||||
#ifdef ASSERT
|
||||
void FieldInfoStream::validate_search_table(ConstantPool* cp, const Array<u1>* fis, const Array<u1>* search_table) {
|
||||
if (search_table == nullptr) {
|
||||
return;
|
||||
}
|
||||
FieldInfoReader reader(fis);
|
||||
int java_fields, injected_fields;
|
||||
reader.read_field_counts(&java_fields, &injected_fields);
|
||||
assert(java_fields > 0, "must be");
|
||||
|
||||
PackedTableLookup lookup(fis->length() - 1, java_fields - 1, search_table);
|
||||
assert(lookup.element_bytes() * java_fields == static_cast<unsigned int>(search_table->length()), "size does not match");
|
||||
|
||||
FieldInfoComparator comparator(&reader, cp, nullptr, nullptr);
|
||||
// Check 1: assert that elements have the correct order based on the comparison function
|
||||
lookup.validate_order(comparator);
|
||||
|
||||
// Check 2: Iterate through the original stream (not just search_table) and try if lookup works as expected
|
||||
reader.set_position_and_next_index(0, 0);
|
||||
reader.read_field_counts(&java_fields, &injected_fields);
|
||||
while (reader.has_next()) {
|
||||
int field_start = reader.position();
|
||||
FieldInfo fi;
|
||||
reader.read_field_info(fi);
|
||||
if (fi.field_flags().is_injected()) {
|
||||
// checking only java fields that precede injected ones
|
||||
break;
|
||||
}
|
||||
|
||||
FieldInfoReader r2(fis);
|
||||
int index = r2.search_table_lookup(search_table, fi.name(cp), fi.signature(cp), cp, java_fields);
|
||||
assert(index == static_cast<int>(fi.index()), "wrong index: %d != %u", index, fi.index());
|
||||
assert(index == r2.next_index(), "index should match");
|
||||
assert(field_start == r2.position(), "must find the same position");
|
||||
}
|
||||
}
|
||||
#endif // ASSERT
|
||||
|
||||
void FieldInfoStream::print_search_table(outputStream* st, ConstantPool* cp, const Array<u1>* fis, const Array<u1>* search_table) {
|
||||
if (search_table == nullptr) {
|
||||
return;
|
||||
}
|
||||
FieldInfoReader reader(fis);
|
||||
int java_fields, injected_fields;
|
||||
reader.read_field_counts(&java_fields, &injected_fields);
|
||||
assert(java_fields > 0, "must be");
|
||||
PackedTableLookup lookup(fis->length() - 1, java_fields - 1, search_table);
|
||||
auto printer = [&] (size_t offset, uint32_t position, uint32_t index) {
|
||||
reader.set_position_and_next_index(position, -1);
|
||||
u2 name_index, sig_index;
|
||||
reader.read_name_and_signature(&name_index, &sig_index);
|
||||
Symbol* name = cp->symbol_at(name_index);
|
||||
Symbol* sig = cp->symbol_at(sig_index);
|
||||
st->print(" [%zu] #%d,#%d = ", offset, name_index, sig_index);
|
||||
name->print_symbol_on(st);
|
||||
st->print(":");
|
||||
sig->print_symbol_on(st);
|
||||
st->print(" @ %p,%p", name, sig);
|
||||
st->cr();
|
||||
};
|
||||
|
||||
lookup.iterate(printer);
|
||||
}
|
||||
|
||||
int FieldInfoReader::search_table_lookup(const Array<u1>* search_table, const Symbol* name, const Symbol* signature, ConstantPool* cp, int java_fields) {
|
||||
assert(java_fields >= 0, "must be");
|
||||
if (java_fields == 0) {
|
||||
return -1;
|
||||
}
|
||||
FieldInfoComparator comp(this, cp, name, signature);
|
||||
PackedTableLookup lookup(_r.limit() - 1, java_fields - 1, search_table);
|
||||
uint32_t position;
|
||||
static_assert(sizeof(uint32_t) == sizeof(_next_index), "field size assert");
|
||||
if (lookup.search(comp, &position, reinterpret_cast<uint32_t*>(&_next_index))) {
|
||||
_r.set_position(static_cast<int>(position));
|
||||
return _next_index;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,29 +222,28 @@ public:
|
||||
void map_field_info(const FieldInfo& fi);
|
||||
};
|
||||
|
||||
|
||||
// Gadget for decoding and reading the stream of field records.
|
||||
class FieldInfoReader {
|
||||
friend class FieldInfoStream;
|
||||
friend class ClassFileParser;
|
||||
friend class FieldStreamBase;
|
||||
friend class FieldInfo;
|
||||
|
||||
UNSIGNED5::Reader<const u1*, int> _r;
|
||||
int _next_index;
|
||||
|
||||
public:
|
||||
public:
|
||||
FieldInfoReader(const Array<u1>* fi);
|
||||
|
||||
private:
|
||||
uint32_t next_uint() { return _r.next_uint(); }
|
||||
private:
|
||||
inline uint32_t next_uint() { return _r.next_uint(); }
|
||||
void skip(int n) { int s = _r.try_skip(n); assert(s == n,""); }
|
||||
|
||||
public:
|
||||
int has_next() { return _r.has_next(); }
|
||||
int position() { return _r.position(); }
|
||||
int next_index() { return _next_index; }
|
||||
void read_field_counts(int* java_fields, int* injected_fields);
|
||||
int has_next() const { return _r.position() < _r.limit(); }
|
||||
int position() const { return _r.position(); }
|
||||
int next_index() const { return _next_index; }
|
||||
void read_name_and_signature(u2* name_index, u2* signature_index);
|
||||
void read_field_info(FieldInfo& fi);
|
||||
|
||||
int search_table_lookup(const Array<u1>* search_table, const Symbol* name, const Symbol* signature, ConstantPool* cp, int java_fields);
|
||||
|
||||
// skip a whole field record, both required and optional bits
|
||||
FieldInfoReader& skip_field_info();
|
||||
|
||||
@@ -271,6 +270,11 @@ class FieldInfoStream : AllStatic {
|
||||
friend class JavaFieldStream;
|
||||
friend class FieldStreamBase;
|
||||
friend class ClassFileParser;
|
||||
friend class FieldInfoReader;
|
||||
friend class FieldInfoComparator;
|
||||
|
||||
private:
|
||||
static int compare_name_and_sig(const Symbol* n1, const Symbol* s1, const Symbol* n2, const Symbol* s2);
|
||||
|
||||
public:
|
||||
static int num_java_fields(const Array<u1>* fis);
|
||||
@@ -278,9 +282,14 @@ class FieldInfoStream : AllStatic {
|
||||
static int num_total_fields(const Array<u1>* fis);
|
||||
|
||||
static Array<u1>* create_FieldInfoStream(GrowableArray<FieldInfo>* fields, int java_fields, int injected_fields,
|
||||
ClassLoaderData* loader_data, TRAPS);
|
||||
ClassLoaderData* loader_data, TRAPS);
|
||||
static Array<u1>* create_search_table(ConstantPool* cp, const Array<u1>* fis, ClassLoaderData* loader_data, TRAPS);
|
||||
static GrowableArray<FieldInfo>* create_FieldInfoArray(const Array<u1>* fis, int* java_fields_count, int* injected_fields_count);
|
||||
static void print_from_fieldinfo_stream(Array<u1>* fis, outputStream* os, ConstantPool* cp);
|
||||
|
||||
DEBUG_ONLY(static void validate_search_table(ConstantPool* cp, const Array<u1>* fis, const Array<u1>* search_table);)
|
||||
|
||||
static void print_search_table(outputStream* st, ConstantPool* cp, const Array<u1>* fis, const Array<u1>* search_table);
|
||||
};
|
||||
|
||||
class FieldStatus {
|
||||
|
||||
@@ -56,16 +56,27 @@ inline Symbol* FieldInfo::lookup_symbol(int symbol_index) const {
|
||||
|
||||
inline int FieldInfoStream::num_injected_java_fields(const Array<u1>* fis) {
|
||||
FieldInfoReader fir(fis);
|
||||
fir.skip(1);
|
||||
return fir.next_uint();
|
||||
int java_fields_count;
|
||||
int injected_fields_count;
|
||||
fir.read_field_counts(&java_fields_count, &injected_fields_count);
|
||||
return injected_fields_count;
|
||||
}
|
||||
|
||||
inline int FieldInfoStream::num_total_fields(const Array<u1>* fis) {
|
||||
FieldInfoReader fir(fis);
|
||||
return fir.next_uint() + fir.next_uint();
|
||||
int java_fields_count;
|
||||
int injected_fields_count;
|
||||
fir.read_field_counts(&java_fields_count, &injected_fields_count);
|
||||
return java_fields_count + injected_fields_count;
|
||||
}
|
||||
|
||||
inline int FieldInfoStream::num_java_fields(const Array<u1>* fis) { return FieldInfoReader(fis).next_uint(); }
|
||||
inline int FieldInfoStream::num_java_fields(const Array<u1>* fis) {
|
||||
FieldInfoReader fir(fis);
|
||||
int java_fields_count;
|
||||
int injected_fields_count;
|
||||
fir.read_field_counts(&java_fields_count, &injected_fields_count);
|
||||
return java_fields_count;
|
||||
}
|
||||
|
||||
template<typename CON>
|
||||
inline void Mapper<CON>::map_field_info(const FieldInfo& fi) {
|
||||
@@ -94,13 +105,22 @@ inline void Mapper<CON>::map_field_info(const FieldInfo& fi) {
|
||||
|
||||
|
||||
inline FieldInfoReader::FieldInfoReader(const Array<u1>* fi)
|
||||
: _r(fi->data(), 0),
|
||||
: _r(fi->data(), fi->length()),
|
||||
_next_index(0) { }
|
||||
|
||||
inline void FieldInfoReader::read_field_counts(int* java_fields, int* injected_fields) {
|
||||
*java_fields = next_uint();
|
||||
*injected_fields = next_uint();
|
||||
}
|
||||
|
||||
inline void FieldInfoReader::read_name_and_signature(u2* name_index, u2* signature_index) {
|
||||
*name_index = checked_cast<u2>(next_uint());
|
||||
*signature_index = checked_cast<u2>(next_uint());
|
||||
}
|
||||
|
||||
inline void FieldInfoReader::read_field_info(FieldInfo& fi) {
|
||||
fi._index = _next_index++;
|
||||
fi._name_index = checked_cast<u2>(next_uint());
|
||||
fi._signature_index = checked_cast<u2>(next_uint());
|
||||
read_name_and_signature(&fi._name_index, &fi._signature_index);
|
||||
fi._offset = next_uint();
|
||||
fi._access_flags = AccessFlags(checked_cast<u2>(next_uint()));
|
||||
fi._field_flags = FieldInfo::FieldFlags(next_uint());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -56,17 +56,23 @@ class FieldStreamBase : public StackObj {
|
||||
|
||||
inline FieldStreamBase(const Array<u1>* fieldinfo_stream, ConstantPool* constants, int start, int limit);
|
||||
|
||||
inline FieldStreamBase(Array<u1>* fieldinfo_stream, ConstantPool* constants);
|
||||
inline FieldStreamBase(const Array<u1>* fieldinfo_stream, ConstantPool* constants);
|
||||
|
||||
private:
|
||||
private:
|
||||
void initialize() {
|
||||
int java_fields_count = _reader.next_uint();
|
||||
int injected_fields_count = _reader.next_uint();
|
||||
assert( _limit <= java_fields_count + injected_fields_count, "Safety check");
|
||||
int java_fields_count;
|
||||
int injected_fields_count;
|
||||
_reader.read_field_counts(&java_fields_count, &injected_fields_count);
|
||||
if (_limit < _index) {
|
||||
_limit = java_fields_count + injected_fields_count;
|
||||
} else {
|
||||
assert( _limit <= java_fields_count + injected_fields_count, "Safety check");
|
||||
}
|
||||
if (_limit != 0) {
|
||||
_reader.read_field_info(_fi_buf);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
inline FieldStreamBase(InstanceKlass* klass);
|
||||
|
||||
@@ -138,8 +144,11 @@ class FieldStreamBase : public StackObj {
|
||||
|
||||
// Iterate over only the Java fields
|
||||
class JavaFieldStream : public FieldStreamBase {
|
||||
Array<u1>* _search_table;
|
||||
|
||||
public:
|
||||
JavaFieldStream(const InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants(), 0, k->java_fields_count()) {}
|
||||
JavaFieldStream(const InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants(), 0, k->java_fields_count()),
|
||||
_search_table(k->fieldinfo_search_table()) {}
|
||||
|
||||
u2 name_index() const {
|
||||
assert(!field()->field_flags().is_injected(), "regular only");
|
||||
@@ -149,7 +158,6 @@ class JavaFieldStream : public FieldStreamBase {
|
||||
u2 signature_index() const {
|
||||
assert(!field()->field_flags().is_injected(), "regular only");
|
||||
return field()->signature_index();
|
||||
return -1;
|
||||
}
|
||||
|
||||
u2 generic_signature_index() const {
|
||||
@@ -164,6 +172,10 @@ class JavaFieldStream : public FieldStreamBase {
|
||||
assert(!field()->field_flags().is_injected(), "regular only");
|
||||
return field()->initializer_index();
|
||||
}
|
||||
|
||||
// Performs either a linear search or binary search through the stream
|
||||
// looking for a matching name/signature combo
|
||||
bool lookup(const Symbol* name, const Symbol* signature);
|
||||
};
|
||||
|
||||
|
||||
@@ -176,7 +188,6 @@ class InternalFieldStream : public FieldStreamBase {
|
||||
|
||||
class AllFieldStream : public FieldStreamBase {
|
||||
public:
|
||||
AllFieldStream(Array<u1>* fieldinfo, ConstantPool* constants): FieldStreamBase(fieldinfo, constants) {}
|
||||
AllFieldStream(const InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants()) {}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -33,22 +33,18 @@
|
||||
FieldStreamBase::FieldStreamBase(const Array<u1>* fieldinfo_stream, ConstantPool* constants, int start, int limit) :
|
||||
_fieldinfo_stream(fieldinfo_stream),
|
||||
_reader(FieldInfoReader(_fieldinfo_stream)),
|
||||
_constants(constantPoolHandle(Thread::current(), constants)), _index(start) {
|
||||
_index = start;
|
||||
if (limit < start) {
|
||||
_limit = FieldInfoStream::num_total_fields(_fieldinfo_stream);
|
||||
} else {
|
||||
_limit = limit;
|
||||
}
|
||||
_constants(constantPoolHandle(Thread::current(), constants)),
|
||||
_index(start),
|
||||
_limit(limit) {
|
||||
initialize();
|
||||
}
|
||||
|
||||
FieldStreamBase::FieldStreamBase(Array<u1>* fieldinfo_stream, ConstantPool* constants) :
|
||||
FieldStreamBase::FieldStreamBase(const Array<u1>* fieldinfo_stream, ConstantPool* constants) :
|
||||
_fieldinfo_stream(fieldinfo_stream),
|
||||
_reader(FieldInfoReader(_fieldinfo_stream)),
|
||||
_constants(constantPoolHandle(Thread::current(), constants)),
|
||||
_index(0),
|
||||
_limit(FieldInfoStream::num_total_fields(_fieldinfo_stream)) {
|
||||
_limit(-1) {
|
||||
initialize();
|
||||
}
|
||||
|
||||
@@ -57,9 +53,28 @@ FieldStreamBase::FieldStreamBase(InstanceKlass* klass) :
|
||||
_reader(FieldInfoReader(_fieldinfo_stream)),
|
||||
_constants(constantPoolHandle(Thread::current(), klass->constants())),
|
||||
_index(0),
|
||||
_limit(FieldInfoStream::num_total_fields(_fieldinfo_stream)) {
|
||||
_limit(-1) {
|
||||
assert(klass == field_holder(), "");
|
||||
initialize();
|
||||
}
|
||||
|
||||
inline bool JavaFieldStream::lookup(const Symbol* name, const Symbol* signature) {
|
||||
if (_search_table != nullptr) {
|
||||
int index = _reader.search_table_lookup(_search_table, name, signature, _constants(), _limit);
|
||||
if (index >= 0) {
|
||||
assert(index < _limit, "must be");
|
||||
_index = index;
|
||||
_reader.read_field_info(_fi_buf);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
for (; !done(); next()) {
|
||||
if (this->name() == name && this->signature() == signature) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // SHARE_OOPS_FIELDSTREAMS_INLINE_HPP
|
||||
|
||||
@@ -686,6 +686,11 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
|
||||
}
|
||||
set_fieldinfo_stream(nullptr);
|
||||
|
||||
if (fieldinfo_search_table() != nullptr && !fieldinfo_search_table()->is_shared()) {
|
||||
MetadataFactory::free_array<u1>(loader_data, fieldinfo_search_table());
|
||||
}
|
||||
set_fieldinfo_search_table(nullptr);
|
||||
|
||||
if (fields_status() != nullptr && !fields_status()->is_shared()) {
|
||||
MetadataFactory::free_array<FieldStatus>(loader_data, fields_status());
|
||||
}
|
||||
@@ -1786,13 +1791,12 @@ FieldInfo InstanceKlass::field(int index) const {
|
||||
}
|
||||
|
||||
bool InstanceKlass::find_local_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const {
|
||||
for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
|
||||
Symbol* f_name = fs.name();
|
||||
Symbol* f_sig = fs.signature();
|
||||
if (f_name == name && f_sig == sig) {
|
||||
fd->reinitialize(const_cast<InstanceKlass*>(this), fs.to_FieldInfo());
|
||||
return true;
|
||||
}
|
||||
JavaFieldStream fs(this);
|
||||
if (fs.lookup(name, sig)) {
|
||||
assert(fs.name() == name, "name must match");
|
||||
assert(fs.signature() == sig, "signature must match");
|
||||
fd->reinitialize(const_cast<InstanceKlass*>(this), fs.to_FieldInfo());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -2610,6 +2614,7 @@ void InstanceKlass::metaspace_pointers_do(MetaspaceClosure* it) {
|
||||
}
|
||||
|
||||
it->push(&_fieldinfo_stream);
|
||||
it->push(&_fieldinfo_search_table);
|
||||
// _fields_status might be written into by Rewriter::scan_method() -> fd.set_has_initialized_final_update()
|
||||
it->push(&_fields_status, MetaspaceClosure::_writable);
|
||||
|
||||
@@ -2710,6 +2715,8 @@ void InstanceKlass::remove_unshareable_info() {
|
||||
DEBUG_ONLY(_shared_class_load_count = 0);
|
||||
|
||||
remove_unshareable_flags();
|
||||
|
||||
DEBUG_ONLY(FieldInfoStream::validate_search_table(_constants, _fieldinfo_stream, _fieldinfo_search_table));
|
||||
}
|
||||
|
||||
void InstanceKlass::remove_unshareable_flags() {
|
||||
@@ -2816,6 +2823,8 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl
|
||||
if (DiagnoseSyncOnValueBasedClasses && has_value_based_class_annotation() && !is_value_based()) {
|
||||
set_is_value_based();
|
||||
}
|
||||
|
||||
DEBUG_ONLY(FieldInfoStream::validate_search_table(_constants, _fieldinfo_stream, _fieldinfo_search_table));
|
||||
}
|
||||
|
||||
// Check if a class or any of its supertypes has a version older than 50.
|
||||
@@ -3492,7 +3501,7 @@ void InstanceKlass::add_osr_nmethod(nmethod* n) {
|
||||
for (int l = CompLevel_limited_profile; l < n->comp_level(); l++) {
|
||||
nmethod *inv = lookup_osr_nmethod(n->method(), n->osr_entry_bci(), l, true);
|
||||
if (inv != nullptr && inv->is_in_use()) {
|
||||
inv->make_not_entrant(nmethod::ChangeReason::OSR_invalidation_of_lower_level);
|
||||
inv->make_not_entrant("OSR invalidation of lower levels");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3760,6 +3769,11 @@ void InstanceKlass::print_on(outputStream* st) const {
|
||||
map++;
|
||||
}
|
||||
st->cr();
|
||||
|
||||
if (fieldinfo_search_table() != nullptr) {
|
||||
st->print_cr(BULLET"---- field info search table:");
|
||||
FieldInfoStream::print_search_table(st, _constants, _fieldinfo_stream, _fieldinfo_search_table);
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceKlass::print_value_on(outputStream* st) const {
|
||||
|
||||
@@ -276,6 +276,7 @@ class InstanceKlass: public Klass {
|
||||
|
||||
// Fields information is stored in an UNSIGNED5 encoded stream (see fieldInfo.hpp)
|
||||
Array<u1>* _fieldinfo_stream;
|
||||
Array<u1>* _fieldinfo_search_table;
|
||||
Array<FieldStatus>* _fields_status;
|
||||
|
||||
// embedded Java vtable follows here
|
||||
@@ -398,6 +399,9 @@ class InstanceKlass: public Klass {
|
||||
Array<u1>* fieldinfo_stream() const { return _fieldinfo_stream; }
|
||||
void set_fieldinfo_stream(Array<u1>* fis) { _fieldinfo_stream = fis; }
|
||||
|
||||
Array<u1>* fieldinfo_search_table() const { return _fieldinfo_search_table; }
|
||||
void set_fieldinfo_search_table(Array<u1>* table) { _fieldinfo_search_table = table; }
|
||||
|
||||
Array<FieldStatus>* fields_status() const {return _fields_status; }
|
||||
void set_fields_status(Array<FieldStatus>* array) { _fields_status = array; }
|
||||
|
||||
|
||||
@@ -1028,7 +1028,7 @@ void Method::set_native_function(address function, bool post_event_flag) {
|
||||
// If so, we have to make it not_entrant.
|
||||
nmethod* nm = code(); // Put it into local variable to guard against concurrent updates
|
||||
if (nm != nullptr) {
|
||||
nm->make_not_entrant(nmethod::ChangeReason::set_native_function);
|
||||
nm->make_not_entrant("set native function");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "memory/metaspaceClosure.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "oops/method.hpp"
|
||||
#include "oops/objArrayKlass.hpp"
|
||||
#include "runtime/handles.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "utilities/resizeableResourceHash.hpp"
|
||||
@@ -286,7 +287,12 @@ private:
|
||||
static bool is_klass_loaded(Klass* k) {
|
||||
if (have_data()) {
|
||||
// If we're running in AOT mode some classes may not be loaded yet
|
||||
return !k->is_instance_klass() || InstanceKlass::cast(k)->is_loaded();
|
||||
if (k->is_objArray_klass()) {
|
||||
k = ObjArrayKlass::cast(k)->bottom_klass();
|
||||
}
|
||||
if (k->is_instance_klass()) {
|
||||
return InstanceKlass::cast(k)->is_loaded();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -37,11 +37,8 @@
|
||||
#include "utilities/copy.hpp"
|
||||
#include "utilities/powerOfTwo.hpp"
|
||||
|
||||
void Block_Array::grow( uint i ) {
|
||||
_nesting.check(_arena); // Check if a potential reallocation in the arena is safe
|
||||
if (i < Max()) {
|
||||
return; // No need to grow
|
||||
}
|
||||
void Block_Array::grow(uint i) {
|
||||
assert(i >= Max(), "Should have been checked before, use maybe_grow?");
|
||||
DEBUG_ONLY(_limit = i+1);
|
||||
if( i < _size ) return;
|
||||
if( !_size ) {
|
||||
|
||||
@@ -53,7 +53,13 @@ class Block_Array : public ArenaObj {
|
||||
ReallocMark _nesting; // Safety checks for arena reallocation
|
||||
protected:
|
||||
Block **_blocks;
|
||||
void grow( uint i ); // Grow array node to fit
|
||||
void maybe_grow(uint i) {
|
||||
_nesting.check(_arena); // Check if a potential reallocation in the arena is safe
|
||||
if (i >= Max()) {
|
||||
grow(i);
|
||||
}
|
||||
}
|
||||
void grow(uint i); // Grow array node to fit
|
||||
|
||||
public:
|
||||
Block_Array(Arena *a) : _size(OptoBlockListSize), _arena(a) {
|
||||
@@ -68,7 +74,7 @@ public:
|
||||
Block *operator[] ( uint i ) const // Lookup, or assert for not mapped
|
||||
{ assert( i < Max(), "oob" ); return _blocks[i]; }
|
||||
// Extend the mapping: index i maps to Block *n.
|
||||
void map( uint i, Block *n ) { grow(i); _blocks[i] = n; }
|
||||
void map( uint i, Block *n ) { maybe_grow(i); _blocks[i] = n; }
|
||||
uint Max() const { DEBUG_ONLY(return _limit); return _size; }
|
||||
};
|
||||
|
||||
|
||||
@@ -65,13 +65,8 @@ public:
|
||||
Node_Stack::push(n, (uint)ns);
|
||||
}
|
||||
void push(Node *n, Node_State ns, Node *parent, int indx) {
|
||||
++_inode_top;
|
||||
if ((_inode_top + 1) >= _inode_max) grow();
|
||||
_inode_top->node = parent;
|
||||
_inode_top->indx = (uint)indx;
|
||||
++_inode_top;
|
||||
_inode_top->node = n;
|
||||
_inode_top->indx = (uint)ns;
|
||||
Node_Stack::push(parent, (uint)indx);
|
||||
Node_Stack::push(n, (uint)ns);
|
||||
}
|
||||
Node *parent() {
|
||||
pop();
|
||||
|
||||
@@ -2798,7 +2798,6 @@ const RegMask &Node::in_RegMask(uint) const {
|
||||
}
|
||||
|
||||
void Node_Array::grow(uint i) {
|
||||
_nesting.check(_a); // Check if a potential reallocation in the arena is safe
|
||||
assert(i >= _max, "Should have been checked before, use maybe_grow?");
|
||||
assert(_max > 0, "invariant");
|
||||
uint old = _max;
|
||||
@@ -3038,10 +3037,6 @@ void Unique_Node_List::remove_useless_nodes(VectorSet &useful) {
|
||||
|
||||
//=============================================================================
|
||||
void Node_Stack::grow() {
|
||||
_nesting.check(_a); // Check if a potential reallocation in the arena is safe
|
||||
if (_inode_top < _inode_max) {
|
||||
return; // No need to grow
|
||||
}
|
||||
size_t old_top = pointer_delta(_inode_top,_inodes,sizeof(INode)); // save _top
|
||||
size_t old_max = pointer_delta(_inode_max,_inodes,sizeof(INode));
|
||||
size_t max = old_max << 1; // max * 2
|
||||
|
||||
@@ -1633,6 +1633,7 @@ protected:
|
||||
|
||||
// Grow array to required capacity
|
||||
void maybe_grow(uint i) {
|
||||
_nesting.check(_a); // Check if a potential reallocation in the arena is safe
|
||||
if (i >= _max) {
|
||||
grow(i);
|
||||
}
|
||||
@@ -1884,7 +1885,15 @@ protected:
|
||||
INode *_inodes; // Array storage for the stack
|
||||
Arena *_a; // Arena to allocate in
|
||||
ReallocMark _nesting; // Safety checks for arena reallocation
|
||||
|
||||
void maybe_grow() {
|
||||
_nesting.check(_a); // Check if a potential reallocation in the arena is safe
|
||||
if (_inode_top >= _inode_max) {
|
||||
grow();
|
||||
}
|
||||
}
|
||||
void grow();
|
||||
|
||||
public:
|
||||
Node_Stack(int size) {
|
||||
size_t max = (size > OptoNodeListSize) ? size : OptoNodeListSize;
|
||||
@@ -1907,7 +1916,7 @@ public:
|
||||
}
|
||||
void push(Node *n, uint i) {
|
||||
++_inode_top;
|
||||
grow();
|
||||
maybe_grow();
|
||||
INode *top = _inode_top; // optimization
|
||||
top->node = n;
|
||||
top->indx = i;
|
||||
|
||||
@@ -3550,6 +3550,13 @@ void VM_RedefineClasses::set_new_constant_pool(
|
||||
Array<u1>* new_fis = FieldInfoStream::create_FieldInfoStream(fields, java_fields, injected_fields, scratch_class->class_loader_data(), CHECK);
|
||||
scratch_class->set_fieldinfo_stream(new_fis);
|
||||
MetadataFactory::free_array<u1>(scratch_class->class_loader_data(), old_stream);
|
||||
|
||||
Array<u1>* old_table = scratch_class->fieldinfo_search_table();
|
||||
Array<u1>* search_table = FieldInfoStream::create_search_table(scratch_class->constants(), new_fis, scratch_class->class_loader_data(), CHECK);
|
||||
scratch_class->set_fieldinfo_search_table(search_table);
|
||||
MetadataFactory::free_array<u1>(scratch_class->class_loader_data(), old_table);
|
||||
|
||||
DEBUG_ONLY(FieldInfoStream::validate_search_table(scratch_class->constants(), new_fis, search_table));
|
||||
}
|
||||
|
||||
// Update constant pool indices in the inner classes info to use
|
||||
|
||||
@@ -794,7 +794,7 @@ class VM_WhiteBoxDeoptimizeFrames : public VM_WhiteBoxOperation {
|
||||
if (_make_not_entrant) {
|
||||
nmethod* nm = CodeCache::find_nmethod(f->pc());
|
||||
assert(nm != nullptr, "did not find nmethod");
|
||||
nm->make_not_entrant(nmethod::ChangeReason::whitebox_deoptimization);
|
||||
nm->make_not_entrant("Whitebox deoptimization");
|
||||
}
|
||||
++_result;
|
||||
}
|
||||
|
||||
@@ -1826,7 +1826,7 @@ void Deoptimization::deoptimize(JavaThread* thread, frame fr, DeoptReason reason
|
||||
#if INCLUDE_JVMCI
|
||||
address Deoptimization::deoptimize_for_missing_exception_handler(nmethod* nm) {
|
||||
// there is no exception handler for this pc => deoptimize
|
||||
nm->make_not_entrant(nmethod::ChangeReason::missing_exception_handler);
|
||||
nm->make_not_entrant("missing exception handler");
|
||||
|
||||
// Use Deoptimization::deoptimize for all of its side-effects:
|
||||
// gathering traps statistics, logging...
|
||||
@@ -2455,7 +2455,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* current, jint tr
|
||||
|
||||
// Recompile
|
||||
if (make_not_entrant) {
|
||||
if (!nm->make_not_entrant(nmethod::ChangeReason::uncommon_trap)) {
|
||||
if (!nm->make_not_entrant("uncommon trap")) {
|
||||
return; // the call did not change nmethod's state
|
||||
}
|
||||
|
||||
|
||||
@@ -2005,6 +2005,10 @@ const int ObjectAlignmentInBytes = 8;
|
||||
product(bool, UseThreadsLockThrottleLock, true, DIAGNOSTIC, \
|
||||
"Use an extra lock during Thread start and exit to alleviate" \
|
||||
"contention on Threads_lock.") \
|
||||
\
|
||||
develop(uint, BinarySearchThreshold, 16, \
|
||||
"Minimal number of elements in a sorted collection to prefer" \
|
||||
"binary search over simple linear search." ) \
|
||||
|
||||
// end of RUNTIME_FLAGS
|
||||
|
||||
|
||||
@@ -1337,7 +1337,7 @@ void JavaThread::make_zombies() {
|
||||
// it is a Java nmethod
|
||||
nmethod* nm = CodeCache::find_nmethod(fst.current()->pc());
|
||||
assert(nm != nullptr, "did not find nmethod");
|
||||
nm->make_not_entrant(nmethod::ChangeReason::zombie);
|
||||
nm->make_not_entrant("zombie");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -771,8 +771,8 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
|
||||
#endif
|
||||
|
||||
if (CDSConfig::is_using_aot_linked_classes()) {
|
||||
AOTLinkedClassBulkLoader::finish_loading_javabase_classes(CHECK_JNI_ERR);
|
||||
SystemDictionary::restore_archived_method_handle_intrinsics();
|
||||
AOTLinkedClassBulkLoader::finish_loading_javabase_classes(CHECK_JNI_ERR);
|
||||
}
|
||||
|
||||
// Start string deduplication thread if requested.
|
||||
|
||||
113
src/hotspot/share/utilities/packedTable.cpp
Normal file
113
src/hotspot/share/utilities/packedTable.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#include <cstring>
|
||||
|
||||
#include "utilities/align.hpp"
|
||||
#include "utilities/count_leading_zeros.hpp"
|
||||
#include "utilities/packedTable.hpp"
|
||||
|
||||
// The thresholds are inclusive, and in practice the limits are rounded
|
||||
// to the nearest power-of-two - 1.
|
||||
// Based on the max_key and max_value we figure out the number of bits required to store
|
||||
// key and value; imagine that only as bits (not aligned to byte boundary... yet).
|
||||
// Then we concatenate the bits for key and value, and 'add' 1-7 padding zeroes
|
||||
// (high-order bits) to align on bytes.
|
||||
// In the end we have each element in the table consuming 1-8 bytes (case with 0 bits for key
|
||||
// is ruled out).
|
||||
PackedTableBase::PackedTableBase(uint32_t max_key, uint32_t max_value) {
|
||||
unsigned int key_bits = max_key == 0 ? 0 : 32 - count_leading_zeros(max_key);
|
||||
unsigned int value_bits = max_value == 0 ? 0 : 32 - count_leading_zeros(max_value);
|
||||
_element_bytes = align_up(key_bits + value_bits, 8) / 8;
|
||||
// shifting left by 32 is undefined behaviour, and in practice returns 1
|
||||
_key_mask = key_bits >= 32 ? -1 : (1U << key_bits) - 1;
|
||||
_value_shift = key_bits;
|
||||
_value_mask = value_bits >= 32 ? -1 : (1U << value_bits) - 1;
|
||||
guarantee(_element_bytes > 0, "wouldn't work");
|
||||
assert(_element_bytes <= sizeof(uint64_t), "shouldn't happen");
|
||||
}
|
||||
|
||||
// Note: we require the supplier to provide the elements in the final order as we can't easily sort
|
||||
// within this method - qsort() accepts only pure function as comparator.
|
||||
void PackedTableBuilder::fill(u1* table, size_t table_length, Supplier &supplier) const {
|
||||
uint32_t key, value;
|
||||
size_t offset = 0;
|
||||
for (; offset <= table_length && supplier.next(&key, &value); offset += _element_bytes) {
|
||||
assert((key & ~_key_mask) == 0, "key out of bounds");
|
||||
assert((value & ~_value_mask) == 0, "value out of bounds: %x vs. %x (%x)", value, _value_mask, ~_value_mask);
|
||||
uint64_t element = static_cast<uint64_t>(key) | (static_cast<uint64_t>(value) << _value_shift);
|
||||
for (unsigned int i = 0; i < _element_bytes; ++i) {
|
||||
table[offset + i] = static_cast<u1>(0xFF & element);
|
||||
element >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
assert(offset == table_length, "Did not fill whole array");
|
||||
assert(!supplier.next(&key, &value), "Supplier has more elements");
|
||||
}
|
||||
|
||||
uint64_t PackedTableLookup::read_element(size_t offset) const {
|
||||
uint64_t element = 0;
|
||||
for (unsigned int i = 0; i < _element_bytes; ++i) {
|
||||
element |= static_cast<uint64_t>(_table[offset + i]) << (8 * i);
|
||||
}
|
||||
assert((element & ~((uint64_t) _key_mask | ((uint64_t) _value_mask << _value_shift))) == 0, "read too much");
|
||||
return element;
|
||||
}
|
||||
|
||||
bool PackedTableLookup::search(Comparator& comparator, uint32_t* found_key, uint32_t* found_value) const {
|
||||
unsigned int low = 0, high = checked_cast<unsigned int>(_table_length / _element_bytes);
|
||||
assert(low < high, "must be");
|
||||
while (low < high) {
|
||||
unsigned int mid = low + (high - low) / 2;
|
||||
assert(mid >= low && mid < high, "integer overflow?");
|
||||
uint64_t element = read_element(_element_bytes * mid);
|
||||
// Ignoring high 32 bits in element on purpose
|
||||
uint32_t key = static_cast<uint32_t>(element) & _key_mask;
|
||||
int cmp = comparator.compare_to(key);
|
||||
if (cmp == 0) {
|
||||
*found_key = key;
|
||||
// Since __builtin_memcpy in read_element does not copy bits outside the element
|
||||
// anything above _value_mask << _value_shift should be zero.
|
||||
*found_value = checked_cast<uint32_t>(element >> _value_shift) & _value_mask;
|
||||
return true;
|
||||
} else if (cmp < 0) {
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
void PackedTableLookup::validate_order(Comparator &comparator) const {
|
||||
auto validator = [&] (size_t offset, uint32_t key, uint32_t value) {
|
||||
if (offset != 0) {
|
||||
assert(comparator.compare_to(key) < 0, "not sorted");
|
||||
}
|
||||
comparator.reset(key);
|
||||
};
|
||||
iterate(validator);
|
||||
}
|
||||
#endif
|
||||
123
src/hotspot/share/utilities/packedTable.hpp
Normal file
123
src/hotspot/share/utilities/packedTable.hpp
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "oops/array.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
// Base for space-optimized structure supporting binary search. Each element
|
||||
// consists of up to 32-bit key, and up to 32-bit value; these are packed
|
||||
// into a bit-record with 1-byte alignment.
|
||||
// The keys are ordered according to a custom comparator.
|
||||
class PackedTableBase {
|
||||
protected:
|
||||
unsigned int _element_bytes;
|
||||
uint32_t _key_mask;
|
||||
unsigned int _value_shift;
|
||||
uint32_t _value_mask;
|
||||
|
||||
public:
|
||||
PackedTableBase(uint32_t max_key, uint32_t max_value);
|
||||
|
||||
// Returns number of bytes each element will occupy.
|
||||
inline unsigned int element_bytes(void) const { return _element_bytes; }
|
||||
};
|
||||
|
||||
// Helper class for constructing a packed table in the provided array.
|
||||
class PackedTableBuilder: public PackedTableBase {
|
||||
public:
|
||||
class Supplier {
|
||||
public:
|
||||
// Returns elements with already ordered keys.
|
||||
// This function should return true when the key and value was set,
|
||||
// and false when there's no more elements.
|
||||
// Packed table does NOT support duplicate keys.
|
||||
virtual bool next(uint32_t* key, uint32_t* value) = 0;
|
||||
};
|
||||
|
||||
// The thresholds are inclusive, and in practice the limits are rounded
|
||||
// to the nearest power-of-two - 1.
|
||||
// See PackedTableBase constructor for details.
|
||||
PackedTableBuilder(uint32_t max_key, uint32_t max_value): PackedTableBase(max_key, max_value) {}
|
||||
|
||||
// Constructs a packed table in the provided array, filling it with elements
|
||||
// from the supplier. Note that no comparator is requied by this method -
|
||||
// the supplier must return elements with already ordered keys.
|
||||
// The table_length (in bytes) should match number of elements provided
|
||||
// by the supplier (when Supplier::next() returns false the whole array should
|
||||
// be filled).
|
||||
void fill(u1* table, size_t table_length, Supplier &supplier) const;
|
||||
};
|
||||
|
||||
// Helper class for lookup in a packed table.
|
||||
class PackedTableLookup: public PackedTableBase {
|
||||
const u1* const _table;
|
||||
const size_t _table_length;
|
||||
|
||||
uint64_t read_element(size_t offset) const;
|
||||
|
||||
public:
|
||||
|
||||
// The comparator implementation does not have to store a key (uint32_t);
|
||||
// the idea is that key can point into a different structure that hosts data
|
||||
// suitable for the actual comparison. That's why PackedTableLookup::search(...)
|
||||
// returns the key it found as well as the value.
|
||||
class Comparator {
|
||||
public:
|
||||
// Returns negative/0/positive if the target referred to by this comparator
|
||||
// is lower/equal/higher than the target referred to by the key.
|
||||
virtual int compare_to(uint32_t key) = 0;
|
||||
// Changes the target this comparator refers to.
|
||||
DEBUG_ONLY(virtual void reset(uint32_t key) = 0);
|
||||
};
|
||||
|
||||
// The thresholds are inclusive, and in practice the limits are rounded
|
||||
// to the nearest power-of-two - 1.
|
||||
// See PackedTableBase constructor for details.
|
||||
PackedTableLookup(uint32_t max_key, uint32_t max_value, const u1 *table, size_t table_length):
|
||||
PackedTableBase(max_key, max_value), _table(table), _table_length(table_length) {}
|
||||
|
||||
PackedTableLookup(uint32_t max_key, uint32_t max_value, const Array<u1> *table):
|
||||
PackedTableLookup(max_key, max_value, table->data(), static_cast<size_t>(table->length())) {}
|
||||
|
||||
// Performs a binary search in the packed table, looking for an element with key
|
||||
// referring to a target equal according to the comparator.
|
||||
// When the element is found, found_key and found_value are updated from the element
|
||||
// and the function returns true.
|
||||
// When the element is not found, found_key and found_value are not changed and
|
||||
// the function returns false.
|
||||
bool search(Comparator& comparator, uint32_t* found_key, uint32_t* found_value) const;
|
||||
|
||||
// Asserts that elements in the packed table follow the order defined by the comparator.
|
||||
DEBUG_ONLY(void validate_order(Comparator &comparator) const);
|
||||
|
||||
template<typename Function>
|
||||
void iterate(Function func) const {
|
||||
for (size_t offset = 0; offset < _table_length; offset += _element_bytes) {
|
||||
uint64_t element = read_element(offset);
|
||||
uint32_t key = static_cast<uint32_t>(element) & _key_mask;
|
||||
uint32_t value = checked_cast<uint32_t>(element >> _value_shift) & _value_mask;
|
||||
func(offset, key, value);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -261,7 +261,7 @@ class UNSIGNED5 : AllStatic {
|
||||
ARR _array;
|
||||
OFF _limit;
|
||||
OFF _position;
|
||||
int next_length() {
|
||||
int next_length() const {
|
||||
return UNSIGNED5::check_length(_array, _position, _limit, GET());
|
||||
}
|
||||
public:
|
||||
@@ -270,7 +270,7 @@ class UNSIGNED5 : AllStatic {
|
||||
uint32_t next_uint() {
|
||||
return UNSIGNED5::read_uint(_array, _position, _limit, GET());
|
||||
}
|
||||
bool has_next() {
|
||||
bool has_next() const {
|
||||
return next_length() != 0;
|
||||
}
|
||||
// tries to skip count logical entries; returns actual number skipped
|
||||
@@ -284,8 +284,9 @@ class UNSIGNED5 : AllStatic {
|
||||
return actual;
|
||||
}
|
||||
ARR array() { return _array; }
|
||||
OFF limit() { return _limit; }
|
||||
OFF position() { return _position; }
|
||||
OFF limit() const { return _limit; }
|
||||
OFF position() const { return _position; }
|
||||
void set_limit(OFF limit) { _limit = limit; }
|
||||
void set_position(OFF position) { _position = position; }
|
||||
|
||||
// For debugging, even in product builds (see debug.cpp).
|
||||
|
||||
@@ -38,7 +38,7 @@ import java.nio.charset.StandardCharsets;
|
||||
* <p>
|
||||
* The {@link #readln()} and {@link #readln(String)} methods decode bytes read from
|
||||
* {@code System.in} into characters. The charset used for decoding is specified by the
|
||||
* {@link System#getProperties stdin.encoding} property. If this property is not present,
|
||||
* {@link System##stdin.encoding stdin.encoding} property. If this property is not present,
|
||||
* or if the charset it names cannot be loaded, then UTF-8 is used instead. Decoding
|
||||
* always replaces malformed and unmappable byte sequences with the charset's default
|
||||
* replacement string.
|
||||
|
||||
@@ -1589,6 +1589,11 @@ public final class String
|
||||
* @return {@code true} if {@link #length()} is {@code 0}, otherwise
|
||||
* {@code false}
|
||||
*
|
||||
* @apiNote
|
||||
* To determine whether a string contains only
|
||||
* {@linkplain Character#isWhitespace(int) white space}, use
|
||||
* {@link #isBlank() isBlank}.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
@Override
|
||||
@@ -3827,9 +3832,13 @@ public final class String
|
||||
* begins with the character at index <i>k</i> and ends with the
|
||||
* character at index <i>m</i>-that is, the result of
|
||||
* {@code this.substring(k, m + 1)}.
|
||||
* <p>
|
||||
* This method may be used to trim space (as defined above) from
|
||||
* the beginning and end of a string.
|
||||
*
|
||||
* @apiNote
|
||||
* This method removes leading and trailing space characters and ASCII control
|
||||
* characters from the string. To remove characters using a Unicode-based definition of
|
||||
* {@linkplain Character#isWhitespace(int) white space}, use {@link #strip() strip},
|
||||
* {@link #stripIndent() stripIndent}, {@link #stripLeading() stripLeading}, or
|
||||
* {@link #stripTrailing() stripTrailing}.
|
||||
*
|
||||
* @return a string whose value is this string, with all leading
|
||||
* and trailing space removed, or this string if it
|
||||
@@ -3934,13 +3943,9 @@ public final class String
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the string is empty or contains only
|
||||
* {@linkplain Character#isWhitespace(int) white space} codepoints,
|
||||
* otherwise {@code false}.
|
||||
*
|
||||
* @return {@code true} if the string is empty or contains only
|
||||
* {@linkplain Character#isWhitespace(int) white space} codepoints,
|
||||
* otherwise {@code false}
|
||||
* {@return {@code true} if the string is {@linkplain #isEmpty empty} or contains
|
||||
* only {@linkplain Character#isWhitespace(int) white space} codepoints,
|
||||
* otherwise {@code false}}
|
||||
*
|
||||
* @see Character#isWhitespace(int)
|
||||
*
|
||||
|
||||
@@ -1030,14 +1030,6 @@ public sealed interface ClassFile
|
||||
*/
|
||||
int JAVA_25_VERSION = 69;
|
||||
|
||||
/**
|
||||
* The class major version introduced by Java SE 26, {@value}.
|
||||
*
|
||||
* @see ClassFileFormatVersion#RELEASE_26
|
||||
* @since 26
|
||||
*/
|
||||
int JAVA_26_VERSION = 70;
|
||||
|
||||
/**
|
||||
* A minor version number {@value} indicating a class uses preview features
|
||||
* of a Java SE release since 12, for major versions {@value
|
||||
@@ -1049,7 +1041,7 @@ public sealed interface ClassFile
|
||||
* {@return the latest class major version supported by the current runtime}
|
||||
*/
|
||||
static int latestMajorVersion() {
|
||||
return JAVA_26_VERSION;
|
||||
return JAVA_25_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -371,18 +371,6 @@ public enum ClassFileFormatVersion {
|
||||
* <cite>The Java Virtual Machine Specification, Java SE 25 Edition</cite></a>
|
||||
*/
|
||||
RELEASE_25(69),
|
||||
|
||||
/**
|
||||
* The version introduced by the Java Platform, Standard Edition
|
||||
* 26.
|
||||
*
|
||||
* @since 26
|
||||
*
|
||||
* @see <a
|
||||
* href="https://docs.oracle.com/javase/specs/jvms/se26/html/index.html">
|
||||
* <cite>The Java Virtual Machine Specification, Java SE 26 Edition</cite></a>
|
||||
*/
|
||||
RELEASE_26(70),
|
||||
; // Reduce code churn when appending new constants
|
||||
|
||||
// Note to maintainers: when adding constants for newer releases,
|
||||
@@ -398,7 +386,7 @@ public enum ClassFileFormatVersion {
|
||||
* {@return the latest class file format version}
|
||||
*/
|
||||
public static ClassFileFormatVersion latest() {
|
||||
return RELEASE_26;
|
||||
return RELEASE_25;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -81,24 +81,24 @@ import java.util.Objects;
|
||||
* {@link PEMRecord}.
|
||||
*
|
||||
* <p> The {@linkplain #decode(String, Class)} and
|
||||
* {@linkplain #decode(InputStream, Class)} methods take a Class parameter
|
||||
* {@linkplain #decode(InputStream, Class)} methods take a class parameter
|
||||
* which determines the type of {@code DEREncodable} that is returned. These
|
||||
* methods are useful when extracting or changing the return class.
|
||||
* For example, if the PEM contains both public and private keys, the
|
||||
* Class parameter can specify which to return. Use
|
||||
* class parameter can specify which to return. Use
|
||||
* {@code PrivateKey.class} to return only the private key.
|
||||
* If the Class parameter is set to {@code X509EncodedKeySpec.class}, the
|
||||
* If the class parameter is set to {@code X509EncodedKeySpec.class}, the
|
||||
* public key will be returned in that format. Any type of PEM data can be
|
||||
* decoded into a {@code PEMRecord} by specifying {@code PEMRecord.class}.
|
||||
* If the Class parameter doesn't match the PEM content, an
|
||||
* {@code IllegalArgumentException} will be thrown.
|
||||
* If the class parameter doesn't match the PEM content, a
|
||||
* {@linkplain ClassCastException} will be thrown.
|
||||
*
|
||||
* <p> A new {@code PEMDecoder} instance is created when configured
|
||||
* with {@linkplain #withFactory(Provider)} and/or
|
||||
* {@linkplain #withDecryption(char[])}. {@linkplain #withFactory(Provider)}
|
||||
* configures the decoder to use only {@linkplain KeyFactory} and
|
||||
* {@linkplain CertificateFactory} instances from the given {@code Provider}.
|
||||
* {@link#withDecryption(char[])} configures the decoder to decrypt all
|
||||
* {@linkplain #withDecryption(char[])} configures the decoder to decrypt all
|
||||
* encrypted private key PEM data using the given password.
|
||||
* Configuring an instance for decryption does not prevent decoding with
|
||||
* unencrypted PEM. Any encrypted PEM that fails decryption
|
||||
@@ -117,15 +117,15 @@ import java.util.Objects;
|
||||
* <p> Here is an example of a {@code PEMDecoder} configured with decryption
|
||||
* and a factory provider:
|
||||
* {@snippet lang = java:
|
||||
* PEMDecoder pe = PEMDecoder.of().withDecryption(password).
|
||||
* PEMDecoder pd = PEMDecoder.of().withDecryption(password).
|
||||
* withFactory(provider);
|
||||
* byte[] pemData = pe.decode(privKey);
|
||||
* byte[] pemData = pd.decode(privKey);
|
||||
* }
|
||||
*
|
||||
* @implNote An implementation may support other PEM types and
|
||||
* {@code DEREncodables}. This implementation additionally supports PEM types:
|
||||
* {@code X509 CERTIFICATE}, {@code X.509 CERTIFICATE}, {@code CRL},
|
||||
* and {@code RSA PRIVATE KEY}.
|
||||
* {@code DEREncodable} objects. This implementation additionally supports
|
||||
* the following PEM types: {@code X509 CERTIFICATE},
|
||||
* {@code X.509 CERTIFICATE}, {@code CRL}, and {@code RSA PRIVATE KEY}.
|
||||
*
|
||||
* @see PEMEncoder
|
||||
* @see PEMRecord
|
||||
@@ -179,13 +179,13 @@ public final class PEMDecoder {
|
||||
return switch (pem.type()) {
|
||||
case Pem.PUBLIC_KEY -> {
|
||||
X509EncodedKeySpec spec =
|
||||
new X509EncodedKeySpec(decoder.decode(pem.pem()));
|
||||
new X509EncodedKeySpec(decoder.decode(pem.content()));
|
||||
yield getKeyFactory(
|
||||
KeyUtil.getAlgorithm(spec.getEncoded())).
|
||||
generatePublic(spec);
|
||||
}
|
||||
case Pem.PRIVATE_KEY -> {
|
||||
PKCS8Key p8key = new PKCS8Key(decoder.decode(pem.pem()));
|
||||
PKCS8Key p8key = new PKCS8Key(decoder.decode(pem.content()));
|
||||
String algo = p8key.getAlgorithm();
|
||||
KeyFactory kf = getKeyFactory(algo);
|
||||
DEREncodable d = kf.generatePrivate(
|
||||
@@ -216,27 +216,27 @@ public final class PEMDecoder {
|
||||
case Pem.ENCRYPTED_PRIVATE_KEY -> {
|
||||
if (password == null) {
|
||||
yield new EncryptedPrivateKeyInfo(decoder.decode(
|
||||
pem.pem()));
|
||||
pem.content()));
|
||||
}
|
||||
yield new EncryptedPrivateKeyInfo(decoder.decode(pem.pem())).
|
||||
yield new EncryptedPrivateKeyInfo(decoder.decode(pem.content())).
|
||||
getKey(password.getPassword());
|
||||
}
|
||||
case Pem.CERTIFICATE, Pem.X509_CERTIFICATE,
|
||||
Pem.X_509_CERTIFICATE -> {
|
||||
CertificateFactory cf = getCertFactory("X509");
|
||||
yield (X509Certificate) cf.generateCertificate(
|
||||
new ByteArrayInputStream(decoder.decode(pem.pem())));
|
||||
new ByteArrayInputStream(decoder.decode(pem.content())));
|
||||
}
|
||||
case Pem.X509_CRL, Pem.CRL -> {
|
||||
CertificateFactory cf = getCertFactory("X509");
|
||||
yield (X509CRL) cf.generateCRL(
|
||||
new ByteArrayInputStream(decoder.decode(pem.pem())));
|
||||
new ByteArrayInputStream(decoder.decode(pem.content())));
|
||||
}
|
||||
case Pem.RSA_PRIVATE_KEY -> {
|
||||
KeyFactory kf = getKeyFactory("RSA");
|
||||
yield kf.generatePrivate(
|
||||
RSAPrivateCrtKeyImpl.getKeySpec(decoder.decode(
|
||||
pem.pem())));
|
||||
pem.content())));
|
||||
}
|
||||
default -> pem;
|
||||
};
|
||||
@@ -271,7 +271,6 @@ public final class PEMDecoder {
|
||||
*/
|
||||
public DEREncodable decode(String str) {
|
||||
Objects.requireNonNull(str);
|
||||
DEREncodable de;
|
||||
try {
|
||||
return decode(new ByteArrayInputStream(
|
||||
str.getBytes(StandardCharsets.UTF_8)));
|
||||
@@ -483,9 +482,6 @@ public final class PEMDecoder {
|
||||
* from the specified {@link Provider} to produce cryptographic objects.
|
||||
* Any errors using the {@code Provider} will occur during decoding.
|
||||
*
|
||||
* <p>If {@code provider} is {@code null}, a new instance is returned with
|
||||
* the default provider configuration.
|
||||
*
|
||||
* @param provider the factory provider
|
||||
* @return a new PEMEncoder instance configured to the {@code Provider}.
|
||||
* @throws NullPointerException if {@code provider} is null
|
||||
|
||||
@@ -71,7 +71,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
* OneAsymmetricKey structure using the "PRIVATE KEY" type.
|
||||
*
|
||||
* <p> When encoding a {@link PEMRecord}, the API surrounds the
|
||||
* {@linkplain PEMRecord#pem()} with the PEM header and footer
|
||||
* {@linkplain PEMRecord#content()} with the PEM header and footer
|
||||
* from {@linkplain PEMRecord#type()}. {@linkplain PEMRecord#leadingData()} is
|
||||
* not included in the encoding. {@code PEMRecord} will not perform
|
||||
* validity checks on the data.
|
||||
@@ -108,7 +108,8 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
* byte[] pemData = pe.encode(privKey);
|
||||
* }
|
||||
*
|
||||
* @implNote An implementation may support other PEM types and DEREncodables.
|
||||
* @implNote An implementation may support other PEM types and
|
||||
* {@code DEREncodable} objects.
|
||||
*
|
||||
*
|
||||
* @see PEMDecoder
|
||||
@@ -287,7 +288,7 @@ public final class PEMEncoder {
|
||||
}
|
||||
|
||||
// If `keySpec` is non-null, then `key` hasn't been established.
|
||||
// Setting a `key' prevents repeated key generations operations.
|
||||
// Setting a `key` prevents repeated key generation operations.
|
||||
// withEncryption() is a configuration method and cannot throw an
|
||||
// exception; therefore generation is delayed.
|
||||
if (keySpec != null) {
|
||||
|
||||
@@ -29,7 +29,6 @@ import jdk.internal.javac.PreviewFeature;
|
||||
|
||||
import sun.security.util.Pem;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -39,20 +38,20 @@ import java.util.Objects;
|
||||
* cryptographic object is not desired or the type has no
|
||||
* {@code DEREncodable}.
|
||||
*
|
||||
* <p> {@code type} and {@code pem} may not be {@code null}.
|
||||
* <p> {@code type} and {@code content} may not be {@code null}.
|
||||
* {@code leadingData} may be null if no non-PEM data preceded PEM header
|
||||
* during decoding. {@code leadingData} may be useful for reading metadata
|
||||
* that accompanies PEM data.
|
||||
*
|
||||
* <p> No validation is performed during instantiation to ensure that
|
||||
* {@code type} conforms to {@code RFC 7468}, that {@code pem} is valid Base64,
|
||||
* or that {@code pem} matches the {@code type}. {@code leadingData} is not
|
||||
* defensively copied and does not return a clone when
|
||||
* {@linkplain #leadingData()} is called.
|
||||
* {@code type} conforms to {@code RFC 7468}, that {@code content} is valid
|
||||
* Base64, or that {@code content} matches the {@code type}.
|
||||
* {@code leadingData} is not defensively copied and does not return a
|
||||
* clone when {@linkplain #leadingData()} is called.
|
||||
*
|
||||
* @param type the type identifier in the PEM header without PEM syntax labels.
|
||||
* For a public key, {@code type} would be "PUBLIC KEY".
|
||||
* @param pem any data between the PEM header and footer.
|
||||
* @param content the Base64-encoded data, excluding the PEM header and footer
|
||||
* @param leadingData any non-PEM data preceding the PEM header when decoding.
|
||||
*
|
||||
* @spec https://www.rfc-editor.org/info/rfc7468
|
||||
@@ -64,25 +63,25 @@ import java.util.Objects;
|
||||
* @since 25
|
||||
*/
|
||||
@PreviewFeature(feature = PreviewFeature.Feature.PEM_API)
|
||||
public record PEMRecord(String type, String pem, byte[] leadingData)
|
||||
public record PEMRecord(String type, String content, byte[] leadingData)
|
||||
implements DEREncodable {
|
||||
|
||||
/**
|
||||
* Creates a {@code PEMRecord} instance with the given parameters.
|
||||
*
|
||||
* @param type the type identifier
|
||||
* @param pem the Base64-encoded data encapsulated by the PEM header and
|
||||
* footer.
|
||||
* @param content the Base64-encoded data, excluding the PEM header and
|
||||
* footer
|
||||
* @param leadingData any non-PEM data read during the decoding process
|
||||
* before the PEM header. This value maybe {@code null}.
|
||||
* @throws IllegalArgumentException if the {@code type} is incorrectly
|
||||
* @throws IllegalArgumentException if {@code type} is incorrectly
|
||||
* formatted.
|
||||
* @throws NullPointerException if {@code type} and/or {@code pem} are
|
||||
* @throws NullPointerException if {@code type} and/or {@code content} are
|
||||
* {@code null}.
|
||||
*/
|
||||
public PEMRecord(String type, String pem, byte[] leadingData) {
|
||||
public PEMRecord {
|
||||
Objects.requireNonNull(type, "\"type\" cannot be null.");
|
||||
Objects.requireNonNull(pem, "\"pem\" cannot be null.");
|
||||
Objects.requireNonNull(content, "\"content\" cannot be null.");
|
||||
|
||||
// With no validity checking on `type`, the constructor accept anything
|
||||
// including lowercase. The onus is on the caller.
|
||||
@@ -92,37 +91,22 @@ public record PEMRecord(String type, String pem, byte[] leadingData)
|
||||
"Only the PEM type identifier is allowed");
|
||||
}
|
||||
|
||||
this.type = type;
|
||||
this.pem = pem;
|
||||
this.leadingData = leadingData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code PEMRecord} instance with a given {@code type} and
|
||||
* {@code pem} data in String form. {@code leadingData} is set to null.
|
||||
* {@code content} data in String form. {@code leadingData} is set to null.
|
||||
*
|
||||
* @param type the PEM type identifier
|
||||
* @param pem the Base64-encoded data encapsulated by the PEM header and
|
||||
* footer.
|
||||
* @throws IllegalArgumentException if the {@code type} is incorrectly
|
||||
* @param content the Base64-encoded data, excluding the PEM header and
|
||||
* footer
|
||||
* @throws IllegalArgumentException if {@code type} is incorrectly
|
||||
* formatted.
|
||||
* @throws NullPointerException if {@code type} and/or {@code pem} are
|
||||
* @throws NullPointerException if {@code type} and/or {@code content} are
|
||||
* {@code null}.
|
||||
*/
|
||||
public PEMRecord(String type, String pem) {
|
||||
this(type, pem, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the binary encoding from the Base64 data contained in
|
||||
* {@code pem}.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code pem} cannot be decoded.
|
||||
* @return a new array of the binary encoding each time this
|
||||
* method is called.
|
||||
*/
|
||||
public byte[] getEncoded() {
|
||||
return Base64.getMimeDecoder().decode(pem);
|
||||
public PEMRecord(String type, String content) {
|
||||
this(type, content, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -621,10 +621,10 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
if (port != -1 && port != url.getDefaultPort()) {
|
||||
host += ":" + String.valueOf(port);
|
||||
}
|
||||
String reqHost = requests.findValue("Host");
|
||||
if (reqHost == null || !reqHost.equalsIgnoreCase(host)) {
|
||||
requests.set("Host", host);
|
||||
}
|
||||
// if the "Host" header hasn't been explicitly set, then set its
|
||||
// value to the one determined through the request URL
|
||||
requests.setIfNotSet("Host", host);
|
||||
|
||||
requests.setIfNotSet("Accept", acceptString);
|
||||
|
||||
/*
|
||||
|
||||
@@ -94,6 +94,15 @@ public class Net {
|
||||
return EXCLUSIVE_BIND;
|
||||
}
|
||||
|
||||
private static final StableValue<Boolean> SHUTDOWN_WRITE_BEFORE_CLOSE = StableValue.of();
|
||||
|
||||
/**
|
||||
* Tells whether a TCP connection should be shutdown for writing before closing.
|
||||
*/
|
||||
static boolean shouldShutdownWriteBeforeClose() {
|
||||
return SHUTDOWN_WRITE_BEFORE_CLOSE.orElseSet(Net::shouldShutdownWriteBeforeClose0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether both IPV6_XXX and IP_XXX socket options should be set on
|
||||
* IPv6 sockets. On some kernels, both IPV6_XXX and IP_XXX socket options
|
||||
@@ -462,6 +471,8 @@ public class Net {
|
||||
*/
|
||||
private static native int isExclusiveBindAvailable();
|
||||
|
||||
private static native boolean shouldShutdownWriteBeforeClose0();
|
||||
|
||||
private static native boolean shouldSetBothIPv4AndIPv6Options0();
|
||||
|
||||
private static native boolean canIPv6SocketJoinIPv4Group0();
|
||||
|
||||
@@ -846,7 +846,7 @@ class SocketChannelImpl
|
||||
/**
|
||||
* Marks the beginning of a connect operation that might block.
|
||||
* @param blocking true if configured blocking
|
||||
* @param isa the remote address
|
||||
* @param sa the remote socket address
|
||||
* @throws ClosedChannelException if the channel is closed
|
||||
* @throws AlreadyConnectedException if already connected
|
||||
* @throws ConnectionPendingException is a connection is pending
|
||||
@@ -1070,8 +1070,8 @@ class SocketChannelImpl
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the socket if there are no I/O operations in progress and the
|
||||
* channel is not registered with a Selector.
|
||||
* Closes the socket if there are no I/O operations in progress (or no I/O
|
||||
* operations tracked), and the channel is not registered with a Selector.
|
||||
*/
|
||||
private boolean tryClose() throws IOException {
|
||||
assert Thread.holdsLock(stateLock) && state == ST_CLOSING;
|
||||
@@ -1096,11 +1096,21 @@ class SocketChannelImpl
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this channel when configured in blocking mode.
|
||||
* Closes this channel when configured in blocking mode. If there are no I/O
|
||||
* operations in progress (or tracked), then the channel's socket is closed. If
|
||||
* there are I/O operations in progress then the behavior is platform specific.
|
||||
*
|
||||
* If there is an I/O operation in progress then the socket is pre-closed
|
||||
* and the I/O threads signalled, in which case the final close is deferred
|
||||
* until all I/O operations complete.
|
||||
* On Unix systems, the channel's socket is pre-closed. This unparks any virtual
|
||||
* threads that are blocked in I/O operations on this channel. If there are
|
||||
* platform threads blocked on the channel's socket then the socket is dup'ed
|
||||
* and the platform threads signalled. The final close is deferred until all I/O
|
||||
* operations complete.
|
||||
*
|
||||
* On Windows, the channel's socket is pre-closed. This unparks any virtual
|
||||
* threads that are blocked in I/O operations on this channel. If there are no
|
||||
* virtual threads blocked in I/O operations on this channel then the channel's
|
||||
* socket is closed. If there are virtual threads in I/O then the final close is
|
||||
* deferred until all I/O operations on virtual threads complete.
|
||||
*
|
||||
* Note that a channel configured blocking may be registered with a Selector
|
||||
* This arises when a key is canceled and the channel configured to blocking
|
||||
@@ -1112,17 +1122,17 @@ class SocketChannelImpl
|
||||
boolean connected = (state == ST_CONNECTED);
|
||||
state = ST_CLOSING;
|
||||
|
||||
if (!tryClose()) {
|
||||
if (connected && Net.shouldShutdownWriteBeforeClose()) {
|
||||
// shutdown output when linger interval not set to 0
|
||||
if (connected) {
|
||||
try {
|
||||
var SO_LINGER = StandardSocketOptions.SO_LINGER;
|
||||
if ((int) Net.getSocketOption(fd, SO_LINGER) != 0) {
|
||||
Net.shutdown(fd, Net.SHUT_WR);
|
||||
}
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
try {
|
||||
var SO_LINGER = StandardSocketOptions.SO_LINGER;
|
||||
if ((int) Net.getSocketOption(fd, SO_LINGER) != 0) {
|
||||
Net.shutdown(fd, Net.SHUT_WR);
|
||||
}
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
|
||||
if (!tryClose()) {
|
||||
// prepare file descriptor for closing
|
||||
nd.preClose(fd, readerThread, writerThread);
|
||||
}
|
||||
|
||||
@@ -565,7 +565,7 @@ public class X509Factory extends CertificateFactorySpi {
|
||||
} catch (EOFException e) {
|
||||
return null;
|
||||
}
|
||||
return Base64.getDecoder().decode(rec.pem());
|
||||
return Base64.getDecoder().decode(rec.content());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
|
||||
@@ -343,7 +343,7 @@ public class Pem {
|
||||
* @return PEM in a string
|
||||
*/
|
||||
public static String pemEncoded(PEMRecord pem) {
|
||||
String p = pem.pem().replaceAll("(.{64})", "$1\r\n");
|
||||
String p = pem.content().replaceAll("(.{64})", "$1\r\n");
|
||||
return pemEncoded(pem.type(), p);
|
||||
}
|
||||
}
|
||||
|
||||
21
src/java.base/share/data/cacerts/sectigocodesignroote46
Normal file
21
src/java.base/share/data/cacerts/sectigocodesignroote46
Normal file
@@ -0,0 +1,21 @@
|
||||
Owner: CN=Sectigo Public Code Signing Root E46, O=Sectigo Limited, C=GB
|
||||
Issuer: CN=Sectigo Public Code Signing Root E46, O=Sectigo Limited, C=GB
|
||||
Serial number: 50249ba2ef8ea6bf6c2c1f1a6385d4c3
|
||||
Valid from: Mon Mar 22 00:00:00 GMT 2021 until: Wed Mar 21 23:59:59 GMT 2046
|
||||
Signature algorithm name: SHA384withECDSA
|
||||
Subject Public Key Algorithm: 384-bit EC (secp384r1) key
|
||||
Version: 3
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICKDCCAa+gAwIBAgIQUCSbou+Opr9sLB8aY4XUwzAKBggqhkjOPQQDAzBWMQsw
|
||||
CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQDEyRT
|
||||
ZWN0aWdvIFB1YmxpYyBDb2RlIFNpZ25pbmcgUm9vdCBFNDYwHhcNMjEwMzIyMDAw
|
||||
MDAwWhcNNDYwMzIxMjM1OTU5WjBWMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2Vj
|
||||
dGlnbyBMaW1pdGVkMS0wKwYDVQQDEyRTZWN0aWdvIFB1YmxpYyBDb2RlIFNpZ25p
|
||||
bmcgUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQIMoEDH487om+BR4zl
|
||||
e7m6wWmyW0nAKLkUWG8kM85Qm3PZO8FoOZx6Yc5c0iJHRKuAhanllayqrmZYhlan
|
||||
uIODzLTRDqlR+EtnOX+MubY5aDSPGUq6jiHrQrisVp0J3AejQjBAMB0GA1UdDgQW
|
||||
BBTPfSygkHqYHd22XoXC4NoVcdLlXjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/
|
||||
BAUwAwEB/zAKBggqhkjOPQQDAwNnADBkAjACd++zAerlV83j8HflRwwwlLmgchbs
|
||||
aGX/4g44dv/oG8KfzCVTRg6sZHMobtK0IqYCMGk5W6+oBFyZMtOebrSwXs8lGjll
|
||||
/zHz43Zy8DMXO+iiqzSEwWGneZ6KupkGGqfVKw==
|
||||
-----END CERTIFICATE-----
|
||||
39
src/java.base/share/data/cacerts/sectigocodesignrootr46
Normal file
39
src/java.base/share/data/cacerts/sectigocodesignrootr46
Normal file
@@ -0,0 +1,39 @@
|
||||
Owner: CN=Sectigo Public Code Signing Root R46, O=Sectigo Limited, C=GB
|
||||
Issuer: CN=Sectigo Public Code Signing Root R46, O=Sectigo Limited, C=GB
|
||||
Serial number: 4b2c3b01018bad2abc8c7b5b3eed9057
|
||||
Valid from: Mon Mar 22 00:00:00 GMT 2021 until: Wed Mar 21 23:59:59 GMT 2046
|
||||
Signature algorithm name: SHA384withRSA
|
||||
Subject Public Key Algorithm: 4096-bit RSA key
|
||||
Version: 3
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFeDCCA2CgAwIBAgIQSyw7AQGLrSq8jHtbPu2QVzANBgkqhkiG9w0BAQwFADBW
|
||||
MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQD
|
||||
EyRTZWN0aWdvIFB1YmxpYyBDb2RlIFNpZ25pbmcgUm9vdCBSNDYwHhcNMjEwMzIy
|
||||
MDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBWMQswCQYDVQQGEwJHQjEYMBYGA1UEChMP
|
||||
U2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQDEyRTZWN0aWdvIFB1YmxpYyBDb2RlIFNp
|
||||
Z25pbmcgUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCN
|
||||
55QSIgQkdC7/FiMCkoq2rjaFrEfUI5ErPtx94jGgUW+shJHjUoq14pbe0IdjJImK
|
||||
/+8Skzt9u7aKvb0Ffyeba2XTpQxpsbxJOZrxbW6q5KCDJ9qaDStQ6Utbs7hkNqR+
|
||||
Sj2pcaths3OzPAsM79szV+W+NDfjlxtd/R8SPYIDdub7P2bSlDFp+m2zNKzBenjc
|
||||
klDyZMeqLQSrw2rq4C+np9xu1+j/2iGrQL+57g2extmeme/G3h+pDHazJyCh1rr9
|
||||
gOcB0u/rgimVcI3/uxXP/tEPNqIuTzKQdEZrRzUTdwUzT2MuuC3hv2WnBGsY2HH6
|
||||
zAjybYmZELGt2z4s5KoYsMYHAXVn3m3pY2MeNn9pib6qRT5uWl+PoVvLnTCGMOgD
|
||||
s0DGDQ84zWeoU4j6uDBl+m/H5x2xg3RpPqzEaDux5mczmrYI4IAFSEDu9oJkRqj1
|
||||
c7AGlfJsZZ+/VVscnFcax3hGfHCqlBuCF6yH6bbJDoEcQNYWFyn8XJwYK+pF9e+9
|
||||
1WdPKF4F7pBMeufG9ND8+s0+MkYTIDaKBOq3qgdGnA2TOglmmVhcKaO5DKYwODzQ
|
||||
RjY1fJy67sPV+Qp2+n4FG0DKkjXp1XrRtX8ArqmQqsV/AZwQsRb8zG4Y3G9i/qZQ
|
||||
p7h7uJ0VP/4gDHXIIloTlRmQAOka1cKG8eOO7F/05QIDAQABo0IwQDAdBgNVHQ4E
|
||||
FgQUMuuSmv81lkgvKEBCcCA2kVwXheYwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB
|
||||
/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAHZlwuPXIkrXHYle/2lexhQCTXOm
|
||||
zc0oyrA36r+nySGqql/av/aDbNCA0QpcAKTL88w5D55BcYjVPOiKe4wXI/fKNHSR
|
||||
bAauUD8AWbImPDwXg1cDPi3RGj3UzwdUskMLUnKoiPXEF/Jv0Vil0WjkPZgIGO42
|
||||
9EhImvpUcPCI1HAWMEJJ0Nk/dUtFcdiuorthDoiFUFe5uhErNikfjyBynlyeidGC
|
||||
2kWNapnahHFrM6UQu3nwl/Z0gaA/V8eGjDCMDjiVrgHGHqvcqB9vL9f/dh6uF3Nt
|
||||
5bl1s2EGqJUzwk5vsjfylb6FVBK5yL1iQnb3Kvz1NzEDJlf+0ebb8BYCcoOMCLOE
|
||||
rKnkB/ihiMQTWlBHVEKm7dBBNCyYsT6iNKEMXb2s9395p79tDFYyhRtLl7jhrOSk
|
||||
PHHxo+FOY9b0Rrr1CwjhYzztolkvCtQsayOinqFN7tESzRgzUO1Bbst/PUFgC2ML
|
||||
ePV170MVtzYLEK/cXBipmNk22R3YhLMGioLjexskp0LO7g8+VlwyfexL3lYrOzu6
|
||||
+XpY0FG2bNb2WKJSJHpEhqEcYD9J0/z6+YQcBcI0v+Lm8RkqmS9WVzWctfUHw0Yv
|
||||
3jg9GQ37o/HfE57nqXJYMa+96trX1m13MzOO9Kz9wb9Jh9JwBWd0Bqb2eEAtFgSR
|
||||
Dx/TFsS4ehcNJMmy
|
||||
-----END CERTIFICATE-----
|
||||
21
src/java.base/share/data/cacerts/sectigotlsroote46
Normal file
21
src/java.base/share/data/cacerts/sectigotlsroote46
Normal file
@@ -0,0 +1,21 @@
|
||||
Owner: CN=Sectigo Public Server Authentication Root E46, O=Sectigo Limited, C=GB
|
||||
Issuer: CN=Sectigo Public Server Authentication Root E46, O=Sectigo Limited, C=GB
|
||||
Serial number: 42f2ccda1b6937445f15fe752810b8f4
|
||||
Valid from: Mon Mar 22 00:00:00 GMT 2021 until: Wed Mar 21 23:59:59 GMT 2046
|
||||
Signature algorithm name: SHA384withECDSA
|
||||
Subject Public Key Algorithm: 384-bit EC (secp384r1) key
|
||||
Version: 3
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQsw
|
||||
CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T
|
||||
ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcN
|
||||
MjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYG
|
||||
A1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT
|
||||
ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA
|
||||
IgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccC
|
||||
WvkEN/U0NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+
|
||||
6xnOQ6OjQjBAMB0GA1UdDgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8B
|
||||
Af8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNnADBkAjAn7qRa
|
||||
qCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RHlAFWovgzJQxC36oCMB3q
|
||||
4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21USAGKcw==
|
||||
-----END CERTIFICATE-----
|
||||
39
src/java.base/share/data/cacerts/sectigotlsrootr46
Normal file
39
src/java.base/share/data/cacerts/sectigotlsrootr46
Normal file
@@ -0,0 +1,39 @@
|
||||
Owner: CN=Sectigo Public Server Authentication Root R46, O=Sectigo Limited, C=GB
|
||||
Issuer: CN=Sectigo Public Server Authentication Root R46, O=Sectigo Limited, C=GB
|
||||
Serial number: 758dfd8bae7c0700faa925a7e1c7ad14
|
||||
Valid from: Mon Mar 22 00:00:00 GMT 2021 until: Wed Mar 21 23:59:59 GMT 2046
|
||||
Signature algorithm name: SHA384withRSA
|
||||
Subject Public Key Algorithm: 4096-bit RSA key
|
||||
Version: 3
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBf
|
||||
MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQD
|
||||
Ey1TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYw
|
||||
HhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEY
|
||||
MBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1Ymxp
|
||||
YyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB
|
||||
AQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDa
|
||||
ef0rty2k1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnz
|
||||
SDBh+oF8HqcIStw+KxwfGExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xf
|
||||
iOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMPFF1bFOdLvt30yNoDN9HWOaEhUTCDsG3X
|
||||
ME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vuZDCQOc2TZYEhMbUjUDM3
|
||||
IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5QazYw6A3OAS
|
||||
VYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgE
|
||||
SJ/AwSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu
|
||||
+Zd4KKTIRJLpfSYFplhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt
|
||||
8uaZFURww3y8nDnAtOFr94MlI1fZEoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+L
|
||||
HaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW6aWWrL3DkJiy4Pmi1KZHQ3xt
|
||||
zwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWIIUkwDgYDVR0P
|
||||
AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c
|
||||
mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQ
|
||||
YKlJfp/imTYpE0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52
|
||||
gDY9hAaLMyZlbcp+nv4fjFg4exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZA
|
||||
Fv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M0ejf5lG5Nkc/kLnHvALcWxxPDkjB
|
||||
JYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI84HxZmduTILA7rpX
|
||||
DhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9mpFui
|
||||
TdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5
|
||||
dHn5HrwdVw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65
|
||||
LvKRRFHQV80MNNVIIb/bE/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp
|
||||
0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmmJ1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAY
|
||||
QqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1449,9 +1449,10 @@ These `java` options control the runtime behavior of the Java HotSpot VM.
|
||||
|
||||
`report-on-exit=`*identifier*
|
||||
: Specifies the name of the view to display when the Java Virtual Machine
|
||||
(JVM) shuts down. This option is not available if the disk option is set
|
||||
to false. For a list of available views, see `jfr help view`. By default,
|
||||
no report is generated.
|
||||
(JVM) shuts down. To specify more than one view, use the report-on-exit
|
||||
parameter repeatedly. This option is not available if the disk option
|
||||
is set to false. For a list of available views, see `jfr help view`.
|
||||
By default, no report is generated.
|
||||
|
||||
`settings=`*path*
|
||||
: Specifies the path and name of the event settings file (of type JFC).
|
||||
|
||||
@@ -91,14 +91,7 @@ DEF_JNI_OnLoad(JavaVM *vm, void *reserved)
|
||||
}
|
||||
|
||||
static int enhancedExceptionsInitialized = 0;
|
||||
static int enhancedExceptionsAllowed = -1;
|
||||
|
||||
#define CHECK_NULL_THROW_ERROR(X) \
|
||||
if (X == NULL) { \
|
||||
JNU_ThrowByName(env, "java/lang/InternalError", \
|
||||
"can't initialize enhanced exceptions"); \
|
||||
return -1; \
|
||||
}
|
||||
static int enhancedExceptionsAllowed = 0;
|
||||
|
||||
int getEnhancedExceptionsAllowed(JNIEnv *env) {
|
||||
jclass cls;
|
||||
@@ -108,9 +101,9 @@ int getEnhancedExceptionsAllowed(JNIEnv *env) {
|
||||
return enhancedExceptionsAllowed;
|
||||
}
|
||||
cls = (*env)->FindClass(env, "jdk/internal/util/Exceptions");
|
||||
CHECK_NULL_THROW_ERROR(cls);
|
||||
CHECK_NULL_RETURN(cls, ENH_INIT_ERROR);
|
||||
fid = (*env)->GetStaticFieldID(env, cls, "enhancedNonSocketExceptionText", "Z");
|
||||
CHECK_NULL_THROW_ERROR(fid);
|
||||
CHECK_NULL_RETURN(fid, ENH_INIT_ERROR);
|
||||
enhancedExceptionsAllowed = (*env)->GetStaticBooleanField(env, cls, fid);
|
||||
enhancedExceptionsInitialized = 1;
|
||||
return enhancedExceptionsAllowed;
|
||||
|
||||
@@ -183,6 +183,11 @@ int lookupCharacteristicsToAddressFamily(int characteristics);
|
||||
|
||||
int addressesInSystemOrder(int characteristics);
|
||||
|
||||
/* return codes */
|
||||
#define ENH_INIT_ERROR -1 /* initialization error: check exceptions */
|
||||
#define ENH_DISABLED 0 /* enhanced exceptions disabled */
|
||||
#define ENH_ENABLED 1 /* enhanced exceptions enabled */
|
||||
|
||||
int getEnhancedExceptionsAllowed(JNIEnv *env);
|
||||
|
||||
#endif /* NET_UTILS_H */
|
||||
|
||||
@@ -188,8 +188,11 @@ void NET_ThrowUnknownHostExceptionWithGaiError(JNIEnv *env,
|
||||
if (error_string == NULL)
|
||||
error_string = "unknown error";
|
||||
int enhancedExceptions = getEnhancedExceptionsAllowed(env);
|
||||
if (enhancedExceptions == ENH_INIT_ERROR && (*env)->ExceptionCheck(env)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (enhancedExceptions) {
|
||||
if (enhancedExceptions == ENH_ENABLED) {
|
||||
size = strlen(hostname);
|
||||
} else {
|
||||
size = 0;
|
||||
@@ -200,7 +203,7 @@ void NET_ThrowUnknownHostExceptionWithGaiError(JNIEnv *env,
|
||||
if (buf) {
|
||||
jstring s;
|
||||
int n;
|
||||
if (enhancedExceptions) {
|
||||
if (enhancedExceptions == ENH_ENABLED) {
|
||||
n = snprintf(buf, size, "%s: %s", hostname, error_string);
|
||||
} else {
|
||||
n = snprintf(buf, size, " %s", error_string);
|
||||
|
||||
@@ -205,6 +205,11 @@ Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_nio_ch_Net_shouldShutdownWriteBeforeClose0(JNIEnv *env, jclass clazz) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_nio_ch_Net_shouldSetBothIPv4AndIPv6Options0(JNIEnv* env, jclass cl)
|
||||
{
|
||||
|
||||
@@ -88,9 +88,12 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
|
||||
|
||||
if (error) {
|
||||
// report error
|
||||
NET_ThrowByNameWithLastError(
|
||||
env, "java/net/UnknownHostException",
|
||||
getEnhancedExceptionsAllowed(env) ? hostname : "");
|
||||
int enh = getEnhancedExceptionsAllowed(env);
|
||||
if (enh == ENH_INIT_ERROR && (*env)->ExceptionCheck(env)) {
|
||||
goto cleanupAndReturn;
|
||||
}
|
||||
const char *hmsg = (enh == ENH_ENABLED) ? hostname : "";
|
||||
NET_ThrowByNameWithLastError( env, "java/net/UnknownHostException", hmsg);
|
||||
goto cleanupAndReturn;
|
||||
} else {
|
||||
int i = 0;
|
||||
|
||||
@@ -83,8 +83,12 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
|
||||
|
||||
if (error) {
|
||||
// report error
|
||||
NET_ThrowByNameWithLastError(env, "java/net/UnknownHostException",
|
||||
getEnhancedExceptionsAllowed(env) ? hostname : "");
|
||||
int enh = getEnhancedExceptionsAllowed(env);
|
||||
if (enh == ENH_INIT_ERROR && (*env)->ExceptionCheck(env)) {
|
||||
goto cleanupAndReturn;
|
||||
}
|
||||
const char *hmsg = (enh == ENH_ENABLED) ? hostname : "";
|
||||
NET_ThrowByNameWithLastError(env, "java/net/UnknownHostException", hmsg);
|
||||
goto cleanupAndReturn;
|
||||
} else {
|
||||
int i = 0, inetCount = 0, inet6Count = 0, inetIndex = 0,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -117,6 +117,11 @@ Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_nio_ch_Net_shouldShutdownWriteBeforeClose0(JNIEnv *env, jclass clazz) {
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_nio_ch_Net_shouldSetBothIPv4AndIPv6Options0(JNIEnv* env, jclass cl)
|
||||
{
|
||||
|
||||
@@ -468,18 +468,6 @@ public enum SourceVersion {
|
||||
* JEP 513: Flexible Constructor Bodies</a>
|
||||
*/
|
||||
RELEASE_25,
|
||||
|
||||
/**
|
||||
* The version introduced by the Java Platform, Standard Edition
|
||||
* 26.
|
||||
*
|
||||
* @since 26
|
||||
*
|
||||
* @see <a
|
||||
* href="https://docs.oracle.com/javase/specs/jls/se26/html/index.html">
|
||||
* <cite>The Java Language Specification, Java SE 26 Edition</cite></a>
|
||||
*/
|
||||
RELEASE_26,
|
||||
; // Reduce code churn when appending new constants
|
||||
|
||||
// Note that when adding constants for newer releases, the
|
||||
@@ -489,7 +477,7 @@ public enum SourceVersion {
|
||||
* {@return the latest source version that can be modeled}
|
||||
*/
|
||||
public static SourceVersion latest() {
|
||||
return RELEASE_26;
|
||||
return RELEASE_25;
|
||||
}
|
||||
|
||||
private static final SourceVersion latestSupported = getLatestSupported();
|
||||
@@ -504,7 +492,7 @@ public enum SourceVersion {
|
||||
private static SourceVersion getLatestSupported() {
|
||||
int intVersion = Runtime.version().feature();
|
||||
return (intVersion >= 11) ?
|
||||
valueOf("RELEASE_" + Math.min(26, intVersion)):
|
||||
valueOf("RELEASE_" + Math.min(25, intVersion)):
|
||||
RELEASE_10;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, 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
|
||||
@@ -44,7 +44,7 @@ import javax.annotation.processing.SupportedSourceVersion;
|
||||
* @see AbstractAnnotationValueVisitor9
|
||||
* @since 14
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_26)
|
||||
@SupportedSourceVersion(RELEASE_25)
|
||||
public abstract class AbstractAnnotationValueVisitor14<R, P> extends AbstractAnnotationValueVisitor9<R, P> {
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, 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
|
||||
@@ -50,7 +50,7 @@ import javax.annotation.processing.ProcessingEnvironment;
|
||||
* @see AbstractAnnotationValueVisitor14
|
||||
* @since 23
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_26)
|
||||
@SupportedSourceVersion(RELEASE_25)
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true)
|
||||
public abstract class AbstractAnnotationValueVisitorPreview<R, P> extends AbstractAnnotationValueVisitor14<R, P> {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, 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
|
||||
@@ -50,7 +50,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see AbstractElementVisitor9
|
||||
* @since 16
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_26)
|
||||
@SupportedSourceVersion(RELEASE_25)
|
||||
public abstract class AbstractElementVisitor14<R, P> extends AbstractElementVisitor9<R, P> {
|
||||
/**
|
||||
* Constructor for concrete subclasses to call.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, 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
|
||||
@@ -53,7 +53,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see AbstractElementVisitor14
|
||||
* @since 23
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_26)
|
||||
@SupportedSourceVersion(RELEASE_25)
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true)
|
||||
public abstract class AbstractElementVisitorPreview<R, P> extends AbstractElementVisitor14<R, P> {
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, 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
|
||||
@@ -47,7 +47,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see AbstractTypeVisitor9
|
||||
* @since 14
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_26)
|
||||
@SupportedSourceVersion(RELEASE_25)
|
||||
public abstract class AbstractTypeVisitor14<R, P> extends AbstractTypeVisitor9<R, P> {
|
||||
/**
|
||||
* Constructor for concrete subclasses to call.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, 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
|
||||
@@ -53,7 +53,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see AbstractTypeVisitor14
|
||||
* @since 23
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_26)
|
||||
@SupportedSourceVersion(RELEASE_25)
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true)
|
||||
public abstract class AbstractTypeVisitorPreview<R, P> extends AbstractTypeVisitor14<R, P> {
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, 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
|
||||
@@ -61,7 +61,7 @@ import javax.lang.model.SourceVersion;
|
||||
* @see ElementKindVisitor9
|
||||
* @since 16
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_26)
|
||||
@SupportedSourceVersion(RELEASE_25)
|
||||
public class ElementKindVisitor14<R, P> extends ElementKindVisitor9<R, P> {
|
||||
/**
|
||||
* Constructor for concrete subclasses; uses {@code null} for the
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, 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
|
||||
@@ -67,7 +67,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see ElementKindVisitor14
|
||||
* @since 23
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_26)
|
||||
@SupportedSourceVersion(RELEASE_25)
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true)
|
||||
public class ElementKindVisitorPreview<R, P> extends ElementKindVisitor14<R, P> {
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, 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
|
||||
@@ -77,7 +77,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see ElementScanner9
|
||||
* @since 16
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_26)
|
||||
@SupportedSourceVersion(RELEASE_25)
|
||||
public class ElementScanner14<R, P> extends ElementScanner9<R, P> {
|
||||
/**
|
||||
* Constructor for concrete subclasses; uses {@code null} for the
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, 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
|
||||
@@ -81,7 +81,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see ElementScanner14
|
||||
* @since 23
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_26)
|
||||
@SupportedSourceVersion(RELEASE_25)
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true)
|
||||
public class ElementScannerPreview<R, P> extends ElementScanner14<R, P> {
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, 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
|
||||
@@ -52,7 +52,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see SimpleAnnotationValueVisitor9
|
||||
* @since 14
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_26)
|
||||
@SupportedSourceVersion(RELEASE_25)
|
||||
public class SimpleAnnotationValueVisitor14<R, P> extends SimpleAnnotationValueVisitor9<R, P> {
|
||||
/**
|
||||
* Constructor for concrete subclasses; uses {@code null} for the
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, 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
|
||||
@@ -58,7 +58,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see SimpleAnnotationValueVisitor14
|
||||
* @since 23
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_26)
|
||||
@SupportedSourceVersion(RELEASE_25)
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true)
|
||||
public class SimpleAnnotationValueVisitorPreview<R, P> extends SimpleAnnotationValueVisitor14<R, P> {
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, 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
|
||||
@@ -58,7 +58,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see SimpleElementVisitor9
|
||||
* @since 16
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_26)
|
||||
@SupportedSourceVersion(RELEASE_25)
|
||||
public class SimpleElementVisitor14<R, P> extends SimpleElementVisitor9<R, P> {
|
||||
/**
|
||||
* Constructor for concrete subclasses; uses {@code null} for the
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, 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
|
||||
@@ -61,7 +61,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see SimpleElementVisitor14
|
||||
* @since 23
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_26)
|
||||
@SupportedSourceVersion(RELEASE_25)
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true)
|
||||
public class SimpleElementVisitorPreview<R, P> extends SimpleElementVisitor14<R, P> {
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, 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
|
||||
@@ -56,7 +56,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see SimpleTypeVisitor9
|
||||
* @since 14
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_26)
|
||||
@SupportedSourceVersion(RELEASE_25)
|
||||
public class SimpleTypeVisitor14<R, P> extends SimpleTypeVisitor9<R, P> {
|
||||
/**
|
||||
* Constructor for concrete subclasses; uses {@code null} for the
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, 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
|
||||
@@ -62,7 +62,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see SimpleTypeVisitor14
|
||||
* @since 23
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_26)
|
||||
@SupportedSourceVersion(RELEASE_25)
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true)
|
||||
public class SimpleTypeVisitorPreview<R, P> extends SimpleTypeVisitor14<R, P> {
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, 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
|
||||
@@ -61,7 +61,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see TypeKindVisitor9
|
||||
* @since 14
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_26)
|
||||
@SupportedSourceVersion(RELEASE_25)
|
||||
public class TypeKindVisitor14<R, P> extends TypeKindVisitor9<R, P> {
|
||||
/**
|
||||
* Constructor for concrete subclasses to call; uses {@code null}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user