Merge branch 'JDK-8348611' into JDK-8344159.

This commit is contained in:
Archie L. Cobbs 2025-07-30 18:50:25 -05:00
commit a76e2e3454
361 changed files with 8053 additions and 7313 deletions

View File

@ -65,4 +65,4 @@ runs:
with:
name: bundles-jtreg-${{ steps.version.outputs.value }}
path: jtreg/installed
retention-days: 1
retention-days: 5

View File

@ -30,15 +30,15 @@ runs:
using: composite
steps:
- name: 'Install MSYS2'
uses: msys2/setup-msys2@v2.22.0
id: msys2
uses: msys2/setup-msys2@v2.28.0
with:
install: 'autoconf tar unzip zip make'
path-type: minimal
location: ${{ runner.tool_cache }}/msys2
release: false
# We can't run bash until this is completed, so stick with pwsh
- name: 'Set MSYS2 path'
run: |
# Prepend msys2/msys64/usr/bin to the PATH
echo "$env:RUNNER_TOOL_CACHE/msys2/msys64/usr/bin" >> $env:GITHUB_PATH
echo "${{ steps.msys2.outputs.msys2-location }}/usr/bin" >> $env:GITHUB_PATH
shell: pwsh

View File

@ -91,5 +91,5 @@ runs:
with:
name: bundles-${{ inputs.platform }}${{ inputs.debug-suffix }}${{ inputs.static-suffix }}${{ inputs.bundle-suffix }}
path: bundles
retention-days: 1
retention-days: 5
if: steps.bundles.outputs.bundles-found == 'true'

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2014, 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
@ -78,7 +78,6 @@ src/jdk.jdi : jdk/src/jdk.jdi
src/jdk.jdwp.agent : jdk/src/jdk.jdwp.agent
src/jdk.jlink : jdk/src/jdk.jlink
src/jdk.jshell : langtools/src/jdk.jshell
src/jdk.jsobject : jdk/src/jdk.jsobject
src/jdk.jstatd : jdk/src/jdk.jstatd
src/jdk.localedata : jdk/src/jdk.localedata
src/jdk.management : jdk/src/jdk.management

View File

@ -736,8 +736,15 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP],
$1_CFLAGS_CPU_JVM="${$1_CFLAGS_CPU_JVM} -mminimal-toc"
elif test "x$FLAGS_CPU" = xppc64le; then
# Little endian machine uses ELFv2 ABI.
# Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI.
$1_CFLAGS_CPU="-mcpu=power8 -mtune=power10"
# Use Power8 for target cpu, this is the first CPU to support PPC64 LE with ELFv2 ABI.
# Use Power10 for tuning target, this is supported by gcc >= 10
POWER_TUNE_VERSION="-mtune=power10"
FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [${POWER_TUNE_VERSION}],
IF_FALSE: [
POWER_TUNE_VERSION="-mtune=power8"
]
)
$1_CFLAGS_CPU="-mcpu=power8 ${POWER_TUNE_VERSION}"
$1_CFLAGS_CPU_JVM="${$1_CFLAGS_CPU_JVM} -DABI_ELFv2"
fi
elif test "x$FLAGS_CPU" = xs390x; then

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2014, 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
@ -51,7 +51,6 @@ DOCS_MODULES= \
jdk.jdwp.agent \
jdk.jfr \
jdk.jlink \
jdk.jsobject \
jdk.jshell \
jdk.jstatd \
jdk.localedata \

View File

@ -62,7 +62,6 @@ UPGRADEABLE_PLATFORM_MODULES= \
java.compiler \
jdk.graal.compiler \
jdk.graal.compiler.management \
jdk.jsobject \
#
PLATFORM_MODULES= \

View File

@ -2362,17 +2362,34 @@ int Matcher::max_vector_size(const BasicType bt) {
}
int Matcher::min_vector_size(const BasicType bt) {
int max_size = max_vector_size(bt);
// Limit the min vector size to 8 bytes.
int size = 8 / type2aelembytes(bt);
if (bt == T_BYTE) {
// To support vector api shuffle/rearrange.
size = 4;
} else if (bt == T_BOOLEAN) {
// To support vector api load/store mask.
size = 2;
// Usually, the shortest vector length supported by AArch64 ISA and
// Vector API species is 64 bits. However, we allow 32-bit or 16-bit
// vectors in a few special cases.
int size;
switch(bt) {
case T_BOOLEAN:
// Load/store a vector mask with only 2 elements for vector types
// such as "2I/2F/2L/2D".
size = 2;
break;
case T_BYTE:
// Generate a "4B" vector, to support vector cast between "8B/16B"
// and "4S/4I/4L/4F/4D".
size = 4;
break;
case T_SHORT:
// Generate a "2S" vector, to support vector cast between "4S/8S"
// and "2I/2L/2F/2D".
size = 2;
break;
default:
// Limit the min vector length to 64-bit.
size = 8 / type2aelembytes(bt);
// The number of elements in a vector should be at least 2.
size = MAX2(size, 2);
}
if (size < 2) size = 2;
int max_size = max_vector_size(bt);
return MIN2(size, max_size);
}
@ -3450,10 +3467,6 @@ encode %{
__ mov(dst_reg, (uint64_t)1);
%}
enc_class aarch64_enc_mov_byte_map_base(iRegP dst, immByteMapBase src) %{
__ load_byte_map_base($dst$$Register);
%}
enc_class aarch64_enc_mov_n(iRegN dst, immN src) %{
Register dst_reg = as_Register($dst$$reg);
address con = (address)$src$$constant;
@ -4554,20 +4567,6 @@ operand immP_1()
interface(CONST_INTER);
%}
// Card Table Byte Map Base
operand immByteMapBase()
%{
// Get base of card map
predicate(BarrierSet::barrier_set()->is_a(BarrierSet::CardTableBarrierSet) &&
SHENANDOAHGC_ONLY(!BarrierSet::barrier_set()->is_a(BarrierSet::ShenandoahBarrierSet) &&)
(CardTable::CardValue*)n->get_ptr() == ((CardTableBarrierSet*)(BarrierSet::barrier_set()))->card_table()->byte_map_base());
match(ConP);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Float and Double operands
// Double Immediate
operand immD()
@ -6854,20 +6853,6 @@ instruct loadConP1(iRegPNoSp dst, immP_1 con)
ins_pipe(ialu_imm);
%}
// Load Byte Map Base Constant
instruct loadByteMapBase(iRegPNoSp dst, immByteMapBase con)
%{
match(Set dst con);
ins_cost(INSN_COST);
format %{ "adr $dst, $con\t# Byte Map Base" %}
ins_encode(aarch64_enc_mov_byte_map_base(dst, con));
ins_pipe(ialu_imm);
%}
// Load Narrow Pointer Constant
instruct loadConN(iRegNNoSp dst, immN con)

View File

@ -131,7 +131,7 @@ source %{
// These operations are not profitable to be vectorized on NEON, because no direct
// NEON instructions support them. But the match rule support for them is profitable for
// Vector API intrinsics.
if ((opcode == Op_VectorCastD2X && bt == T_INT) ||
if ((opcode == Op_VectorCastD2X && (bt == T_INT || bt == T_SHORT)) ||
(opcode == Op_VectorCastL2X && bt == T_FLOAT) ||
(opcode == Op_CountLeadingZerosV && bt == T_LONG) ||
(opcode == Op_CountTrailingZerosV && bt == T_LONG) ||
@ -189,6 +189,18 @@ source %{
return false;
}
break;
case Op_AddReductionVI:
case Op_AndReductionV:
case Op_OrReductionV:
case Op_XorReductionV:
case Op_MinReductionV:
case Op_MaxReductionV:
// Reductions with less than 8 bytes vector length are
// not supported.
if (length_in_bytes < 8) {
return false;
}
break;
case Op_MulReductionVD:
case Op_MulReductionVF:
case Op_MulReductionVI:
@ -4244,8 +4256,8 @@ instruct vzeroExtStoX(vReg dst, vReg src) %{
assert(bt == T_INT || bt == T_LONG, "must be");
uint length_in_bytes = Matcher::vector_length_in_bytes(this);
if (VM_Version::use_neon_for_vector(length_in_bytes)) {
// 4S to 4I
__ neon_vector_extend($dst$$FloatRegister, T_INT, length_in_bytes,
// 2S to 2I/2L, 4S to 4I
__ neon_vector_extend($dst$$FloatRegister, bt, length_in_bytes,
$src$$FloatRegister, T_SHORT, /* is_unsigned */ true);
} else {
assert(UseSVE > 0, "must be sve");
@ -4265,11 +4277,11 @@ instruct vzeroExtItoX(vReg dst, vReg src) %{
uint length_in_bytes = Matcher::vector_length_in_bytes(this);
if (VM_Version::use_neon_for_vector(length_in_bytes)) {
// 2I to 2L
__ neon_vector_extend($dst$$FloatRegister, T_LONG, length_in_bytes,
__ neon_vector_extend($dst$$FloatRegister, bt, length_in_bytes,
$src$$FloatRegister, T_INT, /* is_unsigned */ true);
} else {
assert(UseSVE > 0, "must be sve");
__ sve_vector_extend($dst$$FloatRegister, __ D,
__ sve_vector_extend($dst$$FloatRegister, __ elemType_to_regVariant(bt),
$src$$FloatRegister, __ S, /* is_unsigned */ true);
}
%}
@ -4343,11 +4355,15 @@ instruct vcvtStoX_extend(vReg dst, vReg src) %{
BasicType bt = Matcher::vector_element_basic_type(this);
uint length_in_bytes = Matcher::vector_length_in_bytes(this);
if (VM_Version::use_neon_for_vector(length_in_bytes)) {
// 4S to 4I/4F
__ neon_vector_extend($dst$$FloatRegister, T_INT, length_in_bytes,
$src$$FloatRegister, T_SHORT);
if (bt == T_FLOAT) {
__ scvtfv(__ T4S, $dst$$FloatRegister, $dst$$FloatRegister);
if (is_floating_point_type(bt)) {
// 2S to 2F/2D, 4S to 4F
__ neon_vector_extend($dst$$FloatRegister, bt == T_FLOAT ? T_INT : T_LONG,
length_in_bytes, $src$$FloatRegister, T_SHORT);
__ scvtfv(get_arrangement(this), $dst$$FloatRegister, $dst$$FloatRegister);
} else {
// 2S to 2I/2L, 4S to 4I
__ neon_vector_extend($dst$$FloatRegister, bt, length_in_bytes,
$src$$FloatRegister, T_SHORT);
}
} else {
assert(UseSVE > 0, "must be sve");
@ -4371,7 +4387,7 @@ instruct vcvtItoX_narrow_neon(vReg dst, vReg src) %{
effect(TEMP_DEF dst);
format %{ "vcvtItoX_narrow_neon $dst, $src" %}
ins_encode %{
// 4I to 4B/4S
// 2I to 2S, 4I to 4B/4S
BasicType bt = Matcher::vector_element_basic_type(this);
uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src);
__ neon_vector_narrow($dst$$FloatRegister, bt,
@ -4434,28 +4450,29 @@ instruct vcvtItoX(vReg dst, vReg src) %{
// VectorCastL2X
instruct vcvtLtoI_neon(vReg dst, vReg src) %{
predicate(Matcher::vector_element_basic_type(n) == T_INT &&
instruct vcvtLtoX_narrow_neon(vReg dst, vReg src) %{
predicate((Matcher::vector_element_basic_type(n) == T_INT ||
Matcher::vector_element_basic_type(n) == T_SHORT) &&
VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(1))));
match(Set dst (VectorCastL2X src));
format %{ "vcvtLtoI_neon $dst, $src" %}
format %{ "vcvtLtoX_narrow_neon $dst, $src" %}
ins_encode %{
// 2L to 2I
// 2L to 2S/2I
BasicType bt = Matcher::vector_element_basic_type(this);
uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src);
__ neon_vector_narrow($dst$$FloatRegister, T_INT,
__ neon_vector_narrow($dst$$FloatRegister, bt,
$src$$FloatRegister, T_LONG, length_in_bytes);
%}
ins_pipe(pipe_slow);
%}
instruct vcvtLtoI_sve(vReg dst, vReg src, vReg tmp) %{
predicate((Matcher::vector_element_basic_type(n) == T_INT &&
!VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(1)))) ||
Matcher::vector_element_basic_type(n) == T_BYTE ||
Matcher::vector_element_basic_type(n) == T_SHORT);
instruct vcvtLtoX_narrow_sve(vReg dst, vReg src, vReg tmp) %{
predicate(!VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(1))) &&
!is_floating_point_type(Matcher::vector_element_basic_type(n)) &&
type2aelembytes(Matcher::vector_element_basic_type(n)) <= 4);
match(Set dst (VectorCastL2X src));
effect(TEMP_DEF dst, TEMP tmp);
format %{ "vcvtLtoI_sve $dst, $src\t# KILL $tmp" %}
format %{ "vcvtLtoX_narrow_sve $dst, $src\t# KILL $tmp" %}
ins_encode %{
assert(UseSVE > 0, "must be sve");
BasicType bt = Matcher::vector_element_basic_type(this);
@ -4521,10 +4538,11 @@ instruct vcvtFtoX_narrow_neon(vReg dst, vReg src) %{
effect(TEMP_DEF dst);
format %{ "vcvtFtoX_narrow_neon $dst, $src" %}
ins_encode %{
// 4F to 4B/4S
// 2F to 2S, 4F to 4B/4S
BasicType bt = Matcher::vector_element_basic_type(this);
uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src);
__ fcvtzs($dst$$FloatRegister, __ T4S, $src$$FloatRegister);
__ fcvtzs($dst$$FloatRegister, length_in_bytes == 16 ? __ T4S : __ T2S,
$src$$FloatRegister);
__ neon_vector_narrow($dst$$FloatRegister, bt,
$dst$$FloatRegister, T_INT, length_in_bytes);
%}
@ -4590,12 +4608,14 @@ instruct vcvtFtoX(vReg dst, vReg src) %{
// VectorCastD2X
instruct vcvtDtoI_neon(vReg dst, vReg src) %{
predicate(UseSVE == 0 && Matcher::vector_element_basic_type(n) == T_INT);
predicate(UseSVE == 0 &&
(Matcher::vector_element_basic_type(n) == T_INT ||
Matcher::vector_element_basic_type(n) == T_SHORT));
match(Set dst (VectorCastD2X src));
effect(TEMP_DEF dst);
format %{ "vcvtDtoI_neon $dst, $src\t# 2D to 2I" %}
format %{ "vcvtDtoI_neon $dst, $src\t# 2D to 2S/2I" %}
ins_encode %{
// 2D to 2I
// 2D to 2S/2I
__ ins($dst$$FloatRegister, __ D, $src$$FloatRegister, 0, 1);
// We can't use fcvtzs(vector, integer) instruction here because we need
// saturation arithmetic. See JDK-8276151.
@ -4603,6 +4623,10 @@ instruct vcvtDtoI_neon(vReg dst, vReg src) %{
__ fcvtzdw(rscratch2, $dst$$FloatRegister);
__ fmovs($dst$$FloatRegister, rscratch1);
__ mov($dst$$FloatRegister, __ S, 1, rscratch2);
if (Matcher::vector_element_basic_type(this) == T_SHORT) {
__ neon_vector_narrow($dst$$FloatRegister, T_SHORT,
$dst$$FloatRegister, T_INT, 8);
}
%}
ins_pipe(pipe_slow);
%}
@ -4676,7 +4700,7 @@ instruct vcvtHFtoF(vReg dst, vReg src) %{
ins_encode %{
uint length_in_bytes = Matcher::vector_length_in_bytes(this);
if (VM_Version::use_neon_for_vector(length_in_bytes)) {
// 4HF to 4F
// 2HF to 2F, 4HF to 4F
__ fcvtl($dst$$FloatRegister, __ T4S, $src$$FloatRegister, __ T4H);
} else {
assert(UseSVE > 0, "must be sve");
@ -4692,9 +4716,9 @@ instruct vcvtHFtoF(vReg dst, vReg src) %{
instruct vcvtFtoHF_neon(vReg dst, vReg src) %{
predicate(VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(1))));
match(Set dst (VectorCastF2HF src));
format %{ "vcvtFtoHF_neon $dst, $src\t# 4F to 4HF" %}
format %{ "vcvtFtoHF_neon $dst, $src\t# 2F/4F to 2HF/4HF" %}
ins_encode %{
// 4F to 4HF
// 2F to 2HF, 4F to 4HF
__ fcvtn($dst$$FloatRegister, __ T4H, $src$$FloatRegister, __ T4S);
%}
ins_pipe(pipe_slow);
@ -6396,14 +6420,12 @@ instruct vpopcountI(vReg dst, vReg src) %{
} else {
assert(bt == T_SHORT || bt == T_INT, "unsupported");
if (UseSVE == 0) {
assert(length_in_bytes == 8 || length_in_bytes == 16, "unsupported");
__ cnt($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
$src$$FloatRegister);
__ uaddlp($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
$dst$$FloatRegister);
assert(length_in_bytes <= 16, "unsupported");
bool isQ = length_in_bytes == 16;
__ cnt($dst$$FloatRegister, isQ ? __ T16B : __ T8B, $src$$FloatRegister);
__ uaddlp($dst$$FloatRegister, isQ ? __ T16B : __ T8B, $dst$$FloatRegister);
if (bt == T_INT) {
__ uaddlp($dst$$FloatRegister, length_in_bytes == 16 ? __ T8H : __ T4H,
$dst$$FloatRegister);
__ uaddlp($dst$$FloatRegister, isQ ? __ T8H : __ T4H, $dst$$FloatRegister);
}
} else {
__ sve_cnt($dst$$FloatRegister, __ elemType_to_regVariant(bt),
@ -6465,7 +6487,7 @@ instruct vblend_neon(vReg dst, vReg src1, vReg src2) %{
format %{ "vblend_neon $dst, $src1, $src2" %}
ins_encode %{
uint length_in_bytes = Matcher::vector_length_in_bytes(this);
assert(length_in_bytes == 8 || length_in_bytes == 16, "must be");
assert(length_in_bytes <= 16, "must be");
__ bsl($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
$src2$$FloatRegister, $src1$$FloatRegister);
%}
@ -6852,7 +6874,7 @@ instruct vcountTrailingZeros(vReg dst, vReg src) %{
} else {
assert(bt == T_SHORT || bt == T_INT || bt == T_LONG, "unsupported type");
if (UseSVE == 0) {
assert(length_in_bytes == 8 || length_in_bytes == 16, "unsupported");
assert(length_in_bytes <= 16, "unsupported");
__ neon_reverse_bits($dst$$FloatRegister, $src$$FloatRegister,
bt, /* isQ */ length_in_bytes == 16);
if (bt != T_LONG) {
@ -6911,7 +6933,7 @@ instruct vreverse(vReg dst, vReg src) %{
} else {
assert(bt == T_SHORT || bt == T_INT || bt == T_LONG, "unsupported type");
if (UseSVE == 0) {
assert(length_in_bytes == 8 || length_in_bytes == 16, "unsupported");
assert(length_in_bytes <= 16, "unsupported");
__ neon_reverse_bits($dst$$FloatRegister, $src$$FloatRegister,
bt, /* isQ */ length_in_bytes == 16);
} else {
@ -6947,7 +6969,7 @@ instruct vreverseBytes(vReg dst, vReg src) %{
BasicType bt = Matcher::vector_element_basic_type(this);
uint length_in_bytes = Matcher::vector_length_in_bytes(this);
if (VM_Version::use_neon_for_vector(length_in_bytes)) {
assert(length_in_bytes == 8 || length_in_bytes == 16, "unsupported");
assert(length_in_bytes <= 16, "unsupported");
if (bt == T_BYTE) {
if ($dst$$FloatRegister != $src$$FloatRegister) {
__ orr($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,

View File

@ -121,7 +121,7 @@ source %{
// These operations are not profitable to be vectorized on NEON, because no direct
// NEON instructions support them. But the match rule support for them is profitable for
// Vector API intrinsics.
if ((opcode == Op_VectorCastD2X && bt == T_INT) ||
if ((opcode == Op_VectorCastD2X && (bt == T_INT || bt == T_SHORT)) ||
(opcode == Op_VectorCastL2X && bt == T_FLOAT) ||
(opcode == Op_CountLeadingZerosV && bt == T_LONG) ||
(opcode == Op_CountTrailingZerosV && bt == T_LONG) ||
@ -179,6 +179,18 @@ source %{
return false;
}
break;
case Op_AddReductionVI:
case Op_AndReductionV:
case Op_OrReductionV:
case Op_XorReductionV:
case Op_MinReductionV:
case Op_MaxReductionV:
// Reductions with less than 8 bytes vector length are
// not supported.
if (length_in_bytes < 8) {
return false;
}
break;
case Op_MulReductionVD:
case Op_MulReductionVF:
case Op_MulReductionVI:
@ -2502,31 +2514,31 @@ instruct reinterpret_resize_gt128b(vReg dst, vReg src, pReg ptmp, rFlagsReg cr)
%}
// ---------------------------- Vector zero extend --------------------------------
dnl VECTOR_ZERO_EXTEND($1, $2, $3, $4, $5 $6, $7, )
dnl VECTOR_ZERO_EXTEND(op_name, dst_bt, src_bt, dst_size, src_size, assertion, neon_comment)
dnl VECTOR_ZERO_EXTEND($1, $2, $3, $4, $5, )
dnl VECTOR_ZERO_EXTEND(op_name, src_bt, src_size, assertion, neon_comment)
define(`VECTOR_ZERO_EXTEND', `
instruct vzeroExt$1toX(vReg dst, vReg src) %{
match(Set dst (VectorUCast`$1'2X src));
format %{ "vzeroExt$1toX $dst, $src" %}
ins_encode %{
BasicType bt = Matcher::vector_element_basic_type(this);
assert($6, "must be");
assert($4, "must be");
uint length_in_bytes = Matcher::vector_length_in_bytes(this);
if (VM_Version::use_neon_for_vector(length_in_bytes)) {
// $7
__ neon_vector_extend($dst$$FloatRegister, $2, length_in_bytes,
$src$$FloatRegister, $3, /* is_unsigned */ true);
// $5
__ neon_vector_extend($dst$$FloatRegister, bt, length_in_bytes,
$src$$FloatRegister, $2, /* is_unsigned */ true);
} else {
assert(UseSVE > 0, "must be sve");
__ sve_vector_extend($dst$$FloatRegister, __ $4,
$src$$FloatRegister, __ $5, /* is_unsigned */ true);
__ sve_vector_extend($dst$$FloatRegister, __ elemType_to_regVariant(bt),
$src$$FloatRegister, __ $3, /* is_unsigned */ true);
}
%}
ins_pipe(pipe_slow);
%}')dnl
VECTOR_ZERO_EXTEND(B, bt, T_BYTE, elemType_to_regVariant(bt), B, bt == T_SHORT || bt == T_INT || bt == T_LONG, `4B to 4S/4I, 8B to 8S')
VECTOR_ZERO_EXTEND(S, T_INT, T_SHORT, elemType_to_regVariant(bt), H, bt == T_INT || bt == T_LONG, `4S to 4I')
VECTOR_ZERO_EXTEND(I, T_LONG, T_INT, D, S, bt == T_LONG, `2I to 2L')
VECTOR_ZERO_EXTEND(B, T_BYTE, B, bt == T_SHORT || bt == T_INT || bt == T_LONG, `4B to 4S/4I, 8B to 8S')
VECTOR_ZERO_EXTEND(S, T_SHORT, H, bt == T_INT || bt == T_LONG, `2S to 2I/2L, 4S to 4I')
VECTOR_ZERO_EXTEND(I, T_INT, S, bt == T_LONG, `2I to 2L')
// ------------------------------ Vector cast ----------------------------------
@ -2595,11 +2607,15 @@ instruct vcvtStoX_extend(vReg dst, vReg src) %{
BasicType bt = Matcher::vector_element_basic_type(this);
uint length_in_bytes = Matcher::vector_length_in_bytes(this);
if (VM_Version::use_neon_for_vector(length_in_bytes)) {
// 4S to 4I/4F
__ neon_vector_extend($dst$$FloatRegister, T_INT, length_in_bytes,
$src$$FloatRegister, T_SHORT);
if (bt == T_FLOAT) {
__ scvtfv(__ T4S, $dst$$FloatRegister, $dst$$FloatRegister);
if (is_floating_point_type(bt)) {
// 2S to 2F/2D, 4S to 4F
__ neon_vector_extend($dst$$FloatRegister, bt == T_FLOAT ? T_INT : T_LONG,
length_in_bytes, $src$$FloatRegister, T_SHORT);
__ scvtfv(get_arrangement(this), $dst$$FloatRegister, $dst$$FloatRegister);
} else {
// 2S to 2I/2L, 4S to 4I
__ neon_vector_extend($dst$$FloatRegister, bt, length_in_bytes,
$src$$FloatRegister, T_SHORT);
}
} else {
assert(UseSVE > 0, "must be sve");
@ -2623,7 +2639,7 @@ instruct vcvtItoX_narrow_neon(vReg dst, vReg src) %{
effect(TEMP_DEF dst);
format %{ "vcvtItoX_narrow_neon $dst, $src" %}
ins_encode %{
// 4I to 4B/4S
// 2I to 2S, 4I to 4B/4S
BasicType bt = Matcher::vector_element_basic_type(this);
uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src);
__ neon_vector_narrow($dst$$FloatRegister, bt,
@ -2686,28 +2702,29 @@ instruct vcvtItoX(vReg dst, vReg src) %{
// VectorCastL2X
instruct vcvtLtoI_neon(vReg dst, vReg src) %{
predicate(Matcher::vector_element_basic_type(n) == T_INT &&
instruct vcvtLtoX_narrow_neon(vReg dst, vReg src) %{
predicate((Matcher::vector_element_basic_type(n) == T_INT ||
Matcher::vector_element_basic_type(n) == T_SHORT) &&
VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(1))));
match(Set dst (VectorCastL2X src));
format %{ "vcvtLtoI_neon $dst, $src" %}
format %{ "vcvtLtoX_narrow_neon $dst, $src" %}
ins_encode %{
// 2L to 2I
// 2L to 2S/2I
BasicType bt = Matcher::vector_element_basic_type(this);
uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src);
__ neon_vector_narrow($dst$$FloatRegister, T_INT,
__ neon_vector_narrow($dst$$FloatRegister, bt,
$src$$FloatRegister, T_LONG, length_in_bytes);
%}
ins_pipe(pipe_slow);
%}
instruct vcvtLtoI_sve(vReg dst, vReg src, vReg tmp) %{
predicate((Matcher::vector_element_basic_type(n) == T_INT &&
!VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(1)))) ||
Matcher::vector_element_basic_type(n) == T_BYTE ||
Matcher::vector_element_basic_type(n) == T_SHORT);
instruct vcvtLtoX_narrow_sve(vReg dst, vReg src, vReg tmp) %{
predicate(!VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(1))) &&
!is_floating_point_type(Matcher::vector_element_basic_type(n)) &&
type2aelembytes(Matcher::vector_element_basic_type(n)) <= 4);
match(Set dst (VectorCastL2X src));
effect(TEMP_DEF dst, TEMP tmp);
format %{ "vcvtLtoI_sve $dst, $src\t# KILL $tmp" %}
format %{ "vcvtLtoX_narrow_sve $dst, $src\t# KILL $tmp" %}
ins_encode %{
assert(UseSVE > 0, "must be sve");
BasicType bt = Matcher::vector_element_basic_type(this);
@ -2773,10 +2790,11 @@ instruct vcvtFtoX_narrow_neon(vReg dst, vReg src) %{
effect(TEMP_DEF dst);
format %{ "vcvtFtoX_narrow_neon $dst, $src" %}
ins_encode %{
// 4F to 4B/4S
// 2F to 2S, 4F to 4B/4S
BasicType bt = Matcher::vector_element_basic_type(this);
uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src);
__ fcvtzs($dst$$FloatRegister, __ T4S, $src$$FloatRegister);
__ fcvtzs($dst$$FloatRegister, length_in_bytes == 16 ? __ T4S : __ T2S,
$src$$FloatRegister);
__ neon_vector_narrow($dst$$FloatRegister, bt,
$dst$$FloatRegister, T_INT, length_in_bytes);
%}
@ -2842,12 +2860,14 @@ instruct vcvtFtoX(vReg dst, vReg src) %{
// VectorCastD2X
instruct vcvtDtoI_neon(vReg dst, vReg src) %{
predicate(UseSVE == 0 && Matcher::vector_element_basic_type(n) == T_INT);
predicate(UseSVE == 0 &&
(Matcher::vector_element_basic_type(n) == T_INT ||
Matcher::vector_element_basic_type(n) == T_SHORT));
match(Set dst (VectorCastD2X src));
effect(TEMP_DEF dst);
format %{ "vcvtDtoI_neon $dst, $src\t# 2D to 2I" %}
format %{ "vcvtDtoI_neon $dst, $src\t# 2D to 2S/2I" %}
ins_encode %{
// 2D to 2I
// 2D to 2S/2I
__ ins($dst$$FloatRegister, __ D, $src$$FloatRegister, 0, 1);
// We can't use fcvtzs(vector, integer) instruction here because we need
// saturation arithmetic. See JDK-8276151.
@ -2855,6 +2875,10 @@ instruct vcvtDtoI_neon(vReg dst, vReg src) %{
__ fcvtzdw(rscratch2, $dst$$FloatRegister);
__ fmovs($dst$$FloatRegister, rscratch1);
__ mov($dst$$FloatRegister, __ S, 1, rscratch2);
if (Matcher::vector_element_basic_type(this) == T_SHORT) {
__ neon_vector_narrow($dst$$FloatRegister, T_SHORT,
$dst$$FloatRegister, T_INT, 8);
}
%}
ins_pipe(pipe_slow);
%}
@ -2928,7 +2952,7 @@ instruct vcvtHFtoF(vReg dst, vReg src) %{
ins_encode %{
uint length_in_bytes = Matcher::vector_length_in_bytes(this);
if (VM_Version::use_neon_for_vector(length_in_bytes)) {
// 4HF to 4F
// 2HF to 2F, 4HF to 4F
__ fcvtl($dst$$FloatRegister, __ T4S, $src$$FloatRegister, __ T4H);
} else {
assert(UseSVE > 0, "must be sve");
@ -2944,9 +2968,9 @@ instruct vcvtHFtoF(vReg dst, vReg src) %{
instruct vcvtFtoHF_neon(vReg dst, vReg src) %{
predicate(VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(1))));
match(Set dst (VectorCastF2HF src));
format %{ "vcvtFtoHF_neon $dst, $src\t# 4F to 4HF" %}
format %{ "vcvtFtoHF_neon $dst, $src\t# 2F/4F to 2HF/4HF" %}
ins_encode %{
// 4F to 4HF
// 2F to 2HF, 4F to 4HF
__ fcvtn($dst$$FloatRegister, __ T4H, $src$$FloatRegister, __ T4S);
%}
ins_pipe(pipe_slow);
@ -4417,14 +4441,12 @@ instruct vpopcountI(vReg dst, vReg src) %{
} else {
assert(bt == T_SHORT || bt == T_INT, "unsupported");
if (UseSVE == 0) {
assert(length_in_bytes == 8 || length_in_bytes == 16, "unsupported");
__ cnt($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
$src$$FloatRegister);
__ uaddlp($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
$dst$$FloatRegister);
assert(length_in_bytes <= 16, "unsupported");
bool isQ = length_in_bytes == 16;
__ cnt($dst$$FloatRegister, isQ ? __ T16B : __ T8B, $src$$FloatRegister);
__ uaddlp($dst$$FloatRegister, isQ ? __ T16B : __ T8B, $dst$$FloatRegister);
if (bt == T_INT) {
__ uaddlp($dst$$FloatRegister, length_in_bytes == 16 ? __ T8H : __ T4H,
$dst$$FloatRegister);
__ uaddlp($dst$$FloatRegister, isQ ? __ T8H : __ T4H, $dst$$FloatRegister);
}
} else {
__ sve_cnt($dst$$FloatRegister, __ elemType_to_regVariant(bt),
@ -4475,7 +4497,7 @@ instruct vblend_neon(vReg dst, vReg src1, vReg src2) %{
format %{ "vblend_neon $dst, $src1, $src2" %}
ins_encode %{
uint length_in_bytes = Matcher::vector_length_in_bytes(this);
assert(length_in_bytes == 8 || length_in_bytes == 16, "must be");
assert(length_in_bytes <= 16, "must be");
__ bsl($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,
$src2$$FloatRegister, $src1$$FloatRegister);
%}
@ -4851,7 +4873,7 @@ instruct vcountTrailingZeros(vReg dst, vReg src) %{
} else {
assert(bt == T_SHORT || bt == T_INT || bt == T_LONG, "unsupported type");
if (UseSVE == 0) {
assert(length_in_bytes == 8 || length_in_bytes == 16, "unsupported");
assert(length_in_bytes <= 16, "unsupported");
__ neon_reverse_bits($dst$$FloatRegister, $src$$FloatRegister,
bt, /* isQ */ length_in_bytes == 16);
if (bt != T_LONG) {
@ -4910,7 +4932,7 @@ instruct vreverse(vReg dst, vReg src) %{
} else {
assert(bt == T_SHORT || bt == T_INT || bt == T_LONG, "unsupported type");
if (UseSVE == 0) {
assert(length_in_bytes == 8 || length_in_bytes == 16, "unsupported");
assert(length_in_bytes <= 16, "unsupported");
__ neon_reverse_bits($dst$$FloatRegister, $src$$FloatRegister,
bt, /* isQ */ length_in_bytes == 16);
} else {
@ -4935,7 +4957,7 @@ instruct vreverseBytes(vReg dst, vReg src) %{
BasicType bt = Matcher::vector_element_basic_type(this);
uint length_in_bytes = Matcher::vector_length_in_bytes(this);
if (VM_Version::use_neon_for_vector(length_in_bytes)) {
assert(length_in_bytes == 8 || length_in_bytes == 16, "unsupported");
assert(length_in_bytes <= 16, "unsupported");
if (bt == T_BYTE) {
if ($dst$$FloatRegister != $src$$FloatRegister) {
__ orr($dst$$FloatRegister, length_in_bytes == 16 ? __ T16B : __ T8B,

View File

@ -1778,19 +1778,21 @@ void C2_MacroAssembler::sve_vmask_lasttrue(Register dst, BasicType bt, PRegister
void C2_MacroAssembler::neon_vector_extend(FloatRegister dst, BasicType dst_bt, unsigned dst_vlen_in_bytes,
FloatRegister src, BasicType src_bt, bool is_unsigned) {
if (src_bt == T_BYTE) {
if (dst_bt == T_SHORT) {
// 4B/8B to 4S/8S
_xshll(is_unsigned, dst, T8H, src, T8B, 0);
} else {
// 4B to 4I
assert(dst_vlen_in_bytes == 16 && dst_bt == T_INT, "unsupported");
_xshll(is_unsigned, dst, T8H, src, T8B, 0);
// 4B to 4S/4I, 8B to 8S
assert(dst_vlen_in_bytes == 8 || dst_vlen_in_bytes == 16, "unsupported");
assert(dst_bt == T_SHORT || dst_bt == T_INT, "unsupported");
_xshll(is_unsigned, dst, T8H, src, T8B, 0);
if (dst_bt == T_INT) {
_xshll(is_unsigned, dst, T4S, dst, T4H, 0);
}
} else if (src_bt == T_SHORT) {
// 4S to 4I
assert(dst_vlen_in_bytes == 16 && dst_bt == T_INT, "unsupported");
// 2S to 2I/2L, 4S to 4I
assert(dst_vlen_in_bytes == 8 || dst_vlen_in_bytes == 16, "unsupported");
assert(dst_bt == T_INT || dst_bt == T_LONG, "unsupported");
_xshll(is_unsigned, dst, T4S, src, T4H, 0);
if (dst_bt == T_LONG) {
_xshll(is_unsigned, dst, T2D, dst, T2S, 0);
}
} else if (src_bt == T_INT) {
// 2I to 2L
assert(dst_vlen_in_bytes == 16 && dst_bt == T_LONG, "unsupported");
@ -1810,18 +1812,21 @@ void C2_MacroAssembler::neon_vector_narrow(FloatRegister dst, BasicType dst_bt,
assert(dst_bt == T_BYTE, "unsupported");
xtn(dst, T8B, src, T8H);
} else if (src_bt == T_INT) {
// 4I to 4B/4S
assert(src_vlen_in_bytes == 16, "unsupported");
// 2I to 2S, 4I to 4B/4S
assert(src_vlen_in_bytes == 8 || src_vlen_in_bytes == 16, "unsupported");
assert(dst_bt == T_BYTE || dst_bt == T_SHORT, "unsupported");
xtn(dst, T4H, src, T4S);
if (dst_bt == T_BYTE) {
xtn(dst, T8B, dst, T8H);
}
} else if (src_bt == T_LONG) {
// 2L to 2I
// 2L to 2S/2I
assert(src_vlen_in_bytes == 16, "unsupported");
assert(dst_bt == T_INT, "unsupported");
assert(dst_bt == T_INT || dst_bt == T_SHORT, "unsupported");
xtn(dst, T2S, src, T2D);
if (dst_bt == T_SHORT) {
xtn(dst, T4H, dst, T4S);
}
} else {
ShouldNotReachHere();
}

View File

@ -292,7 +292,8 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm,
} else {
assert(is_phantom, "only remaining strength");
assert(!is_narrow, "phantom access cannot be narrow");
__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom));
// AOT saved adapters need relocation for this call.
__ lea(lr, RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom)));
}
__ blr(lr);
__ mov(rscratch1, r0);

View File

@ -117,7 +117,8 @@ define_pd_global(intx, InlineSmallCode, 1000);
product(ccstr, OnSpinWaitInst, "yield", DIAGNOSTIC, \
"The instruction to use to implement " \
"java.lang.Thread.onSpinWait()." \
"Options: none, nop, isb, yield, sb.") \
"Valid values are: none, nop, isb, yield, sb.") \
constraint(OnSpinWaitInstNameConstraintFunc, AtParse) \
product(uint, OnSpinWaitInstCount, 1, DIAGNOSTIC, \
"The number of OnSpinWaitInst instructions to generate." \
"It cannot be used with OnSpinWaitInst=none.") \

View File

@ -6816,6 +6816,7 @@ void MacroAssembler::spin_wait() {
yield();
break;
case SpinWait::SB:
assert(VM_Version::supports_sb(), "current CPU does not support SB instruction");
sb();
break;
default:

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright Amazon.com Inc. 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
@ -21,18 +21,32 @@
* questions.
*/
/*
* @test
* @summary run CTW for all classes from jdk.jsobject module
*
* @library /test/lib / /testlibrary/ctw/src
* @modules java.base/jdk.internal.access
* java.base/jdk.internal.jimage
* java.base/jdk.internal.misc
* java.base/jdk.internal.reflect
* @modules jdk.jsobject
*
* @build jdk.test.whitebox.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run driver/timeout=7200 sun.hotspot.tools.ctw.CtwRunner modules:jdk.jsobject
*/
#include "spin_wait_aarch64.hpp"
#include "utilities/debug.hpp"
#include <string.h>
bool SpinWait::supports(const char *name) {
return name != nullptr &&
(strcmp(name, "nop") == 0 ||
strcmp(name, "isb") == 0 ||
strcmp(name, "yield") == 0 ||
strcmp(name, "sb") == 0 ||
strcmp(name, "none") == 0);
}
SpinWait::Inst SpinWait::from_name(const char* name) {
assert(supports(name), "checked by OnSpinWaitInstNameConstraintFunc");
if (strcmp(name, "nop") == 0) {
return SpinWait::NOP;
} else if (strcmp(name, "isb") == 0) {
return SpinWait::ISB;
} else if (strcmp(name, "yield") == 0) {
return SpinWait::YIELD;
} else if (strcmp(name, "sb") == 0) {
return SpinWait::SB;
}
return SpinWait::NONE;
}

View File

@ -19,7 +19,6 @@
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_AARCH64_SPIN_WAIT_AARCH64_HPP
@ -39,11 +38,16 @@ private:
Inst _inst;
int _count;
Inst from_name(const char *name);
public:
SpinWait(Inst inst = NONE, int count = 0) : _inst(inst), _count(count) {}
SpinWait(Inst inst = NONE, int count = 0) : _inst(inst), _count(inst == NONE ? 0 : count) {}
SpinWait(const char *name, int count) : SpinWait(from_name(name), count) {}
Inst inst() const { return _inst; }
int inst_count() const { return _count; }
static bool supports(const char *name);
};
#endif // CPU_AARCH64_SPIN_WAIT_AARCH64_HPP

View File

@ -11680,8 +11680,6 @@ class StubGenerator: public StubCodeGenerator {
}
if (UseCRC32Intrinsics) {
// set table address before stub generation which use it
StubRoutines::_crc_table_adr = (address)StubRoutines::aarch64::_crc_table;
StubRoutines::_updateBytesCRC32 = generate_updateBytesCRC32();
}

View File

@ -71,6 +71,10 @@ ATTRIBUTE_ALIGNED(64) uint32_t StubRoutines::aarch64::_dilithiumConsts[] =
/**
* crc_table[] from jdk/src/share/native/java/util/zip/zlib-1.2.5/crc32.h
*/
address StubRoutines::crc_table_addr() { return (address)StubRoutines::aarch64::_crc_table; }
address StubRoutines::crc32c_table_addr() { ShouldNotCallThis(); return nullptr; }
ATTRIBUTE_ALIGNED(4096) juint StubRoutines::aarch64::_crc_table[] =
{
// Table 0

View File

@ -47,6 +47,7 @@ enum platform_dependent_constants {
class aarch64 {
friend class StubGenerator;
friend class StubRoutines;
#if INCLUDE_JVMCI
friend class JVMCIVMStructs;
#endif

View File

@ -51,26 +51,12 @@ uintptr_t VM_Version::_pac_mask;
SpinWait VM_Version::_spin_wait;
static SpinWait get_spin_wait_desc() {
if (strcmp(OnSpinWaitInst, "nop") == 0) {
return SpinWait(SpinWait::NOP, OnSpinWaitInstCount);
} else if (strcmp(OnSpinWaitInst, "isb") == 0) {
return SpinWait(SpinWait::ISB, OnSpinWaitInstCount);
} else if (strcmp(OnSpinWaitInst, "yield") == 0) {
return SpinWait(SpinWait::YIELD, OnSpinWaitInstCount);
} else if (strcmp(OnSpinWaitInst, "sb") == 0) {
if (!VM_Version::supports_sb()) {
vm_exit_during_initialization("OnSpinWaitInst is SB but current CPU does not support SB instruction");
}
return SpinWait(SpinWait::SB, OnSpinWaitInstCount);
} else if (strcmp(OnSpinWaitInst, "none") != 0) {
vm_exit_during_initialization("The options for OnSpinWaitInst are nop, isb, yield, sb, and none", OnSpinWaitInst);
SpinWait spin_wait(OnSpinWaitInst, OnSpinWaitInstCount);
if (spin_wait.inst() == SpinWait::SB && !VM_Version::supports_sb()) {
vm_exit_during_initialization("OnSpinWaitInst is SB but current CPU does not support SB instruction");
}
if (!FLAG_IS_DEFAULT(OnSpinWaitInstCount) && OnSpinWaitInstCount > 0) {
vm_exit_during_initialization("OnSpinWaitInstCount cannot be used for OnSpinWaitInst 'none'");
}
return SpinWait{};
return spin_wait;
}
void VM_Version::initialize() {

View File

@ -36,3 +36,6 @@ STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY, DEFINE_ARCH_ENTRY_INIT)
#undef DEFINE_ARCH_ENTRY_INIT
#undef DEFINE_ARCH_ENTRY
address StubRoutines::crc_table_addr() { ShouldNotCallThis(); return nullptr; }
address StubRoutines::crc32c_table_addr() { ShouldNotCallThis(); return nullptr; }

View File

@ -4982,13 +4982,11 @@ void generate_lookup_secondary_supers_table_stub() {
// CRC32 Intrinsics.
if (UseCRC32Intrinsics) {
StubRoutines::_crc_table_adr = StubRoutines::ppc::generate_crc_constants(REVERSE_CRC32_POLY);
StubRoutines::_updateBytesCRC32 = generate_CRC32_updateBytes(StubId::stubgen_updateBytesCRC32_id);
}
// CRC32C Intrinsics.
if (UseCRC32CIntrinsics) {
StubRoutines::_crc32c_table_addr = StubRoutines::ppc::generate_crc_constants(REVERSE_CRC32C_POLY);
StubRoutines::_updateBytesCRC32C = generate_CRC32_updateBytes(StubId::stubgen_updateBytesCRC32C_id);
}

View File

@ -54,6 +54,7 @@ enum platform_dependent_constants {
class ppc {
friend class StubGenerator;
friend class StubRoutines;
private:
public:

View File

@ -74,6 +74,22 @@ static julong compute_inverse_poly(julong long_poly) {
return div;
}
static address _crc_table_addr = nullptr;
static address _crc32c_table_addr = nullptr;
address StubRoutines::crc_table_addr() {
if (_crc_table_addr == nullptr) {
_crc_table_addr = StubRoutines::ppc::generate_crc_constants(REVERSE_CRC32_POLY);
}
return _crc_table_addr;
}
address StubRoutines::crc32c_table_addr() {
if (_crc32c_table_addr == nullptr) {
_crc32c_table_addr = StubRoutines::ppc::generate_crc_constants(REVERSE_CRC32C_POLY);
}
return _crc32c_table_addr;
}
// Constants to fold n words as needed by macroAssembler.
address StubRoutines::ppc::generate_crc_constants(juint reverse_poly) {
// Layout of constant table:

View File

@ -772,7 +772,7 @@ void LIRGenerator::do_ArrayCopy(Intrinsic* x) {
ciArrayKlass* expected_type = nullptr;
arraycopy_helper(x, &flags, &expected_type);
if (x->check_flag(Instruction::OmitChecksFlag)) {
flags = 0;
flags = (flags & LIR_OpArrayCopy::get_initial_copy_flags());
}
__ arraycopy(src.result(), src_pos.result(), dst.result(), dst_pos.result(), length.result(), tmp,

View File

@ -1952,16 +1952,15 @@ void C2_MacroAssembler::arrays_hashcode(Register ary, Register cnt, Register res
mv(pow31_3, 29791); // [31^^3]
mv(pow31_2, 961); // [31^^2]
slli(chunks_end, chunks, chunks_end_shift);
add(chunks_end, ary, chunks_end);
shadd(chunks_end, chunks, ary, t0, chunks_end_shift);
andi(cnt, cnt, stride - 1); // don't forget about tail!
bind(WIDE_LOOP);
mulw(result, result, pow31_4); // 31^^4 * h
arrays_hashcode_elload(t0, Address(ary, 0 * elsize), eltype);
arrays_hashcode_elload(t1, Address(ary, 1 * elsize), eltype);
arrays_hashcode_elload(tmp5, Address(ary, 2 * elsize), eltype);
arrays_hashcode_elload(tmp6, Address(ary, 3 * elsize), eltype);
mulw(result, result, pow31_4); // 31^^4 * h
mulw(t0, t0, pow31_3); // 31^^3 * ary[i+0]
addw(result, result, t0);
mulw(t1, t1, pow31_2); // 31^^2 * ary[i+1]
@ -1976,8 +1975,7 @@ void C2_MacroAssembler::arrays_hashcode(Register ary, Register cnt, Register res
beqz(cnt, DONE);
bind(TAIL);
slli(chunks_end, cnt, chunks_end_shift);
add(chunks_end, ary, chunks_end);
shadd(chunks_end, cnt, ary, t0, chunks_end_shift);
bind(TAIL_LOOP);
arrays_hashcode_elload(t0, Address(ary), eltype);

View File

@ -2276,10 +2276,6 @@ encode %{
__ mv(dst_reg, 1);
%}
enc_class riscv_enc_mov_byte_map_base(iRegP dst) %{
__ load_byte_map_base($dst$$Register);
%}
enc_class riscv_enc_mov_n(iRegN dst, immN src) %{
Register dst_reg = as_Register($dst$$reg);
address con = (address)$src$$constant;
@ -2834,21 +2830,6 @@ operand immP_1()
interface(CONST_INTER);
%}
// Card Table Byte Map Base
operand immByteMapBase()
%{
// Get base of card map
predicate(BarrierSet::barrier_set()->is_a(BarrierSet::CardTableBarrierSet) &&
SHENANDOAHGC_ONLY(!BarrierSet::barrier_set()->is_a(BarrierSet::ShenandoahBarrierSet) &&)
(CardTable::CardValue*)n->get_ptr() ==
((CardTableBarrierSet*)(BarrierSet::barrier_set()))->card_table()->byte_map_base());
match(ConP);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Int Immediate: low 16-bit mask
operand immI_16bits()
%{
@ -4808,18 +4789,6 @@ instruct loadConP1(iRegPNoSp dst, immP_1 con)
ins_pipe(ialu_imm);
%}
// Load Byte Map Base Constant
instruct loadByteMapBase(iRegPNoSp dst, immByteMapBase con)
%{
match(Set dst con);
ins_cost(ALU_COST);
format %{ "mv $dst, $con\t# Byte Map Base, #@loadByteMapBase" %}
ins_encode(riscv_enc_mov_byte_map_base(dst));
ins_pipe(ialu_imm);
%}
// Load Narrow Pointer Constant
instruct loadConN(iRegNNoSp dst, immN con)
%{

View File

@ -6686,8 +6686,6 @@ static const int64_t right_3_bits = right_n_bits(3);
StubRoutines::_catch_exception_entry = generate_catch_exception();
if (UseCRC32Intrinsics) {
// set table address before stub generation which use it
StubRoutines::_crc_table_adr = (address)StubRoutines::riscv::_crc_table;
StubRoutines::_updateBytesCRC32 = generate_updateBytesCRC32();
}

View File

@ -52,6 +52,10 @@ bool StubRoutines::riscv::_completed = false;
/**
* crc_table[] from jdk/src/java.base/share/native/libzip/zlib/crc32.h
*/
address StubRoutines::crc_table_addr() { return (address)StubRoutines::riscv::_crc_table; }
address StubRoutines::crc32c_table_addr() { ShouldNotCallThis(); return nullptr; }
ATTRIBUTE_ALIGNED(4096) juint StubRoutines::riscv::_crc_table[] =
{
// Table 0

View File

@ -48,6 +48,7 @@ enum platform_dependent_constants {
class riscv {
friend class StubGenerator;
friend class StubRoutines;
#if INCLUDE_JVMCI
friend class JVMCIVMStructs;
#endif

View File

@ -3308,12 +3308,10 @@ class StubGenerator: public StubCodeGenerator {
}
if (UseCRC32Intrinsics) {
StubRoutines::_crc_table_adr = (address)StubRoutines::zarch::_crc_table;
StubRoutines::_updateBytesCRC32 = generate_CRC32_updateBytes();
}
if (UseCRC32CIntrinsics) {
StubRoutines::_crc32c_table_addr = (address)StubRoutines::zarch::_crc32c_table;
StubRoutines::_updateBytesCRC32C = generate_CRC32C_updateBytes();
}

View File

@ -78,14 +78,17 @@ void StubRoutines::zarch::generate_load_absolute_address(MacroAssembler* masm, R
#endif
}
address StubRoutines::crc_table_addr() { return (address)StubRoutines::zarch::_crc_table; }
address StubRoutines::crc32c_table_addr() { return (address)StubRoutines::zarch::_crc32c_table; }
void StubRoutines::zarch::generate_load_crc_table_addr(MacroAssembler* masm, Register table) {
const uint64_t table_contents = 0x77073096UL; // required contents of table[1]
generate_load_absolute_address(masm, table, StubRoutines::_crc_table_adr, table_contents);
generate_load_absolute_address(masm, table, StubRoutines::crc_table_addr(), table_contents);
}
void StubRoutines::zarch::generate_load_crc32c_table_addr(MacroAssembler* masm, Register table) {
const uint64_t table_contents = 0xf26b8303UL; // required contents of table[1]
generate_load_absolute_address(masm, table, StubRoutines::_crc32c_table_addr, table_contents);
generate_load_absolute_address(masm, table, StubRoutines::crc32c_table_addr(), table_contents);
}

View File

@ -62,6 +62,7 @@ enum method_handles_platform_dependent_constants {
class zarch {
friend class StubGenerator;
friend class StubRoutines;
public:
enum { nof_instance_allocators = 10 };

View File

@ -306,10 +306,10 @@ void PatchingStub::emit_code(LIR_Assembler* ce) {
}
assert(_obj != noreg, "must be a valid register");
Register tmp = rax;
__ push(tmp);
__ push_ppx(tmp);
__ movptr(tmp, Address(_obj, java_lang_Class::klass_offset()));
__ cmpptr(r15_thread, Address(tmp, InstanceKlass::init_thread_offset()));
__ pop(tmp); // pop it right away, no matter which path we take
__ pop_ppx(tmp); // pop it right away, no matter which path we take
__ jccb(Assembler::notEqual, call_patch);
// access_field patches may execute the patched code before it's

View File

@ -1385,11 +1385,11 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L
__ cmpptr(klass_RInfo, k_RInfo);
__ jcc(Assembler::equal, *success_target);
__ push(klass_RInfo);
__ push(k_RInfo);
__ push_ppx(klass_RInfo);
__ push_ppx(k_RInfo);
__ call(RuntimeAddress(Runtime1::entry_for(StubId::c1_slow_subtype_check_id)));
__ pop(klass_RInfo);
__ pop(klass_RInfo);
__ pop_ppx(klass_RInfo);
__ pop_ppx(klass_RInfo);
// result is a boolean
__ testl(klass_RInfo, klass_RInfo);
__ jcc(Assembler::equal, *failure_target);
@ -1399,11 +1399,11 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L
// perform the fast part of the checking logic
__ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, success_target, failure_target, nullptr);
// call out-of-line instance of __ check_klass_subtype_slow_path(...):
__ push(klass_RInfo);
__ push(k_RInfo);
__ push_ppx(klass_RInfo);
__ push_ppx(k_RInfo);
__ call(RuntimeAddress(Runtime1::entry_for(StubId::c1_slow_subtype_check_id)));
__ pop(klass_RInfo);
__ pop(k_RInfo);
__ pop_ppx(klass_RInfo);
__ pop_ppx(k_RInfo);
// result is a boolean
__ testl(k_RInfo, k_RInfo);
__ jcc(Assembler::equal, *failure_target);
@ -1478,11 +1478,11 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
// perform the fast part of the checking logic
__ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, success_target, failure_target, nullptr);
// call out-of-line instance of __ check_klass_subtype_slow_path(...):
__ push(klass_RInfo);
__ push(k_RInfo);
__ push_ppx(klass_RInfo);
__ push_ppx(k_RInfo);
__ call(RuntimeAddress(Runtime1::entry_for(StubId::c1_slow_subtype_check_id)));
__ pop(klass_RInfo);
__ pop(k_RInfo);
__ pop_ppx(klass_RInfo);
__ pop_ppx(k_RInfo);
// result is a boolean
__ testl(k_RInfo, k_RInfo);
__ jcc(Assembler::equal, *failure_target);
@ -2536,26 +2536,26 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
// safely do the copy.
Label cont, slow;
__ push(src);
__ push(dst);
__ push_ppx(src);
__ push_ppx(dst);
__ load_klass(src, src, tmp_load_klass);
__ load_klass(dst, dst, tmp_load_klass);
__ check_klass_subtype_fast_path(src, dst, tmp, &cont, &slow, nullptr);
__ push(src);
__ push(dst);
__ push_ppx(src);
__ push_ppx(dst);
__ call(RuntimeAddress(Runtime1::entry_for(StubId::c1_slow_subtype_check_id)));
__ pop(dst);
__ pop(src);
__ pop_ppx(dst);
__ pop_ppx(src);
__ testl(src, src);
__ jcc(Assembler::notEqual, cont);
__ bind(slow);
__ pop(dst);
__ pop(src);
__ pop_ppx(dst);
__ pop_ppx(src);
address copyfunc_addr = StubRoutines::checkcast_arraycopy();
if (copyfunc_addr != nullptr) { // use stub if available
@ -2904,13 +2904,13 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
if (exact_klass != nullptr) {
Label ok;
__ load_klass(tmp, obj, tmp_load_klass);
__ push(tmp);
__ push_ppx(tmp);
__ mov_metadata(tmp, exact_klass->constant_encoding());
__ cmpptr(tmp, Address(rsp, 0));
__ jcc(Assembler::equal, ok);
__ stop("exact klass and actual klass differ");
__ bind(ok);
__ pop(tmp);
__ pop_ppx(tmp);
}
#endif
if (!no_conflict) {
@ -2975,7 +2975,7 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
{
Label ok;
__ push(tmp);
__ push_ppx(tmp);
__ testptr(mdo_addr, TypeEntries::type_mask);
__ jcc(Assembler::zero, ok);
// may have been set by another thread
@ -2986,7 +2986,7 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
__ stop("unexpected profiling mismatch");
__ bind(ok);
__ pop(tmp);
__ pop_ppx(tmp);
}
#else
__ jccb(Assembler::zero, next);

View File

@ -719,7 +719,7 @@ OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) {
// verify callee-saved register
#ifdef ASSERT
guarantee(thread != rax, "change this code");
__ push(rax);
__ push_ppx(rax);
{ Label L;
__ get_thread_slow(rax);
__ cmpptr(thread, rax);
@ -727,7 +727,7 @@ OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) {
__ stop("StubAssembler::call_RT: rdi/r15 not callee saved?");
__ bind(L);
}
__ pop(rax);
__ pop_ppx(rax);
#endif
__ reset_last_Java_frame(true);
@ -1070,10 +1070,10 @@ OopMapSet* Runtime1::generate_code_for(StubId id, StubAssembler* sasm) {
};
__ set_info("slow_subtype_check", dont_gc_arguments);
__ push(rdi);
__ push(rsi);
__ push(rcx);
__ push(rax);
__ push_ppx(rdi);
__ push_ppx(rsi);
__ push_ppx(rcx);
__ push_ppx(rax);
// This is called by pushing args and not with C abi
__ movptr(rsi, Address(rsp, (klass_off) * VMRegImpl::stack_slot_size)); // subclass
@ -1084,10 +1084,10 @@ OopMapSet* Runtime1::generate_code_for(StubId id, StubAssembler* sasm) {
// fallthrough on success:
__ movptr(Address(rsp, (result_off) * VMRegImpl::stack_slot_size), 1); // result
__ pop(rax);
__ pop(rcx);
__ pop(rsi);
__ pop(rdi);
__ pop_ppx(rax);
__ pop_ppx(rcx);
__ pop_ppx(rsi);
__ pop_ppx(rdi);
__ ret(0);
__ bind(miss);

View File

@ -352,8 +352,8 @@ static void generate_string_indexof_stubs(StubGenerator *stubgen, address *fnptr
__ movdq(save_r15, r15);
__ movdq(save_rbx, rbx);
#ifdef _WIN64
__ push(rsi);
__ push(rdi);
__ push_ppx(rsi);
__ push_ppx(rdi);
// Move to Linux-style ABI
__ movq(rdi, rcx);
@ -368,7 +368,7 @@ static void generate_string_indexof_stubs(StubGenerator *stubgen, address *fnptr
const Register needle_len = rcx;
const Register save_ndl_len = r12;
__ push(rbp);
__ push_ppx(rbp);
__ subptr(rsp, STACK_SPACE);
if (isReallyUL) {
@ -459,10 +459,10 @@ static void generate_string_indexof_stubs(StubGenerator *stubgen, address *fnptr
// Restore stack, vzeroupper and return
__ bind(L_return);
__ addptr(rsp, STACK_SPACE);
__ pop(rbp);
__ pop_ppx(rbp);
#ifdef _WIN64
__ pop(rdi);
__ pop(rsi);
__ pop_ppx(rdi);
__ pop_ppx(rsi);
#endif
__ movdq(r12, save_r12);
__ movdq(r13, save_r13);

View File

@ -500,8 +500,8 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler*
__ prologue("g1_pre_barrier", false);
// arg0 : previous value of memory
__ push(rax);
__ push(rdx);
__ push_ppx(rax);
__ push_ppx(rdx);
const Register pre_val = rax;
const Register thread = r15_thread;
@ -549,8 +549,8 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler*
__ bind(done);
__ pop(rdx);
__ pop(rax);
__ pop_ppx(rdx);
__ pop_ppx(rax);
__ epilogue();
}
@ -573,8 +573,8 @@ void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler*
Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
__ push(rax);
__ push(rcx);
__ push_ppx(rax);
__ push_ppx(rcx);
const Register cardtable = rax;
const Register card_addr = rcx;
@ -599,7 +599,7 @@ void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler*
__ movb(Address(card_addr, 0), CardTable::dirty_card_val());
const Register tmp = rdx;
__ push(rdx);
__ push_ppx(rdx);
__ movptr(tmp, queue_index);
__ testptr(tmp, tmp);
@ -618,11 +618,11 @@ void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler*
__ pop_call_clobbered_registers();
__ bind(enqueued);
__ pop(rdx);
__ pop_ppx(rdx);
__ bind(done);
__ pop(rcx);
__ pop(rax);
__ pop_ppx(rcx);
__ pop_ppx(rax);
__ epilogue();
}

View File

@ -288,7 +288,7 @@ void ZBarrierSetAssembler::load_at(MacroAssembler* masm,
Register scratch = tmp1;
if (tmp1 == noreg) {
scratch = r12;
__ push(scratch);
__ push_ppx(scratch);
}
assert_different_registers(dst, scratch);
@ -348,7 +348,7 @@ void ZBarrierSetAssembler::load_at(MacroAssembler* masm,
// Restore scratch register
if (tmp1 == noreg) {
__ pop(scratch);
__ pop_ppx(scratch);
}
BLOCK_COMMENT("} ZBarrierSetAssembler::load_at");
@ -462,10 +462,10 @@ void ZBarrierSetAssembler::store_barrier_fast(MacroAssembler* masm,
__ movptr(rnew_zpointer, rnew_zaddress);
}
assert_different_registers(rcx, rnew_zpointer);
__ push(rcx);
__ push_ppx(rcx);
__ movptr(rcx, ExternalAddress((address)&ZPointerLoadShift));
__ shlq(rnew_zpointer);
__ pop(rcx);
__ pop_ppx(rcx);
__ orq(rnew_zpointer, Address(r15_thread, ZThreadLocalData::store_good_mask_offset()));
}
}
@ -483,7 +483,7 @@ static void store_barrier_buffer_add(MacroAssembler* masm,
__ jcc(Assembler::equal, slow_path);
Register tmp2 = r15_thread;
__ push(tmp2);
__ push_ppx(tmp2);
// Bump the pointer
__ movq(tmp2, Address(tmp1, ZStoreBarrierBuffer::current_offset()));
@ -501,7 +501,7 @@ static void store_barrier_buffer_add(MacroAssembler* masm,
__ movptr(tmp1, Address(tmp1, 0));
__ movptr(Address(tmp2, in_bytes(ZStoreBarrierEntry::prev_offset())), tmp1);
__ pop(tmp2);
__ pop_ppx(tmp2);
}
void ZBarrierSetAssembler::store_barrier_medium(MacroAssembler* masm,
@ -528,9 +528,9 @@ void ZBarrierSetAssembler::store_barrier_medium(MacroAssembler* masm,
// If we get this far, we know there is a young raw null value in the field.
// Try to self-heal null values for atomic accesses
__ push(rax);
__ push(rbx);
__ push(rcx);
__ push_ppx(rax);
__ push_ppx(rbx);
__ push_ppx(rcx);
__ lea(rcx, ref_addr);
__ xorq(rax, rax);
@ -539,9 +539,9 @@ void ZBarrierSetAssembler::store_barrier_medium(MacroAssembler* masm,
__ lock();
__ cmpxchgq(rbx, Address(rcx, 0));
__ pop(rcx);
__ pop(rbx);
__ pop(rax);
__ pop_ppx(rcx);
__ pop_ppx(rbx);
__ pop_ppx(rax);
__ jcc(Assembler::notEqual, slow_path);
@ -583,10 +583,10 @@ void ZBarrierSetAssembler::store_at(MacroAssembler* masm,
} else {
__ movptr(tmp1, src);
}
__ push(rcx);
__ push_ppx(rcx);
__ movptr(rcx, ExternalAddress((address)&ZPointerLoadShift));
__ shlq(tmp1);
__ pop(rcx);
__ pop_ppx(rcx);
__ orq(tmp1, Address(r15_thread, ZThreadLocalData::store_good_mask_offset()));
} else {
Label done;
@ -1007,10 +1007,10 @@ void ZBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm,
__ shrq(tmp);
__ movptr(obj, tmp);
} else {
__ push(rcx);
__ push_ppx(rcx);
__ movptr(rcx, ExternalAddress((address)&ZPointerLoadShift));
__ shrq(obj);
__ pop(rcx);
__ pop_ppx(rcx);
}
__ bind(done);
@ -1089,7 +1089,7 @@ void ZBarrierSetAssembler::generate_c1_load_barrier_stub(LIR_Assembler* ce,
// Save rax unless it is the result or tmp register
if (ref != rax && tmp != rax) {
__ push(rax);
__ push_ppx(rax);
}
// Setup arguments and call runtime stub
@ -1109,7 +1109,7 @@ void ZBarrierSetAssembler::generate_c1_load_barrier_stub(LIR_Assembler* ce,
// Restore rax unless it is the result or tmp register
if (ref != rax && tmp != rax) {
__ pop(rax);
__ pop_ppx(rax);
}
// Stub exit
@ -1451,12 +1451,12 @@ void ZBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Registe
// Uncolor presumed zpointer
assert(obj != rcx, "bad choice of register");
if (rcx != tmp1 && rcx != tmp2) {
__ push(rcx);
__ push_ppx(rcx);
}
__ movl(rcx, Address(tmp2, tmp1, Address::times_4, 0));
__ shrq(obj);
if (rcx != tmp1 && rcx != tmp2) {
__ pop(rcx);
__ pop_ppx(rcx);
}
__ jmp(check_zaddress);

View File

@ -41,16 +41,16 @@ void x86_generate_icache_fence(MacroAssembler* _masm) {
__ sfence();
break;
case 4:
__ push(rax);
__ push(rbx);
__ push(rcx);
__ push(rdx);
__ push_ppx(rax);
__ push_ppx(rbx);
__ push_ppx(rcx);
__ push_ppx(rdx);
__ xorptr(rax, rax);
__ cpuid();
__ pop(rdx);
__ pop(rcx);
__ pop(rbx);
__ pop(rax);
__ pop_ppx(rdx);
__ pop_ppx(rcx);
__ pop_ppx(rbx);
__ pop_ppx(rax);
break;
case 5:
__ serialize();

View File

@ -795,6 +795,22 @@ void MacroAssembler::pop_d(XMMRegister r) {
addptr(rsp, 2 * Interpreter::stackElementSize);
}
void MacroAssembler::push_ppx(Register src) {
if (VM_Version::supports_apx_f()) {
pushp(src);
} else {
Assembler::push(src);
}
}
void MacroAssembler::pop_ppx(Register dst) {
if (VM_Version::supports_apx_f()) {
popp(dst);
} else {
Assembler::pop(dst);
}
}
void MacroAssembler::andpd(XMMRegister dst, AddressLiteral src, Register rscratch) {
// Used in sign-masking with aligned address.
assert((UseAVX > 0) || (((intptr_t)src.target() & 15) == 0), "SSE mode requires address alignment 16 bytes");

View File

@ -989,6 +989,9 @@ public:
void push_d(XMMRegister r);
void pop_d(XMMRegister r);
void push_ppx(Register src);
void pop_ppx(Register dst);
void andpd(XMMRegister dst, XMMRegister src) { Assembler::andpd(dst, src); }
void andpd(XMMRegister dst, Address src) { Assembler::andpd(dst, src); }
void andpd(XMMRegister dst, AddressLiteral src, Register rscratch = noreg);

View File

@ -131,7 +131,7 @@ void MethodHandles::verify_method(MacroAssembler* _masm, Register method, Regist
const Register method_holder = temp;
__ load_method_holder(method_holder, method);
__ push(method_holder); // keep holder around for diagnostic purposes
__ push_ppx(method_holder); // keep holder around for diagnostic purposes
switch (iid) {
case vmIntrinsicID::_invokeBasic:
@ -165,7 +165,7 @@ void MethodHandles::verify_method(MacroAssembler* _masm, Register method, Regist
__ STOP("Method holder klass is not initialized");
__ BIND(L_ok);
__ pop(method_holder); // restore stack layout
__ pop_ppx(method_holder); // restore stack layout
}
BLOCK_COMMENT("} verify_method");
}

View File

@ -292,7 +292,7 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() {
address start = __ pc();
// Exception pc is 'return address' for stack walker
__ push(rdx);
__ push_ppx(rdx);
__ subptr(rsp, SimpleRuntimeFrame::return_off << LogBytesPerInt); // Prolog
// Save callee-saved registers. See x86_64.ad.
@ -347,7 +347,7 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() {
__ movptr(rbp, Address(rsp, SimpleRuntimeFrame::rbp_off << LogBytesPerInt));
__ addptr(rsp, SimpleRuntimeFrame::return_off << LogBytesPerInt); // Epilog
__ pop(rdx); // No need for exception pc anymore
__ pop_ppx(rdx); // No need for exception pc anymore
// rax: exception handler

View File

@ -574,7 +574,7 @@ address StubGenerator::generate_verify_mxcsr() {
if (CheckJNICalls) {
Label ok_ret;
ExternalAddress mxcsr_std(StubRoutines::x86::addr_mxcsr_std());
__ push(rax);
__ push_ppx(rax);
__ subptr(rsp, wordSize); // allocate a temp location
__ cmp32_mxcsr_std(mxcsr_save, rax, rscratch1);
__ jcc(Assembler::equal, ok_ret);
@ -585,7 +585,7 @@ address StubGenerator::generate_verify_mxcsr() {
__ bind(ok_ret);
__ addptr(rsp, wordSize);
__ pop(rax);
__ pop_ppx(rax);
}
__ ret(0);
@ -602,10 +602,10 @@ address StubGenerator::generate_f2i_fixup() {
Label L;
__ push(rax);
__ push(c_rarg3);
__ push(c_rarg2);
__ push(c_rarg1);
__ push_ppx(rax);
__ push_ppx(c_rarg3);
__ push_ppx(c_rarg2);
__ push_ppx(c_rarg1);
__ movl(rax, 0x7f800000);
__ xorl(c_rarg3, c_rarg3);
@ -622,10 +622,10 @@ address StubGenerator::generate_f2i_fixup() {
__ bind(L);
__ movptr(inout, c_rarg3);
__ pop(c_rarg1);
__ pop(c_rarg2);
__ pop(c_rarg3);
__ pop(rax);
__ pop_ppx(c_rarg1);
__ pop_ppx(c_rarg2);
__ pop_ppx(c_rarg3);
__ pop_ppx(rax);
__ ret(0);
@ -640,10 +640,10 @@ address StubGenerator::generate_f2l_fixup() {
Label L;
__ push(rax);
__ push(c_rarg3);
__ push(c_rarg2);
__ push(c_rarg1);
__ push_ppx(rax);
__ push_ppx(c_rarg3);
__ push_ppx(c_rarg2);
__ push_ppx(c_rarg1);
__ movl(rax, 0x7f800000);
__ xorl(c_rarg3, c_rarg3);
@ -660,10 +660,10 @@ address StubGenerator::generate_f2l_fixup() {
__ bind(L);
__ movptr(inout, c_rarg3);
__ pop(c_rarg1);
__ pop(c_rarg2);
__ pop(c_rarg3);
__ pop(rax);
__ pop_ppx(c_rarg1);
__ pop_ppx(c_rarg2);
__ pop_ppx(c_rarg3);
__ pop_ppx(rax);
__ ret(0);
@ -679,11 +679,11 @@ address StubGenerator::generate_d2i_fixup() {
Label L;
__ push(rax);
__ push(c_rarg3);
__ push(c_rarg2);
__ push(c_rarg1);
__ push(c_rarg0);
__ push_ppx(rax);
__ push_ppx(c_rarg3);
__ push_ppx(c_rarg2);
__ push_ppx(c_rarg1);
__ push_ppx(c_rarg0);
__ movl(rax, 0x7ff00000);
__ movq(c_rarg2, inout);
@ -707,11 +707,11 @@ address StubGenerator::generate_d2i_fixup() {
__ bind(L);
__ movptr(inout, c_rarg2);
__ pop(c_rarg0);
__ pop(c_rarg1);
__ pop(c_rarg2);
__ pop(c_rarg3);
__ pop(rax);
__ pop_ppx(c_rarg0);
__ pop_ppx(c_rarg1);
__ pop_ppx(c_rarg2);
__ pop_ppx(c_rarg3);
__ pop_ppx(rax);
__ ret(0);
@ -727,11 +727,11 @@ address StubGenerator::generate_d2l_fixup() {
Label L;
__ push(rax);
__ push(c_rarg3);
__ push(c_rarg2);
__ push(c_rarg1);
__ push(c_rarg0);
__ push_ppx(rax);
__ push_ppx(c_rarg3);
__ push_ppx(c_rarg2);
__ push_ppx(c_rarg1);
__ push_ppx(c_rarg0);
__ movl(rax, 0x7ff00000);
__ movq(c_rarg2, inout);
@ -755,11 +755,11 @@ address StubGenerator::generate_d2l_fixup() {
__ bind(L);
__ movq(inout, c_rarg2);
__ pop(c_rarg0);
__ pop(c_rarg1);
__ pop(c_rarg2);
__ pop(c_rarg3);
__ pop(rax);
__ pop_ppx(c_rarg0);
__ pop_ppx(c_rarg1);
__ pop_ppx(c_rarg2);
__ pop_ppx(c_rarg3);
__ pop_ppx(rax);
__ ret(0);
@ -1180,11 +1180,11 @@ address StubGenerator::generate_verify_oop() {
__ pushf();
__ incrementl(ExternalAddress((address) StubRoutines::verify_oop_count_addr()), rscratch1);
__ push(r12);
__ push_ppx(r12);
// save c_rarg2 and c_rarg3
__ push(c_rarg2);
__ push(c_rarg3);
__ push_ppx(c_rarg2);
__ push_ppx(c_rarg3);
enum {
// After previous pushes.
@ -1211,9 +1211,9 @@ address StubGenerator::generate_verify_oop() {
__ bind(exit);
__ movptr(rax, Address(rsp, saved_rax)); // get saved rax back
__ movptr(rscratch1, Address(rsp, saved_r10)); // get saved r10 back
__ pop(c_rarg3); // restore c_rarg3
__ pop(c_rarg2); // restore c_rarg2
__ pop(r12); // restore r12
__ pop_ppx(c_rarg3); // restore c_rarg3
__ pop_ppx(c_rarg2); // restore c_rarg2
__ pop_ppx(r12); // restore r12
__ popf(); // restore flags
__ ret(4 * wordSize); // pop caller saved stuff
@ -1221,9 +1221,9 @@ address StubGenerator::generate_verify_oop() {
__ bind(error);
__ movptr(rax, Address(rsp, saved_rax)); // get saved rax back
__ movptr(rscratch1, Address(rsp, saved_r10)); // get saved r10 back
__ pop(c_rarg3); // get saved c_rarg3 back
__ pop(c_rarg2); // get saved c_rarg2 back
__ pop(r12); // get saved r12 back
__ pop_ppx(c_rarg3); // get saved c_rarg3 back
__ pop_ppx(c_rarg2); // get saved c_rarg2 back
__ pop_ppx(r12); // get saved r12 back
__ popf(); // get saved flags off stack --
// will be ignored
@ -1431,10 +1431,10 @@ address StubGenerator::generate_md5_implCompress(StubId stub_id) {
const Address limit_param(rsp, 1 * wordSize + 4);
__ enter();
__ push(rbx);
__ push(rdi);
__ push(rsi);
__ push(r15);
__ push_ppx(rbx);
__ push_ppx(rdi);
__ push_ppx(rsi);
__ push_ppx(r15);
__ subptr(rsp, 2 * wordSize);
__ movptr(buf_param, c_rarg0);
@ -1446,10 +1446,10 @@ address StubGenerator::generate_md5_implCompress(StubId stub_id) {
__ fast_md5(buf_param, state_param, ofs_param, limit_param, multi_block);
__ addptr(rsp, 2 * wordSize);
__ pop(r15);
__ pop(rsi);
__ pop(rdi);
__ pop(rbx);
__ pop_ppx(r15);
__ pop_ppx(rsi);
__ pop_ppx(rdi);
__ pop_ppx(rbx);
__ leave();
__ ret(0);
@ -1790,10 +1790,10 @@ address StubGenerator::generate_base64_encodeBlock()
__ enter();
// Save callee-saved registers before using them
__ push(r12);
__ push(r13);
__ push(r14);
__ push(r15);
__ push_ppx(r12);
__ push_ppx(r13);
__ push_ppx(r14);
__ push_ppx(r15);
// arguments
const Register source = c_rarg0; // Source Array
@ -2153,10 +2153,10 @@ address StubGenerator::generate_base64_encodeBlock()
__ jcc(Assembler::aboveEqual, L_processdata);
__ BIND(L_exit);
__ pop(r15);
__ pop(r14);
__ pop(r13);
__ pop(r12);
__ pop_ppx(r15);
__ pop_ppx(r14);
__ pop_ppx(r13);
__ pop_ppx(r12);
__ leave();
__ ret(0);
@ -2490,11 +2490,11 @@ address StubGenerator::generate_base64_decodeBlock() {
__ enter();
// Save callee-saved registers before using them
__ push(r12);
__ push(r13);
__ push(r14);
__ push(r15);
__ push(rbx);
__ push_ppx(r12);
__ push_ppx(r13);
__ push_ppx(r14);
__ push_ppx(r15);
__ push_ppx(rbx);
// arguments
const Register source = c_rarg0; // Source Array
@ -2562,7 +2562,7 @@ address StubGenerator::generate_base64_decodeBlock() {
// calculate length from offsets
__ movl(length, end_offset);
__ subl(length, start_offset);
__ push(dest); // Save for return value calc
__ push_ppx(dest); // Save for return value calc
// If AVX512 VBMI not supported, just compile non-AVX code
if(VM_Version::supports_avx512_vbmi() &&
@ -2793,14 +2793,14 @@ address StubGenerator::generate_base64_decodeBlock() {
__ BIND(L_exit);
__ vzeroupper();
__ pop(rax); // Get original dest value
__ pop_ppx(rax); // Get original dest value
__ subptr(dest, rax); // Number of bytes converted
__ movptr(rax, dest);
__ pop(rbx);
__ pop(r15);
__ pop(r14);
__ pop(r13);
__ pop(r12);
__ pop_ppx(rbx);
__ pop_ppx(r15);
__ pop_ppx(r14);
__ pop_ppx(r13);
__ pop_ppx(r12);
__ leave();
__ ret(0);
@ -2987,14 +2987,14 @@ address StubGenerator::generate_base64_decodeBlock() {
__ jcc(Assembler::positive, L_forceLoop);
__ BIND(L_exit_no_vzero);
__ pop(rax); // Get original dest value
__ subptr(dest, rax); // Number of bytes converted
__ pop_ppx(rax); // Get original dest value
__ subptr(dest, rax); // Number of bytes converted
__ movptr(rax, dest);
__ pop(rbx);
__ pop(r15);
__ pop(r14);
__ pop(r13);
__ pop(r12);
__ pop_ppx(rbx);
__ pop_ppx(r15);
__ pop_ppx(r14);
__ pop_ppx(r13);
__ pop_ppx(r12);
__ leave();
__ ret(0);
@ -3117,8 +3117,8 @@ address StubGenerator::generate_updateBytesCRC32C(bool is_pclmulqdq_supported) {
__ bind(L_doSmall);
}
#ifdef _WIN64
__ push(y);
__ push(z);
__ push_ppx(y);
__ push_ppx(z);
#endif
__ crc32c_ipl_alg2_alt2(crc, buf, len,
a, j, k,
@ -3126,8 +3126,8 @@ address StubGenerator::generate_updateBytesCRC32C(bool is_pclmulqdq_supported) {
c_farg0, c_farg1, c_farg2,
is_pclmulqdq_supported);
#ifdef _WIN64
__ pop(z);
__ pop(y);
__ pop_ppx(z);
__ pop_ppx(y);
#endif
__ bind(L_continue);
@ -3313,7 +3313,7 @@ address StubGenerator::generate_method_entry_barrier() {
// save c_rarg0, because we want to use that value.
// We could do without it but then we depend on the number of slots used by pusha
__ push(c_rarg0);
__ push_ppx(c_rarg0);
__ lea(c_rarg0, Address(rsp, wordSize * 3)); // 1 for cookie, 1 for rbp, 1 for c_rarg0 - this should be the return address
@ -3350,7 +3350,7 @@ address StubGenerator::generate_method_entry_barrier() {
__ jcc(Assembler::equal, deoptimize_label);
__ popa();
__ pop(c_rarg0);
__ pop_ppx(c_rarg0);
__ leave();
@ -3361,7 +3361,7 @@ address StubGenerator::generate_method_entry_barrier() {
__ BIND(deoptimize_label);
__ popa();
__ pop(c_rarg0);
__ pop_ppx(c_rarg0);
__ leave();
@ -3465,10 +3465,10 @@ address StubGenerator::generate_bigIntegerRightShift() {
// For windows, since last argument is on stack, we need to move it to the appropriate register.
__ movl(totalNumIter, Address(rsp, 6 * wordSize));
// Save callee save registers.
__ push(tmp3);
__ push(tmp4);
__ push_ppx(tmp3);
__ push_ppx(tmp4);
#endif
__ push(tmp5);
__ push_ppx(tmp5);
// Rename temps used throughout the code.
const Register idx = tmp1;
@ -3541,10 +3541,10 @@ address StubGenerator::generate_bigIntegerRightShift() {
__ BIND(Exit);
__ vzeroupper();
// Restore callee save registers.
__ pop(tmp5);
__ pop_ppx(tmp5);
#ifdef _WIN64
__ pop(tmp4);
__ pop(tmp3);
__ pop_ppx(tmp4);
__ pop_ppx(tmp3);
restore_arg_regs();
#endif
__ leave(); // required for proper stackwalking of RuntimeStub frame
@ -3598,10 +3598,10 @@ address StubGenerator::generate_bigIntegerLeftShift() {
// For windows, since last argument is on stack, we need to move it to the appropriate register.
__ movl(totalNumIter, Address(rsp, 6 * wordSize));
// Save callee save registers.
__ push(tmp3);
__ push(tmp4);
__ push_ppx(tmp3);
__ push_ppx(tmp4);
#endif
__ push(tmp5);
__ push_ppx(tmp5);
// Rename temps used throughout the code
const Register idx = tmp1;
@ -3666,10 +3666,10 @@ address StubGenerator::generate_bigIntegerLeftShift() {
__ BIND(Exit);
__ vzeroupper();
// Restore callee save registers.
__ pop(tmp5);
__ pop_ppx(tmp5);
#ifdef _WIN64
__ pop(tmp4);
__ pop(tmp3);
__ pop_ppx(tmp4);
__ pop_ppx(tmp3);
restore_arg_regs();
#endif
__ leave(); // required for proper stackwalking of RuntimeStub frame
@ -3813,7 +3813,7 @@ address StubGenerator::generate_cont_thaw(StubId stub_id) {
if (return_barrier) {
// Preserve possible return value from a method returning to the return barrier.
__ push(rax);
__ push_ppx(rax);
__ push_d(xmm0);
}
@ -3826,7 +3826,7 @@ address StubGenerator::generate_cont_thaw(StubId stub_id) {
// Restore return value from a method returning to the return barrier.
// No safepoint in the call to thaw, so even an oop return value should be OK.
__ pop_d(xmm0);
__ pop(rax);
__ pop_ppx(rax);
}
#ifdef ASSERT
@ -3852,7 +3852,7 @@ address StubGenerator::generate_cont_thaw(StubId stub_id) {
if (return_barrier) {
// Preserve possible return value from a method returning to the return barrier. (Again.)
__ push(rax);
__ push_ppx(rax);
__ push_d(xmm0);
}
@ -3866,7 +3866,7 @@ address StubGenerator::generate_cont_thaw(StubId stub_id) {
// Restore return value from a method returning to the return barrier. (Again.)
// No safepoint in the call to thaw, so even an oop return value should be OK.
__ pop_d(xmm0);
__ pop(rax);
__ pop_ppx(rax);
} else {
// Return 0 (success) from doYield.
__ xorptr(rax, rax);
@ -3882,7 +3882,7 @@ address StubGenerator::generate_cont_thaw(StubId stub_id) {
__ movptr(c_rarg1, Address(rsp, wordSize)); // return address
// rax still holds the original exception oop, save it before the call
__ push(rax);
__ push_ppx(rax);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), 2);
__ movptr(rbx, rax);
@ -3891,7 +3891,7 @@ address StubGenerator::generate_cont_thaw(StubId stub_id) {
// rax: exception oop
// rbx: exception handler
// rdx: exception pc
__ pop(rax);
__ pop_ppx(rax);
__ verify_oop(rax);
__ pop(rbp); // pop out RBP here too
__ pop(rdx);
@ -4095,15 +4095,11 @@ void StubGenerator::generate_initial_stubs() {
StubRoutines::x86::_double_sign_flip = generate_fp_mask(StubId::stubgen_double_sign_flip_id, 0x8000000000000000);
if (UseCRC32Intrinsics) {
// set table address before stub generation which use it
StubRoutines::_crc_table_adr = (address)StubRoutines::x86::_crc_table;
StubRoutines::_updateBytesCRC32 = generate_updateBytesCRC32();
}
if (UseCRC32CIntrinsics) {
bool supports_clmul = VM_Version::supports_clmul();
StubRoutines::x86::generate_CRC32C_table(supports_clmul);
StubRoutines::_crc32c_table_addr = (address)StubRoutines::x86::_crc32c_table;
StubRoutines::_updateBytesCRC32C = generate_updateBytesCRC32C(supports_clmul);
}

View File

@ -279,14 +279,14 @@ address StubGenerator::generate_galoisCounterMode_AESCrypt() {
#endif
__ enter();
// Save state before entering routine
__ push(r12);//holds pointer to avx512_subkeyHtbl
__ push(r14);//holds CTR_CHECK value to check for overflow
__ push(r15);//holds number of rounds
__ push(rbx);//scratch register
__ push_ppx(r12);//holds pointer to avx512_subkeyHtbl
__ push_ppx(r14);//holds CTR_CHECK value to check for overflow
__ push_ppx(r15);//holds number of rounds
__ push_ppx(rbx);//scratch register
#ifdef _WIN64
// on win64, fill len_reg from stack position
__ push(rsi);
__ push(rdi);
__ push_ppx(rsi);
__ push_ppx(rdi);
__ movptr(key, key_mem);
__ movptr(state, state_mem);
#endif
@ -304,15 +304,15 @@ address StubGenerator::generate_galoisCounterMode_AESCrypt() {
// Restore state before leaving routine
#ifdef _WIN64
__ lea(rsp, Address(rbp, -6 * wordSize));
__ pop(rdi);
__ pop(rsi);
__ pop_ppx(rdi);
__ pop_ppx(rsi);
#else
__ lea(rsp, Address(rbp, -4 * wordSize));
#endif
__ pop(rbx);
__ pop(r15);
__ pop(r14);
__ pop(r12);
__ pop_ppx(rbx);
__ pop_ppx(r15);
__ pop_ppx(r14);
__ pop_ppx(r12);
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
@ -364,15 +364,15 @@ address StubGenerator::generate_avx2_galoisCounterMode_AESCrypt() {
#endif
__ enter();
// Save state before entering routine
__ push(r12);
__ push(r13);
__ push(r14);
__ push(r15);
__ push(rbx);
__ push_ppx(r12);
__ push_ppx(r13);
__ push_ppx(r14);
__ push_ppx(r15);
__ push_ppx(rbx);
#ifdef _WIN64
// on win64, fill len_reg from stack position
__ push(rsi);
__ push(rdi);
__ push_ppx(rsi);
__ push_ppx(rdi);
__ movptr(key, key_mem);
__ movptr(state, state_mem);
#endif
@ -390,14 +390,14 @@ address StubGenerator::generate_avx2_galoisCounterMode_AESCrypt() {
__ movq(rsp, r14);
// Restore state before leaving routine
#ifdef _WIN64
__ pop(rdi);
__ pop(rsi);
__ pop_ppx(rdi);
__ pop_ppx(rsi);
#endif
__ pop(rbx);
__ pop(r15);
__ pop(r14);
__ pop(r13);
__ pop(r12);
__ pop_ppx(rbx);
__ pop_ppx(r15);
__ pop_ppx(r14);
__ pop_ppx(r13);
__ pop_ppx(r12);
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
@ -434,10 +434,10 @@ address StubGenerator::generate_counterMode_VectorAESCrypt() {
#endif
__ enter();
// Save state before entering routine
__ push(r12);
__ push(r13);
__ push(r14);
__ push(r15);
__ push_ppx(r12);
__ push_ppx(r13);
__ push_ppx(r14);
__ push_ppx(r15);
#ifdef _WIN64
// on win64, fill len_reg from stack position
__ movl(len_reg, len_mem);
@ -445,26 +445,26 @@ address StubGenerator::generate_counterMode_VectorAESCrypt() {
__ movptr(used_addr, used_mem);
__ movl(used, Address(used_addr, 0));
#else
__ push(len_reg); // Save
__ push_ppx(len_reg); // Save
__ movptr(used_addr, used_mem);
__ movl(used, Address(used_addr, 0));
#endif
__ push(rbx);
__ push_ppx(rbx);
aesctr_encrypt(from, to, key, counter, len_reg, used, used_addr, saved_encCounter_start);
__ vzeroupper();
// Restore state before leaving routine
__ pop(rbx);
__ pop_ppx(rbx);
#ifdef _WIN64
__ movl(rax, len_mem); // return length
#else
__ pop(rax); // return length
__ pop_ppx(rax); // return length
#endif
__ pop(r15);
__ pop(r14);
__ pop(r13);
__ pop(r12);
__ pop_ppx(r15);
__ pop_ppx(r14);
__ pop_ppx(r13);
__ pop_ppx(r12);
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
@ -576,12 +576,12 @@ address StubGenerator::generate_counterMode_AESCrypt_Parallel() {
__ movptr(used_addr, used_mem);
__ movl(used, Address(used_addr, 0));
#else
__ push(len_reg); // Save
__ push_ppx(len_reg); // Save
__ movptr(used_addr, used_mem);
__ movl(used, Address(used_addr, 0));
#endif
__ push(rbx); // Save RBX
__ push_ppx(rbx); // Save RBX
__ movdqu(xmm_curr_counter, Address(counter, 0x00)); // initialize counter with initial counter
__ movdqu(xmm_counter_shuf_mask, ExternalAddress(counter_shuffle_mask_addr()), pos /*rscratch*/);
__ pshufb(xmm_curr_counter, xmm_counter_shuf_mask); //counter is shuffled
@ -767,14 +767,14 @@ address StubGenerator::generate_counterMode_AESCrypt_Parallel() {
__ BIND(L_exit);
__ pshufb(xmm_curr_counter, xmm_counter_shuf_mask); //counter is shuffled back.
__ movdqu(Address(counter, 0), xmm_curr_counter); //save counter back
__ pop(rbx); // pop the saved RBX.
__ pop_ppx(rbx); // pop the saved RBX.
#ifdef _WIN64
__ movl(rax, len_mem);
__ movptr(r13, Address(rsp, saved_r13_offset * wordSize));
__ movptr(r14, Address(rsp, saved_r14_offset * wordSize));
__ addptr(rsp, 2 * wordSize);
#else
__ pop(rax); // return 'len'
__ pop_ppx(rax); // return 'len'
#endif
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
@ -810,9 +810,9 @@ address StubGenerator::generate_cipherBlockChaining_decryptVectorAESCrypt() {
// on win64, fill len_reg from stack position
__ movl(len_reg, len_mem);
#else
__ push(len_reg); // Save
__ push_ppx(len_reg); // Save
#endif
__ push(rbx);
__ push_ppx(rbx);
__ vzeroupper();
// Temporary variable declaration for swapping key bytes
@ -1046,11 +1046,11 @@ address StubGenerator::generate_cipherBlockChaining_decryptVectorAESCrypt() {
__ BIND(Lcbc_exit);
__ vzeroupper();
__ pop(rbx);
__ pop_ppx(rbx);
#ifdef _WIN64
__ movl(rax, len_mem);
#else
__ pop(rax); // return length
__ pop_ppx(rax); // return length
#endif
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
@ -1301,7 +1301,7 @@ address StubGenerator::generate_cipherBlockChaining_encryptAESCrypt() {
// on win64, fill len_reg from stack position
__ movl(len_reg, len_mem);
#else
__ push(len_reg); // Save
__ push_ppx(len_reg); // Save
#endif
const XMMRegister xmm_key_shuf_mask = xmm_temp; // used temporarily to swap key bytes up front
@ -1343,7 +1343,7 @@ address StubGenerator::generate_cipherBlockChaining_encryptAESCrypt() {
#ifdef _WIN64
__ movl(rax, len_mem);
#else
__ pop(rax); // return length
__ pop_ppx(rax); // return length
#endif
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
@ -1456,9 +1456,9 @@ address StubGenerator::generate_cipherBlockChaining_decryptAESCrypt_Parallel() {
// on win64, fill len_reg from stack position
__ movl(len_reg, len_mem);
#else
__ push(len_reg); // Save
__ push_ppx(len_reg); // Save
#endif
__ push(rbx);
__ push_ppx(rbx);
// the java expanded key ordering is rotated one position from what we want
// so we start from 0x10 here and hit 0x00 last
const XMMRegister xmm_key_shuf_mask = xmm1; // used temporarily to swap key bytes up front
@ -1646,11 +1646,11 @@ __ opc(xmm_result3, src_reg); \
__ BIND(L_exit);
__ movdqu(Address(rvec, 0), xmm_prev_block_cipher); // final value of r stored in rvec of CipherBlockChaining object
__ pop(rbx);
__ pop_ppx(rbx);
#ifdef _WIN64
__ movl(rax, len_mem);
#else
__ pop(rax); // return length
__ pop_ppx(rax); // return length
#endif
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
@ -1801,8 +1801,8 @@ void StubGenerator::aesecb_encrypt(Register src_addr, Register dest_addr, Regist
const Register rounds = r12;
Label NO_PARTS, LOOP, Loop_start, LOOP2, AES192, END_LOOP, AES256, REMAINDER, LAST2, END, KEY_192, KEY_256, EXIT;
__ push(r13);
__ push(r12);
__ push_ppx(r13);
__ push_ppx(r12);
// For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge
// context for the registers used, where all instructions below are using 128-bit mode
@ -1811,8 +1811,8 @@ void StubGenerator::aesecb_encrypt(Register src_addr, Register dest_addr, Regist
__ movl(rax, 0xffff);
__ kmovql(k1, rax);
}
__ push(len); // Save
__ push(rbx);
__ push_ppx(len); // Save
__ push_ppx(rbx);
__ vzeroupper();
@ -1999,10 +1999,10 @@ void StubGenerator::aesecb_encrypt(Register src_addr, Register dest_addr, Regist
__ evpxorq(xmm21, xmm21, xmm21, Assembler::AVX_512bit);
__ evpxorq(xmm22, xmm22, xmm22, Assembler::AVX_512bit);
__ bind(EXIT);
__ pop(rbx);
__ pop(rax); // return length
__ pop(r12);
__ pop(r13);
__ pop_ppx(rbx);
__ pop_ppx(rax); // return length
__ pop_ppx(r12);
__ pop_ppx(r13);
}
// AES-ECB Decrypt Operation
@ -2011,8 +2011,8 @@ void StubGenerator::aesecb_decrypt(Register src_addr, Register dest_addr, Regist
Label NO_PARTS, LOOP, Loop_start, LOOP2, AES192, END_LOOP, AES256, REMAINDER, LAST2, END, KEY_192, KEY_256, EXIT;
const Register pos = rax;
const Register rounds = r12;
__ push(r13);
__ push(r12);
__ push_ppx(r13);
__ push_ppx(r12);
// For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge
// context for the registers used, where all instructions below are using 128-bit mode
@ -2022,8 +2022,8 @@ void StubGenerator::aesecb_decrypt(Register src_addr, Register dest_addr, Regist
__ kmovql(k1, rax);
}
__ push(len); // Save
__ push(rbx);
__ push_ppx(len); // Save
__ push_ppx(rbx);
__ vzeroupper();
@ -2210,10 +2210,10 @@ void StubGenerator::aesecb_decrypt(Register src_addr, Register dest_addr, Regist
__ evpxorq(xmm22, xmm22, xmm22, Assembler::AVX_512bit);
__ bind(EXIT);
__ pop(rbx);
__ pop(rax); // return length
__ pop(r12);
__ pop(r13);
__ pop_ppx(rbx);
__ pop_ppx(rax); // return length
__ pop_ppx(r12);
__ pop_ppx(r13);
}

View File

@ -2943,7 +2943,7 @@ address StubGenerator::generate_generic_copy(address byte_copy_entry, address sh
__ enter(); // required for proper stackwalking of RuntimeStub frame
#ifdef _WIN64
__ push(rklass_tmp); // rdi is callee-save on Windows
__ push_ppx(rklass_tmp); // rdi is callee-save on Windows
#endif
// bump this on entry, not on exit:
@ -3077,7 +3077,7 @@ address StubGenerator::generate_generic_copy(address byte_copy_entry, address sh
__ andl(rax_lh, Klass::_lh_log2_element_size_mask); // rax_lh -> rax_elsize
#ifdef _WIN64
__ pop(rklass_tmp); // Restore callee-save rdi
__ pop_ppx(rklass_tmp); // Restore callee-save rdi
#endif
// next registers should be set before the jump to corresponding stub
@ -3149,7 +3149,7 @@ __ BIND(L_objArray);
__ movl2ptr(count, r11_length); // length
__ BIND(L_plain_copy);
#ifdef _WIN64
__ pop(rklass_tmp); // Restore callee-save rdi
__ pop_ppx(rklass_tmp); // Restore callee-save rdi
#endif
__ jump(RuntimeAddress(oop_copy_entry));
@ -3191,7 +3191,7 @@ __ BIND(L_checkcast_copy);
assert_clean_int(sco_temp, rax);
#ifdef _WIN64
__ pop(rklass_tmp); // Restore callee-save rdi
__ pop_ppx(rklass_tmp); // Restore callee-save rdi
#endif
// the checkcast_copy loop needs two extra arguments:
@ -3204,7 +3204,7 @@ __ BIND(L_checkcast_copy);
__ BIND(L_failed);
#ifdef _WIN64
__ pop(rklass_tmp); // Restore callee-save rdi
__ pop_ppx(rklass_tmp); // Restore callee-save rdi
#endif
__ xorptr(rax, rax);
__ notptr(rax); // return -1

View File

@ -185,11 +185,11 @@ address StubGenerator::generate_libmCos() {
__ enter(); // required for proper stackwalking of RuntimeStub frame
#ifdef _WIN64
__ push(rsi);
__ push(rdi);
__ push_ppx(rsi);
__ push_ppx(rdi);
#endif
__ push(rbx);
__ push_ppx(rbx);
__ subq(rsp, 16);
__ movsd(Address(rsp, 8), xmm0);
@ -609,11 +609,11 @@ address StubGenerator::generate_libmCos() {
__ bind(B1_4);
__ addq(rsp, 16);
__ pop(rbx);
__ pop_ppx(rbx);
#ifdef _WIN64
__ pop(rdi);
__ pop(rsi);
__ pop_ppx(rdi);
__ pop_ppx(rsi);
#endif
__ leave(); // required for proper stackwalking of RuntimeStub frame

View File

@ -105,7 +105,7 @@ address StubGenerator::generate_ghash_processBlocks() {
__ enter();
__ push(rbx); // scratch
__ push_ppx(rbx); // scratch
__ movdqu(xmm_temp10, ExternalAddress(ghash_long_swap_mask_addr()), rbx /*rscratch*/);
@ -206,7 +206,7 @@ address StubGenerator::generate_ghash_processBlocks() {
__ pshufb(xmm_temp6, xmm_temp10); // Byte swap 16-byte result
__ movdqu(Address(state, 0), xmm_temp6); // store the result
__ pop(rbx);
__ pop_ppx(rbx);
__ leave();
__ ret(0);
@ -229,11 +229,11 @@ address StubGenerator::generate_avx_ghash_processBlocks() {
const Register data = c_rarg2;
const Register blocks = c_rarg3;
__ enter();
__ push(rbx);
__ push_ppx(rbx);
avx_ghash(state, htbl, data, blocks);
__ pop(rbx);
__ pop_ppx(rbx);
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);

View File

@ -603,7 +603,7 @@ address generate_kyberNttMult_avx512(StubGenerator *stubgen,
const Register perms = r11;
const Register loopCnt = r12;
__ push(r12);
__ push_ppx(r12);
__ movl(loopCnt, 2);
Label Loop;
@ -692,7 +692,7 @@ address generate_kyberNttMult_avx512(StubGenerator *stubgen,
__ subl(loopCnt, 1);
__ jcc(Assembler::greater, Loop);
__ pop(r12);
__ pop_ppx(r12);
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ mov64(rax, 0); // return 0

View File

@ -916,15 +916,15 @@ address StubGenerator::generate_poly1305_processBlocks() {
__ enter();
// Save all 'SOE' registers
__ push(rbx);
__ push_ppx(rbx);
#ifdef _WIN64
__ push(rsi);
__ push(rdi);
__ push_ppx(rsi);
__ push_ppx(rdi);
#endif
__ push(r12);
__ push(r13);
__ push(r14);
__ push(r15);
__ push_ppx(r12);
__ push_ppx(r13);
__ push_ppx(r14);
__ push_ppx(r15);
// Register Map
const Register input = rdi; // msg
@ -1016,15 +1016,15 @@ address StubGenerator::generate_poly1305_processBlocks() {
// Write output
poly1305_limbs_out(a0, a1, a2, accumulator, t0, t1);
__ pop(r15);
__ pop(r14);
__ pop(r13);
__ pop(r12);
__ pop_ppx(r15);
__ pop_ppx(r14);
__ pop_ppx(r13);
__ pop_ppx(r12);
#ifdef _WIN64
__ pop(rdi);
__ pop(rsi);
__ pop_ppx(rdi);
__ pop_ppx(rsi);
#endif
__ pop(rbx);
__ pop_ppx(rbx);
__ leave();
__ ret(0);
@ -1169,7 +1169,7 @@ void StubGenerator::poly1305_process_blocks_avx2(
// Setup stack frame
// Save rbp and rsp
__ push(rbp);
__ push_ppx(rbp);
__ movq(rbp, rsp);
// Align stack and reserve space
__ andq(rsp, -32);
@ -1483,7 +1483,7 @@ void StubGenerator::poly1305_process_blocks_avx2(
// Save rbp and rsp; clear stack frame
__ movq(rsp, rbp);
__ pop(rbp);
__ pop_ppx(rbp);
}

View File

@ -574,14 +574,14 @@ address StubGenerator::generate_intpoly_montgomeryMult_P256() {
montgomeryMultiply(aLimbs, bLimbs, rLimbs, tmp, _masm);
} else {
assert(VM_Version::supports_avxifma(), "Require AVX_IFMA support");
__ push(r12);
__ push(r13);
__ push(r14);
__ push_ppx(r12);
__ push_ppx(r13);
__ push_ppx(r14);
#ifdef _WIN64
__ push(rsi);
__ push(rdi);
__ push_ppx(rsi);
__ push_ppx(rdi);
#endif
__ push(rbp);
__ push_ppx(rbp);
__ movq(rbp, rsp);
__ andq(rsp, -32);
__ subptr(rsp, 32);
@ -608,14 +608,14 @@ address StubGenerator::generate_intpoly_montgomeryMult_P256() {
tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, _masm);
__ movq(rsp, rbp);
__ pop(rbp);
__ pop_ppx(rbp);
#ifdef _WIN64
__ pop(rdi);
__ pop(rsi);
__ pop_ppx(rdi);
__ pop_ppx(rsi);
#endif
__ pop(r14);
__ pop(r13);
__ pop(r12);
__ pop_ppx(r14);
__ pop_ppx(r13);
__ pop_ppx(r12);
}
__ leave();

View File

@ -130,9 +130,9 @@ static address generate_sha3_implCompress(StubId stub_id,
__ enter();
__ push(r12);
__ push(r13);
__ push(r14);
__ push_ppx(r12);
__ push_ppx(r13);
__ push_ppx(r14);
#ifdef _WIN64
// on win64, fill limit from stack position
@ -309,9 +309,9 @@ static address generate_sha3_implCompress(StubId stub_id,
__ evmovdquq(Address(state, i * 40), k5, xmm(i), true, Assembler::AVX_512bit);
}
__ pop(r14);
__ pop(r13);
__ pop(r12);
__ pop_ppx(r14);
__ pop_ppx(r13);
__ pop_ppx(r12);
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);

View File

@ -195,11 +195,11 @@ address StubGenerator::generate_libmSin() {
__ enter(); // required for proper stackwalking of RuntimeStub frame
#ifdef _WIN64
__ push(rsi);
__ push(rdi);
__ push_ppx(rsi);
__ push_ppx(rdi);
#endif
__ push(rbx);
__ push_ppx(rbx);
__ subq(rsp, 16);
__ movsd(Address(rsp, 8), xmm0);
__ movl(rax, Address(rsp, 12));
@ -635,11 +635,11 @@ address StubGenerator::generate_libmSin() {
__ bind(B1_4);
__ addq(rsp, 16);
__ pop(rbx);
__ pop_ppx(rbx);
#ifdef _WIN64
__ pop(rdi);
__ pop(rsi);
__ pop_ppx(rdi);
__ pop_ppx(rsi);
#endif
__ leave(); // required for proper stackwalking of RuntimeStub frame

View File

@ -483,11 +483,11 @@ address StubGenerator::generate_libmTan() {
__ enter(); // required for proper stackwalking of RuntimeStub frame
#ifdef _WIN64
__ push(rsi);
__ push(rdi);
__ push_ppx(rsi);
__ push_ppx(rdi);
#endif
__ push(rbx);
__ push_ppx(rbx);
__ subq(rsp, 16);
__ movsd(Address(rsp, 8), xmm0);
@ -1015,11 +1015,11 @@ address StubGenerator::generate_libmTan() {
__ bind(B1_4);
__ addq(rsp, 16);
__ pop(rbx);
__ pop_ppx(rbx);
#ifdef _WIN64
__ pop(rdi);
__ pop(rsi);
__ pop_ppx(rdi);
__ pop_ppx(rsi);
#endif
__ leave(); // required for proper stackwalking of RuntimeStub frame

View File

@ -45,6 +45,17 @@ STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY, DEFINE_ARCH_ENTRY_INIT)
#undef DEFINE_ARCH_ENTRY_INIT
#undef DEFINE_ARCH_ENTRY
address StubRoutines::crc_table_addr() {
return (address)StubRoutines::x86::_crc_table;
}
address StubRoutines::crc32c_table_addr() {
if (StubRoutines::x86::_crc32c_table == nullptr) {
bool supports_clmul = VM_Version::supports_clmul();
StubRoutines::x86::generate_CRC32C_table(supports_clmul);
}
return (address)StubRoutines::x86::_crc32c_table;
}
address StubRoutines::x86::_k256_adr = nullptr;
address StubRoutines::x86::_k256_W_adr = nullptr;
address StubRoutines::x86::_k512_W_addr = nullptr;
@ -291,7 +302,7 @@ static uint32_t crc32c_f_pow_n(uint32_t n) {
return result;
}
juint *StubRoutines::x86::_crc32c_table;
juint* StubRoutines::x86::_crc32c_table = nullptr;
void StubRoutines::x86::generate_CRC32C_table(bool is_pclmulqdq_table_supported) {

View File

@ -44,6 +44,7 @@ enum platform_dependent_constants {
class x86 {
friend class StubGenerator;
friend class StubRoutines;
friend class VMStructs;
// declare fields for arch-specific entries

View File

@ -49,7 +49,7 @@ VM_Version::CpuidInfo VM_Version::_cpuid_info = { 0, };
#define DECLARE_CPU_FEATURE_NAME(id, name, bit) name,
const char* VM_Version::_features_names[] = { CPU_FEATURE_FLAGS(DECLARE_CPU_FEATURE_NAME)};
#undef DECLARE_CPU_FEATURE_FLAG
#undef DECLARE_CPU_FEATURE_NAME
// Address of instruction which causes SEGV
address VM_Version::_cpuinfo_segv_addr = nullptr;

View File

@ -37,7 +37,7 @@
do_arch_blob, \
do_arch_entry, \
do_arch_entry_init) \
do_arch_blob(initial, 0) \
do_arch_blob(initial, 32) \
#define STUBGEN_CONTINUATION_BLOBS_ARCH_DO(do_stub, \
@ -58,7 +58,7 @@
do_arch_blob, \
do_arch_entry, \
do_arch_entry_init) \
do_arch_blob(final, 0) \
do_arch_blob(final, 32) \
#endif // CPU_ZERO_STUBDECLARATIONS_HPP

View File

@ -28,4 +28,5 @@
#include "runtime/javaThread.hpp"
#include "runtime/stubRoutines.hpp"
// zero has no arch-specific stubs nor any associated entries
address StubRoutines::crc_table_addr() { ShouldNotCallThis(); return nullptr; }
address StubRoutines::crc32c_table_addr() { ShouldNotCallThis(); return nullptr; }

View File

@ -1110,7 +1110,10 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
if (result != nullptr) {
return result;
}
if (ebuf == nullptr || ebuflen < 1) {
// no error reporting requested
return nullptr;
}
Events::log_dll_message(nullptr, "Loading shared library %s failed, %s", filename, error_report);
log_info(os)("shared library load of %s failed, %s", filename, error_report);
int diag_msg_max_length=ebuflen-strlen(ebuf);

View File

@ -1685,6 +1685,11 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
return result;
}
if (ebuf == nullptr || ebuflen < 1) {
// no error reporting requested
return nullptr;
}
Elf32_Ehdr elf_head;
size_t prefix_len = strlen(ebuf);
ssize_t diag_msg_max_length = ebuflen - prefix_len;

View File

@ -1729,6 +1729,12 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) {
log_info(os)("shared library load of %s was successful", name);
return result;
}
if (ebuf == nullptr || ebuflen < 1) {
// no error reporting requested
return nullptr;
}
DWORD errcode = GetLastError();
// Read system error message into ebuf
// It may or may not be overwritten below (in the for loop and just above)
@ -2261,6 +2267,8 @@ void os::jvm_path(char *buf, jint buflen) {
// from src/windows/hpi/src/system_md.c
size_t os::lasterror(char* buf, size_t len) {
assert(buf != nullptr && len > 0, "invalid buffer passed");
DWORD errval;
if ((errval = GetLastError()) != 0) {

View File

@ -49,8 +49,10 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/timer.hpp"
#include "runtime/vm_version.hpp"
#include "signals_posix.hpp"
#include "utilities/align.hpp"
#include "utilities/debug.hpp"
#include "utilities/events.hpp"
#include "utilities/vmError.hpp"
@ -524,40 +526,32 @@ static inline void atomic_copy64(const volatile void *src, volatile void *dst) {
}
extern "C" {
// needs local assembler label '1:' to avoid trouble when using linktime optimization
int SpinPause() {
// We don't use StubRoutines::aarch64::spin_wait stub in order to
// avoid a costly call to os::current_thread_enable_wx() on MacOS.
// We should return 1 if SpinPause is implemented, and since there
// will be a sequence of 11 instructions for NONE and YIELD and 12
// instructions for NOP and ISB, SpinPause will always return 1.
uint64_t br_dst;
const int instructions_per_case = 2;
int64_t off = VM_Version::spin_wait_desc().inst() * instructions_per_case * Assembler::instruction_size;
assert(VM_Version::spin_wait_desc().inst() >= SpinWait::NONE &&
VM_Version::spin_wait_desc().inst() <= SpinWait::YIELD, "must be");
assert(-1 == SpinWait::NONE, "must be");
assert( 0 == SpinWait::NOP, "must be");
assert( 1 == SpinWait::ISB, "must be");
assert( 2 == SpinWait::YIELD, "must be");
asm volatile(
" adr %[d], 20 \n" // 20 == PC here + 5 instructions => address
// to entry for case SpinWait::NOP
" add %[d], %[d], %[o] \n"
" br %[d] \n"
" b 1f \n" // case SpinWait::NONE (-1)
" nop \n" // padding
" nop \n" // case SpinWait::NOP ( 0)
" b 1f \n"
" isb \n" // case SpinWait::ISB ( 1)
" b 1f \n"
" yield \n" // case SpinWait::YIELD ( 2)
"1: \n"
: [d]"=&r"(br_dst)
: [o]"r"(off)
: "memory");
// will be always a sequence of instructions, SpinPause will always return 1.
switch (VM_Version::spin_wait_desc().inst()) {
case SpinWait::NONE:
break;
case SpinWait::NOP:
asm volatile("nop" : : : "memory");
break;
case SpinWait::ISB:
asm volatile("isb" : : : "memory");
break;
case SpinWait::YIELD:
asm volatile("yield" : : : "memory");
break;
case SpinWait::SB:
assert(VM_Version::supports_sb(), "current CPU does not support SB instruction");
asm volatile(".inst 0xd50330ff" : : : "memory");
break;
#ifdef ASSERT
default:
ShouldNotReachHere();
#endif
}
return 1;
}

View File

@ -626,7 +626,7 @@ csize_t CodeBuffer::total_relocation_size() const {
return (csize_t) align_up(total, HeapWordSize);
}
csize_t CodeBuffer::copy_relocations_to(address buf, csize_t buf_limit, bool only_inst) const {
csize_t CodeBuffer::copy_relocations_to(address buf, csize_t buf_limit) const {
csize_t buf_offset = 0;
csize_t code_end_so_far = 0;
csize_t code_point_so_far = 0;
@ -635,10 +635,6 @@ csize_t CodeBuffer::copy_relocations_to(address buf, csize_t buf_limit, bool onl
assert(buf_limit % HeapWordSize == 0, "buf must be evenly sized");
for (int n = (int) SECT_FIRST; n < (int)SECT_LIMIT; n++) {
if (only_inst && (n != (int)SECT_INSTS)) {
// Need only relocation info for code.
continue;
}
// pull relocs out of each section
const CodeSection* cs = code_section(n);
assert(!(cs->is_empty() && cs->locs_count() > 0), "sanity");
@ -705,7 +701,7 @@ csize_t CodeBuffer::copy_relocations_to(address buf, csize_t buf_limit, bool onl
buf_offset += sizeof(relocInfo);
}
assert(only_inst || code_end_so_far == total_content_size(), "sanity");
assert(code_end_so_far == total_content_size(), "sanity");
return buf_offset;
}
@ -721,7 +717,7 @@ csize_t CodeBuffer::copy_relocations_to(CodeBlob* dest) const {
}
// if dest is null, this is just the sizing pass
//
buf_offset = copy_relocations_to(buf, buf_limit, false);
buf_offset = copy_relocations_to(buf, buf_limit);
return buf_offset;
}

View File

@ -641,6 +641,7 @@ class CodeBuffer: public StackObj DEBUG_ONLY(COMMA private Scrubber) {
// copies combined relocations to the blob, returns bytes copied
// (if target is null, it is a dry run only, just for sizing)
csize_t copy_relocations_to(CodeBlob* blob) const;
csize_t copy_relocations_to(address buf, csize_t buf_limit) const;
// copies combined code to the blob (assumes relocs are already in there)
void copy_code_to(CodeBlob* blob);
@ -791,8 +792,6 @@ class CodeBuffer: public StackObj DEBUG_ONLY(COMMA private Scrubber) {
int total_skipped_instructions_size() const;
csize_t copy_relocations_to(address buf, csize_t buf_limit, bool only_inst) const;
// allocated size of any and all recorded oops
csize_t total_oop_size() const {
OopRecorder* recorder = oop_recorder();

View File

@ -351,7 +351,8 @@ LIR_OpArrayCopy::LIR_OpArrayCopy(LIR_Opr src, LIR_Opr src_pos, LIR_Opr dst, LIR_
, _expected_type(expected_type)
, _flags(flags) {
#if defined(X86) || defined(AARCH64) || defined(S390) || defined(RISCV64) || defined(PPC64)
if (expected_type != nullptr && flags == 0) {
if (expected_type != nullptr &&
((flags & ~LIR_OpArrayCopy::get_initial_copy_flags()) == 0)) {
_stub = nullptr;
} else {
_stub = new ArrayCopyStub(this);

View File

@ -1282,6 +1282,8 @@ public:
int flags() const { return _flags; }
ciArrayKlass* expected_type() const { return _expected_type; }
ArrayCopyStub* stub() const { return _stub; }
static int get_initial_copy_flags() { return LIR_OpArrayCopy::unaligned |
LIR_OpArrayCopy::overlapping; }
virtual void emit_code(LIR_Assembler* masm);
virtual LIR_OpArrayCopy* as_OpArrayCopy() { return this; }

View File

@ -598,6 +598,7 @@ void CDSConfig::check_aotmode_create() {
//
// Since application is not executed in the assembly phase, there's no need to load
// the agents anyway -- no one will notice that the agents are not loaded.
log_info(aot)("Disabled all JVMTI agents during -XX:AOTMode=create");
JvmtiAgentList::disable_agent_list();
}
@ -702,6 +703,13 @@ bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_fla
}
}
if (is_dumping_classic_static_archive() && AOTClassLinking) {
if (JvmtiAgentList::disable_agent_list()) {
FLAG_SET_ERGO(AllowArchivingWithJavaAgent, false);
log_warning(cds)("Disabled all JVMTI agents with -Xshare:dump -XX:+AOTClassLinking");
}
}
return true;
}

View File

@ -110,11 +110,13 @@ CDSHeapVerifier::CDSHeapVerifier() : _archived_objs(0), _problems(0)
ADD_EXCL("java/lang/System", "bootLayer"); // A
ADD_EXCL("java/util/Collections", "EMPTY_LIST"); // E
ADD_EXCL("java/util/Collections", "EMPTY_LIST"); // E
// A dummy object used by HashSet. The value doesn't matter and it's never
// tested for equality.
ADD_EXCL("java/util/HashSet", "PRESENT"); // E
ADD_EXCL("jdk/internal/loader/BootLoader", "UNNAMED_MODULE"); // A
ADD_EXCL("jdk/internal/loader/BuiltinClassLoader", "packageToModule"); // A
ADD_EXCL("jdk/internal/loader/ClassLoaders", "BOOT_LOADER", // A
"APP_LOADER", // A

View File

@ -120,7 +120,6 @@ PackageEntry* CDSProtectionDomain::get_package_entry_from_class(InstanceKlass* i
if (CDSConfig::is_using_full_module_graph() && ik->is_shared() && pkg_entry != nullptr) {
assert(MetaspaceShared::is_in_shared_metaspace(pkg_entry), "must be");
assert(!ik->defined_by_other_loaders(), "unexpected archived package entry for an unregistered class");
assert(ik->module()->is_named(), "unexpected archived package entry for a class in an unnamed module");
return pkg_entry;
}
TempNewSymbol pkg_name = ClassLoader::package_from_class_name(ik->name());

View File

@ -24,6 +24,7 @@
#include "cds/aotLogging.hpp"
#include "cds/cdsConfig.hpp"
#include "cds/heapShared.hpp"
#include "cds/serializeClosure.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/classLoaderDataShared.hpp"
@ -42,6 +43,7 @@ bool ClassLoaderDataShared::_full_module_graph_loaded = false;
class ArchivedClassLoaderData {
Array<PackageEntry*>* _packages;
Array<ModuleEntry*>* _modules;
ModuleEntry* _unnamed_module;
void assert_valid(ClassLoaderData* loader_data) {
// loader_data may be null if the boot layer has loaded no modules for the platform or
@ -52,15 +54,19 @@ class ArchivedClassLoaderData {
}
}
public:
ArchivedClassLoaderData() : _packages(nullptr), _modules(nullptr) {}
ArchivedClassLoaderData() : _packages(nullptr), _modules(nullptr), _unnamed_module(nullptr) {}
void iterate_symbols(ClassLoaderData* loader_data, MetaspaceClosure* closure);
void allocate(ClassLoaderData* loader_data);
void init_archived_entries(ClassLoaderData* loader_data);
ModuleEntry* unnamed_module() {
return _unnamed_module;
}
void serialize(SerializeClosure* f) {
f->do_ptr(&_packages);
f->do_ptr(&_modules);
f->do_ptr(&_unnamed_module);
}
void restore(ClassLoaderData* loader_data, bool do_entries, bool do_oops);
@ -71,6 +77,8 @@ static ArchivedClassLoaderData _archived_boot_loader_data;
static ArchivedClassLoaderData _archived_platform_loader_data;
static ArchivedClassLoaderData _archived_system_loader_data;
static ModuleEntry* _archived_javabase_moduleEntry = nullptr;
static int _platform_loader_root_index = -1;
static int _system_loader_root_index = -1;
void ArchivedClassLoaderData::iterate_symbols(ClassLoaderData* loader_data, MetaspaceClosure* closure) {
assert(CDSConfig::is_dumping_full_module_graph(), "must be");
@ -78,6 +86,7 @@ void ArchivedClassLoaderData::iterate_symbols(ClassLoaderData* loader_data, Meta
if (loader_data != nullptr) {
loader_data->packages()->iterate_symbols(closure);
loader_data->modules() ->iterate_symbols(closure);
loader_data->unnamed_module()->iterate_symbols(closure);
}
}
@ -91,6 +100,7 @@ void ArchivedClassLoaderData::allocate(ClassLoaderData* loader_data) {
// the hashtables using these arrays.
_packages = loader_data->packages()->allocate_archived_entries();
_modules = loader_data->modules() ->allocate_archived_entries();
_unnamed_module = loader_data->unnamed_module()->allocate_archived_entry();
}
}
@ -100,6 +110,7 @@ void ArchivedClassLoaderData::init_archived_entries(ClassLoaderData* loader_data
if (loader_data != nullptr) {
loader_data->packages()->init_archived_entries(_packages);
loader_data->modules() ->init_archived_entries(_modules);
_unnamed_module->init_as_archived_entry();
}
}
@ -117,6 +128,12 @@ void ArchivedClassLoaderData::restore(ClassLoaderData* loader_data, bool do_entr
}
if (do_oops) {
modules->restore_archived_oops(loader_data, _modules);
if (_unnamed_module != nullptr) {
oop module_oop = _unnamed_module->module_oop();
assert(module_oop != nullptr, "must be already set");
assert(_unnamed_module == java_lang_Module::module_entry(module_oop), "must be already set");
assert(loader_data->class_loader() == java_lang_Module::loader(module_oop), "must be set in dump time");
}
}
}
}
@ -127,6 +144,9 @@ void ArchivedClassLoaderData::clear_archived_oops() {
for (int i = 0; i < _modules->length(); i++) {
_modules->at(i)->clear_archived_oops();
}
if (_unnamed_module != nullptr) {
_unnamed_module->clear_archived_oops();
}
}
}
@ -177,10 +197,15 @@ void ClassLoaderDataShared::allocate_archived_tables() {
void ClassLoaderDataShared::init_archived_tables() {
assert(CDSConfig::is_dumping_full_module_graph(), "must be");
_archived_boot_loader_data.init_archived_entries (null_class_loader_data());
_archived_platform_loader_data.init_archived_entries(java_platform_loader_data_or_null());
_archived_system_loader_data.init_archived_entries (java_system_loader_data_or_null());
_archived_javabase_moduleEntry = ModuleEntry::get_archived_entry(ModuleEntryTable::javabase_moduleEntry());
_platform_loader_root_index = HeapShared::append_root(SystemDictionary::java_platform_loader());
_system_loader_root_index = HeapShared::append_root(SystemDictionary::java_system_loader());
}
void ClassLoaderDataShared::serialize(SerializeClosure* f) {
@ -188,21 +213,54 @@ void ClassLoaderDataShared::serialize(SerializeClosure* f) {
_archived_platform_loader_data.serialize(f);
_archived_system_loader_data.serialize(f);
f->do_ptr(&_archived_javabase_moduleEntry);
f->do_int(&_platform_loader_root_index);
f->do_int(&_system_loader_root_index);
}
if (f->reading() && CDSConfig::is_using_full_module_graph()) {
// Must be done before ClassLoader::create_javabase()
_archived_boot_loader_data.restore(null_class_loader_data(), true, false);
ModuleEntryTable::set_javabase_moduleEntry(_archived_javabase_moduleEntry);
aot_log_info(aot)("use_full_module_graph = true; java.base = " INTPTR_FORMAT,
p2i(_archived_javabase_moduleEntry));
ModuleEntry* ClassLoaderDataShared::archived_boot_unnamed_module() {
if (CDSConfig::is_using_full_module_graph()) {
return _archived_boot_loader_data.unnamed_module();
} else {
return nullptr;
}
}
ModuleEntry* ClassLoaderDataShared::archived_unnamed_module(ClassLoaderData* loader_data) {
ModuleEntry* archived_module = nullptr;
if (!Universe::is_module_initialized() && CDSConfig::is_using_full_module_graph()) {
precond(_platform_loader_root_index >= 0);
precond(_system_loader_root_index >= 0);
if (loader_data->class_loader() == HeapShared::get_root(_platform_loader_root_index)) {
archived_module = _archived_platform_loader_data.unnamed_module();
} else if (loader_data->class_loader() == HeapShared::get_root(_system_loader_root_index)) {
archived_module = _archived_system_loader_data.unnamed_module();
}
}
return archived_module;
}
void ClassLoaderDataShared::clear_archived_oops() {
assert(!CDSConfig::is_using_full_module_graph(), "must be");
_archived_boot_loader_data.clear_archived_oops();
_archived_platform_loader_data.clear_archived_oops();
_archived_system_loader_data.clear_archived_oops();
if (_platform_loader_root_index >= 0) {
HeapShared::clear_root(_platform_loader_root_index);
HeapShared::clear_root(_system_loader_root_index);
}
}
// Must be done before ClassLoader::create_javabase()
void ClassLoaderDataShared::restore_archived_entries_for_null_class_loader_data() {
precond(CDSConfig::is_using_full_module_graph());
_archived_boot_loader_data.restore(null_class_loader_data(), true, false);
ModuleEntryTable::set_javabase_moduleEntry(_archived_javabase_moduleEntry);
aot_log_info(aot)("use_full_module_graph = true; java.base = " INTPTR_FORMAT,
p2i(_archived_javabase_moduleEntry));
}
oop ClassLoaderDataShared::restore_archived_oops_for_null_class_loader_data() {

View File

@ -30,6 +30,7 @@
class ClassLoaderData;
class MetaspaceClosure;
class ModuleEntry;
class SerializeClosure;
class ClassLoaderDataShared : AllStatic {
@ -42,9 +43,12 @@ public:
static void init_archived_tables();
static void serialize(SerializeClosure* f);
static void clear_archived_oops();
static void restore_archived_entries_for_null_class_loader_data();
static oop restore_archived_oops_for_null_class_loader_data();
static void restore_java_platform_loader_from_archive(ClassLoaderData* loader_data);
static void restore_java_system_loader_from_archive(ClassLoaderData* loader_data);
static ModuleEntry* archived_boot_unnamed_module();
static ModuleEntry* archived_unnamed_module(ClassLoaderData* loader_data);
static bool is_full_module_graph_loaded() { return _full_module_graph_loaded; }
};

View File

@ -658,13 +658,11 @@ static void find_empty_vtable_slots(GrowableArray<EmptyVtableSlot*>* slots,
if (super->default_methods() != nullptr) {
for (int i = 0; i < super->default_methods()->length(); ++i) {
Method* m = super->default_methods()->at(i);
// m is a method that would have been a miranda if not for the
// default method processing that occurred on behalf of our superclass,
// so it's a method we want to re-examine in this new context. That is,
// unless we have a real implementation of it in the current class.
if (!already_in_vtable_slots(slots, m)) {
// m is a method that we need to re-examine, unless we have a valid concrete
// implementation in the current class - see FindMethodsByErasedSig::visit.
Method* impl = klass->lookup_method(m->name(), m->signature());
if (impl == nullptr || impl->is_overpass() || impl->is_static()) {
if (impl == nullptr || impl->is_overpass() || impl->is_static() || impl->is_private()) {
slots->append(new EmptyVtableSlot(m));
}
}

View File

@ -29,9 +29,11 @@
#include "cds/heapShared.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/classLoaderDataShared.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/moduleEntry.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "jni.h"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
@ -317,6 +319,15 @@ ModuleEntry* ModuleEntry::create_unnamed_module(ClassLoaderData* cld) {
// corresponding unnamed module can be found in the java.lang.ClassLoader object.
oop module = java_lang_ClassLoader::unnamedModule(cld->class_loader());
#if INCLUDE_CDS_JAVA_HEAP
ModuleEntry* archived_unnamed_module = ClassLoaderDataShared::archived_unnamed_module(cld);
if (archived_unnamed_module != nullptr) {
archived_unnamed_module->load_from_archive(cld);
archived_unnamed_module->restore_archived_oops(cld);
return archived_unnamed_module;
}
#endif
// Ensure that the unnamed module was correctly set when the class loader was constructed.
// Guarantee will cause a recognizable crash if the user code has circumvented calling the ClassLoader constructor.
ResourceMark rm;
@ -333,6 +344,16 @@ ModuleEntry* ModuleEntry::create_unnamed_module(ClassLoaderData* cld) {
}
ModuleEntry* ModuleEntry::create_boot_unnamed_module(ClassLoaderData* cld) {
#if INCLUDE_CDS_JAVA_HEAP
ModuleEntry* archived_unnamed_module = ClassLoaderDataShared::archived_boot_unnamed_module();
if (archived_unnamed_module != nullptr) {
archived_unnamed_module->load_from_archive(cld);
// It's too early to call archived_unnamed_module->restore_archived_oops(cld).
// We will do it inside Modules::set_bootloader_unnamed_module()
return archived_unnamed_module;
}
#endif
// For the boot loader, the java.lang.Module for the unnamed module
// is not known until a call to JVM_SetBootLoaderUnnamedModule is made. At
// this point initially create the ModuleEntry for the unnamed module.
@ -345,7 +366,6 @@ ModuleEntry* ModuleEntry::create_boot_unnamed_module(ClassLoaderData* cld) {
// This is okay because the unnamed module gets created before the ClassLoaderData
// is available to other threads.
ModuleEntry* ModuleEntry::new_unnamed_module_entry(Handle module_handle, ClassLoaderData* cld) {
ModuleEntry* entry = new ModuleEntry(module_handle, /*is_open*/true, /*name*/nullptr,
/*version*/ nullptr, /*location*/ nullptr,
cld);
@ -395,17 +415,17 @@ static int _num_archived_module_entries = 0;
static int _num_inited_module_entries = 0;
#endif
bool ModuleEntry::should_be_archived() const {
return SystemDictionaryShared::is_builtin_loader(loader_data());
}
ModuleEntry* ModuleEntry::allocate_archived_entry() const {
assert(is_named(), "unnamed packages/modules are not archived");
precond(should_be_archived());
precond(CDSConfig::is_dumping_full_module_graph());
ModuleEntry* archived_entry = (ModuleEntry*)ArchiveBuilder::rw_region_alloc(sizeof(ModuleEntry));
memcpy((void*)archived_entry, (void*)this, sizeof(ModuleEntry));
if (CDSConfig::is_dumping_full_module_graph()) {
archived_entry->_archived_module_index = HeapShared::append_root(module_oop());
} else {
archived_entry->_archived_module_index = -1;
}
archived_entry->_archived_module_index = HeapShared::append_root(module_oop());
if (_archive_modules_entries == nullptr) {
_archive_modules_entries = new (mtClass)ArchivedModuleEntries();
}
@ -489,10 +509,14 @@ void ModuleEntry::init_as_archived_entry() {
set_archived_reads(write_growable_array(reads()));
_loader_data = nullptr; // re-init at runtime
_shared_path_index = AOTClassLocationConfig::dumptime()->get_module_shared_path_index(_location);
if (name() != nullptr) {
_shared_path_index = AOTClassLocationConfig::dumptime()->get_module_shared_path_index(_location);
_name = ArchiveBuilder::get_buffered_symbol(_name);
ArchivePtrMarker::mark_pointer((address*)&_name);
} else {
// _shared_path_index is used only by SystemDictionary::is_shared_class_visible_impl()
// for checking classes in named modules.
_shared_path_index = -1;
}
if (_version != nullptr) {
_version = ArchiveBuilder::get_buffered_symbol(_version);
@ -741,7 +765,7 @@ void ModuleEntryTable::modules_do(ModuleClosure* closure) {
_table.iterate_all(do_f);
}
void ModuleEntry::print(outputStream* st) {
void ModuleEntry::print(outputStream* st) const {
st->print_cr("entry " PTR_FORMAT " name %s module " PTR_FORMAT " loader %s version %s location %s strict %s",
p2i(this),
name_as_C_string(),

View File

@ -186,10 +186,10 @@ public:
static ModuleEntry* new_unnamed_module_entry(Handle module_handle, ClassLoaderData* cld);
// Note caller requires ResourceMark
const char* name_as_C_string() {
const char* name_as_C_string() const {
return is_named() ? name()->as_C_string() : UNNAMED_MODULE;
}
void print(outputStream* st = tty);
void print(outputStream* st = tty) const;
void verify();
CDS_ONLY(int shared_path_index() { return _shared_path_index;})
@ -197,6 +197,7 @@ public:
JFR_ONLY(DEFINE_TRACE_ID_METHODS;)
#if INCLUDE_CDS_JAVA_HEAP
bool should_be_archived() const;
void iterate_symbols(MetaspaceClosure* closure);
ModuleEntry* allocate_archived_entry() const;
void init_as_archived_entry();

View File

@ -474,6 +474,7 @@ void Modules::define_module(Handle module, jboolean is_open, jstring version,
}
#if INCLUDE_CDS_JAVA_HEAP
static bool _seen_boot_unnamed_module = false;
static bool _seen_platform_unnamed_module = false;
static bool _seen_system_unnamed_module = false;
@ -509,24 +510,20 @@ void Modules::check_archived_module_oop(oop orig_module_obj) {
// For each named module, we archive both the java.lang.Module oop and the ModuleEntry.
assert(orig_module_ent->has_been_archived(), "sanity");
} else {
// We only archive two unnamed module oops (for platform and system loaders). These do NOT have an archived
// ModuleEntry.
//
// At runtime, these oops are fetched from java_lang_ClassLoader::unnamedModule(loader) and
// are initialized in ClassLoaderData::ClassLoaderData() => ModuleEntry::create_unnamed_module(), where
// a new ModuleEntry is allocated.
assert(!loader_data->is_boot_class_loader_data(), "unnamed module for boot loader should be not archived");
assert(!orig_module_ent->has_been_archived(), "sanity");
// We always archive unnamed module oop for boot, platform, and system loaders.
precond(orig_module_ent->should_be_archived());
precond(orig_module_ent->has_been_archived());
if (SystemDictionary::is_platform_class_loader(loader_data->class_loader())) {
if (loader_data->is_boot_class_loader_data()) {
assert(!_seen_boot_unnamed_module, "only once");
_seen_boot_unnamed_module = true;
} else if (SystemDictionary::is_platform_class_loader(loader_data->class_loader())) {
assert(!_seen_platform_unnamed_module, "only once");
_seen_platform_unnamed_module = true;
} else if (SystemDictionary::is_system_class_loader(loader_data->class_loader())) {
assert(!_seen_system_unnamed_module, "only once");
_seen_system_unnamed_module = true;
} else {
// The java.lang.Module oop and ModuleEntry of the unnamed module of the boot loader are
// not in the archived module graph. These are always allocated at runtime.
ShouldNotReachHere();
}
}
@ -777,9 +774,18 @@ void Modules::set_bootloader_unnamed_module(Handle module, TRAPS) {
ClassLoaderData* boot_loader_data = ClassLoaderData::the_null_class_loader_data();
ModuleEntry* unnamed_module = boot_loader_data->unnamed_module();
assert(unnamed_module != nullptr, "boot loader's unnamed ModuleEntry not defined");
unnamed_module->set_module_handle(boot_loader_data->add_handle(module));
// Store pointer to the ModuleEntry in the unnamed module's java.lang.Module object.
java_lang_Module::set_module_entry(module(), unnamed_module);
#if INCLUDE_CDS_JAVA_HEAP
if (CDSConfig::is_using_full_module_graph()) {
precond(unnamed_module == ClassLoaderDataShared::archived_boot_unnamed_module());
unnamed_module->restore_archived_oops(boot_loader_data);
} else
#endif
{
unnamed_module->set_module_handle(boot_loader_data->add_handle(module));
// Store pointer to the ModuleEntry in the unnamed module's java.lang.Module object.
java_lang_Module::set_module_entry(module(), unnamed_module);
}
}
void Modules::add_module_exports(Handle from_module, jstring package_name, Handle to_module, TRAPS) {

View File

@ -30,6 +30,7 @@
#include "classfile/packageEntry.hpp"
#include "classfile/vmSymbols.hpp"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/resourceArea.hpp"
#include "oops/array.hpp"
#include "oops/symbol.hpp"
@ -218,8 +219,12 @@ typedef ResourceHashtable<
AnyObj::C_HEAP> ArchivedPackageEntries;
static ArchivedPackageEntries* _archived_packages_entries = nullptr;
bool PackageEntry::should_be_archived() const {
return module()->should_be_archived();
}
PackageEntry* PackageEntry::allocate_archived_entry() const {
assert(!in_unnamed_module(), "unnamed packages/modules are not archived");
precond(should_be_archived());
PackageEntry* archived_entry = (PackageEntry*)ArchiveBuilder::rw_region_alloc(sizeof(PackageEntry));
memcpy((void*)archived_entry, (void*)this, sizeof(PackageEntry));
@ -257,6 +262,12 @@ void PackageEntry::init_as_archived_entry() {
ArchivePtrMarker::mark_pointer((address*)&_name);
ArchivePtrMarker::mark_pointer((address*)&_module);
ArchivePtrMarker::mark_pointer((address*)&_qualified_exports);
LogStreamHandle(Info, aot, package) st;
if (st.is_enabled()) {
st.print("archived ");
print(&st);
}
}
void PackageEntry::load_from_archive() {
@ -280,7 +291,7 @@ Array<PackageEntry*>* PackageEntryTable::allocate_archived_entries() {
// First count the packages in named modules
int n = 0;
auto count = [&] (const SymbolHandle& key, PackageEntry*& p) {
if (p->module()->is_named()) {
if (p->should_be_archived()) {
n++;
}
};
@ -290,9 +301,7 @@ Array<PackageEntry*>* PackageEntryTable::allocate_archived_entries() {
// reset n
n = 0;
auto grab = [&] (const SymbolHandle& key, PackageEntry*& p) {
if (p->module()->is_named()) {
// We don't archive unnamed modules, or packages in unnamed modules. They will be
// created on-demand at runtime as classes in such packages are loaded.
if (p->should_be_archived()) {
archived_packages->at_put(n++, p);
}
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 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
@ -208,6 +208,7 @@ public:
void print(outputStream* st = tty);
#if INCLUDE_CDS_JAVA_HEAP
bool should_be_archived() const;
void iterate_symbols(MetaspaceClosure* closure);
PackageEntry* allocate_archived_entry() const;
void init_as_archived_entry();

View File

@ -379,8 +379,8 @@ public:
static void init2() NOT_CDS_RETURN;
static void close() NOT_CDS_RETURN;
static bool is_on() CDS_ONLY({ return cache() != nullptr && !_cache->closing(); }) NOT_CDS_RETURN_(false);
static bool is_on_for_use() { return is_on() && _cache->for_use(); }
static bool is_on_for_dump() { return is_on() && _cache->for_dump(); }
static bool is_on_for_use() CDS_ONLY({ return is_on() && _cache->for_use(); }) NOT_CDS_RETURN_(false);
static bool is_on_for_dump() CDS_ONLY({ return is_on() && _cache->for_dump(); }) NOT_CDS_RETURN_(false);
static bool is_dumping_stub() NOT_CDS_RETURN_(false);
static bool is_dumping_adapter() NOT_CDS_RETURN_(false);
static bool is_using_stub() NOT_CDS_RETURN_(false);

View File

@ -2446,7 +2446,7 @@ void nmethod::do_unloading(bool unloading_occurred) {
}
}
void nmethod::oops_do(OopClosure* f, bool allow_dead) {
void nmethod::oops_do(OopClosure* f) {
// Prevent extra code cache walk for platforms that don't have immediate oops.
if (relocInfo::mustIterateImmediateOopsInCode()) {
RelocIterator iter(this, oops_reloc_begin());

View File

@ -919,8 +919,7 @@ public:
bool jvmci_skip_profile_deopt() const;
#endif
void oops_do(OopClosure* f) { oops_do(f, false); }
void oops_do(OopClosure* f, bool allow_dead);
void oops_do(OopClosure* f);
// All-in-one claiming of nmethods: returns true if the caller successfully claimed that
// nmethod.

View File

@ -367,33 +367,31 @@ void CompileQueue::add(CompileTask* task) {
*/
void CompileQueue::delete_all() {
MutexLocker mu(MethodCompileQueue_lock);
CompileTask* next = _first;
CompileTask* current = _first;
// Iterate over all tasks in the compile queue
while (next != nullptr) {
CompileTask* current = next;
next = current->next();
bool found_waiter = false;
{
MutexLocker ct_lock(CompileTaskWait_lock);
assert(current->waiting_for_completion_count() <= 1, "more than one thread are waiting for task");
if (current->waiting_for_completion_count() > 0) {
// If another thread waits for this task, we must wake them up
// so they will stop waiting and free the task.
CompileTaskWait_lock->notify_all();
found_waiter = true;
}
}
if (!found_waiter) {
// If no one was waiting for this task, we need to delete it ourselves.
// In this case, the task is also certainly unlocked, because, again, there is no waiter.
// Otherwise, by convention, it's the waiters responsibility to delete the task.
while (current != nullptr) {
if (!current->is_blocking()) {
// Non-blocking task. No one is waiting for it, delete it now.
delete current;
} else {
// Blocking task. By convention, it is the waiters responsibility
// to delete the task. We cannot delete it here, because we do not
// coordinate with waiters. We will notify the waiters later.
}
current = current->next();
}
_first = nullptr;
_last = nullptr;
// Wake up all blocking task waiters to deal with remaining blocking
// tasks. This is not a performance sensitive path, so we do this
// unconditionally to simplify coding/testing.
{
MonitorLocker ml(Thread::current(), CompileTaskWait_lock);
ml.notify_all();
}
// Wake up all threads that block on the queue.
MethodCompileQueue_lock->notify_all();
}
@ -1720,23 +1718,26 @@ void CompileBroker::wait_for_completion(CompileTask* task) {
} else
#endif
{
MonitorLocker ml(thread, CompileTaskWait_lock);
free_task = true;
task->inc_waiting_for_completion();
// Wait until the task is complete or compilation is shut down.
MonitorLocker ml(thread, CompileTaskWait_lock);
while (!task->is_complete() && !is_compilation_disabled_forever()) {
ml.wait();
}
task->dec_waiting_for_completion();
}
// It is harmless to check this status without the lock, because
// completion is a stable property.
if (!task->is_complete() && is_compilation_disabled_forever()) {
// Task is not complete, and we are exiting for compilation shutdown.
// The task can still be executed by some compiler thread, therefore
// we cannot delete it. This will leave task allocated, which leaks it.
// At this (degraded) point, it is less risky to abandon the task,
// rather than attempting a more complicated deletion protocol.
free_task = false;
}
if (free_task) {
if (is_compilation_disabled_forever()) {
delete task;
return;
}
// It is harmless to check this status without the lock, because
// completion is a stable property (until the task object is deleted).
assert(task->is_complete(), "Compilation should have completed");
// By convention, the waiter is responsible for deleting a

View File

@ -381,7 +381,7 @@ public:
}
static bool is_compilation_disabled_forever() {
return _should_compile_new_jobs == shutdown_compilation;
return Atomic::load(&_should_compile_new_jobs) == shutdown_compilation;
}
static void wait_for_no_active_tasks();

View File

@ -56,8 +56,6 @@ CompileTask::CompileTask(int compile_id,
_comp_level = comp_level;
_num_inlined_bytecodes = 0;
_waiting_count = 0;
_is_complete = false;
_is_success = false;

View File

@ -99,7 +99,6 @@ class CompileTask : public CHeapObj<mtCompiler> {
// Compilation state for a blocking JVMCI compilation
JVMCICompileState* _blocking_jvmci_compile_state;
#endif
int _waiting_count; // See waiting_for_completion_count()
int _comp_level;
int _num_inlined_bytecodes;
CompileTask* _next, *_prev;
@ -164,23 +163,6 @@ class CompileTask : public CHeapObj<mtCompiler> {
}
#endif
// See how many threads are waiting for this task. Must have lock to read this.
int waiting_for_completion_count() {
assert(CompileTaskWait_lock->owned_by_self(), "must have lock to use waiting_for_completion_count()");
return _waiting_count;
}
// Indicates that a thread is waiting for this task to complete. Must have lock to use this.
void inc_waiting_for_completion() {
assert(CompileTaskWait_lock->owned_by_self(), "must have lock to use inc_waiting_for_completion()");
_waiting_count++;
}
// Indicates that a thread stopped waiting for this task to complete. Must have lock to use this.
void dec_waiting_for_completion() {
assert(CompileTaskWait_lock->owned_by_self(), "must have lock to use dec_waiting_for_completion()");
assert(_waiting_count > 0, "waiting count is not positive");
_waiting_count--;
}
void mark_complete() { _is_complete = true; }
void mark_success() { _is_success = true; }
void mark_started(jlong time) { _time_started = time; }

View File

@ -1732,6 +1732,66 @@ static bool gc_counter_less_than(uint x, uint y) {
#define LOG_COLLECT_CONCURRENTLY_COMPLETE(cause, result) \
LOG_COLLECT_CONCURRENTLY(cause, "complete %s", BOOL_TO_STR(result))
bool G1CollectedHeap::wait_full_mark_finished(GCCause::Cause cause,
uint old_marking_started_before,
uint old_marking_started_after,
uint old_marking_completed_after) {
// Request is finished if a full collection (concurrent or stw)
// was started after this request and has completed, e.g.
// started_before < completed_after.
if (gc_counter_less_than(old_marking_started_before,
old_marking_completed_after)) {
LOG_COLLECT_CONCURRENTLY_COMPLETE(cause, true);
return true;
}
if (old_marking_started_after != old_marking_completed_after) {
// If there is an in-progress cycle (possibly started by us), then
// wait for that cycle to complete, e.g.
// while completed_now < started_after.
LOG_COLLECT_CONCURRENTLY(cause, "wait");
MonitorLocker ml(G1OldGCCount_lock);
while (gc_counter_less_than(_old_marking_cycles_completed,
old_marking_started_after)) {
ml.wait();
}
// Request is finished if the collection we just waited for was
// started after this request.
if (old_marking_started_before != old_marking_started_after) {
LOG_COLLECT_CONCURRENTLY(cause, "complete after wait");
return true;
}
}
return false;
}
// After calling wait_full_mark_finished(), this method determines whether we
// previously failed for ordinary reasons (concurrent cycle in progress, whitebox
// has control). Returns if this has been such an ordinary reason.
static bool should_retry_vm_op(GCCause::Cause cause,
VM_G1TryInitiateConcMark* op) {
if (op->cycle_already_in_progress()) {
// If VMOp failed because a cycle was already in progress, it
// is now complete. But it didn't finish this user-requested
// GC, so try again.
LOG_COLLECT_CONCURRENTLY(cause, "retry after in-progress");
return true;
} else if (op->whitebox_attached()) {
// If WhiteBox wants control, wait for notification of a state
// change in the controller, then try again. Don't wait for
// release of control, since collections may complete while in
// control. Note: This won't recognize a STW full collection
// while waiting; we can't wait on multiple monitors.
LOG_COLLECT_CONCURRENTLY(cause, "whitebox control stall");
MonitorLocker ml(ConcurrentGCBreakpoints::monitor());
if (ConcurrentGCBreakpoints::is_controlled()) {
ml.wait();
}
return true;
}
return false;
}
bool G1CollectedHeap::try_collect_concurrently(GCCause::Cause cause,
uint gc_counter,
uint old_marking_started_before) {
@ -1792,7 +1852,45 @@ bool G1CollectedHeap::try_collect_concurrently(GCCause::Cause cause,
LOG_COLLECT_CONCURRENTLY(cause, "ignoring STW full GC");
old_marking_started_before = old_marking_started_after;
}
} else if (GCCause::is_codecache_requested_gc(cause)) {
// For a CodeCache requested GC, before marking, progress is ensured as the
// following Remark pause unloads code (and signals the requester such).
// Otherwise we must ensure that it is restarted.
//
// For a CodeCache requested GC, a successful GC operation means that
// (1) marking is in progress. I.e. the VMOp started the marking or a
// Remark pause is pending from a different VM op; we will potentially
// abort a mixed phase if needed.
// (2) a new cycle was started (by this thread or some other), or
// (3) a Full GC was performed.
//
// Cases (2) and (3) are detected together by a change to
// _old_marking_cycles_started.
//
// Compared to other "automatic" GCs (see below), we do not consider being
// in whitebox as sufficient too because we might be anywhere within that
// cycle and we need to make progress.
if (op.mark_in_progress() ||
(old_marking_started_before != old_marking_started_after)) {
LOG_COLLECT_CONCURRENTLY_COMPLETE(cause, true);
return true;
}
if (wait_full_mark_finished(cause,
old_marking_started_before,
old_marking_started_after,
old_marking_completed_after)) {
return true;
}
if (should_retry_vm_op(cause, &op)) {
continue;
}
} else if (!GCCause::is_user_requested_gc(cause)) {
assert(cause == GCCause::_g1_humongous_allocation ||
cause == GCCause::_g1_periodic_collection,
"Unsupported cause %s", GCCause::to_string(cause));
// For an "automatic" (not user-requested) collection, we just need to
// ensure that progress is made.
//
@ -1804,11 +1902,6 @@ bool G1CollectedHeap::try_collect_concurrently(GCCause::Cause cause,
// (5) a Full GC was performed.
// Cases (4) and (5) are detected together by a change to
// _old_marking_cycles_started.
//
// Note that (1) does not imply (4). If we're still in the mixed
// phase of an earlier concurrent collection, the request to make the
// collection a concurrent start won't be honored. If we don't check for
// both conditions we'll spin doing back-to-back collections.
if (op.gc_succeeded() ||
op.cycle_already_in_progress() ||
op.whitebox_attached() ||
@ -1832,56 +1925,20 @@ bool G1CollectedHeap::try_collect_concurrently(GCCause::Cause cause,
BOOL_TO_STR(op.gc_succeeded()),
old_marking_started_before, old_marking_started_after);
// Request is finished if a full collection (concurrent or stw)
// was started after this request and has completed, e.g.
// started_before < completed_after.
if (gc_counter_less_than(old_marking_started_before,
old_marking_completed_after)) {
LOG_COLLECT_CONCURRENTLY_COMPLETE(cause, true);
if (wait_full_mark_finished(cause,
old_marking_started_before,
old_marking_started_after,
old_marking_completed_after)) {
return true;
}
if (old_marking_started_after != old_marking_completed_after) {
// If there is an in-progress cycle (possibly started by us), then
// wait for that cycle to complete, e.g.
// while completed_now < started_after.
LOG_COLLECT_CONCURRENTLY(cause, "wait");
MonitorLocker ml(G1OldGCCount_lock);
while (gc_counter_less_than(_old_marking_cycles_completed,
old_marking_started_after)) {
ml.wait();
}
// Request is finished if the collection we just waited for was
// started after this request.
if (old_marking_started_before != old_marking_started_after) {
LOG_COLLECT_CONCURRENTLY(cause, "complete after wait");
return true;
}
}
// If VMOp was successful then it started a new cycle that the above
// wait &etc should have recognized as finishing this request. This
// differs from a non-user-request, where gc_succeeded does not imply
// a new cycle was started.
assert(!op.gc_succeeded(), "invariant");
if (op.cycle_already_in_progress()) {
// If VMOp failed because a cycle was already in progress, it
// is now complete. But it didn't finish this user-requested
// GC, so try again.
LOG_COLLECT_CONCURRENTLY(cause, "retry after in-progress");
continue;
} else if (op.whitebox_attached()) {
// If WhiteBox wants control, wait for notification of a state
// change in the controller, then try again. Don't wait for
// release of control, since collections may complete while in
// control. Note: This won't recognize a STW full collection
// while waiting; we can't wait on multiple monitors.
LOG_COLLECT_CONCURRENTLY(cause, "whitebox control stall");
MonitorLocker ml(ConcurrentGCBreakpoints::monitor());
if (ConcurrentGCBreakpoints::is_controlled()) {
ml.wait();
}
if (should_retry_vm_op(cause, &op)) {
continue;
}
}

View File

@ -274,6 +274,14 @@ private:
// (e) cause == _g1_periodic_collection and +G1PeriodicGCInvokesConcurrent.
bool should_do_concurrent_full_gc(GCCause::Cause cause);
// Wait until a full mark (either currently in progress or one that completed
// after the current request) has finished. Returns whether that full mark started
// after this request. If so, we typically do not need another one.
bool wait_full_mark_finished(GCCause::Cause cause,
uint old_marking_started_before,
uint old_marking_started_after,
uint old_marking_completed_after);
// Attempt to start a concurrent cycle with the indicated cause.
// precondition: should_do_concurrent_full_gc(cause)
bool try_collect_concurrently(GCCause::Cause cause,

View File

@ -60,6 +60,9 @@ class G1CollectorState {
// do the concurrent start phase work.
volatile bool _initiate_conc_mark_if_possible;
// Marking is in progress. Set from start of the concurrent start pause to the
// end of the Remark pause.
bool _mark_in_progress;
// Marking or rebuilding remembered set work is in progress. Set from the end
// of the concurrent start pause to the end of the Cleanup pause.
bool _mark_or_rebuild_in_progress;
@ -78,6 +81,7 @@ public:
_in_concurrent_start_gc(false),
_initiate_conc_mark_if_possible(false),
_mark_in_progress(false),
_mark_or_rebuild_in_progress(false),
_clear_bitmap_in_progress(false),
_in_full_gc(false) { }
@ -92,6 +96,7 @@ public:
void set_initiate_conc_mark_if_possible(bool v) { _initiate_conc_mark_if_possible = v; }
void set_mark_in_progress(bool v) { _mark_in_progress = v; }
void set_mark_or_rebuild_in_progress(bool v) { _mark_or_rebuild_in_progress = v; }
void set_clear_bitmap_in_progress(bool v) { _clear_bitmap_in_progress = v; }
@ -106,6 +111,7 @@ public:
bool initiate_conc_mark_if_possible() const { return _initiate_conc_mark_if_possible; }
bool mark_in_progress() const { return _mark_in_progress; }
bool mark_or_rebuild_in_progress() const { return _mark_or_rebuild_in_progress; }
bool clear_bitmap_in_progress() const { return _clear_bitmap_in_progress; }

View File

@ -591,6 +591,7 @@ void G1Policy::record_full_collection_end() {
collector_state()->set_in_young_gc_before_mixed(false);
collector_state()->set_initiate_conc_mark_if_possible(need_to_start_conc_mark("end of Full GC"));
collector_state()->set_in_concurrent_start_gc(false);
collector_state()->set_mark_in_progress(false);
collector_state()->set_mark_or_rebuild_in_progress(false);
collector_state()->set_clear_bitmap_in_progress(false);
@ -703,6 +704,7 @@ void G1Policy::record_concurrent_mark_remark_end() {
double elapsed_time_ms = (end_time_sec - start_time_sec) * 1000.0;
_analytics->report_concurrent_mark_remark_times_ms(elapsed_time_ms);
record_pause(G1GCPauseType::Remark, start_time_sec, end_time_sec);
collector_state()->set_mark_in_progress(false);
}
G1CollectionSetCandidates* G1Policy::candidates() const {
@ -936,6 +938,7 @@ void G1Policy::record_young_collection_end(bool concurrent_operation_is_full_mar
assert(!(G1GCPauseTypeHelper::is_concurrent_start_pause(this_pause) && collector_state()->mark_or_rebuild_in_progress()),
"If the last pause has been concurrent start, we should not have been in the marking window");
if (G1GCPauseTypeHelper::is_concurrent_start_pause(this_pause)) {
collector_state()->set_mark_in_progress(concurrent_operation_is_full_mark);
collector_state()->set_mark_or_rebuild_in_progress(concurrent_operation_is_full_mark);
}
@ -1222,6 +1225,17 @@ void G1Policy::initiate_conc_mark() {
collector_state()->set_initiate_conc_mark_if_possible(false);
}
static const char* requester_for_mixed_abort(GCCause::Cause cause) {
if (cause == GCCause::_wb_breakpoint) {
return "run_to breakpoint";
} else if (GCCause::is_codecache_requested_gc(cause)) {
return "codecache";
} else {
assert(G1CollectedHeap::heap()->is_user_requested_concurrent_full_gc(cause), "must be");
return "user";
}
}
void G1Policy::decide_on_concurrent_start_pause() {
// We are about to decide on whether this pause will be a
// concurrent start pause.
@ -1254,8 +1268,7 @@ void G1Policy::decide_on_concurrent_start_pause() {
initiate_conc_mark();
log_debug(gc, ergo)("Initiate concurrent cycle (concurrent cycle initiation requested)");
} else if (_g1h->is_user_requested_concurrent_full_gc(cause) ||
(cause == GCCause::_codecache_GC_threshold) ||
(cause == GCCause::_codecache_GC_aggressive) ||
GCCause::is_codecache_requested_gc(cause) ||
(cause == GCCause::_wb_breakpoint)) {
// Initiate a concurrent start. A concurrent start must be a young only
// GC, so the collector state must be updated to reflect this.
@ -1270,7 +1283,7 @@ void G1Policy::decide_on_concurrent_start_pause() {
abort_time_to_mixed_tracking();
initiate_conc_mark();
log_debug(gc, ergo)("Initiate concurrent cycle (%s requested concurrent cycle)",
(cause == GCCause::_wb_breakpoint) ? "run_to breakpoint" : "user");
requester_for_mixed_abort(cause));
} else {
// The concurrent marking thread is still finishing up the
// previous cycle. If we start one right now the two cycles

View File

@ -59,6 +59,7 @@ VM_G1TryInitiateConcMark::VM_G1TryInitiateConcMark(uint gc_count_before,
GCCause::Cause gc_cause) :
VM_GC_Collect_Operation(gc_count_before, gc_cause),
_transient_failure(false),
_mark_in_progress(false),
_cycle_already_in_progress(false),
_whitebox_attached(false),
_terminating(false),
@ -83,6 +84,9 @@ void VM_G1TryInitiateConcMark::doit() {
// Record for handling by caller.
_terminating = g1h->concurrent_mark_is_terminating();
_mark_in_progress = g1h->collector_state()->mark_in_progress();
_cycle_already_in_progress = g1h->concurrent_mark()->cm_thread()->in_progress();
if (_terminating && GCCause::is_user_requested_gc(_gc_cause)) {
// When terminating, the request to initiate a concurrent cycle will be
// ignored by do_collection_pause_at_safepoint; instead it will just do
@ -91,9 +95,8 @@ void VM_G1TryInitiateConcMark::doit() {
// requests the alternative GC might still be needed.
} else if (!g1h->policy()->force_concurrent_start_if_outside_cycle(_gc_cause)) {
// Failure to force the next GC pause to be a concurrent start indicates
// there is already a concurrent marking cycle in progress. Set flag
// to notify the caller and return immediately.
_cycle_already_in_progress = true;
// there is already a concurrent marking cycle in progress. Flags to indicate
// that were already set, so return immediately.
} else if ((_gc_cause != GCCause::_wb_breakpoint) &&
ConcurrentGCBreakpoints::is_controlled()) {
// WhiteBox wants to be in control of concurrent cycles, so don't try to

View File

@ -45,6 +45,7 @@ public:
class VM_G1TryInitiateConcMark : public VM_GC_Collect_Operation {
bool _transient_failure;
bool _mark_in_progress;
bool _cycle_already_in_progress;
bool _whitebox_attached;
bool _terminating;
@ -59,6 +60,7 @@ public:
virtual bool doit_prologue();
virtual void doit();
bool transient_failure() const { return _transient_failure; }
bool mark_in_progress() const { return _mark_in_progress; }
bool cycle_already_in_progress() const { return _cycle_already_in_progress; }
bool whitebox_attached() const { return _whitebox_attached; }
bool terminating() const { return _terminating; }

View File

@ -1,226 +0,0 @@
/*
* Copyright (c) 2004, 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 "gc/parallel/gcAdaptivePolicyCounters.hpp"
#include "memory/resourceArea.hpp"
// This class keeps statistical information and computes the
// size of the heap.
GCAdaptivePolicyCounters::GCAdaptivePolicyCounters(const char* name,
int collectors,
int generations,
AdaptiveSizePolicy* size_policy_arg)
: GCPolicyCounters(name, collectors, generations),
_size_policy(size_policy_arg) {
if (UsePerfData) {
EXCEPTION_MARK;
ResourceMark rm;
const char* cname = PerfDataManager::counter_name(name_space(), "edenSize");
_eden_size_counter = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Bytes, _size_policy->calculated_eden_size_in_bytes(), CHECK);
cname = PerfDataManager::counter_name(name_space(), "promoSize");
_promo_size_counter = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Bytes, size_policy()->calculated_promo_size_in_bytes(),
CHECK);
cname = PerfDataManager::counter_name(name_space(), "youngCapacity");
size_t young_capacity_in_bytes =
_size_policy->calculated_eden_size_in_bytes() +
_size_policy->calculated_survivor_size_in_bytes();
_young_capacity_counter = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Bytes, young_capacity_in_bytes, CHECK);
cname = PerfDataManager::counter_name(name_space(), "avgSurvivedAvg");
_avg_survived_avg_counter = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Bytes, size_policy()->calculated_survivor_size_in_bytes(),
CHECK);
cname = PerfDataManager::counter_name(name_space(), "avgSurvivedDev");
_avg_survived_dev_counter = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Bytes, (jlong) 0 , CHECK);
cname = PerfDataManager::counter_name(name_space(), "avgSurvivedPaddedAvg");
_avg_survived_padded_avg_counter =
PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes,
size_policy()->calculated_survivor_size_in_bytes(), CHECK);
cname = PerfDataManager::counter_name(name_space(), "avgMinorPauseTime");
_avg_minor_pause_counter = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Ticks, (jlong) _size_policy->_avg_minor_pause->average(),
CHECK);
cname = PerfDataManager::counter_name(name_space(), "avgMinorIntervalTime");
_avg_minor_interval_counter = PerfDataManager::create_variable(SUN_GC,
cname,
PerfData::U_Ticks,
(jlong) _size_policy->_avg_minor_interval->average(),
CHECK);
#ifdef NOT_PRODUCT
// This is a counter for the most recent minor pause time
// (the last sample, not the average). It is useful for
// verifying the average pause time but not worth putting
// into the product.
cname = PerfDataManager::counter_name(name_space(), "minorPauseTime");
_minor_pause_counter = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Ticks, (jlong) _size_policy->_avg_minor_pause->last_sample(),
CHECK);
#endif
cname = PerfDataManager::counter_name(name_space(), "minorGcCost");
_minor_gc_cost_counter = PerfDataManager::create_variable(SUN_GC,
cname,
PerfData::U_Ticks,
(jlong) _size_policy->minor_gc_cost(),
CHECK);
cname = PerfDataManager::counter_name(name_space(), "mutatorCost");
_mutator_cost_counter = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Ticks, (jlong) _size_policy->mutator_cost(), CHECK);
cname = PerfDataManager::counter_name(name_space(), "survived");
_survived_counter = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Bytes, (jlong) 0, CHECK);
cname = PerfDataManager::counter_name(name_space(), "promoted");
_promoted_counter = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Bytes, (jlong) 0, CHECK);
cname = PerfDataManager::counter_name(name_space(), "avgYoungLive");
_avg_young_live_counter = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Bytes, (jlong) size_policy()->avg_young_live()->average(),
CHECK);
cname = PerfDataManager::counter_name(name_space(), "avgOldLive");
_avg_old_live_counter = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Bytes, (jlong) size_policy()->avg_old_live()->average(),
CHECK);
cname = PerfDataManager::counter_name(name_space(), "survivorOverflowed");
_survivor_overflowed_counter = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Events, (jlong)0, CHECK);
cname = PerfDataManager::counter_name(name_space(),
"decrementTenuringThresholdForGcCost");
_decrement_tenuring_threshold_for_gc_cost_counter =
PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Events,
(jlong)0, CHECK);
cname = PerfDataManager::counter_name(name_space(),
"incrementTenuringThresholdForGcCost");
_increment_tenuring_threshold_for_gc_cost_counter =
PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Events,
(jlong)0, CHECK);
cname = PerfDataManager::counter_name(name_space(),
"decrementTenuringThresholdForSurvivorLimit");
_decrement_tenuring_threshold_for_survivor_limit_counter =
PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Events,
(jlong)0, CHECK);
cname = PerfDataManager::counter_name(name_space(),
"changeYoungGenForMinPauses");
_change_young_gen_for_min_pauses_counter =
PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Events,
(jlong)0, CHECK);
cname = PerfDataManager::counter_name(name_space(),
"changeOldGenForMajPauses");
_change_old_gen_for_maj_pauses_counter =
PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Events,
(jlong)0, CHECK);
cname = PerfDataManager::counter_name(name_space(),
"increaseOldGenForThroughput");
_change_old_gen_for_throughput_counter =
PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Events,
(jlong)0, CHECK);
cname = PerfDataManager::counter_name(name_space(),
"increaseYoungGenForThroughput");
_change_young_gen_for_throughput_counter =
PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Events,
(jlong)0, CHECK);
cname = PerfDataManager::counter_name(name_space(),
"decreaseForFootprint");
_decrease_for_footprint_counter =
PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Events, (jlong)0, CHECK);
cname = PerfDataManager::counter_name(name_space(), "decideAtFullGc");
_decide_at_full_gc_counter = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_None, (jlong)0, CHECK);
cname = PerfDataManager::counter_name(name_space(), "minorPauseYoungSlope");
_minor_pause_young_slope_counter =
PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_None, (jlong) 0, CHECK);
cname = PerfDataManager::counter_name(name_space(), "majorCollectionSlope");
_major_collection_slope_counter =
PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_None, (jlong) 0, CHECK);
cname = PerfDataManager::counter_name(name_space(), "minorCollectionSlope");
_minor_collection_slope_counter =
PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_None, (jlong) 0, CHECK);
}
}
void GCAdaptivePolicyCounters::update_counters_from_policy() {
if (UsePerfData && (size_policy() != nullptr)) {
update_avg_minor_pause_counter();
update_avg_minor_interval_counter();
#ifdef NOT_PRODUCT
update_minor_pause_counter();
#endif
update_minor_gc_cost_counter();
update_avg_young_live_counter();
update_survivor_size_counters();
update_avg_survived_avg_counters();
update_avg_survived_dev_counters();
update_avg_survived_padded_avg_counters();
update_change_old_gen_for_throughput();
update_change_young_gen_for_throughput();
update_decrease_for_footprint();
update_change_young_gen_for_min_pauses();
update_change_old_gen_for_maj_pauses();
update_minor_pause_young_slope_counter();
update_minor_collection_slope_counter();
update_major_collection_slope_counter();
}
}
void GCAdaptivePolicyCounters::update_counters() {
if (UsePerfData) {
update_counters_from_policy();
}
}

View File

@ -1,228 +0,0 @@
/*
* Copyright (c) 2004, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_GC_PARALLEL_GCADAPTIVEPOLICYCOUNTERS_HPP
#define SHARE_GC_PARALLEL_GCADAPTIVEPOLICYCOUNTERS_HPP
#include "gc/shared/adaptiveSizePolicy.hpp"
#include "gc/shared/gcPolicyCounters.hpp"
#include "utilities/macros.hpp"
// This class keeps statistical information and computes the
// size of the heap.
class GCAdaptivePolicyCounters : public GCPolicyCounters {
protected:
PerfVariable* _eden_size_counter;
PerfVariable* _promo_size_counter;
PerfVariable* _young_capacity_counter;
PerfVariable* _minor_gc_cost_counter;
PerfVariable* _major_gc_cost_counter;
PerfVariable* _mutator_cost_counter;
PerfVariable* _avg_young_live_counter;
PerfVariable* _avg_old_live_counter;
PerfVariable* _avg_minor_pause_counter;
PerfVariable* _avg_minor_interval_counter;
#ifdef NOT_PRODUCT
PerfVariable* _minor_pause_counter;
#endif
PerfVariable* _change_young_gen_for_min_pauses_counter;
PerfVariable* _change_young_gen_for_throughput_counter;
PerfVariable* _change_old_gen_for_maj_pauses_counter;
PerfVariable* _change_old_gen_for_throughput_counter;
PerfVariable* _decrease_for_footprint_counter;
PerfVariable* _minor_pause_young_slope_counter;
PerfVariable* _decide_at_full_gc_counter;
PerfVariable* _survived_counter;
PerfVariable* _promoted_counter;
PerfVariable* _avg_survived_avg_counter;
PerfVariable* _avg_survived_dev_counter;
PerfVariable* _avg_survived_padded_avg_counter;
PerfVariable* _survivor_overflowed_counter;
PerfVariable* _increment_tenuring_threshold_for_gc_cost_counter;
PerfVariable* _decrement_tenuring_threshold_for_gc_cost_counter;
PerfVariable* _decrement_tenuring_threshold_for_survivor_limit_counter;
PerfVariable* _minor_collection_slope_counter;
PerfVariable* _major_collection_slope_counter;
AdaptiveSizePolicy* _size_policy;
inline void update_eden_size() {
size_t eden_size_in_bytes = size_policy()->calculated_eden_size_in_bytes();
_eden_size_counter->set_value(eden_size_in_bytes);
}
inline void update_promo_size() {
_promo_size_counter->set_value(
size_policy()->calculated_promo_size_in_bytes());
}
inline void update_avg_minor_pause_counter() {
_avg_minor_pause_counter->set_value((jlong)
(size_policy()->avg_minor_pause()->average() * 1000.0));
}
inline void update_avg_minor_interval_counter() {
_avg_minor_interval_counter->set_value((jlong)
(size_policy()->avg_minor_interval()->average() * 1000.0));
}
#ifdef NOT_PRODUCT
inline void update_minor_pause_counter() {
_minor_pause_counter->set_value((jlong)
(size_policy()->avg_minor_pause()->last_sample() * 1000.0));
}
#endif
inline void update_minor_gc_cost_counter() {
_minor_gc_cost_counter->set_value((jlong)
(size_policy()->minor_gc_cost() * 100.0));
}
inline void update_avg_young_live_counter() {
_avg_young_live_counter->set_value(
(jlong)(size_policy()->avg_young_live()->average())
);
}
inline void update_avg_survived_avg_counters() {
_avg_survived_avg_counter->set_value(
(jlong)(size_policy()->_avg_survived->average())
);
}
inline void update_avg_survived_dev_counters() {
_avg_survived_dev_counter->set_value(
(jlong)(size_policy()->_avg_survived->deviation())
);
}
inline void update_avg_survived_padded_avg_counters() {
_avg_survived_padded_avg_counter->set_value(
(jlong)(size_policy()->_avg_survived->padded_average())
);
}
inline void update_change_old_gen_for_throughput() {
_change_old_gen_for_throughput_counter->set_value(
size_policy()->change_old_gen_for_throughput());
}
inline void update_change_young_gen_for_throughput() {
_change_young_gen_for_throughput_counter->set_value(
size_policy()->change_young_gen_for_throughput());
}
inline void update_decrease_for_footprint() {
_decrease_for_footprint_counter->set_value(
size_policy()->decrease_for_footprint());
}
inline void update_decide_at_full_gc_counter() {
_decide_at_full_gc_counter->set_value(
size_policy()->decide_at_full_gc());
}
inline void update_minor_pause_young_slope_counter() {
_minor_pause_young_slope_counter->set_value(
(jlong)(size_policy()->minor_pause_young_slope() * 1000)
);
}
virtual void update_counters_from_policy();
protected:
virtual AdaptiveSizePolicy* size_policy() { return _size_policy; }
public:
GCAdaptivePolicyCounters(const char* name,
int collectors,
int generations,
AdaptiveSizePolicy* size_policy);
inline void update_survived(size_t survived) {
_survived_counter->set_value(survived);
}
inline void update_promoted(size_t promoted) {
_promoted_counter->set_value(promoted);
}
inline void update_young_capacity(size_t size_in_bytes) {
_young_capacity_counter->set_value(size_in_bytes);
}
virtual void update_counters();
inline void update_survivor_size_counters() {
desired_survivor_size()->set_value(
size_policy()->calculated_survivor_size_in_bytes());
}
inline void update_survivor_overflowed(bool survivor_overflowed) {
_survivor_overflowed_counter->set_value(survivor_overflowed);
}
inline void update_tenuring_threshold(uint threshold) {
tenuring_threshold()->set_value(threshold);
}
inline void update_increment_tenuring_threshold_for_gc_cost() {
_increment_tenuring_threshold_for_gc_cost_counter->set_value(
size_policy()->increment_tenuring_threshold_for_gc_cost());
}
inline void update_decrement_tenuring_threshold_for_gc_cost() {
_decrement_tenuring_threshold_for_gc_cost_counter->set_value(
size_policy()->decrement_tenuring_threshold_for_gc_cost());
}
inline void update_decrement_tenuring_threshold_for_survivor_limit() {
_decrement_tenuring_threshold_for_survivor_limit_counter->set_value(
size_policy()->decrement_tenuring_threshold_for_survivor_limit());
}
inline void update_change_young_gen_for_min_pauses() {
_change_young_gen_for_min_pauses_counter->set_value(
size_policy()->change_young_gen_for_min_pauses());
}
inline void update_change_old_gen_for_maj_pauses() {
_change_old_gen_for_maj_pauses_counter->set_value(
size_policy()->change_old_gen_for_maj_pauses());
}
inline void update_minor_collection_slope_counter() {
_minor_collection_slope_counter->set_value(
(jlong)(size_policy()->minor_collection_slope() * 1000)
);
}
inline void update_major_collection_slope_counter() {
_major_collection_slope_counter->set_value(
(jlong)(size_policy()->major_collection_slope() * 1000)
);
}
void set_size_policy(AdaptiveSizePolicy* v) { _size_policy = v; }
};
#endif // SHARE_GC_PARALLEL_GCADAPTIVEPOLICYCOUNTERS_HPP

View File

@ -66,6 +66,11 @@ void ParallelArguments::initialize() {
}
}
// True in product build, since tests using debug build often stress GC
if (FLAG_IS_DEFAULT(UseGCOverheadLimit)) {
FLAG_SET_DEFAULT(UseGCOverheadLimit, trueInProduct);
}
if (InitialSurvivorRatio < MinSurvivorRatio) {
if (FLAG_IS_CMDLINE(InitialSurvivorRatio)) {
if (FLAG_IS_CMDLINE(MinSurvivorRatio)) {

View File

@ -48,6 +48,7 @@
#include "memory/universe.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/cpuTimeCounters.hpp"
#include "runtime/globals_extension.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/java.hpp"
#include "runtime/vmThread.hpp"
@ -58,7 +59,7 @@
PSYoungGen* ParallelScavengeHeap::_young_gen = nullptr;
PSOldGen* ParallelScavengeHeap::_old_gen = nullptr;
PSAdaptiveSizePolicy* ParallelScavengeHeap::_size_policy = nullptr;
PSGCAdaptivePolicyCounters* ParallelScavengeHeap::_gc_policy_counters = nullptr;
GCPolicyCounters* ParallelScavengeHeap::_gc_policy_counters = nullptr;
jint ParallelScavengeHeap::initialize() {
const size_t reserved_heap_size = ParallelArguments::heap_reserved_size_bytes();
@ -100,24 +101,15 @@ jint ParallelScavengeHeap::initialize() {
double max_gc_pause_sec = ((double) MaxGCPauseMillis)/1000.0;
const size_t eden_capacity = _young_gen->eden_space()->capacity_in_bytes();
const size_t old_capacity = _old_gen->capacity_in_bytes();
const size_t initial_promo_size = MIN2(eden_capacity, old_capacity);
_size_policy =
new PSAdaptiveSizePolicy(eden_capacity,
initial_promo_size,
young_gen()->to_space()->capacity_in_bytes(),
SpaceAlignment,
max_gc_pause_sec,
GCTimeRatio
);
_size_policy = new PSAdaptiveSizePolicy(SpaceAlignment,
max_gc_pause_sec,
GCTimeRatio);
assert((old_gen()->virtual_space()->high_boundary() ==
young_gen()->virtual_space()->low_boundary()),
"Boundaries must meet");
// initialize the policy counters - 2 collectors, 2 generations
_gc_policy_counters =
new PSGCAdaptivePolicyCounters("ParScav:MSC", 2, 2, _size_policy);
_gc_policy_counters = new GCPolicyCounters("ParScav:MSC", 2, 2);
if (!PSParallelCompact::initialize_aux_data()) {
return JNI_ENOMEM;
@ -190,6 +182,21 @@ void ParallelScavengeHeap::post_initialize() {
GCLocker::initialize();
}
void ParallelScavengeHeap::gc_epilogue(bool full) {
if (_is_heap_almost_full) {
// Reset emergency state if eden is empty after a young/full gc
if (_young_gen->eden_space()->is_empty()) {
log_debug(gc)("Leaving memory constrained state; back to normal");
_is_heap_almost_full = false;
}
} else {
if (full && !_young_gen->eden_space()->is_empty()) {
log_debug(gc)("Non-empty young-gen after full-gc; in memory constrained state");
_is_heap_almost_full = true;
}
}
}
void ParallelScavengeHeap::update_counters() {
young_gen()->update_counters();
old_gen()->update_counters();
@ -272,18 +279,17 @@ HeapWord* ParallelScavengeHeap::mem_allocate(size_t size,
HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size,
bool is_tlab,
bool* gc_overhead_limit_was_exceeded) {
// In general gc_overhead_limit_was_exceeded should be false so
// set it so here and reset it to true only if the gc time
// limit is being exceeded as checked below.
*gc_overhead_limit_was_exceeded = false;
HeapWord* result = young_gen()->allocate(size);
{
HeapWord* result = young_gen()->allocate(size);
if (result != nullptr) {
return result;
}
}
uint loop_count = 0;
uint gc_count = 0;
while (result == nullptr) {
while (true) {
// We don't want to have multiple collections for a single filled generation.
// To prevent this, each thread tracks the total_collections() value, and if
// the count has changed, does not do a new collection.
@ -299,21 +305,20 @@ HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size,
MutexLocker ml(Heap_lock);
gc_count = total_collections();
result = young_gen()->allocate(size);
HeapWord* result = young_gen()->allocate(size);
if (result != nullptr) {
return result;
}
// If certain conditions hold, try allocating from the old gen.
if (!is_tlab) {
result = mem_allocate_old_gen(size);
if (!is_tlab && !should_alloc_in_eden(size)) {
result = old_gen()->cas_allocate_noexpand(size);
if (result != nullptr) {
return result;
}
}
}
assert(result == nullptr, "inv");
{
VM_ParallelCollectForAllocation op(size, is_tlab, gc_count);
VMThread::execute(&op);
@ -324,76 +329,61 @@ HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size,
if (op.gc_succeeded()) {
assert(is_in_or_null(op.result()), "result not in heap");
// Exit the loop if the gc time limit has been exceeded.
// The allocation must have failed above ("result" guarding
// this path is null) and the most recent collection has exceeded the
// gc overhead limit (although enough may have been collected to
// satisfy the allocation). Exit the loop so that an out-of-memory
// will be thrown (return a null ignoring the contents of
// op.result()),
// but clear gc_overhead_limit_exceeded so that the next collection
// starts with a clean slate (i.e., forgets about previous overhead
// excesses). Fill op.result() with a filler object so that the
// heap remains parsable.
const bool limit_exceeded = size_policy()->gc_overhead_limit_exceeded();
const bool softrefs_clear = soft_ref_policy()->all_soft_refs_clear();
if (limit_exceeded && softrefs_clear) {
*gc_overhead_limit_was_exceeded = true;
size_policy()->set_gc_overhead_limit_exceeded(false);
log_trace(gc)("ParallelScavengeHeap::mem_allocate: return null because gc_overhead_limit_exceeded is set");
if (op.result() != nullptr) {
CollectedHeap::fill_with_object(op.result(), size);
}
return nullptr;
}
return op.result();
}
// Was the gc-overhead reached inside the safepoint? If so, this mutator should return null as well for global consistency.
if (_gc_overhead_counter >= GCOverheadLimitThreshold) {
return nullptr;
}
}
// The policy object will prevent us from looping forever. If the
// time spent in gc crosses a threshold, we will bail out.
loop_count++;
if ((result == nullptr) && (QueuedAllocationWarningCount > 0) &&
if ((QueuedAllocationWarningCount > 0) &&
(loop_count % QueuedAllocationWarningCount == 0)) {
log_warning(gc)("ParallelScavengeHeap::mem_allocate retries %d times", loop_count);
log_warning(gc)("\tsize=%zu", size);
}
}
return result;
}
HeapWord* ParallelScavengeHeap::allocate_old_gen_and_record(size_t size) {
assert_locked_or_safepoint(Heap_lock);
HeapWord* res = old_gen()->allocate(size);
if (res != nullptr) {
_size_policy->tenured_allocation(size * HeapWordSize);
}
return res;
}
HeapWord* ParallelScavengeHeap::mem_allocate_old_gen(size_t size) {
if (!should_alloc_in_eden(size)) {
// Size is too big for eden.
return allocate_old_gen_and_record(size);
}
return nullptr;
}
void ParallelScavengeHeap::do_full_collection(bool clear_all_soft_refs) {
PSParallelCompact::invoke(clear_all_soft_refs);
}
HeapWord* ParallelScavengeHeap::expand_heap_and_allocate(size_t size, bool is_tlab) {
HeapWord* result = nullptr;
static bool check_gc_heap_free_limit(size_t free_bytes, size_t capacity_bytes) {
return (free_bytes * 100 / capacity_bytes) < GCHeapFreeLimit;
}
bool ParallelScavengeHeap::check_gc_overhead_limit() {
assert(SafepointSynchronize::is_at_safepoint(), "precondition");
if (UseGCOverheadLimit) {
// The goal here is to return null prematurely so that apps can exit
// gracefully when GC takes the most time.
bool little_mutator_time = _size_policy->mutator_time_percent() * 100 < (100 - GCTimeLimit);
bool little_free_space = check_gc_heap_free_limit(_young_gen->free_in_bytes(), _young_gen->capacity_in_bytes())
&& check_gc_heap_free_limit( _old_gen->free_in_bytes(), _old_gen->capacity_in_bytes());
if (little_mutator_time && little_free_space) {
_gc_overhead_counter++;
if (_gc_overhead_counter >= GCOverheadLimitThreshold) {
return true;
}
} else {
_gc_overhead_counter = 0;
}
}
return false;
}
HeapWord* ParallelScavengeHeap::expand_heap_and_allocate(size_t size, bool is_tlab) {
assert(SafepointSynchronize::is_at_safepoint(), "precondition");
// We just finished a young/full gc, try everything to satisfy this allocation request.
HeapWord* result = young_gen()->expand_and_allocate(size);
result = young_gen()->allocate(size);
if (result == nullptr && !is_tlab) {
result = old_gen()->expand_and_allocate(size);
}
return result; // Could be null if we are out of space.
}
@ -402,13 +392,19 @@ HeapWord* ParallelScavengeHeap::satisfy_failed_allocation(size_t size, bool is_t
HeapWord* result = nullptr;
// If young-gen can handle this allocation, attempt young-gc firstly.
bool should_run_young_gc = is_tlab || should_alloc_in_eden(size);
collect_at_safepoint(!should_run_young_gc);
if (!_is_heap_almost_full) {
// If young-gen can handle this allocation, attempt young-gc firstly, as young-gc is usually cheaper.
bool should_run_young_gc = is_tlab || should_alloc_in_eden(size);
result = expand_heap_and_allocate(size, is_tlab);
if (result != nullptr) {
return result;
collect_at_safepoint(!should_run_young_gc);
// If gc-overhead is reached, we will skip allocation.
if (!check_gc_overhead_limit()) {
result = expand_heap_and_allocate(size, is_tlab);
if (result != nullptr) {
return result;
}
}
}
// If we reach this point, we're really out of memory. Try every trick
@ -428,18 +424,15 @@ HeapWord* ParallelScavengeHeap::satisfy_failed_allocation(size_t size, bool is_t
HeapMaximumCompactionInterval = old_interval;
}
result = expand_heap_and_allocate(size, is_tlab);
if (result != nullptr) {
return result;
if (check_gc_overhead_limit()) {
log_info(gc)("GCOverheadLimitThreshold %zu reached.", GCOverheadLimitThreshold);
return nullptr;
}
// What else? We might try synchronous finalization later. If the total
// space available is large enough for the allocation, then a more
// complete compaction phase than we've tried so far might be
// appropriate.
return nullptr;
}
result = expand_heap_and_allocate(size, is_tlab);
return result;
}
void ParallelScavengeHeap::ensure_parsability(bool retire_tlabs) {
CollectedHeap::ensure_parsability(retire_tlabs);
@ -666,7 +659,6 @@ void ParallelScavengeHeap::gc_threads_do(ThreadClosure* tc) const {
}
void ParallelScavengeHeap::print_tracing_info() const {
AdaptiveSizePolicyOutput::print();
log_debug(gc, heap, exit)("Accumulated young generation GC time %3.7f secs", PSScavenge::accumulated_time()->seconds());
log_debug(gc, heap, exit)("Accumulated old generation GC time %3.7f secs", PSParallelCompact::accumulated_time()->seconds());
}
@ -763,15 +755,96 @@ PSCardTable* ParallelScavengeHeap::card_table() {
return static_cast<PSCardTable*>(barrier_set()->card_table());
}
void ParallelScavengeHeap::resize_young_gen(size_t eden_size,
size_t survivor_size) {
// Delegate the resize to the generation.
_young_gen->resize(eden_size, survivor_size);
static size_t calculate_free_from_free_ratio_flag(size_t live, uintx free_percent) {
assert(free_percent != 100, "precondition");
// We want to calculate how much free memory there can be based on the
// live size.
// percent * (free + live) = free
// =>
// free = (live * percent) / (1 - percent)
const double percent = free_percent / 100.0;
return live * percent / (1.0 - percent);
}
void ParallelScavengeHeap::resize_old_gen(size_t desired_free_space) {
// Delegate the resize to the generation.
_old_gen->resize(desired_free_space);
size_t ParallelScavengeHeap::calculate_desired_old_gen_capacity(size_t old_gen_live_size) {
// If min free percent is 100%, the old-gen should always be in its max capacity
if (MinHeapFreeRatio == 100) {
return _old_gen->max_gen_size();
}
// Using recorded data to calculate the new capacity of old-gen to avoid
// excessive expansion but also keep footprint low
size_t promoted_estimate = _size_policy->padded_average_promoted_in_bytes();
// Should have at least this free room for the next young-gc promotion.
size_t free_size = promoted_estimate;
size_t largest_live_size = MAX2((size_t)_size_policy->peak_old_gen_used_estimate(), old_gen_live_size);
free_size += largest_live_size - old_gen_live_size;
// Respect free percent
if (MinHeapFreeRatio != 0) {
size_t min_free = calculate_free_from_free_ratio_flag(old_gen_live_size, MinHeapFreeRatio);
free_size = MAX2(free_size, min_free);
}
if (MaxHeapFreeRatio != 100) {
size_t max_free = calculate_free_from_free_ratio_flag(old_gen_live_size, MaxHeapFreeRatio);
free_size = MIN2(max_free, free_size);
}
return old_gen_live_size + free_size;
}
void ParallelScavengeHeap::resize_old_gen_after_full_gc() {
size_t current_capacity = _old_gen->capacity_in_bytes();
size_t desired_capacity = calculate_desired_old_gen_capacity(old_gen()->used_in_bytes());
// If MinHeapFreeRatio is at its default value; shrink cautiously. Otherwise, users expect prompt shrinking.
if (FLAG_IS_DEFAULT(MinHeapFreeRatio)) {
if (desired_capacity < current_capacity) {
// Shrinking
if (total_full_collections() < AdaptiveSizePolicyReadyThreshold) {
// No enough data for shrinking
return;
}
}
}
_old_gen->resize(desired_capacity);
}
void ParallelScavengeHeap::resize_after_young_gc(bool is_survivor_overflowing) {
_young_gen->resize_after_young_gc(is_survivor_overflowing);
// Consider if should shrink old-gen
if (!is_survivor_overflowing) {
// Upper bound for a single step shrink
size_t max_shrink_bytes = SpaceAlignment;
size_t shrink_bytes = _size_policy->compute_old_gen_shrink_bytes(old_gen()->free_in_bytes(), max_shrink_bytes);
if (shrink_bytes != 0) {
if (MinHeapFreeRatio != 0) {
size_t new_capacity = old_gen()->capacity_in_bytes() - shrink_bytes;
size_t new_free_size = old_gen()->free_in_bytes() - shrink_bytes;
if ((double)new_free_size / new_capacity * 100 < MinHeapFreeRatio) {
// Would violate MinHeapFreeRatio
return;
}
}
old_gen()->shrink(shrink_bytes);
}
}
}
void ParallelScavengeHeap::resize_after_full_gc() {
resize_old_gen_after_full_gc();
// We don't resize young-gen after full-gc because:
// 1. eden-size directly affects young-gc frequency (GCTimeRatio), and we
// don't have enough info to determine its desired size.
// 2. eden can contain live objs after a full-gc, which is unsafe for
// resizing. We will perform expansion on allocation if needed, in
// satisfy_failed_allocation().
}
HeapWord* ParallelScavengeHeap::allocate_loaded_archive_space(size_t size) {

View File

@ -25,7 +25,7 @@
#ifndef SHARE_GC_PARALLEL_PARALLELSCAVENGEHEAP_HPP
#define SHARE_GC_PARALLEL_PARALLELSCAVENGEHEAP_HPP
#include "gc/parallel/psGCAdaptivePolicyCounters.hpp"
#include "gc/parallel/psAdaptiveSizePolicy.hpp"
#include "gc/parallel/psOldGen.hpp"
#include "gc/parallel/psYoungGen.hpp"
#include "gc/shared/cardTableBarrierSet.hpp"
@ -60,11 +60,11 @@ class ReservedSpace;
// +-- generation boundary (fixed after startup)
// |
// |<- old gen (reserved) ->|<- young gen (reserved) ->|
// +---------------+--------+-----------------+--------+--------+--------+
// | old | | eden | from | to | |
// | | | | (to) | (from) | |
// +---------------+--------+-----------------+--------+--------+--------+
// |<- committed ->| |<- committed ->|
// +---------------+--------+--------+--------+------------------+-------+
// | old | | from | to | eden | |
// | | | (to) | (from) | | |
// +---------------+--------+--------+--------+------------------+-------+
// |<- committed ->| |<- committed ->|
//
class ParallelScavengeHeap : public CollectedHeap {
friend class VMStructs;
@ -74,7 +74,7 @@ class ParallelScavengeHeap : public CollectedHeap {
// Sizing policy for entire heap
static PSAdaptiveSizePolicy* _size_policy;
static PSGCAdaptivePolicyCounters* _gc_policy_counters;
static GCPolicyCounters* _gc_policy_counters;
GCMemoryManager* _young_manager;
GCMemoryManager* _old_manager;
@ -85,14 +85,15 @@ class ParallelScavengeHeap : public CollectedHeap {
WorkerThreads _workers;
uint _gc_overhead_counter;
bool _is_heap_almost_full;
void initialize_serviceability() override;
void trace_actual_reserved_page_size(const size_t reserved_heap_size, const ReservedSpace rs);
void trace_heap(GCWhen::Type when, const GCTracer* tracer) override;
// Allocate in oldgen and record the allocation with the size_policy.
HeapWord* allocate_old_gen_and_record(size_t word_size);
void update_parallel_worker_threads_cpu_time();
bool must_clear_all_soft_refs();
@ -101,8 +102,6 @@ class ParallelScavengeHeap : public CollectedHeap {
inline bool should_alloc_in_eden(size_t size) const;
HeapWord* mem_allocate_old_gen(size_t size);
HeapWord* mem_allocate_work(size_t size,
bool is_tlab,
bool* gc_overhead_limit_was_exceeded);
@ -111,6 +110,12 @@ class ParallelScavengeHeap : public CollectedHeap {
void do_full_collection(bool clear_all_soft_refs) override;
bool check_gc_overhead_limit();
size_t calculate_desired_old_gen_capacity(size_t old_gen_live_size);
void resize_old_gen_after_full_gc();
void print_tracing_info() const override;
void stop() override {};
@ -122,7 +127,9 @@ public:
_eden_pool(nullptr),
_survivor_pool(nullptr),
_old_pool(nullptr),
_workers("GC Thread", ParallelGCThreads) { }
_workers("GC Thread", ParallelGCThreads),
_gc_overhead_counter(0),
_is_heap_almost_full(false) {}
Name kind() const override {
return CollectedHeap::Parallel;
@ -132,6 +139,9 @@ public:
return "Parallel";
}
// Invoked at gc-pause-end
void gc_epilogue(bool full);
GrowableArray<GCMemoryManager*> memory_managers() override;
GrowableArray<MemoryPool*> memory_pools() override;
@ -140,7 +150,7 @@ public:
PSAdaptiveSizePolicy* size_policy() { return _size_policy; }
static PSGCAdaptivePolicyCounters* gc_policy_counters() { return _gc_policy_counters; }
static GCPolicyCounters* gc_policy_counters() { return _gc_policy_counters; }
static ParallelScavengeHeap* heap() {
return named_heap<ParallelScavengeHeap>(CollectedHeap::Parallel);
@ -226,13 +236,8 @@ public:
void verify(VerifyOption option /* ignored */) override;
// Resize the young generation. The reserved space for the
// generation may be expanded in preparation for the resize.
void resize_young_gen(size_t eden_size, size_t survivor_size);
// Resize the old generation. The reserved space for the
// generation may be expanded in preparation for the resize.
void resize_old_gen(size_t desired_free_space);
void resize_after_young_gc(bool is_survivor_overflowing);
void resize_after_full_gc();
GCMemoryManager* old_gc_manager() const { return _old_manager; }
GCMemoryManager* young_gc_manager() const { return _young_manager; }
@ -250,33 +255,4 @@ public:
void unpin_object(JavaThread* thread, oop obj) override;
};
// Class that can be used to print information about the
// adaptive size policy at intervals specified by
// AdaptiveSizePolicyOutputInterval. Only print information
// if an adaptive size policy is in use.
class AdaptiveSizePolicyOutput : AllStatic {
static bool enabled() {
return UseParallelGC &&
UseAdaptiveSizePolicy &&
log_is_enabled(Debug, gc, ergo);
}
public:
static void print() {
if (enabled()) {
ParallelScavengeHeap::heap()->size_policy()->print();
}
}
static void print(AdaptiveSizePolicy* size_policy, uint count) {
bool do_print =
enabled() &&
(AdaptiveSizePolicyOutputInterval > 0) &&
(count % AdaptiveSizePolicyOutputInterval) == 0;
if (do_print) {
size_policy->print();
}
}
};
#endif // SHARE_GC_PARALLEL_PARALLELSCAVENGEHEAP_HPP

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,6 @@
#define SHARE_GC_PARALLEL_PSADAPTIVESIZEPOLICY_HPP
#include "gc/shared/adaptiveSizePolicy.hpp"
#include "gc/shared/gcCause.hpp"
#include "gc/shared/gcUtil.hpp"
#include "utilities/align.hpp"
@ -34,151 +33,34 @@
// optimal free space for both the young and old generation
// based on current application characteristics (based on gc cost
// and application footprint).
//
// It also computes an optimal tenuring threshold between the young
// and old generations, so as to equalize the cost of collections
// of those generations, as well as optimal survivor space sizes
// for the young generation.
//
// While this class is specifically intended for a generational system
// consisting of a young gen (containing an Eden and two semi-spaces)
// and a tenured gen, as well as a perm gen for reflective data, it
// makes NO references to specific generations.
//
// 05/02/2003 Update
// The 1.5 policy makes use of data gathered for the costs of GC on
// specific generations. That data does reference specific
// generation. Also diagnostics specific to generations have
// been added.
// Forward decls
class elapsedTimer;
class PSAdaptiveSizePolicy : public AdaptiveSizePolicy {
friend class PSGCAdaptivePolicyCounters;
private:
// These values are used to record decisions made during the
// policy. For example, if the young generation was decreased
// to decrease the GC cost of minor collections the value
// decrease_young_gen_for_throughput_true is used.
// Last calculated sizes, in bytes, and aligned
// NEEDS_CLEANUP should use sizes.hpp, but it works in ints, not size_t's
// Time statistics
AdaptivePaddedAverage* _avg_major_pause;
// Footprint statistics
AdaptiveWeightedAverage* _avg_base_footprint;
// Statistics for promoted objs
AdaptivePaddedNoZeroDevAverage* _avg_promoted;
// Variable for estimating the major and minor pause times.
// These variables represent linear least-squares fits of
// the data.
// major pause time vs. old gen size
LinearLeastSquareFit* _major_pause_old_estimator;
// major pause time vs. young gen size
LinearLeastSquareFit* _major_pause_young_estimator;
// These record the most recent collection times. They
// are available as an alternative to using the averages
// for making ergonomic decisions.
double _latest_major_mutator_interval_seconds;
const size_t _space_alignment; // alignment for eden, survivors
// The amount of live data in the heap at the last full GC, used
// as a baseline to help us determine when we need to perform the
// next full GC.
size_t _live_at_last_full_gc;
// decrease/increase the old generation for minor pause time
int _change_old_gen_for_min_pauses;
// increase/decrease the young generation for major pause time
int _change_young_gen_for_maj_pauses;
// To facilitate faster growth at start up, supplement the normal
// growth percentage for the young gen eden and the
// old gen space for promotion with these value which decay
// with increasing collections.
uint _young_gen_size_increment_supplement;
uint _old_gen_size_increment_supplement;
private:
size_t decrease_eden_for_minor_pause_time(size_t current_eden_size);
void adjust_eden_for_minor_pause_time(size_t* desired_eden_size_ptr);
// Change the generation sizes to achieve a GC pause time goal
// Returned sizes are not necessarily aligned.
void adjust_promo_for_pause_time(size_t* desired_promo_size_ptr);
void adjust_eden_for_pause_time(size_t* desired_eden_size_ptr);
// Change the generation sizes to achieve an application throughput goal
// Returned sizes are not necessarily aligned.
void adjust_promo_for_throughput(bool is_full_gc,
size_t* desired_promo_size_ptr);
void adjust_eden_for_throughput(bool is_full_gc,
size_t* desired_eden_size_ptr);
// Change the generation sizes to achieve minimum footprint
// Returned sizes are not aligned.
size_t adjust_promo_for_footprint(size_t desired_promo_size,
size_t desired_total);
size_t adjust_eden_for_footprint(size_t desired_promo_size,
size_t desired_total);
size_t increase_eden(size_t current_eden_size);
// Size in bytes for an increment or decrement of eden.
size_t eden_decrement_aligned_down(size_t cur_eden);
size_t eden_increment_with_supplement_aligned_up(size_t cur_eden);
// Size in bytes for an increment or decrement of the promotion area
size_t promo_decrement_aligned_down(size_t cur_promo);
size_t promo_increment_with_supplement_aligned_up(size_t cur_promo);
// Returns a change that has been scaled down. Result
// is not aligned. (If useful, move to some shared
// location.)
size_t scale_down(size_t change, double part, double total);
protected:
// Footprint accessors
size_t live_space() const {
return (size_t)(avg_young_live()->average() +
avg_old_live()->average());
}
size_t free_space() const {
return _eden_size + _promo_size;
}
void set_promo_size(size_t new_size) {
_promo_size = new_size;
}
// Update estimators
void update_minor_pause_old_estimator(double minor_pause_in_ms);
virtual GCPolicyKind kind() const { return _gc_ps_adaptive_size_policy; }
public:
// Accessors for use by performance counters
AdaptivePaddedNoZeroDevAverage* avg_promoted() const {
return _avg_promoted;
}
AdaptiveWeightedAverage* avg_base_footprint() const {
return _avg_base_footprint;
}
public:
// Input arguments are initial free space sizes for young and old
// generations, the initial survivor space size, the
// alignment values and the pause & throughput goals.
//
// NEEDS_CLEANUP this is a singleton object
PSAdaptiveSizePolicy(size_t init_eden_size,
size_t init_promo_size,
size_t init_survivor_size,
size_t space_alignment,
PSAdaptiveSizePolicy(size_t space_alignment,
double gc_pause_goal_sec,
uint gc_time_ratio);
@ -186,18 +68,11 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy {
// called by GC algorithms. It is the responsibility of users of this
// policy to call these methods at the correct times!
void major_collection_begin();
void major_collection_end(size_t amount_live, GCCause::Cause gc_cause);
void major_collection_end();
void tenured_allocation(size_t size) {
_avg_pretenured->sample(size);
}
void print_stats(bool is_survivor_overflowing);
// Accessors
// NEEDS_CLEANUP should use sizes.hpp
static size_t calculate_free_based_on_live(size_t live, uintx ratio_as_percentage);
size_t calculated_old_free_size_in_bytes() const;
size_t average_promoted_in_bytes() const {
return (size_t)avg_promoted()->average();
@ -207,63 +82,14 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy {
return (size_t)avg_promoted()->padded_average();
}
int change_young_gen_for_maj_pauses() {
return _change_young_gen_for_maj_pauses;
}
void set_change_young_gen_for_maj_pauses(int v) {
_change_young_gen_for_maj_pauses = v;
}
size_t compute_desired_eden_size(bool is_survivor_overflowing, size_t cur_eden);
int change_old_gen_for_min_pauses() {
return _change_old_gen_for_min_pauses;
}
void set_change_old_gen_for_min_pauses(int v) {
_change_old_gen_for_min_pauses = v;
}
size_t compute_desired_survivor_size(size_t current_survivor_size, size_t max_gen_size);
// Accessors for estimators. The slope of the linear fit is
// currently all that is used for making decisions.
size_t compute_old_gen_shrink_bytes(size_t old_gen_free_bytes, size_t max_shrink_bytes);
LinearLeastSquareFit* major_pause_old_estimator() {
return _major_pause_old_estimator;
}
virtual void clear_generation_free_space_flags();
double major_pause_old_slope() { return _major_pause_old_estimator->slope(); }
double major_pause_young_slope() {
return _major_pause_young_estimator->slope();
}
// Calculates optimal (free) space sizes for both the young and old
// generations. Stores results in _eden_size and _promo_size.
// Takes current used space in all generations as input, as well
// as an indication if a full gc has just been performed, for use
// in deciding if an OOM error should be thrown.
void compute_generations_free_space(size_t young_live,
size_t eden_live,
size_t old_live,
size_t cur_eden, // current eden in bytes
size_t max_old_gen_size,
size_t max_eden_size,
bool is_full_gc);
void compute_eden_space_size(size_t young_live,
size_t eden_live,
size_t cur_eden, // current eden in bytes
size_t max_eden_size,
bool is_full_gc);
void compute_old_gen_free_space(size_t old_live,
size_t cur_eden, // current eden in bytes
size_t max_old_gen_size,
bool is_full_gc);
// Calculates new survivor space size; returns a new tenuring threshold
// value. Stores new survivor size in _survivor_size.
uint compute_survivor_space_size_and_threshold(bool is_survivor_overflow,
uint tenuring_threshold,
size_t survivor_limit);
uint compute_tenuring_threshold(bool is_survivor_overflowing,
uint tenuring_threshold);
// Return the maximum size of a survivor space if the young generation were of
// size gen_size.
@ -279,21 +105,14 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy {
return sz > alignment ? align_down(sz, alignment) : alignment;
}
size_t live_at_last_full_gc() {
return _live_at_last_full_gc;
}
// Update averages that are always used (even
// if adaptive sizing is turned off).
void update_averages(bool is_survivor_overflow,
size_t survived,
size_t promoted);
// Printing support
virtual bool print() const;
// Decay the supplemental growth additive.
void decay_supplemental_growth(bool is_full_gc);
void decay_supplemental_growth(uint num_minor_gcs);
};
#endif // SHARE_GC_PARALLEL_PSADAPTIVESIZEPOLICY_HPP

View File

@ -1,179 +0,0 @@
/*
* Copyright (c) 2003, 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 "gc/parallel/psGCAdaptivePolicyCounters.hpp"
#include "memory/resourceArea.hpp"
PSGCAdaptivePolicyCounters::PSGCAdaptivePolicyCounters(const char* name_arg,
int collectors,
int generations,
PSAdaptiveSizePolicy* size_policy_arg)
: GCAdaptivePolicyCounters(name_arg,
collectors,
generations,
size_policy_arg) {
if (UsePerfData) {
EXCEPTION_MARK;
ResourceMark rm;
const char* cname;
cname = PerfDataManager::counter_name(name_space(), "oldPromoSize");
_old_promo_size = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Bytes, ps_size_policy()->calculated_promo_size_in_bytes(), CHECK);
cname = PerfDataManager::counter_name(name_space(), "oldEdenSize");
_old_eden_size = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Bytes, ps_size_policy()->calculated_eden_size_in_bytes(), CHECK);
cname = PerfDataManager::counter_name(name_space(), "oldCapacity");
_old_capacity = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Bytes, (jlong) InitialHeapSize, CHECK);
cname = PerfDataManager::counter_name(name_space(), "avgPromotedAvg");
_avg_promoted_avg_counter =
PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes,
ps_size_policy()->calculated_promo_size_in_bytes(), CHECK);
cname = PerfDataManager::counter_name(name_space(), "avgPromotedDev");
_avg_promoted_dev_counter =
PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes,
(jlong) 0 , CHECK);
cname = PerfDataManager::counter_name(name_space(), "avgPromotedPaddedAvg");
_avg_promoted_padded_avg_counter =
PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes,
ps_size_policy()->calculated_promo_size_in_bytes(), CHECK);
cname = PerfDataManager::counter_name(name_space(),
"avgPretenuredPaddedAvg");
_avg_pretenured_padded_avg =
PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes,
(jlong) 0, CHECK);
cname = PerfDataManager::counter_name(name_space(),
"changeYoungGenForMajPauses");
_change_young_gen_for_maj_pauses_counter =
PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Events,
(jlong)0, CHECK);
cname = PerfDataManager::counter_name(name_space(),
"changeOldGenForMinPauses");
_change_old_gen_for_min_pauses =
PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Events,
(jlong)0, CHECK);
cname = PerfDataManager::counter_name(name_space(), "avgMajorPauseTime");
_avg_major_pause = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Ticks, (jlong) ps_size_policy()->_avg_major_pause->average(), CHECK);
cname = PerfDataManager::counter_name(name_space(), "avgMajorIntervalTime");
_avg_major_interval = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Ticks, (jlong) ps_size_policy()->_avg_major_interval->average(), CHECK);
cname = PerfDataManager::counter_name(name_space(), "majorGcCost");
_major_gc_cost_counter = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Ticks, (jlong) ps_size_policy()->major_gc_cost(), CHECK);
cname = PerfDataManager::counter_name(name_space(), "liveSpace");
_live_space = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Bytes, ps_size_policy()->live_space(), CHECK);
cname = PerfDataManager::counter_name(name_space(), "freeSpace");
_free_space = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Bytes, ps_size_policy()->free_space(), CHECK);
cname = PerfDataManager::counter_name(name_space(), "liveAtLastFullGc");
_live_at_last_full_gc_counter =
PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Bytes, ps_size_policy()->live_at_last_full_gc(), CHECK);
cname = PerfDataManager::counter_name(name_space(), "majorPauseOldSlope");
_major_pause_old_slope = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_None, (jlong) 0, CHECK);
cname = PerfDataManager::counter_name(name_space(), "minorPauseOldSlope");
_minor_pause_old_slope = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_None, (jlong) 0, CHECK);
cname = PerfDataManager::counter_name(name_space(), "majorPauseYoungSlope");
_major_pause_young_slope = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_None, (jlong) 0, CHECK);
_counter_time_stamp.update();
}
assert(size_policy()->is_gc_ps_adaptive_size_policy(),
"Wrong type of size policy");
}
void PSGCAdaptivePolicyCounters::update_counters_from_policy() {
if (UsePerfData) {
GCAdaptivePolicyCounters::update_counters_from_policy();
update_eden_size();
update_promo_size();
update_avg_old_live();
update_survivor_size_counters();
update_avg_promoted_avg();
update_avg_promoted_dev();
update_avg_promoted_padded_avg();
update_avg_pretenured_padded_avg();
update_avg_major_pause();
update_avg_major_interval();
update_minor_gc_cost_counter();
update_major_gc_cost_counter();
update_mutator_cost_counter();
update_decrement_tenuring_threshold_for_gc_cost();
update_increment_tenuring_threshold_for_gc_cost();
update_decrement_tenuring_threshold_for_survivor_limit();
update_live_space();
update_free_space();
update_change_old_gen_for_maj_pauses();
update_change_young_gen_for_maj_pauses();
update_change_old_gen_for_min_pauses();
update_change_old_gen_for_throughput();
update_change_young_gen_for_throughput();
update_decrease_for_footprint();
update_decide_at_full_gc_counter();
update_major_pause_old_slope();
update_minor_pause_old_slope();
update_major_pause_young_slope();
update_minor_collection_slope_counter();
update_gc_overhead_limit_exceeded_counter();
update_live_at_last_full_gc_counter();
}
}
void PSGCAdaptivePolicyCounters::update_counters() {
if (UsePerfData) {
update_counters_from_policy();
}
}

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