Merge branch 'openjdk:master' into cas-alloc-1

This commit is contained in:
Xiaolong Peng 2026-03-09 11:55:44 -07:00 committed by GitHub
commit 341e2f86b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
529 changed files with 14347 additions and 9348 deletions

View File

@ -578,6 +578,11 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
TOOLCHAIN_CFLAGS_JDK_CONLY="-fno-strict-aliasing" # technically NOT for CXX
fi
if test "x$ENABLE_LINKTIME_GC" = xtrue; then
TOOLCHAIN_CFLAGS_JDK="$TOOLCHAIN_CFLAGS_JDK -ffunction-sections -fdata-sections"
TOOLCHAIN_CFLAGS_JVM="$TOOLCHAIN_CFLAGS_JVM -ffunction-sections -fdata-sections"
fi
if test "x$OPENJDK_TARGET_OS" = xaix; then
TOOLCHAIN_CFLAGS_JVM="$TOOLCHAIN_CFLAGS_JVM -ffunction-sections -ftls-model -fno-math-errno"
TOOLCHAIN_CFLAGS_JDK="-ffunction-sections -fsigned-char"

View File

@ -80,6 +80,10 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER],
if test "x$CXX_IS_USER_SUPPLIED" = xfalse && test "x$CC_IS_USER_SUPPLIED" = xfalse; then
UTIL_REQUIRE_TOOLCHAIN_PROGS(LLD, lld)
fi
if test "x$ENABLE_LINKTIME_GC" = xtrue; then
BASIC_LDFLAGS_JDK_ONLY="$BASIC_LDFLAGS_JDK_ONLY -Wl,--gc-sections"
fi
fi
if test "x$OPENJDK_TARGET_OS" = xaix; then
BASIC_LDFLAGS="-Wl,-b64 -Wl,-brtl -Wl,-bnorwexec -Wl,-blibpath:/usr/lib:lib -Wl,-bnoexpall \

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
// Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved.
// Copyright (c) 2014, 2024, Red Hat, Inc. All rights reserved.
// Copyright 2025 Arm Limited and/or its affiliates.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@ -2467,11 +2467,8 @@ bool Matcher::is_generic_vector(MachOper* opnd) {
return opnd->opcode() == VREG;
}
#ifdef ASSERT
// Return whether or not this register is ever used as an argument.
// This function is used on startup to build the trampoline stubs in
// generateOptoStub. Registers not mentioned will be killed by the VM
// call in the trampoline, and arguments in those registers not be
// available to the callee.
bool Matcher::can_be_java_arg(int reg)
{
return
@ -2492,11 +2489,7 @@ bool Matcher::can_be_java_arg(int reg)
reg == V6_num || reg == V6_H_num ||
reg == V7_num || reg == V7_H_num;
}
bool Matcher::is_spillable_arg(int reg)
{
return can_be_java_arg(reg);
}
#endif
uint Matcher::int_pressure_limit()
{
@ -3814,11 +3807,6 @@ frame %{
// Compiled code's Frame Pointer
frame_pointer(R31);
// Interpreter stores its frame pointer in a register which is
// stored to the stack by I2CAdaptors.
// I2CAdaptors convert from interpreted java to compiled java.
interpreter_frame_pointer(R29);
// Stack alignment requirement
stack_alignment(StackAlignmentInBytes); // Alignment size in bytes (128-bit -> 16 bytes)

View File

@ -3814,8 +3814,8 @@ public:
}
private:
void sve_cpy(FloatRegister Zd, SIMD_RegVariant T, PRegister Pg, int imm8,
bool isMerge, bool isFloat) {
void _sve_cpy(FloatRegister Zd, SIMD_RegVariant T, PRegister Pg, int imm8,
bool isMerge, bool isFloat) {
starti;
assert(T != Q, "invalid size");
int sh = 0;
@ -3839,11 +3839,11 @@ private:
public:
// SVE copy signed integer immediate to vector elements (predicated)
void sve_cpy(FloatRegister Zd, SIMD_RegVariant T, PRegister Pg, int imm8, bool isMerge) {
sve_cpy(Zd, T, Pg, imm8, isMerge, /*isFloat*/false);
_sve_cpy(Zd, T, Pg, imm8, isMerge, /*isFloat*/false);
}
// SVE copy floating-point immediate to vector elements (predicated)
void sve_cpy(FloatRegister Zd, SIMD_RegVariant T, PRegister Pg, double d) {
sve_cpy(Zd, T, Pg, checked_cast<uint8_t>(pack(d)), /*isMerge*/true, /*isFloat*/true);
_sve_cpy(Zd, T, Pg, checked_cast<uint8_t>(pack(d)), /*isMerge*/true, /*isFloat*/true);
}
// SVE conditionally select elements from two vectors

View File

@ -42,7 +42,6 @@ define_pd_global(bool, TieredCompilation, false);
define_pd_global(intx, CompileThreshold, 1500 );
define_pd_global(intx, OnStackReplacePercentage, 933 );
define_pd_global(intx, NewSizeThreadIncrease, 4*K );
define_pd_global(size_t, InitialCodeCacheSize, 160*K);
define_pd_global(size_t, ReservedCodeCacheSize, 32*M );
define_pd_global(size_t, NonProfiledCodeHeapSize, 13*M );

View File

@ -2875,3 +2875,24 @@ void C2_MacroAssembler::vector_expand_sve(FloatRegister dst, FloatRegister src,
// dst = 00 87 00 65 00 43 00 21
sve_tbl(dst, size, src, dst);
}
// Optimized SVE cpy (imm, zeroing) instruction.
//
// `movi; cpy(imm, merging)` and `cpy(imm, zeroing)` have the same
// functionality, but test results show that `movi; cpy(imm, merging)` has
// higher throughput on some microarchitectures. This would depend on
// microarchitecture and so may vary between implementations.
void C2_MacroAssembler::sve_cpy(FloatRegister dst, SIMD_RegVariant T,
PRegister pg, int imm8, bool isMerge) {
if (VM_Version::prefer_sve_merging_mode_cpy() && !isMerge) {
// Generates a NEON instruction `movi V<dst>.2d, #0`.
// On AArch64, Z and V registers alias in the low 128 bits, so V<dst> is
// the low 128 bits of Z<dst>. A write to V<dst> also clears all bits of
// Z<dst> above 128, so this `movi` instruction effectively zeroes the
// entire Z<dst> register. According to the Arm Software Optimization
// Guide, `movi` is zero latency.
movi(dst, T2D, 0);
isMerge = true;
}
Assembler::sve_cpy(dst, T, pg, imm8, isMerge);
}

View File

@ -75,6 +75,8 @@
unsigned vector_length_in_bytes);
public:
using Assembler::sve_cpy;
// jdk.internal.util.ArraysSupport.vectorizedHashCode
address arrays_hashcode(Register ary, Register cnt, Register result, FloatRegister vdata0,
FloatRegister vdata1, FloatRegister vdata2, FloatRegister vdata3,
@ -244,4 +246,7 @@
void vector_expand_sve(FloatRegister dst, FloatRegister src, PRegister pg,
FloatRegister tmp1, FloatRegister tmp2, BasicType bt,
int vector_length_in_bytes);
void sve_cpy(FloatRegister dst, SIMD_RegVariant T, PRegister pg, int imm8,
bool isMerge);
#endif // CPU_AARCH64_C2_MACROASSEMBLER_AARCH64_HPP

View File

@ -47,7 +47,6 @@ define_pd_global(intx, ConditionalMoveLimit, 3);
define_pd_global(intx, FreqInlineSize, 325);
define_pd_global(intx, MinJumpTableSize, 10);
define_pd_global(intx, InteriorEntryAlignment, 16);
define_pd_global(intx, NewSizeThreadIncrease, ScaleForWordSize(4*K));
define_pd_global(intx, LoopUnrollLimit, 60);
define_pd_global(intx, LoopPercentProfileLimit, 10);
// InitialCodeCacheSize derived from specjbb2000 run.

View File

@ -95,7 +95,7 @@ define_pd_global(intx, InlineSmallCode, 1000);
"Use simplest and shortest implementation for array equals") \
product(bool, UseSIMDForBigIntegerShiftIntrinsics, true, \
"Use SIMD instructions for left/right shift of BigInteger") \
product(bool, UseSIMDForSHA3Intrinsic, true, \
product(bool, UseSIMDForSHA3Intrinsic, false, \
"Use SIMD SHA3 instructions for SHA3 intrinsic") \
product(bool, AvoidUnalignedAccesses, false, \
"Avoid generating unaligned memory accesses") \

View File

@ -11876,16 +11876,13 @@ class StubGenerator: public StubCodeGenerator {
StubRoutines::_sha512_implCompress = generate_sha512_implCompress(StubId::stubgen_sha512_implCompress_id);
StubRoutines::_sha512_implCompressMB = generate_sha512_implCompress(StubId::stubgen_sha512_implCompressMB_id);
}
if (UseSHA3Intrinsics) {
if (UseSHA3Intrinsics && UseSIMDForSHA3Intrinsic) {
StubRoutines::_double_keccak = generate_double_keccak();
if (UseSIMDForSHA3Intrinsic) {
StubRoutines::_sha3_implCompress = generate_sha3_implCompress(StubId::stubgen_sha3_implCompress_id);
StubRoutines::_sha3_implCompressMB = generate_sha3_implCompress(StubId::stubgen_sha3_implCompressMB_id);
} else {
StubRoutines::_sha3_implCompress = generate_sha3_implCompress_gpr(StubId::stubgen_sha3_implCompress_id);
StubRoutines::_sha3_implCompressMB = generate_sha3_implCompress_gpr(StubId::stubgen_sha3_implCompressMB_id);
}
StubRoutines::_sha3_implCompress = generate_sha3_implCompress(StubId::stubgen_sha3_implCompress_id);
StubRoutines::_sha3_implCompressMB = generate_sha3_implCompress(StubId::stubgen_sha3_implCompressMB_id);
} else if (UseSHA3Intrinsics) {
StubRoutines::_sha3_implCompress = generate_sha3_implCompress_gpr(StubId::stubgen_sha3_implCompress_id);
StubRoutines::_sha3_implCompressMB = generate_sha3_implCompress_gpr(StubId::stubgen_sha3_implCompressMB_id);
}
if (UsePoly1305Intrinsics) {

View File

@ -365,16 +365,28 @@ void VM_Version::initialize() {
FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
}
if (UseSHA && VM_Version::supports_sha3()) {
// Auto-enable UseSHA3Intrinsics on hardware with performance benefit.
// Note that the evaluation of UseSHA3Intrinsics shows better performance
if (UseSHA) {
// No need to check VM_Version::supports_sha3(), since a fallback GPR intrinsic implementation is provided.
if (FLAG_IS_DEFAULT(UseSHA3Intrinsics)) {
FLAG_SET_DEFAULT(UseSHA3Intrinsics, true);
}
} else if (UseSHA3Intrinsics) {
// Matches the documented and tested behavior: the -UseSHA option disables all SHA intrinsics.
warning("UseSHA3Intrinsics requires that UseSHA is enabled.");
FLAG_SET_DEFAULT(UseSHA3Intrinsics, false);
}
if (UseSHA3Intrinsics && VM_Version::supports_sha3()) {
// Auto-enable UseSIMDForSHA3Intrinsic on hardware with performance benefit.
// Note that the evaluation of SHA3 extension Intrinsics shows better performance
// on Apple and Qualcomm silicon but worse performance on Neoverse V1 and N2.
if (_cpu == CPU_APPLE || _cpu == CPU_QUALCOMM) { // Apple or Qualcomm silicon
if (FLAG_IS_DEFAULT(UseSHA3Intrinsics)) {
FLAG_SET_DEFAULT(UseSHA3Intrinsics, true);
if (FLAG_IS_DEFAULT(UseSIMDForSHA3Intrinsic)) {
FLAG_SET_DEFAULT(UseSIMDForSHA3Intrinsic, true);
}
}
} else if (UseSHA3Intrinsics && UseSIMDForSHA3Intrinsic) {
}
if (UseSHA3Intrinsics && UseSIMDForSHA3Intrinsic && !VM_Version::supports_sha3()) {
warning("Intrinsics for SHA3-224, SHA3-256, SHA3-384 and SHA3-512 crypto hash functions not available on this CPU.");
FLAG_SET_DEFAULT(UseSHA3Intrinsics, false);
}

View File

@ -55,6 +55,9 @@ protected:
static int _max_supported_sve_vector_length;
static bool _rop_protection;
static uintptr_t _pac_mask;
// When _prefer_sve_merging_mode_cpy is true, `cpy (imm, zeroing)` is
// implemented as `movi; cpy(imm, merging)`.
static constexpr bool _prefer_sve_merging_mode_cpy = true;
static SpinWait _spin_wait;
@ -242,6 +245,8 @@ public:
static bool use_rop_protection() { return _rop_protection; }
static bool prefer_sve_merging_mode_cpy() { return _prefer_sve_merging_mode_cpy; }
// For common 64/128-bit unpredicated vector operations, we may prefer
// emitting NEON instructions rather than the corresponding SVE instructions.
static bool use_neon_for_vector(int vector_length_in_bytes) {

View File

@ -1088,10 +1088,8 @@ bool Matcher::pd_clone_address_expressions(AddPNode* m, Matcher::MStack& mstack,
return clone_base_plus_offset_address(m, mstack, address_visited);
}
// Return whether or not this register is ever used as an argument. This
// function is used on startup to build the trampoline stubs in generateOptoStub.
// Registers not mentioned will be killed by the VM call in the trampoline, and
// arguments in those registers not be available to the callee.
#ifdef ASSERT
// Return whether or not this register is ever used as an argument.
bool Matcher::can_be_java_arg( int reg ) {
if (reg == R_R0_num ||
reg == R_R1_num ||
@ -1102,10 +1100,7 @@ bool Matcher::can_be_java_arg( int reg ) {
reg <= R_S13_num) return true;
return false;
}
bool Matcher::is_spillable_arg( int reg ) {
return can_be_java_arg(reg);
}
#endif
uint Matcher::int_pressure_limit()
{

View File

@ -43,7 +43,6 @@ define_pd_global(bool, TieredCompilation, false);
define_pd_global(intx, CompileThreshold, 1500 );
define_pd_global(intx, OnStackReplacePercentage, 933 );
define_pd_global(size_t, NewSizeThreadIncrease, 4*K );
define_pd_global(size_t, InitialCodeCacheSize, 160*K);
define_pd_global(size_t, ReservedCodeCacheSize, 32*M );
define_pd_global(size_t, NonProfiledCodeHeapSize, 13*M );

View File

@ -47,7 +47,6 @@ define_pd_global(intx, ConditionalMoveLimit, 4);
// C2 gets to use all the float/double registers
define_pd_global(intx, FreqInlineSize, 175);
define_pd_global(intx, InteriorEntryAlignment, 16); // = CodeEntryAlignment
define_pd_global(size_t, NewSizeThreadIncrease, ScaleForWordSize(4*K));
// The default setting 16/16 seems to work best.
// (For _228_jack 16/16 is 2% better than 4/4, 16/4, 32/32, 32/16, or 16/32.)
//define_pd_global(intx, OptoLoopAlignment, 16); // = 4*wordSize

View File

@ -52,7 +52,6 @@ define_pd_global(size_t, CodeCacheExpansionSize, 32*K);
define_pd_global(size_t, CodeCacheMinBlockLength, 1);
define_pd_global(size_t, CodeCacheMinimumUseSpace, 400*K);
define_pd_global(bool, NeverActAsServerClassMachine, true);
define_pd_global(size_t, NewSizeThreadIncrease, 16*K);
define_pd_global(size_t, InitialCodeCacheSize, 160*K);
#endif // !COMPILER2

View File

@ -47,7 +47,6 @@ define_pd_global(intx, ConditionalMoveLimit, 3);
define_pd_global(intx, FreqInlineSize, 325);
define_pd_global(intx, MinJumpTableSize, 10);
define_pd_global(intx, InteriorEntryAlignment, 16);
define_pd_global(size_t, NewSizeThreadIncrease, ScaleForWordSize(4*K));
define_pd_global(intx, RegisterCostAreaRatio, 16000);
define_pd_global(intx, LoopUnrollLimit, 60);
define_pd_global(intx, LoopPercentProfileLimit, 10);

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2018 SAP SE. All rights reserved.
* Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2026 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -24,6 +24,7 @@
*/
#include "runtime/icache.hpp"
#include "runtime/vm_version.hpp"
// Use inline assembler to implement icache flush.
int ICache::ppc64_flush_icache(address start, int lines, int magic) {
@ -67,6 +68,9 @@ int ICache::ppc64_flush_icache(address start, int lines, int magic) {
void ICacheStubGenerator::generate_icache_flush(ICache::flush_icache_stub_t* flush_icache_stub) {
guarantee(VM_Version::get_icache_line_size() >= ICache::line_size,
"processors with smaller cache line size are no longer supported");
*flush_icache_stub = (ICache::flush_icache_stub_t)ICache::ppc64_flush_icache;
// First call to flush itself.

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2013 SAP SE. All rights reserved.
* Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2026 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -35,9 +35,8 @@ class ICache : public AbstractICache {
public:
enum {
// Actually, cache line size is 64, but keeping it as it is to be
// on the safe side on ALL PPC64 implementations.
log2_line_size = 5,
// Cache line size is 128 on all supported PPC64 implementations.
log2_line_size = 7,
line_size = 1 << log2_line_size
};

View File

@ -2412,10 +2412,8 @@ bool Matcher::is_generic_vector(MachOper* opnd) {
return false;
}
// Return whether or not this register is ever used as an argument. This
// function is used on startup to build the trampoline stubs in generateOptoStub.
// Registers not mentioned will be killed by the VM call in the trampoline, and
// arguments in those registers not be available to the callee.
#ifdef ASSERT
// Return whether or not this register is ever used as an argument.
bool Matcher::can_be_java_arg(int reg) {
// We must include the virtual halves in order to get STDs and LDs
// instead of STWs and LWs in the trampoline stubs.
@ -2447,10 +2445,7 @@ bool Matcher::can_be_java_arg(int reg) {
return false;
}
bool Matcher::is_spillable_arg(int reg) {
return can_be_java_arg(reg);
}
#endif
uint Matcher::int_pressure_limit()
{
@ -3715,13 +3710,6 @@ frame %{
// Compiled code's Frame Pointer.
frame_pointer(R1); // R1_SP
// Interpreter stores its frame pointer in a register which is
// stored to the stack by I2CAdaptors. I2CAdaptors convert from
// interpreted java to compiled java.
//
// R14_state holds pointer to caller's cInterpreter.
interpreter_frame_pointer(R14); // R14_state
stack_alignment(frame::alignment_in_bytes);
// Number of outgoing stack slots killed above the

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2025 SAP SE. All rights reserved.
* Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2026 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -475,19 +475,12 @@ void VM_Version::print_features() {
void VM_Version::determine_features() {
#if defined(ABI_ELFv2)
// 1 InstWord per call for the blr instruction.
const int code_size = (num_features+1+2*1)*BytesPerInstWord;
const int code_size = (num_features + 1 /*blr*/) * BytesPerInstWord;
#else
// 7 InstWords for each call (function descriptor + blr instruction).
const int code_size = (num_features+1+2*7)*BytesPerInstWord;
const int code_size = (num_features + 1 /*blr*/ + 6 /* fd */) * BytesPerInstWord;
#endif
int features = 0;
// create test area
enum { BUFFER_SIZE = 2*4*K }; // Needs to be >=2* max cache line size (cache line size can't exceed min page size).
char test_area[BUFFER_SIZE];
char *mid_of_test_area = &test_area[BUFFER_SIZE>>1];
// Allocate space for the code.
ResourceMark rm;
CodeBuffer cb("detect_cpu_features", code_size, 0);
@ -497,20 +490,13 @@ void VM_Version::determine_features() {
_features = VM_Version::all_features_m;
// Emit code.
void (*test)(address addr, uint64_t offset)=(void(*)(address addr, uint64_t offset))(void *)a->function_entry();
void (*test)() = (void(*)())(void *)a->function_entry();
uint32_t *code = (uint32_t *)a->pc();
// Keep R3_ARG1 unmodified, it contains &field (see below).
// Keep R4_ARG2 unmodified, it contains offset = 0 (see below).
a->mfdscr(R0);
a->darn(R7);
a->brw(R5, R6);
a->blr();
// Emit function to set one cache line to zero. Emit function descriptor and get pointer to it.
void (*zero_cacheline_func_ptr)(char*) = (void(*)(char*))(void *)a->function_entry();
a->dcbz(R3_ARG1); // R3_ARG1 = addr
a->blr();
uint32_t *code_end = (uint32_t *)a->pc();
a->flush();
_features = VM_Version::unknown_m;
@ -522,18 +508,9 @@ void VM_Version::determine_features() {
Disassembler::decode((u_char*)code, (u_char*)code_end, tty);
}
// Measure cache line size.
memset(test_area, 0xFF, BUFFER_SIZE); // Fill test area with 0xFF.
(*zero_cacheline_func_ptr)(mid_of_test_area); // Call function which executes dcbz to the middle.
int count = 0; // count zeroed bytes
for (int i = 0; i < BUFFER_SIZE; i++) if (test_area[i] == 0) count++;
guarantee(is_power_of_2(count), "cache line size needs to be a power of 2");
_L1_data_cache_line_size = count;
// Execute code. Illegal instructions will be replaced by 0 in the signal handler.
VM_Version::_is_determine_features_test_running = true;
// We must align the first argument to 16 bytes because of the lqarx check.
(*test)(align_up((address)mid_of_test_area, 16), 0);
(*test)();
VM_Version::_is_determine_features_test_running = false;
// determine which instructions are legal.
@ -550,6 +527,10 @@ void VM_Version::determine_features() {
}
_features = features;
_L1_data_cache_line_size = VM_Version::get_dcache_line_size();
assert(_L1_data_cache_line_size >= DEFAULT_CACHE_LINE_SIZE,
"processors with smaller cache line size are no longer supported");
}
// Power 8: Configure Data Stream Control Register.

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2025 SAP SE. All rights reserved.
* Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2026 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -81,6 +81,9 @@ public:
static uint64_t _dscr_val;
static void initialize_cpu_information(void);
static int get_dcache_line_size();
static int get_icache_line_size();
};
#endif // CPU_PPC_VM_VERSION_PPC_HPP

View File

@ -42,7 +42,6 @@ define_pd_global(bool, TieredCompilation, false);
define_pd_global(intx, CompileThreshold, 1500 );
define_pd_global(intx, OnStackReplacePercentage, 933 );
define_pd_global(intx, NewSizeThreadIncrease, 4*K );
define_pd_global(size_t, InitialCodeCacheSize, 160*K);
define_pd_global(size_t, ReservedCodeCacheSize, 32*M );
define_pd_global(size_t, NonProfiledCodeHeapSize, 13*M );

View File

@ -47,7 +47,6 @@ define_pd_global(intx, ConditionalMoveLimit, 3);
define_pd_global(intx, FreqInlineSize, 325);
define_pd_global(intx, MinJumpTableSize, 10);
define_pd_global(intx, InteriorEntryAlignment, 16);
define_pd_global(intx, NewSizeThreadIncrease, ScaleForWordSize(4*K));
define_pd_global(intx, LoopUnrollLimit, 60);
define_pd_global(intx, LoopPercentProfileLimit, 10);
// InitialCodeCacheSize derived from specjbb2000 run.

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
// Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved.
// Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
// Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@ -2060,11 +2060,8 @@ bool Matcher::is_generic_vector(MachOper* opnd) {
return false;
}
#ifdef ASSERT
// Return whether or not this register is ever used as an argument.
// This function is used on startup to build the trampoline stubs in
// generateOptoStub. Registers not mentioned will be killed by the VM
// call in the trampoline, and arguments in those registers not be
// available to the callee.
bool Matcher::can_be_java_arg(int reg)
{
return
@ -2085,11 +2082,7 @@ bool Matcher::can_be_java_arg(int reg)
reg == F16_num || reg == F16_H_num ||
reg == F17_num || reg == F17_H_num;
}
bool Matcher::is_spillable_arg(int reg)
{
return can_be_java_arg(reg);
}
#endif
uint Matcher::int_pressure_limit()
{
@ -2559,11 +2552,6 @@ frame %{
// Compiled code's Frame Pointer
frame_pointer(R2);
// Interpreter stores its frame pointer in a register which is
// stored to the stack by I2CAdaptors.
// I2CAdaptors convert from interpreted java to compiled java.
interpreter_frame_pointer(R8);
// Stack alignment requirement
stack_alignment(StackAlignmentInBytes); // Alignment size in bytes (128-bit -> 16 bytes)

View File

@ -52,7 +52,6 @@ define_pd_global(size_t, CodeCacheExpansionSize, 32*K);
define_pd_global(size_t, CodeCacheMinBlockLength, 1);
define_pd_global(size_t, CodeCacheMinimumUseSpace, 400*K);
define_pd_global(bool, NeverActAsServerClassMachine, true);
define_pd_global(size_t, NewSizeThreadIncrease, 16*K);
define_pd_global(size_t, InitialCodeCacheSize, 160*K);
#endif // !COMPILER2

View File

@ -46,7 +46,6 @@ define_pd_global(intx, OnStackReplacePercentage, 140);
define_pd_global(intx, ConditionalMoveLimit, 4);
define_pd_global(intx, FreqInlineSize, 325);
define_pd_global(intx, InteriorEntryAlignment, 4);
define_pd_global(size_t, NewSizeThreadIncrease, ScaleForWordSize(4*K));
define_pd_global(intx, RegisterCostAreaRatio, 12000);
define_pd_global(intx, LoopUnrollLimit, 60);
define_pd_global(intx, LoopPercentProfileLimit, 10);

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
// Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved.
// Copyright (c) 2017, 2024 SAP SE. All rights reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
@ -1890,10 +1890,8 @@ const int z_num_iarg_registers = sizeof(z_iarg_reg) / sizeof(z_iarg_reg[0]);
const int z_num_farg_registers = sizeof(z_farg_reg) / sizeof(z_farg_reg[0]);
// Return whether or not this register is ever used as an argument. This
// function is used on startup to build the trampoline stubs in generateOptoStub.
// Registers not mentioned will be killed by the VM call in the trampoline, and
// arguments in those registers not be available to the callee.
#ifdef ASSERT
// Return whether or not this register is ever used as an argument.
bool Matcher::can_be_java_arg(int reg) {
// We return true for all registers contained in z_iarg_reg[] and
// z_farg_reg[] and their virtual halves.
@ -1917,10 +1915,7 @@ bool Matcher::can_be_java_arg(int reg) {
return false;
}
bool Matcher::is_spillable_arg(int reg) {
return can_be_java_arg(reg);
}
#endif
uint Matcher::int_pressure_limit()
{
@ -2606,13 +2601,6 @@ frame %{
// z/Architecture stack pointer
frame_pointer(Z_R15); // Z_SP
// Interpreter stores its frame pointer in a register which is
// stored to the stack by I2CAdaptors. I2CAdaptors convert from
// interpreted java to compiled java.
//
// Z_state holds pointer to caller's cInterpreter.
interpreter_frame_pointer(Z_R7); // Z_state
// Use alignment_in_bytes instead of log_2_of_alignment_in_bits.
stack_alignment(frame::alignment_in_bytes);

View File

@ -5442,6 +5442,13 @@ void Assembler::pmovsxwd(XMMRegister dst, XMMRegister src) {
emit_int16(0x23, (0xC0 | encode));
}
void Assembler::pmovzxwd(XMMRegister dst, XMMRegister src) {
assert(VM_Version::supports_sse4_1(), "");
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
emit_int16(0x33, (0xC0 | encode));
}
void Assembler::vpmovzxbw(XMMRegister dst, Address src, int vector_len) {
assert(VM_Version::supports_avx(), "");
InstructionMark im(this);

View File

@ -1965,6 +1965,7 @@ private:
void pmovsxbq(XMMRegister dst, XMMRegister src);
void pmovsxbw(XMMRegister dst, XMMRegister src);
void pmovsxwd(XMMRegister dst, XMMRegister src);
void pmovzxwd(XMMRegister dst, XMMRegister src);
void vpmovsxbd(XMMRegister dst, XMMRegister src, int vector_len);
void vpmovsxbq(XMMRegister dst, XMMRegister src, int vector_len);
void vpmovsxbw(XMMRegister dst, XMMRegister src, int vector_len);

View File

@ -41,7 +41,6 @@ define_pd_global(bool, TieredCompilation, false);
define_pd_global(intx, CompileThreshold, 1500 );
define_pd_global(intx, OnStackReplacePercentage, 933 );
define_pd_global(size_t, NewSizeThreadIncrease, 4*K );
define_pd_global(size_t, InitialCodeCacheSize, 160*K);
define_pd_global(size_t, ReservedCodeCacheSize, 32*M );
define_pd_global(size_t, NonProfiledCodeHeapSize, 13*M );

View File

@ -1729,6 +1729,24 @@ void C2_MacroAssembler::reduce_operation_128(BasicType typ, int opcode, XMMRegis
default: assert(false, "wrong type");
}
break;
case Op_UMinReductionV:
switch (typ) {
case T_BYTE: vpminub(dst, dst, src, Assembler::AVX_128bit); break;
case T_SHORT: vpminuw(dst, dst, src, Assembler::AVX_128bit); break;
case T_INT: vpminud(dst, dst, src, Assembler::AVX_128bit); break;
case T_LONG: evpminuq(dst, k0, dst, src, true, Assembler::AVX_128bit); break;
default: assert(false, "wrong type");
}
break;
case Op_UMaxReductionV:
switch (typ) {
case T_BYTE: vpmaxub(dst, dst, src, Assembler::AVX_128bit); break;
case T_SHORT: vpmaxuw(dst, dst, src, Assembler::AVX_128bit); break;
case T_INT: vpmaxud(dst, dst, src, Assembler::AVX_128bit); break;
case T_LONG: evpmaxuq(dst, k0, dst, src, true, Assembler::AVX_128bit); break;
default: assert(false, "wrong type");
}
break;
case Op_AddReductionVF: addss(dst, src); break;
case Op_AddReductionVD: addsd(dst, src); break;
case Op_AddReductionVI:
@ -1792,6 +1810,24 @@ void C2_MacroAssembler::reduce_operation_256(BasicType typ, int opcode, XMMRegis
default: assert(false, "wrong type");
}
break;
case Op_UMinReductionV:
switch (typ) {
case T_BYTE: vpminub(dst, src1, src2, vector_len); break;
case T_SHORT: vpminuw(dst, src1, src2, vector_len); break;
case T_INT: vpminud(dst, src1, src2, vector_len); break;
case T_LONG: evpminuq(dst, k0, src1, src2, true, vector_len); break;
default: assert(false, "wrong type");
}
break;
case Op_UMaxReductionV:
switch (typ) {
case T_BYTE: vpmaxub(dst, src1, src2, vector_len); break;
case T_SHORT: vpmaxuw(dst, src1, src2, vector_len); break;
case T_INT: vpmaxud(dst, src1, src2, vector_len); break;
case T_LONG: evpmaxuq(dst, k0, src1, src2, true, vector_len); break;
default: assert(false, "wrong type");
}
break;
case Op_AddReductionVI:
switch (typ) {
case T_BYTE: vpaddb(dst, src1, src2, vector_len); break;
@ -2058,7 +2094,11 @@ void C2_MacroAssembler::reduce8B(int opcode, Register dst, Register src1, XMMReg
psrldq(vtmp2, 1);
reduce_operation_128(T_BYTE, opcode, vtmp1, vtmp2);
movdl(vtmp2, src1);
pmovsxbd(vtmp1, vtmp1);
if (opcode == Op_UMinReductionV || opcode == Op_UMaxReductionV) {
pmovzxbd(vtmp1, vtmp1);
} else {
pmovsxbd(vtmp1, vtmp1);
}
reduce_operation_128(T_INT, opcode, vtmp1, vtmp2);
pextrb(dst, vtmp1, 0x0);
movsbl(dst, dst);
@ -2135,7 +2175,11 @@ void C2_MacroAssembler::reduce4S(int opcode, Register dst, Register src1, XMMReg
reduce_operation_128(T_SHORT, opcode, vtmp1, vtmp2);
}
movdl(vtmp2, src1);
pmovsxwd(vtmp1, vtmp1);
if (opcode == Op_UMinReductionV || opcode == Op_UMaxReductionV) {
pmovzxwd(vtmp1, vtmp1);
} else {
pmovsxwd(vtmp1, vtmp1);
}
reduce_operation_128(T_INT, opcode, vtmp1, vtmp2);
pextrw(dst, vtmp1, 0x0);
movswl(dst, dst);

View File

@ -46,7 +46,6 @@ define_pd_global(intx, FreqInlineSize, 325);
define_pd_global(intx, MinJumpTableSize, 10);
define_pd_global(intx, LoopPercentProfileLimit, 10);
define_pd_global(intx, InteriorEntryAlignment, 16);
define_pd_global(size_t, NewSizeThreadIncrease, ScaleForWordSize(4*K));
define_pd_global(intx, LoopUnrollLimit, 60);
// InitialCodeCacheSize derived from specjbb2000 run.
define_pd_global(size_t, InitialCodeCacheSize, 2496*K); // Integral multiple of CodeCacheExpansionSize

View File

@ -961,7 +961,7 @@ void MacroAssembler::call(AddressLiteral entry, Register rscratch) {
void MacroAssembler::ic_call(address entry, jint method_index) {
RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index);
// Needs full 64-bit immediate for later patching.
mov64(rax, (int64_t)Universe::non_oop_word());
Assembler::mov64(rax, (int64_t)Universe::non_oop_word());
call(AddressLiteral(entry, rh));
}
@ -1961,6 +1961,20 @@ void MacroAssembler::movflt(XMMRegister dst, AddressLiteral src, Register rscrat
}
}
void MacroAssembler::mov64(Register dst, int64_t imm64) {
if (is_uimm32(imm64)) {
movl(dst, checked_cast<uint32_t>(imm64));
} else if (is_simm32(imm64)) {
movq(dst, checked_cast<int32_t>(imm64));
} else {
Assembler::mov64(dst, imm64);
}
}
void MacroAssembler::mov64(Register dst, int64_t imm64, relocInfo::relocType rtype, int format) {
Assembler::mov64(dst, imm64, rtype, format);
}
void MacroAssembler::movptr(Register dst, Register src) {
movq(dst, src);
}
@ -1971,13 +1985,7 @@ void MacroAssembler::movptr(Register dst, Address src) {
// src should NEVER be a real pointer. Use AddressLiteral for true pointers
void MacroAssembler::movptr(Register dst, intptr_t src) {
if (is_uimm32(src)) {
movl(dst, checked_cast<uint32_t>(src));
} else if (is_simm32(src)) {
movq(dst, checked_cast<int32_t>(src));
} else {
mov64(dst, src);
}
mov64(dst, src);
}
void MacroAssembler::movptr(Address dst, Register src) {

View File

@ -1869,6 +1869,9 @@ public:
void mov_metadata(Register dst, Metadata* obj);
void mov_metadata(Address dst, Metadata* obj, Register rscratch);
void mov64(Register dst, int64_t imm64);
void mov64(Register dst, int64_t imm64, relocInfo::relocType rtype, int format);
void movptr(Register dst, Register src);
void movptr(Register dst, Address src);
void movptr(Register dst, AddressLiteral src);

View File

@ -2726,11 +2726,8 @@ bool Matcher::is_short_branch_offset(int rule, int br_size, int offset) {
return (-128 <= offset && offset <= 127);
}
#ifdef ASSERT
// Return whether or not this register is ever used as an argument.
// This function is used on startup to build the trampoline stubs in
// generateOptoStub. Registers not mentioned will be killed by the VM
// call in the trampoline, and arguments in those registers not be
// available to the callee.
bool Matcher::can_be_java_arg(int reg)
{
return
@ -2750,11 +2747,7 @@ bool Matcher::can_be_java_arg(int reg)
reg == XMM6_num || reg == XMM6b_num ||
reg == XMM7_num || reg == XMM7b_num;
}
bool Matcher::is_spillable_arg(int reg)
{
return can_be_java_arg(reg);
}
#endif
uint Matcher::int_pressure_limit()
{
@ -3341,6 +3334,18 @@ bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) {
return false;
}
break;
case Op_UMinReductionV:
case Op_UMaxReductionV:
if (UseAVX == 0) {
return false;
}
if (bt == T_LONG && !VM_Version::supports_avx512vl()) {
return false;
}
if (UseAVX > 2 && size_in_bits == 512 && !VM_Version::supports_avx512vl()) {
return false;
}
break;
case Op_MaxV:
case Op_MinV:
if (UseSSE < 4 && is_integral_type(bt)) {
@ -4679,11 +4684,6 @@ frame
// Compiled code's Frame Pointer
frame_pointer(RSP);
// Interpreter stores its frame pointer in a register which is
// stored to the stack by I2CAdaptors.
// I2CAdaptors convert from interpreted java to compiled java.
interpreter_frame_pointer(RBP);
// Stack alignment requirement
stack_alignment(StackAlignmentInBytes); // Alignment size in bytes (128-bit -> 16 bytes)
@ -19371,6 +19371,8 @@ instruct reductionI(rRegI dst, rRegI src1, legVec src2, legVec vtmp1, legVec vtm
match(Set dst (XorReductionV src1 src2));
match(Set dst (MinReductionV src1 src2));
match(Set dst (MaxReductionV src1 src2));
match(Set dst (UMinReductionV src1 src2));
match(Set dst (UMaxReductionV src1 src2));
effect(TEMP vtmp1, TEMP vtmp2);
format %{ "vector_reduction_int $dst,$src1,$src2 ; using $vtmp1, $vtmp2 as TEMP" %}
ins_encode %{
@ -19392,6 +19394,8 @@ instruct reductionL(rRegL dst, rRegL src1, legVec src2, legVec vtmp1, legVec vtm
match(Set dst (XorReductionV src1 src2));
match(Set dst (MinReductionV src1 src2));
match(Set dst (MaxReductionV src1 src2));
match(Set dst (UMinReductionV src1 src2));
match(Set dst (UMaxReductionV src1 src2));
effect(TEMP vtmp1, TEMP vtmp2);
format %{ "vector_reduction_long $dst,$src1,$src2 ; using $vtmp1, $vtmp2 as TEMP" %}
ins_encode %{
@ -19411,6 +19415,8 @@ instruct reductionL_avx512dq(rRegL dst, rRegL src1, vec src2, vec vtmp1, vec vtm
match(Set dst (XorReductionV src1 src2));
match(Set dst (MinReductionV src1 src2));
match(Set dst (MaxReductionV src1 src2));
match(Set dst (UMinReductionV src1 src2));
match(Set dst (UMaxReductionV src1 src2));
effect(TEMP vtmp1, TEMP vtmp2);
format %{ "vector_reduction_long $dst,$src1,$src2 ; using $vtmp1, $vtmp2 as TEMP" %}
ins_encode %{
@ -19639,6 +19645,8 @@ instruct reductionB(rRegI dst, rRegI src1, legVec src2, legVec vtmp1, legVec vtm
match(Set dst (XorReductionV src1 src2));
match(Set dst (MinReductionV src1 src2));
match(Set dst (MaxReductionV src1 src2));
match(Set dst (UMinReductionV src1 src2));
match(Set dst (UMaxReductionV src1 src2));
effect(TEMP vtmp1, TEMP vtmp2);
format %{ "vector_reduction_byte $dst,$src1,$src2 ; using $vtmp1, $vtmp2 as TEMP" %}
ins_encode %{
@ -19657,6 +19665,8 @@ instruct reductionB_avx512bw(rRegI dst, rRegI src1, vec src2, vec vtmp1, vec vtm
match(Set dst (XorReductionV src1 src2));
match(Set dst (MinReductionV src1 src2));
match(Set dst (MaxReductionV src1 src2));
match(Set dst (UMinReductionV src1 src2));
match(Set dst (UMaxReductionV src1 src2));
effect(TEMP vtmp1, TEMP vtmp2);
format %{ "vector_reduction_byte $dst,$src1,$src2 ; using $vtmp1, $vtmp2 as TEMP" %}
ins_encode %{
@ -19678,6 +19688,8 @@ instruct reductionS(rRegI dst, rRegI src1, legVec src2, legVec vtmp1, legVec vtm
match(Set dst (XorReductionV src1 src2));
match(Set dst (MinReductionV src1 src2));
match(Set dst (MaxReductionV src1 src2));
match(Set dst (UMinReductionV src1 src2));
match(Set dst (UMaxReductionV src1 src2));
effect(TEMP vtmp1, TEMP vtmp2);
format %{ "vector_reduction_short $dst,$src1,$src2 ; using $vtmp1, $vtmp2 as TEMP" %}
ins_encode %{

View File

@ -37,16 +37,6 @@
range, \
constraint) \
\
/* Whether to allow the VM to run if EXTSHM=ON. EXTSHM is an environment */ \
/* variable used on AIX to activate certain hacks which allow more shm segments */\
/* for 32bit processes. For 64bit processes, it is pointless and may have */ \
/* harmful side effects (e.g. for some reasonn prevents allocation of 64k pages */\
/* via shmctl). */ \
/* Per default we quit with an error if that variable is found; for certain */ \
/* customer scenarios, we may want to be able to run despite that variable. */ \
product(bool, AllowExtshm, false, DIAGNOSTIC, \
"Allow VM to run with EXTSHM=ON.") \
\
/* Maximum expected size of the data segment. That correlates with the */ \
/* maximum C Heap consumption we expect. */ \
/* We need to leave "breathing space" for the data segment when */ \

View File

@ -126,7 +126,6 @@ int mread_real_time(timebasestruct_t *t, size_t size_of_timebasestruct_t);
// for multipage initialization error analysis (in 'g_multipage_error')
#define ERROR_MP_OS_TOO_OLD 100
#define ERROR_MP_EXTSHM_ACTIVE 101
#define ERROR_MP_VMGETINFO_FAILED 102
#define ERROR_MP_VMGETINFO_CLAIMS_NO_SUPPORT_FOR_64K 103
@ -178,9 +177,6 @@ uint32_t os::Aix::_os_version = 0;
// -1 = uninitialized, 0 - no, 1 - yes
int os::Aix::_xpg_sus_mode = -1;
// -1 = uninitialized, 0 - no, 1 - yes
int os::Aix::_extshm = -1;
////////////////////////////////////////////////////////////////////////////////
// local variables
@ -1195,13 +1191,6 @@ void os::print_memory_info(outputStream* st) {
const char* const ldr_cntrl = ::getenv("LDR_CNTRL");
st->print_cr(" LDR_CNTRL=%s.", ldr_cntrl ? ldr_cntrl : "<unset>");
// Print out EXTSHM because it is an unsupported setting.
const char* const extshm = ::getenv("EXTSHM");
st->print_cr(" EXTSHM=%s.", extshm ? extshm : "<unset>");
if ( (strcmp(extshm, "on") == 0) || (strcmp(extshm, "ON") == 0) ) {
st->print_cr(" *** Unsupported! Please remove EXTSHM from your environment! ***");
}
// Print out AIXTHREAD_GUARDPAGES because it affects the size of pthread stacks.
const char* const aixthread_guardpages = ::getenv("AIXTHREAD_GUARDPAGES");
st->print_cr(" AIXTHREAD_GUARDPAGES=%s.",
@ -2133,8 +2122,6 @@ void os::init(void) {
// datapsize = 64k. Data segment, thread stacks are 64k paged.
// This normally means that we can allocate 64k pages dynamically.
// (There is one special case where this may be false: EXTSHM=on.
// but we decided to not support that mode).
assert0(g_multipage_support.can_use_64K_pages || g_multipage_support.can_use_64K_mmap_pages);
set_page_size(64*K);
@ -2543,28 +2530,13 @@ void os::Aix::initialize_os_info() {
void os::Aix::scan_environment() {
char* p;
int rc;
// Warn explicitly if EXTSHM=ON is used. That switch changes how
// System V shared memory behaves. One effect is that page size of
// shared memory cannot be change dynamically, effectivly preventing
// large pages from working.
// This switch was needed on AIX 32bit, but on AIX 64bit the general
// recommendation is (in OSS notes) to switch it off.
// Reject EXTSHM=ON. That switch changes how System V shared memory behaves
// and prevents allocation of 64k pages for the heap.
p = ::getenv("EXTSHM");
trcVerbose("EXTSHM=%s.", p ? p : "<unset>");
if (p && strcasecmp(p, "ON") == 0) {
_extshm = 1;
log_warning(os)("*** Unsupported mode! Please remove EXTSHM from your environment! ***");
if (!AllowExtshm) {
// We allow under certain conditions the user to continue. However, we want this
// to be a fatal error by default. On certain AIX systems, leaving EXTSHM=ON means
// that the VM is not able to allocate 64k pages for the heap.
// We do not want to run with reduced performance.
vm_exit_during_initialization("EXTSHM is ON. Please remove EXTSHM from your environment.");
}
} else {
_extshm = 0;
vm_exit_during_initialization("EXTSHM is ON. Please remove EXTSHM from your environment.");
}
// SPEC1170 behaviour: will change the behaviour of a number of POSIX APIs.

View File

@ -49,11 +49,6 @@ class os::Aix {
// 1 - SPEC1170 requested (XPG_SUS_ENV is ON)
static int _xpg_sus_mode;
// -1 = uninitialized,
// 0 - EXTSHM=OFF or not set
// 1 - EXTSHM=ON
static int _extshm;
static bool available_memory(physical_memory_size_type& value);
static bool free_memory(physical_memory_size_type& value);
static physical_memory_size_type physical_memory() { return _physical_memory; }
@ -111,12 +106,6 @@ class os::Aix {
return _xpg_sus_mode;
}
// Returns true if EXTSHM=ON.
static bool extshm() {
assert(_extshm != -1, "not initialized");
return _extshm;
}
// result struct for get_meminfo()
struct meminfo_t {

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2026 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* 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 "runtime/vm_version.hpp"
#include <sys/systemcfg.h>
int VM_Version::get_dcache_line_size() {
return _system_configuration.dcache_line;
}
int VM_Version::get_icache_line_size() {
return _system_configuration.icache_line;
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2026 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* 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 "runtime/vm_version.hpp"
#include <unistd.h>
int VM_Version::get_dcache_line_size() {
// This should work on all modern linux versions:
int size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
// It may fail with very old linux / glibc versions. We use DEFAULT_CACHE_LINE_SIZE in this case.
// That is the correct value for all currently supported processors.
return (size <= 0) ? DEFAULT_CACHE_LINE_SIZE : size;
}
int VM_Version::get_icache_line_size() {
// This should work on all modern linux versions:
int size = sysconf(_SC_LEVEL1_ICACHE_LINESIZE);
// It may fail with very old linux / glibc versions. We use DEFAULT_CACHE_LINE_SIZE in this case.
// That is the correct value for all currently supported processors.
return (size <= 0) ? DEFAULT_CACHE_LINE_SIZE : size;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -993,9 +993,6 @@ void ADLParser::frame_parse(void) {
if (strcmp(token,"frame_pointer")==0) {
frame_pointer_parse(frame, false);
}
if (strcmp(token,"interpreter_frame_pointer")==0) {
interpreter_frame_pointer_parse(frame, false);
}
if (strcmp(token,"inline_cache_reg")==0) {
inline_cache_parse(frame, false);
}
@ -1119,11 +1116,6 @@ void ADLParser::frame_pointer_parse(FrameForm *frame, bool native) {
else { frame->_frame_pointer = frame_pointer; }
}
//------------------------------interpreter_frame_pointer_parse----------------------------
void ADLParser::interpreter_frame_pointer_parse(FrameForm *frame, bool native) {
frame->_interpreter_frame_pointer_reg = parse_one_arg("interpreter frame pointer entry");
}
//------------------------------inline_cache_parse-----------------------------
void ADLParser::inline_cache_parse(FrameForm *frame, bool native) {
frame->_inline_cache_reg = parse_one_arg("inline cache reg entry");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -120,7 +120,6 @@ protected:
// Parse the components of the frame section
void sync_stack_slots_parse(FrameForm *frame);
void frame_pointer_parse(FrameForm *frame, bool native);
void interpreter_frame_pointer_parse(FrameForm *frame, bool native);
void inline_cache_parse(FrameForm *frame, bool native);
void interpreter_arg_ptr_parse(FrameForm *frame, bool native);
void interpreter_method_parse(FrameForm *frame, bool native);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -476,7 +476,6 @@ void AllocClass::forms_do(FormClosure* f) {
FrameForm::FrameForm() {
_sync_stack_slots = nullptr;
_inline_cache_reg = nullptr;
_interpreter_frame_pointer_reg = nullptr;
_cisc_spilling_operand_name = nullptr;
_frame_pointer = nullptr;
_c_frame_pointer = nullptr;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -347,7 +347,6 @@ public:
// Public Data
char *_sync_stack_slots;
char *_inline_cache_reg;
char *_interpreter_frame_pointer_reg;
char *_cisc_spilling_operand_name;
char *_frame_pointer;
char *_c_frame_pointer;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -4212,14 +4212,6 @@ void ArchDesc::buildFrameMethods(FILE *fp_cpp) {
fprintf(fp_cpp,"int Matcher::inline_cache_reg_encode() {");
fprintf(fp_cpp," return _regEncode[inline_cache_reg()]; }\n\n");
// Interpreter's Frame Pointer Register
fprintf(fp_cpp,"OptoReg::Name Matcher::interpreter_frame_pointer_reg() {");
if (_frame->_interpreter_frame_pointer_reg == nullptr)
fprintf(fp_cpp," return OptoReg::Bad; }\n\n");
else
fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n",
_frame->_interpreter_frame_pointer_reg);
// Frame Pointer definition
/* CNC - I can not contemplate having a different frame pointer between
Java and native code; makes my head hurt to think about it.

View File

@ -447,9 +447,6 @@ void CompilerConfig::set_jvmci_specific_flags() {
if (FLAG_IS_DEFAULT(InitialCodeCacheSize)) {
FLAG_SET_DEFAULT(InitialCodeCacheSize, MAX2(16*M, InitialCodeCacheSize));
}
if (FLAG_IS_DEFAULT(NewSizeThreadIncrease)) {
FLAG_SET_DEFAULT(NewSizeThreadIncrease, MAX2(4*K, NewSizeThreadIncrease));
}
if (FLAG_IS_DEFAULT(Tier3DelayOn)) {
// This effectively prevents the compile broker scheduling tier 2
// (i.e., limited C1 profiling) compilations instead of tier 3

View File

@ -58,7 +58,6 @@ define_pd_global(bool, TieredCompilation, false);
define_pd_global(intx, CompileThreshold, 0);
define_pd_global(intx, OnStackReplacePercentage, 0);
define_pd_global(size_t, NewSizeThreadIncrease, 4*K);
define_pd_global(bool, InlineClassNatives, true);
define_pd_global(bool, InlineUnsafeOps, true);
define_pd_global(size_t, InitialCodeCacheSize, 160*K);

View File

@ -1652,21 +1652,13 @@ jint G1CollectedHeap::initialize() {
return JNI_OK;
}
bool G1CollectedHeap::concurrent_mark_is_terminating() const {
assert(_cm != nullptr, "_cm must have been created");
assert(_cm->is_fully_initialized(), "thread must exist in order to check if mark is terminating");
return _cm->cm_thread()->should_terminate();
}
void G1CollectedHeap::stop() {
// Stop all concurrent threads. We do this to make sure these threads
// do not continue to execute and access resources (e.g. logging)
// that are destroyed during shutdown.
_cr->stop();
_service_thread->stop();
if (_cm->is_fully_initialized()) {
_cm->cm_thread()->stop();
}
_cm->stop();
}
void G1CollectedHeap::safepoint_synchronize_begin() {
@ -1857,12 +1849,12 @@ void G1CollectedHeap::increment_old_marking_cycles_completed(bool concurrent,
record_whole_heap_examined_timestamp();
}
// We need to clear the "in_progress" flag in the CM thread before
// We need to tell G1ConcurrentMark to update the state before
// we wake up any waiters (especially when ExplicitInvokesConcurrent
// is set) so that if a waiter requests another System.gc() it doesn't
// incorrectly see that a marking cycle is still in progress.
if (concurrent) {
_cm->cm_thread()->set_idle();
_cm->notify_concurrent_cycle_completed();
}
// Notify threads waiting in System.gc() (with ExplicitGCInvokesConcurrent)
@ -2565,11 +2557,9 @@ void G1CollectedHeap::start_concurrent_cycle(bool concurrent_operation_is_full_m
assert(!_cm->in_progress(), "Can not start concurrent operation while in progress");
MutexLocker x(G1CGC_lock, Mutex::_no_safepoint_check_flag);
if (concurrent_operation_is_full_mark) {
_cm->post_concurrent_mark_start();
_cm->cm_thread()->start_full_mark();
_cm->start_full_concurrent_cycle();
} else {
_cm->post_concurrent_undo_start();
_cm->cm_thread()->start_undo_mark();
_cm->start_undo_concurrent_cycle();
}
G1CGC_lock->notify();
}

View File

@ -915,9 +915,6 @@ public:
// specified by the policy object.
jint initialize() override;
// Returns whether concurrent mark threads (and the VM) are about to terminate.
bool concurrent_mark_is_terminating() const;
void safepoint_synchronize_begin() override;
void safepoint_synchronize_end() override;

View File

@ -581,6 +581,11 @@ PartialArrayStateManager* G1ConcurrentMark::partial_array_state_manager() const
return _partial_array_state_manager;
}
G1ConcurrentMarkThread* G1ConcurrentMark::cm_thread() const {
assert(is_fully_initialized(), "must be");
return _cm_thread;
}
void G1ConcurrentMark::reset() {
_has_aborted.store_relaxed(false);
@ -715,7 +720,6 @@ public:
private:
// Heap region closure used for clearing the _mark_bitmap.
class G1ClearBitmapHRClosure : public G1HeapRegionClosure {
private:
G1ConcurrentMark* _cm;
G1CMBitMap* _bitmap;
bool _suspendible; // If suspendible, do yield checks.
@ -959,7 +963,7 @@ void G1ConcurrentMark::pre_concurrent_start(GCCause::Cause cause) {
_gc_tracer_cm->set_gc_cause(cause);
}
void G1ConcurrentMark::post_concurrent_mark_start() {
void G1ConcurrentMark::start_full_concurrent_cycle() {
// Start Concurrent Marking weak-reference discovery.
ReferenceProcessor* rp = _g1h->ref_processor_cm();
rp->start_discovery(false /* always_clear */);
@ -976,10 +980,26 @@ void G1ConcurrentMark::post_concurrent_mark_start() {
// when marking is on. So, it's also called at the end of the
// concurrent start pause to update the heap end, if the heap expands
// during it. No need to call it here.
// Signal the thread to start work.
cm_thread()->start_full_mark();
}
void G1ConcurrentMark::post_concurrent_undo_start() {
void G1ConcurrentMark::start_undo_concurrent_cycle() {
root_regions()->cancel_scan();
// Signal the thread to start work.
cm_thread()->start_undo_mark();
}
void G1ConcurrentMark::notify_concurrent_cycle_completed() {
cm_thread()->set_idle();
}
void G1ConcurrentMark::stop() {
if (is_fully_initialized()) {
cm_thread()->stop();
}
}
/*
@ -1943,7 +1963,7 @@ bool G1ConcurrentMark::concurrent_cycle_abort() {
// has been signalled is already rare), and this work should be negligible compared
// to actual full gc work.
if (!is_fully_initialized() || (!cm_thread()->in_progress() && !_g1h->concurrent_mark_is_terminating())) {
if (!is_fully_initialized() || (!cm_thread()->in_progress() && !cm_thread()->should_terminate())) {
return false;
}

View File

@ -352,6 +352,7 @@ class G1ConcurrentMark : public CHeapObj<mtGC> {
friend class G1CMRemarkTask;
friend class G1CMRootRegionScanTask;
friend class G1CMTask;
friend class G1ClearBitMapTask;
friend class G1ConcurrentMarkThread;
G1ConcurrentMarkThread* _cm_thread; // The thread doing the work
@ -524,6 +525,9 @@ class G1ConcurrentMark : public CHeapObj<mtGC> {
Atomic<HeapWord*>* _top_at_rebuild_starts;
// True when Remark pause selected regions for rebuilding.
bool _needs_remembered_set_rebuild;
G1ConcurrentMarkThread* cm_thread() const;
public:
// To be called when an object is marked the first time, e.g. after a successful
// mark_in_bitmap call. Updates various statistics data.
@ -602,8 +606,6 @@ public:
G1RegionToSpaceMapper* bitmap_storage);
~G1ConcurrentMark();
G1ConcurrentMarkThread* cm_thread() { return _cm_thread; }
G1CMBitMap* mark_bitmap() const { return (G1CMBitMap*)&_mark_bitmap; }
// Calculates the number of concurrent GC threads to be used in the marking phase.
@ -632,8 +634,15 @@ public:
// These two methods do the work that needs to be done at the start and end of the
// concurrent start pause.
void pre_concurrent_start(GCCause::Cause cause);
void post_concurrent_mark_start();
void post_concurrent_undo_start();
// Start the particular type of concurrent cycle. After this call threads may be running.
void start_full_concurrent_cycle();
void start_undo_concurrent_cycle();
void notify_concurrent_cycle_completed();
// Stop active components/the concurrent mark thread.
void stop();
// Scan all the root regions and mark everything reachable from
// them.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -366,6 +366,12 @@ static size_t target_heap_capacity(size_t used_bytes, uintx free_ratio) {
}
size_t G1HeapSizingPolicy::full_collection_resize_amount(bool& expand, size_t allocation_word_size) {
// User-requested Full GCs introduce GC load unrelated to heap size; reset CPU
// usage tracking so heap resizing heuristics are driven only by GC pressure.
if (GCCause::is_user_requested_gc(_g1h->gc_cause())) {
reset_cpu_usage_tracking_data();
}
const size_t capacity_after_gc = _g1h->capacity();
// Capacity, free and used after the GC counted as full regions to
// include the waste in the following calculations.

View File

@ -1,83 +0,0 @@
/*
* Copyright (c) 2002, 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/serial/cSpaceCounters.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
CSpaceCounters::CSpaceCounters(const char* name, int ordinal, size_t max_size,
ContiguousSpace* s, GenerationCounters* gc)
: _space(s) {
if (UsePerfData) {
EXCEPTION_MARK;
ResourceMark rm;
const char* cns = PerfDataManager::name_space(gc->name_space(), "space",
ordinal);
_name_space = NEW_C_HEAP_ARRAY(char, strlen(cns)+1, mtGC);
strcpy(_name_space, cns);
const char* cname = PerfDataManager::counter_name(_name_space, "name");
PerfDataManager::create_string_constant(SUN_GC, cname, name, CHECK);
cname = PerfDataManager::counter_name(_name_space, "maxCapacity");
_max_capacity = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Bytes,
(jlong)max_size,
CHECK);
cname = PerfDataManager::counter_name(_name_space, "capacity");
_capacity = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Bytes,
_space->capacity(),
CHECK);
cname = PerfDataManager::counter_name(_name_space, "used");
_used = PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes,
_space->used(),
CHECK);
cname = PerfDataManager::counter_name(_name_space, "initCapacity");
PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_Bytes,
_space->capacity(), CHECK);
}
}
CSpaceCounters::~CSpaceCounters() {
FREE_C_HEAP_ARRAY(char, _name_space);
}
void CSpaceCounters::update_capacity() {
_capacity->set_value(_space->capacity());
}
void CSpaceCounters::update_used() {
_used->set_value(_space->used());
}
void CSpaceCounters::update_all() {
update_used();
update_capacity();
}

View File

@ -1,62 +0,0 @@
/*
* Copyright (c) 2002, 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.
*
*/
#ifndef SHARE_GC_SERIAL_CSPACECOUNTERS_HPP
#define SHARE_GC_SERIAL_CSPACECOUNTERS_HPP
#include "gc/shared/generationCounters.hpp"
#include "gc/shared/space.hpp"
#include "runtime/perfData.hpp"
// A CSpaceCounters is a holder class for performance counters
// that track a space;
class CSpaceCounters: public CHeapObj<mtGC> {
private:
PerfVariable* _capacity;
PerfVariable* _used;
PerfVariable* _max_capacity;
// Constant PerfData types don't need to retain a reference.
// However, it's a good idea to document them here.
// PerfConstant* _size;
ContiguousSpace* _space;
char* _name_space;
public:
CSpaceCounters(const char* name, int ordinal, size_t max_size,
ContiguousSpace* s, GenerationCounters* gc);
~CSpaceCounters();
void update_capacity();
void update_used();
void update_all();
const char* name_space() const { return _name_space; }
};
#endif // SHARE_GC_SERIAL_CSPACECOUNTERS_HPP

View File

@ -39,6 +39,7 @@
#include "gc/shared/gcTimer.hpp"
#include "gc/shared/gcTrace.hpp"
#include "gc/shared/gcTraceTime.inline.hpp"
#include "gc/shared/hSpaceCounters.hpp"
#include "gc/shared/oopStorageSet.inline.hpp"
#include "gc/shared/referencePolicy.hpp"
#include "gc/shared/referenceProcessorPhaseTimes.hpp"
@ -248,12 +249,12 @@ DefNewGeneration::DefNewGeneration(ReservedSpace rs,
min_size, max_size, _virtual_space.committed_size());
_gc_counters = new CollectorCounters(policy, 0);
_eden_counters = new CSpaceCounters("eden", 0, _max_eden_size, _eden_space,
_gen_counters);
_from_counters = new CSpaceCounters("s0", 1, _max_survivor_size, _from_space,
_gen_counters);
_to_counters = new CSpaceCounters("s1", 2, _max_survivor_size, _to_space,
_gen_counters);
_eden_counters = new HSpaceCounters(_gen_counters->name_space(), "eden", 0,
_max_eden_size, _eden_space->capacity());
_from_counters = new HSpaceCounters(_gen_counters->name_space(), "s0", 1,
_max_survivor_size, _from_space->capacity());
_to_counters = new HSpaceCounters(_gen_counters->name_space(), "s1", 2,
_max_survivor_size, _to_space->capacity());
update_counters();
_old_gen = nullptr;
@ -319,7 +320,7 @@ void DefNewGeneration::swap_spaces() {
_to_space = s;
if (UsePerfData) {
CSpaceCounters* c = _from_counters;
HSpaceCounters* c = _from_counters;
_from_counters = _to_counters;
_to_counters = c;
}
@ -348,38 +349,6 @@ void DefNewGeneration::expand_eden_by(size_t delta_bytes) {
post_resize();
}
size_t DefNewGeneration::calculate_thread_increase_size(int threads_count) const {
size_t thread_increase_size = 0;
// Check an overflow at 'threads_count * NewSizeThreadIncrease'.
if (threads_count > 0 && NewSizeThreadIncrease <= max_uintx / threads_count) {
thread_increase_size = threads_count * NewSizeThreadIncrease;
}
return thread_increase_size;
}
size_t DefNewGeneration::adjust_for_thread_increase(size_t new_size_candidate,
size_t new_size_before,
size_t alignment,
size_t thread_increase_size) const {
size_t desired_new_size = new_size_before;
if (NewSizeThreadIncrease > 0 && thread_increase_size > 0) {
// 1. Check an overflow at 'new_size_candidate + thread_increase_size'.
if (new_size_candidate <= max_uintx - thread_increase_size) {
new_size_candidate += thread_increase_size;
// 2. Check an overflow at 'align_up'.
size_t aligned_max = ((max_uintx - alignment) & ~(alignment-1));
if (new_size_candidate <= aligned_max) {
desired_new_size = align_up(new_size_candidate, alignment);
}
}
}
return desired_new_size;
}
size_t DefNewGeneration::calculate_desired_young_gen_bytes() const {
size_t old_size = SerialHeap::heap()->old_gen()->capacity();
size_t new_size_before = _virtual_space.committed_size();
@ -391,14 +360,8 @@ size_t DefNewGeneration::calculate_desired_young_gen_bytes() const {
// All space sizes must be multiples of Generation::GenGrain.
size_t alignment = Generation::GenGrain;
int threads_count = Threads::number_of_non_daemon_threads();
size_t thread_increase_size = calculate_thread_increase_size(threads_count);
size_t new_size_candidate = old_size / NewRatio;
// Compute desired new generation size based on NewRatio and NewSizeThreadIncrease
// and reverts to previous value if any overflow happens
size_t desired_new_size = adjust_for_thread_increase(new_size_candidate, new_size_before,
alignment, thread_increase_size);
size_t desired_new_size = align_up(new_size_candidate, alignment);
// Adjust new generation size
desired_new_size = clamp(desired_new_size, min_new_size, max_new_size);
@ -821,9 +784,9 @@ void DefNewGeneration::gc_epilogue() {
void DefNewGeneration::update_counters() {
if (UsePerfData) {
_eden_counters->update_all();
_from_counters->update_all();
_to_counters->update_all();
_eden_counters->update_all(_eden_space->capacity(), _eden_space->used());
_from_counters->update_all(_from_space->capacity(), _from_space->used());
_to_counters->update_all(_to_space->capacity(), _to_space->used());
_gen_counters->update_capacity(_virtual_space.committed_size());
}
}

View File

@ -25,7 +25,6 @@
#ifndef SHARE_GC_SERIAL_DEFNEWGENERATION_HPP
#define SHARE_GC_SERIAL_DEFNEWGENERATION_HPP
#include "gc/serial/cSpaceCounters.hpp"
#include "gc/serial/generation.hpp"
#include "gc/serial/tenuredGeneration.hpp"
#include "gc/shared/ageTable.hpp"
@ -38,7 +37,7 @@
#include "utilities/stack.hpp"
class ContiguousSpace;
class CSpaceCounters;
class HSpaceCounters;
class OldGenScanClosure;
class YoungGenScanClosure;
class DefNewTracer;
@ -102,9 +101,9 @@ class DefNewGeneration: public Generation {
// Performance Counters
GenerationCounters* _gen_counters;
CSpaceCounters* _eden_counters;
CSpaceCounters* _from_counters;
CSpaceCounters* _to_counters;
HSpaceCounters* _eden_counters;
HSpaceCounters* _from_counters;
HSpaceCounters* _to_counters;
// sizing information
size_t _max_eden_size;
@ -230,15 +229,6 @@ class DefNewGeneration: public Generation {
// Initialize eden/from/to spaces.
void init_spaces();
// Return adjusted new size for NewSizeThreadIncrease.
// If any overflow happens, revert to previous new size.
size_t adjust_for_thread_increase(size_t new_size_candidate,
size_t new_size_before,
size_t alignment,
size_t thread_increase_size) const;
size_t calculate_thread_increase_size(int threads_count) const;
// Scavenge support
void swap_spaces();

View File

@ -32,6 +32,7 @@
#include "gc/shared/gcTimer.hpp"
#include "gc/shared/gcTrace.hpp"
#include "gc/shared/genArguments.hpp"
#include "gc/shared/hSpaceCounters.hpp"
#include "gc/shared/space.hpp"
#include "gc/shared/spaceDecorator.hpp"
#include "logging/log.hpp"
@ -330,9 +331,9 @@ TenuredGeneration::TenuredGeneration(ReservedSpace rs,
_gc_counters = new CollectorCounters("Serial full collection pauses", 1);
_space_counters = new CSpaceCounters(gen_name, 0,
_space_counters = new HSpaceCounters(_gen_counters->name_space(), gen_name, 0,
_virtual_space.reserved_size(),
_the_space, _gen_counters);
_the_space->capacity());
}
void TenuredGeneration::gc_prologue() {
@ -367,7 +368,7 @@ void TenuredGeneration::update_promote_stats() {
void TenuredGeneration::update_counters() {
if (UsePerfData) {
_space_counters->update_all();
_space_counters->update_all(_the_space->capacity(), _the_space->used());
_gen_counters->update_capacity(_virtual_space.committed_size());
}
}

View File

@ -25,7 +25,6 @@
#ifndef SHARE_GC_SERIAL_TENUREDGENERATION_HPP
#define SHARE_GC_SERIAL_TENUREDGENERATION_HPP
#include "gc/serial/cSpaceCounters.hpp"
#include "gc/serial/generation.hpp"
#include "gc/serial/serialBlockOffsetTable.hpp"
#include "gc/shared/generationCounters.hpp"
@ -34,6 +33,7 @@
class CardTableRS;
class ContiguousSpace;
class HSpaceCounters;
// TenuredGeneration models the heap containing old (promoted/tenured) objects
// contained in a single contiguous space. This generation is covered by a card
@ -68,7 +68,7 @@ class TenuredGeneration: public Generation {
ContiguousSpace* _the_space; // Actual space holding objects
GenerationCounters* _gen_counters;
CSpaceCounters* _space_counters;
HSpaceCounters* _space_counters;
// Avg amount promoted; used for avoiding promotion undo
// This class does not update deviations if the sample is zero.

View File

@ -289,7 +289,7 @@ protected:
DEBUG_ONLY(bool is_in_or_null(const void* p) const { return p == nullptr || is_in(p); })
void set_gc_cause(GCCause::Cause v);
GCCause::Cause gc_cause() { return _gc_cause; }
GCCause::Cause gc_cause() const { return _gc_cause; }
oop obj_allocate(Klass* klass, size_t size, TRAPS);
virtual oop array_allocate(Klass* klass, size_t size, int length, bool do_zero, TRAPS);

View File

@ -480,11 +480,6 @@
"Ratio of old/new generation sizes") \
range(0, max_uintx-1) \
\
product_pd(size_t, NewSizeThreadIncrease, \
"Additional size added to desired new generation size per " \
"non-daemon thread (in bytes)") \
range(0, max_uintx) \
\
product(uintx, QueuedAllocationWarningCount, 0, \
"Number of times an allocation that queues behind a GC " \
"will retry before printing a warning") \

View File

@ -137,7 +137,7 @@ void ShenandoahCollectionSet::clear() {
_live = 0;
_region_count = 0;
_current_index = 0;
_current_index.store_relaxed(0);
_young_bytes_to_evacuate = 0;
_young_bytes_to_promote = 0;
@ -155,11 +155,11 @@ ShenandoahHeapRegion* ShenandoahCollectionSet::claim_next() {
// before hitting the (potentially contended) atomic index.
size_t max = _heap->num_regions();
size_t old = AtomicAccess::load(&_current_index);
size_t old = _current_index.load_relaxed();
for (size_t index = old; index < max; index++) {
if (is_in(index)) {
size_t cur = AtomicAccess::cmpxchg(&_current_index, old, index + 1, memory_order_relaxed);
size_t cur = _current_index.compare_exchange(old, index + 1, memory_order_relaxed);
assert(cur >= old, "Always move forward");
if (cur == old) {
// Successfully moved the claim index, this is our region.
@ -179,9 +179,9 @@ ShenandoahHeapRegion* ShenandoahCollectionSet::next() {
assert(Thread::current()->is_VM_thread(), "Must be VMThread");
size_t max = _heap->num_regions();
for (size_t index = _current_index; index < max; index++) {
for (size_t index = _current_index.load_relaxed(); index < max; index++) {
if (is_in(index)) {
_current_index = index + 1;
_current_index.store_relaxed(index + 1);
return _heap->get_region(index);
}
}

View File

@ -32,6 +32,7 @@
#include "memory/allocation.hpp"
#include "memory/reservedSpace.hpp"
#include "memory/virtualspace.hpp"
#include "runtime/atomic.hpp"
class ShenandoahCollectionSet : public CHeapObj<mtGC> {
friend class ShenandoahHeap;
@ -80,7 +81,7 @@ private:
size_t _old_available_bytes_collected;
shenandoah_padding(0);
volatile size_t _current_index;
Atomic<size_t> _current_index;
shenandoah_padding(1);
public:
@ -99,7 +100,7 @@ public:
bool is_empty() const { return _region_count == 0; }
void clear_current_index() {
_current_index = 0;
_current_index.store_relaxed(0);
}
inline bool is_in(ShenandoahHeapRegion* r) const;

View File

@ -31,11 +31,11 @@
void ShenandoahController::update_gc_id() {
AtomicAccess::inc(&_gc_id);
_gc_id.add_then_fetch((size_t)1);
}
size_t ShenandoahController::get_gc_id() {
return AtomicAccess::load(&_gc_id);
return _gc_id.load_relaxed();
}
void ShenandoahController::handle_alloc_failure(const ShenandoahAllocRequest& req, bool block) {

View File

@ -29,6 +29,7 @@
#include "gc/shared/gcCause.hpp"
#include "gc/shenandoah/shenandoahAllocRequest.hpp"
#include "gc/shenandoah/shenandoahSharedVariables.hpp"
#include "runtime/atomic.hpp"
/**
* This interface exposes methods necessary for the heap to interact
@ -38,7 +39,7 @@ class ShenandoahController: public ConcurrentGCThread {
private:
shenandoah_padding(0);
// A monotonically increasing GC count.
volatile size_t _gc_id;
Atomic<size_t> _gc_id;
shenandoah_padding(1);
protected:

View File

@ -32,7 +32,6 @@
#include "gc/shenandoah/shenandoahHeapRegionSet.hpp"
#include "logging/logStream.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/atomicAccess.hpp"
#include "runtime/perfData.inline.hpp"
#include "utilities/defaultStream.hpp"
@ -106,8 +105,8 @@ void ShenandoahHeapRegionCounters::write_snapshot(PerfLongVariable** regions,
void ShenandoahHeapRegionCounters::update() {
if (ShenandoahRegionSampling) {
jlong current = nanos_to_millis(os::javaTimeNanos());
jlong last = _last_sample_millis;
if (current - last > ShenandoahRegionSamplingRate && AtomicAccess::cmpxchg(&_last_sample_millis, last, current) == last) {
jlong last = _last_sample_millis.load_relaxed();
if (current - last > ShenandoahRegionSamplingRate && _last_sample_millis.compare_exchange(last, current) == last) {
ShenandoahHeap* heap = ShenandoahHeap::heap();
_status->set_value(encode_heap_status(heap));

View File

@ -28,6 +28,7 @@
#include "logging/logFileStreamOutput.hpp"
#include "memory/allocation.hpp"
#include "runtime/atomic.hpp"
/**
* This provides the following in JVMStat:
@ -88,7 +89,7 @@ private:
PerfLongVariable** _regions_data;
PerfLongVariable* _timestamp;
PerfLongVariable* _status;
volatile jlong _last_sample_millis;
Atomic<jlong> _last_sample_millis;
void write_snapshot(PerfLongVariable** regions,
PerfLongVariable* ts,

View File

@ -198,11 +198,11 @@ void BinaryMagnitudeSeq::clear() {
for (int c = 0; c < BitsPerSize_t; c++) {
_mags[c] = 0;
}
_sum = 0;
_sum.store_relaxed(0);
}
void BinaryMagnitudeSeq::add(size_t val) {
AtomicAccess::add(&_sum, val);
_sum.add_then_fetch(val);
int mag = log2i_graceful(val) + 1;
@ -237,7 +237,7 @@ size_t BinaryMagnitudeSeq::num() const {
}
size_t BinaryMagnitudeSeq::sum() const {
return _sum;
return _sum.load_relaxed();
}
int BinaryMagnitudeSeq::min_level() const {

View File

@ -25,6 +25,7 @@
#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHNUMBERSEQ_HPP
#define SHARE_GC_SHENANDOAH_SHENANDOAHNUMBERSEQ_HPP
#include "runtime/atomic.hpp"
#include "utilities/numberSeq.hpp"
// HDR sequence stores the low-resolution high-dynamic-range values.
@ -59,7 +60,7 @@ public:
// is not needed, it is preferred over HdrSeq.
class BinaryMagnitudeSeq : public CHeapObj<mtGC> {
private:
size_t _sum;
Atomic<size_t> _sum;
size_t* _mags;
public:

View File

@ -45,7 +45,7 @@ ShenandoahJavaThreadsIterator::ShenandoahJavaThreadsIterator(ShenandoahPhaseTimi
}
uint ShenandoahJavaThreadsIterator::claim() {
return AtomicAccess::fetch_then_add(&_claimed, _stride, memory_order_relaxed);
return _claimed.fetch_then_add(_stride, memory_order_relaxed);
}
void ShenandoahJavaThreadsIterator::threads_do(ThreadClosure* cl, uint worker_id) {

View File

@ -33,6 +33,7 @@
#include "gc/shenandoah/shenandoahSharedVariables.hpp"
#include "gc/shenandoah/shenandoahUtils.hpp"
#include "memory/iterator.hpp"
#include "runtime/atomic.hpp"
#include "runtime/threads.hpp"
template <bool CONCURRENT>
@ -73,7 +74,7 @@ private:
ThreadsListHandle _threads;
uint const _length;
uint const _stride;
volatile uint _claimed;
Atomic<uint> _claimed;
ShenandoahPhaseTimings::Phase _phase;
uint claim();

View File

@ -1024,7 +1024,7 @@ ShenandoahRegionChunkIterator::ShenandoahRegionChunkIterator(ShenandoahHeap* hea
}
void ShenandoahRegionChunkIterator::reset() {
_index = 0;
_index.store_relaxed(0);
}
ShenandoahReconstructRememberedSetTask::ShenandoahReconstructRememberedSetTask(ShenandoahRegionIterator* regions)

View File

@ -973,7 +973,7 @@ private:
const size_t _total_chunks;
shenandoah_padding(0);
volatile size_t _index;
Atomic<size_t> _index;
shenandoah_padding(1);
size_t _region_index[_maximum_groups]; // The region index for the first region spanned by this group

View File

@ -380,14 +380,14 @@ ShenandoahScanRemembered::process_region_slice(ShenandoahHeapRegion *region, siz
}
inline bool ShenandoahRegionChunkIterator::has_next() const {
return _index < _total_chunks;
return _index.load_relaxed() < _total_chunks;
}
inline bool ShenandoahRegionChunkIterator::next(struct ShenandoahRegionChunk *assignment) {
if (_index >= _total_chunks) {
if (_index.load_relaxed() >= _total_chunks) {
return false;
}
size_t new_index = AtomicAccess::add(&_index, (size_t) 1, memory_order_relaxed);
size_t new_index = _index.add_then_fetch((size_t) 1, memory_order_relaxed);
if (new_index > _total_chunks) {
// First worker that hits new_index == _total_chunks continues, other
// contending workers return false.

View File

@ -30,6 +30,7 @@
#include "gc/shared/taskTerminator.hpp"
#include "gc/shenandoah/shenandoahPadding.hpp"
#include "nmt/memTag.hpp"
#include "runtime/atomic.hpp"
#include "runtime/atomicAccess.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/mutex.hpp"
@ -306,7 +307,7 @@ template <class T, MemTag MT>
class ParallelClaimableQueueSet: public GenericTaskQueueSet<T, MT> {
private:
shenandoah_padding(0);
volatile jint _claimed_index;
Atomic<jint> _claimed_index;
shenandoah_padding(1);
DEBUG_ONLY(uint _reserved; )
@ -325,7 +326,7 @@ public:
// reserve queues that not for parallel claiming
void reserve(uint n) {
assert(n <= size(), "Sanity");
_claimed_index = (jint)n;
_claimed_index.store_relaxed((jint)n);
DEBUG_ONLY(_reserved = n;)
}
@ -336,11 +337,11 @@ template <class T, MemTag MT>
T* ParallelClaimableQueueSet<T, MT>::claim_next() {
jint size = (jint)GenericTaskQueueSet<T, MT>::size();
if (_claimed_index >= size) {
if (_claimed_index.load_relaxed() >= size) {
return nullptr;
}
jint index = AtomicAccess::add(&_claimed_index, 1, memory_order_relaxed);
jint index = _claimed_index.add_then_fetch(1, memory_order_relaxed);
if (index <= size) {
return GenericTaskQueueSet<T, MT>::queue((uint)index - 1);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -74,7 +74,7 @@ public:
static ContainerType encode(ValueType value) {
assert(((ContainerType)value & (FieldMask << ValueShift)) == (ContainerType)value, "Invalid value");
return ((ContainerType)value >> ValueShift) << FieldShift;
return checked_cast<ContainerType>(((ContainerType)value >> ValueShift) << FieldShift);
}
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -78,14 +78,10 @@ class OopMapForCacheEntry: public GenerateOopMap {
int _stack_top;
virtual bool report_results() const { return false; }
virtual bool possible_gc_point (BytecodeStream *bcs);
virtual void fill_stackmap_prolog (int nof_gc_points);
virtual void fill_stackmap_epilog ();
virtual void fill_stackmap_for_opcodes (BytecodeStream *bcs,
CellTypeState* vars,
CellTypeState* stack,
int stack_top);
virtual void fill_init_vars (GrowableArray<intptr_t> *init_vars);
public:
OopMapForCacheEntry(const methodHandle& method, int bci, OopMapCacheEntry *entry);
@ -120,26 +116,6 @@ bool OopMapForCacheEntry::compute_map(Thread* current) {
}
bool OopMapForCacheEntry::possible_gc_point(BytecodeStream *bcs) {
return false; // We are not reporting any result. We call result_for_basicblock directly
}
void OopMapForCacheEntry::fill_stackmap_prolog(int nof_gc_points) {
// Do nothing
}
void OopMapForCacheEntry::fill_stackmap_epilog() {
// Do nothing
}
void OopMapForCacheEntry::fill_init_vars(GrowableArray<intptr_t> *init_vars) {
// Do nothing
}
void OopMapForCacheEntry::fill_stackmap_for_opcodes(BytecodeStream *bcs,
CellTypeState* vars,
CellTypeState* stack,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,8 +26,10 @@
#include "jfr/leakprofiler/chains/edgeUtils.hpp"
#include "jfr/leakprofiler/sampling/objectSample.hpp"
#include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp"
#include "jfr/recorder/service/jfrOptionSet.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/safepoint.hpp"
#include "utilities/resizableHashTable.hpp"
StoredEdge::StoredEdge(const Edge* parent, UnifiedOopRef reference) : Edge(parent, reference), _gc_root_id(0), _skip_length(0) {}
@ -216,84 +218,62 @@ bool EdgeStore::put_edges(StoredEdge** previous, const Edge** current, size_t li
return nullptr == *current;
}
static GrowableArray<const StoredEdge*>* _leak_context_edges = nullptr;
typedef ResizeableHashTable<uintptr_t, const StoredEdge*, AnyObj::C_HEAP, mtTracing> SampleToLeakContextEdgeMap;
static SampleToLeakContextEdgeMap* _sample_to_leak_context_edge_map = nullptr;
EdgeStore::EdgeStore() : _edges(new EdgeHashTable(this)) {}
EdgeStore::~EdgeStore() {
assert(_edges != nullptr, "invariant");
delete _edges;
delete _leak_context_edges;
_leak_context_edges = nullptr;
delete _sample_to_leak_context_edge_map;
_sample_to_leak_context_edge_map = nullptr;
}
static int leak_context_edge_idx(const ObjectSample* sample) {
static const StoredEdge* leak_context_edge(const ObjectSample* sample) {
assert(sample != nullptr, "invariant");
return static_cast<int>(sample->object()->mark().value()) >> markWord::lock_bits;
assert(_sample_to_leak_context_edge_map != nullptr, "invariant");
const StoredEdge** edge = _sample_to_leak_context_edge_map->get(p2u(sample->object()));
return edge != nullptr ? *edge : nullptr;
}
bool EdgeStore::has_leak_context(const ObjectSample* sample) const {
const int idx = leak_context_edge_idx(sample);
if (idx == 0) {
return false;
}
assert(idx > 0, "invariant");
assert(_leak_context_edges != nullptr, "invariant");
assert(idx < _leak_context_edges->length(), "invariant");
assert(_leak_context_edges->at(idx) != nullptr, "invariant");
return true;
return _sample_to_leak_context_edge_map != nullptr && leak_context_edge(sample) != nullptr;
}
const StoredEdge* EdgeStore::get(const ObjectSample* sample) const {
assert(sample != nullptr, "invariant");
if (_leak_context_edges != nullptr) {
if (_sample_to_leak_context_edge_map != nullptr) {
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
const int idx = leak_context_edge_idx(sample);
if (idx > 0) {
assert(idx < _leak_context_edges->length(), "invariant");
const StoredEdge* const edge =_leak_context_edges->at(idx);
assert(edge != nullptr, "invariant");
const StoredEdge* const edge = leak_context_edge(sample);
if (edge != nullptr) {
return edge;
}
}
return get(UnifiedOopRef::encode_in_native(sample->object_addr()));
}
#ifdef ASSERT
// max_idx to ensure idx fit in lower 32-bits of markword together with lock bits.
static constexpr const int max_idx = right_n_bits(32 - markWord::lock_bits);
static constexpr const unsigned max_map_size = max_jint >> 1;
static void store_idx_precondition(oop sample_object, int idx) {
assert(sample_object != nullptr, "invariant");
assert(sample_object->mark().is_marked(), "invariant");
assert(idx > 0, "invariant");
assert(idx <= max_idx, "invariant");
}
#endif
static void store_idx_in_markword(oop sample_object, int idx) {
DEBUG_ONLY(store_idx_precondition(sample_object, idx);)
const markWord idx_mark_word(sample_object->mark().value() | idx << markWord::lock_bits);
sample_object->set_mark(idx_mark_word);
assert(sample_object->mark().is_marked(), "must still be marked");
}
static const int initial_size = 64;
static int save(const StoredEdge* edge) {
assert(edge != nullptr, "invariant");
if (_leak_context_edges == nullptr) {
_leak_context_edges = new (mtTracing) GrowableArray<const StoredEdge*>(initial_size, mtTracing);
_leak_context_edges->append(nullptr); // next idx now at 1, for disambiguation in markword.
static inline unsigned map_size() {
assert(JfrOptionSet::old_object_queue_size() > 0, "invariant");
unsigned size = JfrOptionSet::old_object_queue_size();
size = round_up_power_of_2(size);
if (size < 1024) {
return 1024;
}
return _leak_context_edges->append(edge);
size <<= 1;
return size >= max_map_size ? max_map_size : size;
}
// We associate the leak context edge with the leak candidate object by saving the
// edge in an array and storing the array idx (shifted) into the markword of the candidate object.
static void associate_with_candidate(const StoredEdge* leak_context_edge) {
assert(leak_context_edge != nullptr, "invariant");
store_idx_in_markword(leak_context_edge->pointee(), save(leak_context_edge));
if (_sample_to_leak_context_edge_map == nullptr) {
const unsigned size = map_size();
_sample_to_leak_context_edge_map = new (mtTracing) SampleToLeakContextEdgeMap(size, size);
}
assert(_sample_to_leak_context_edge_map != nullptr, "invariant");
_sample_to_leak_context_edge_map->put(p2u(leak_context_edge->pointee()), leak_context_edge);
}
StoredEdge* EdgeStore::associate_leak_context_with_candidate(const Edge* edge) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -39,7 +39,6 @@ class StoredEdge : public Edge {
size_t _skip_length;
public:
StoredEdge();
StoredEdge(const Edge* parent, UnifiedOopRef reference);
StoredEdge(const Edge& edge);
StoredEdge(const StoredEdge& edge);

View File

@ -41,7 +41,7 @@
#include "oops/oop.inline.hpp"
#include "runtime/handles.inline.hpp"
ArrayKlass::ArrayKlass() {
ArrayKlass::ArrayKlass() : _dimension() {
assert(CDSConfig::is_dumping_static_archive() || CDSConfig::is_using_archive(), "only for CDS");
}
@ -88,9 +88,9 @@ Method* ArrayKlass::uncached_lookup_method(const Symbol* name,
return super()->uncached_lookup_method(name, signature, OverpassLookupMode::skip, private_mode);
}
ArrayKlass::ArrayKlass(Symbol* name, KlassKind kind) :
ArrayKlass::ArrayKlass(int n, Symbol* name, KlassKind kind) :
Klass(kind),
_dimension(1),
_dimension(n),
_higher_dimension(nullptr),
_lower_dimension(nullptr) {
// Arrays don't add any new methods, so their vtable is the same size as

View File

@ -38,7 +38,7 @@ class ArrayKlass: public Klass {
private:
// If you add a new field that points to any metaspace object, you
// must add this field to ArrayKlass::metaspace_pointers_do().
int _dimension; // This is n'th-dimensional array.
const int _dimension; // This is n'th-dimensional array.
ObjArrayKlass* volatile _higher_dimension; // Refers the (n+1)'th-dimensional array (if present).
ArrayKlass* volatile _lower_dimension; // Refers the (n-1)'th-dimensional array (if present).
@ -46,7 +46,7 @@ class ArrayKlass: public Klass {
// Constructors
// The constructor with the Symbol argument does the real array
// initialization, the other is a dummy
ArrayKlass(Symbol* name, KlassKind kind);
ArrayKlass(int n, Symbol* name, KlassKind kind);
ArrayKlass();
public:
@ -63,7 +63,6 @@ class ArrayKlass: public Klass {
// Instance variables
int dimension() const { return _dimension; }
void set_dimension(int dimension) { _dimension = dimension; }
ObjArrayKlass* higher_dimension() const { return _higher_dimension; }
inline ObjArrayKlass* higher_dimension_acquire() const; // load with acquire semantics

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -391,7 +391,6 @@ void CellTypeState::print(outputStream *os) {
//
void GenerateOopMap::initialize_bb() {
_gc_points = 0;
_bb_count = 0;
_bb_hdr_bits.reinitialize(method()->code_size());
}
@ -409,7 +408,7 @@ void GenerateOopMap::bb_mark_fct(GenerateOopMap *c, int bci, int *data) {
}
void GenerateOopMap::mark_bbheaders_and_count_gc_points() {
void GenerateOopMap::mark_bbheaders() {
initialize_bb();
bool fellThrough = false; // False to get first BB marked.
@ -445,9 +444,6 @@ void GenerateOopMap::mark_bbheaders_and_count_gc_points() {
default:
break;
}
if (possible_gc_point(&bcs))
_gc_points++;
}
}
@ -2119,8 +2115,6 @@ bool GenerateOopMap::compute_map(Thread* current) {
// if no code - do nothing
// compiler needs info
if (method()->code_size() == 0 || _max_locals + method()->max_stack() == 0) {
fill_stackmap_prolog(0);
fill_stackmap_epilog();
return true;
}
// Step 1: Compute all jump targets and their return value
@ -2129,7 +2123,7 @@ bool GenerateOopMap::compute_map(Thread* current) {
// Step 2: Find all basic blocks and count GC points
if (!_got_error)
mark_bbheaders_and_count_gc_points();
mark_bbheaders();
// Step 3: Calculate stack maps
if (!_got_error)
@ -2186,9 +2180,6 @@ void GenerateOopMap::report_result() {
// We now want to report the result of the parse
_report_result = true;
// Prolog code
fill_stackmap_prolog(_gc_points);
// Mark everything changed, then do one interpretation pass.
for (int i = 0; i<_bb_count; i++) {
if (_basic_blocks[i].is_reachable()) {
@ -2197,14 +2188,6 @@ void GenerateOopMap::report_result() {
}
}
// Note: Since we are skipping dead-code when we are reporting results, then
// the no. of encountered gc-points might be fewer than the previously number
// we have counted. (dead-code is a pain - it should be removed before we get here)
fill_stackmap_epilog();
// Report initvars
fill_init_vars(_init_vars);
_report_result = false;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -348,17 +348,15 @@ class GenerateOopMap {
// Basicblock info
BasicBlock * _basic_blocks; // Array of basicblock info
int _gc_points;
int _bb_count;
ResourceBitMap _bb_hdr_bits;
// Basicblocks methods
void initialize_bb ();
void mark_bbheaders_and_count_gc_points();
void mark_bbheaders();
bool is_bb_header (int bci) const {
return _bb_hdr_bits.at(bci);
}
int gc_points () const { return _gc_points; }
int bb_count () const { return _bb_count; }
void set_bbmark_bit (int bci);
BasicBlock * get_basic_block_at (int bci) const;
@ -450,7 +448,7 @@ class GenerateOopMap {
int binsToHold (int no) { return ((no+(BitsPerWord-1))/BitsPerWord); }
char *state_vec_to_string (CellTypeState* vec, int len);
// Helper method. Can be used in subclasses to fx. calculate gc_points. If the current instruction
// Helper method. If the current instruction
// is a control transfer, then calls the jmpFct all possible destinations.
void ret_jump_targets_do (BytecodeStream *bcs, jmpFct_t jmpFct, int varNo,int *data);
bool jump_targets_do (BytecodeStream *bcs, jmpFct_t jmpFct, int *data);
@ -480,14 +478,7 @@ class GenerateOopMap {
bool monitor_safe() { return _monitor_safe; }
// Specialization methods. Intended use:
// - possible_gc_point must return true for every bci for which the stackmaps must be returned
// - fill_stackmap_prolog is called just before the result is reported. The arguments tells the estimated
// number of gc points
// - fill_stackmap_for_opcodes is called once for each bytecode index in order (0...code_length-1)
// - fill_stackmap_epilog is called after all results has been reported. Note: Since the algorithm does not report
// stackmaps for deadcode, fewer gc_points might have been encountered than assumed during the epilog. It is the
// responsibility of the subclass to count the correct number.
// - fill_init_vars are called once with the result of the init_vars computation
//
// All these methods are used during a call to: compute_map. Note: Non of the return results are valid
// after compute_map returns, since all values are allocated as resource objects.
@ -496,14 +487,10 @@ class GenerateOopMap {
virtual bool allow_rewrites () const { return false; }
virtual bool report_results () const { return true; }
virtual bool report_init_vars () const { return true; }
virtual bool possible_gc_point (BytecodeStream *bcs) { ShouldNotReachHere(); return false; }
virtual void fill_stackmap_prolog (int nof_gc_points) { ShouldNotReachHere(); }
virtual void fill_stackmap_epilog () { ShouldNotReachHere(); }
virtual void fill_stackmap_for_opcodes (BytecodeStream *bcs,
CellTypeState* vars,
CellTypeState* stack,
int stackTop) { ShouldNotReachHere(); }
virtual void fill_init_vars (GrowableArray<intptr_t> *init_vars) { ShouldNotReachHere();; }
};
//
@ -513,19 +500,13 @@ class GenerateOopMap {
class ResolveOopMapConflicts: public GenerateOopMap {
private:
bool _must_clear_locals;
virtual bool report_results() const { return false; }
virtual bool report_init_vars() const { return true; }
virtual bool allow_rewrites() const { return true; }
virtual bool possible_gc_point (BytecodeStream *bcs) { return false; }
virtual void fill_stackmap_prolog (int nof_gc_points) {}
virtual void fill_stackmap_epilog () {}
virtual void fill_stackmap_for_opcodes (BytecodeStream *bcs,
CellTypeState* vars,
CellTypeState* stack,
int stack_top) {}
virtual void fill_init_vars (GrowableArray<intptr_t> *init_vars) { _must_clear_locals = init_vars->length() > 0; }
#ifndef PRODUCT
// Statistics
@ -535,10 +516,8 @@ class ResolveOopMapConflicts: public GenerateOopMap {
#endif
public:
ResolveOopMapConflicts(const methodHandle& method) : GenerateOopMap(method) { _must_clear_locals = false; };
ResolveOopMapConflicts(const methodHandle& method) : GenerateOopMap(method) { }
methodHandle do_potential_rewrite(TRAPS);
bool must_clear_locals() const { return _must_clear_locals; }
};
@ -551,14 +530,10 @@ class GeneratePairingInfo: public GenerateOopMap {
virtual bool report_results() const { return false; }
virtual bool report_init_vars() const { return false; }
virtual bool allow_rewrites() const { return false; }
virtual bool possible_gc_point (BytecodeStream *bcs) { return false; }
virtual void fill_stackmap_prolog (int nof_gc_points) {}
virtual void fill_stackmap_epilog () {}
virtual void fill_stackmap_for_opcodes (BytecodeStream *bcs,
CellTypeState* vars,
CellTypeState* stack,
int stack_top) {}
virtual void fill_init_vars (GrowableArray<intptr_t> *init_vars) {}
public:
GeneratePairingInfo(const methodHandle& method) : GenerateOopMap(method) {};

View File

@ -120,8 +120,7 @@ ObjArrayKlass* ObjArrayKlass::allocate_objArray_klass(ClassLoaderData* loader_da
return oak;
}
ObjArrayKlass::ObjArrayKlass(int n, Klass* element_klass, Symbol* name) : ArrayKlass(name, Kind) {
set_dimension(n);
ObjArrayKlass::ObjArrayKlass(int n, Klass* element_klass, Symbol* name) : ArrayKlass(n, name, Kind) {
set_element_klass(element_klass);
Klass* bk;

View File

@ -78,7 +78,7 @@ u2 TypeArrayKlass::compute_modifier_flags() const {
return JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC;
}
TypeArrayKlass::TypeArrayKlass(BasicType type, Symbol* name) : ArrayKlass(name, Kind) {
TypeArrayKlass::TypeArrayKlass(BasicType type, Symbol* name) : ArrayKlass(1, name, Kind) {
set_layout_helper(array_layout_helper(type));
assert(is_array_klass(), "sanity");
assert(is_typeArray_klass(), "sanity");

View File

@ -2675,6 +2675,10 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) {
for( uint i=1; i<req(); ++i ) {// For all paths in
Node *ii = in(i);
Node *new_in = MemNode::optimize_memory_chain(ii, at, nullptr, phase);
// MemNode::optimize_memory_chain above may kill us!
if (outcnt() == 0) {
return top;
}
if (ii != new_in ) {
set_req_X(i, new_in, phase);
progress = this;

View File

@ -40,16 +40,60 @@ class PrintProperties
{
private:
IdealGraphPrinter* _printer;
void print_alias_properties(Node* node);
void print_escape_properties(Node* node);
public:
PrintProperties(IdealGraphPrinter* printer) : _printer(printer) {}
void print_node_properties(Node* node);
void print_node_details(Node* node);
void print_lrg_properties(const LRG& lrg, const char* buffer);
void print_property(int flag, const char* name);
void print_property(int flag, const char* name, const char* val);
void print_property(int flag, const char* name, int val);
};
void PrintProperties::print_alias_properties(Node* node) {
const TypePtr* adr_type = node->adr_type();
Compile* C = _printer->C;
if (adr_type != nullptr && C->have_alias_type(adr_type)) {
Compile::AliasType* at = C->alias_type(adr_type);
if (at != nullptr) {
print_property(true, "alias_index", at->index());
// The value of at->field(), if present, is already dumped in the
// "source"/"destination" properties.
const Type* element = at->element();
if (element != nullptr) {
stringStream element_stream;
element->dump_on(&element_stream);
print_property(true, "alias_element", element_stream.freeze());
}
print_property(at->is_rewritable(), "alias_is_rewritable");
print_property(at->is_volatile(), "alias_is_volatile");
print_property(at->general_index() != at->index(), "alias_general_index", at->general_index());
}
}
}
void PrintProperties::print_escape_properties(Node* node) {
// Dump escape analysis state for relevant nodes.
if (node->is_Allocate()) {
AllocateNode* alloc = node->as_Allocate();
print_property(alloc->_is_scalar_replaceable, "is_scalar_replaceable");
print_property(alloc->_is_non_escaping, "is_non_escaping");
print_property(alloc->does_not_escape_thread(), "does_not_escape_thread");
}
if (node->is_SafePoint() && node->as_SafePoint()->has_ea_local_in_scope()) {
print_property(true, "has_ea_local_in_scope");
}
if (node->is_CallJava() && node->as_CallJava()->arg_escape()) {
print_property(true, "arg_escape");
}
if (node->is_Initialize() && node->as_Initialize()->does_not_escape()) {
print_property(true, "does_not_escape");
}
}
void PrintProperties::print_node_properties(Node* node) {
const jushort flags = node->flags();
print_property((flags & Node::Flag_is_Copy), "is_copy");
@ -75,6 +119,15 @@ void PrintProperties::print_node_properties(Node* node) {
}
}
void PrintProperties::print_node_details(Node* node) {
print_alias_properties(node);
print_escape_properties(node);
print_property(node->is_block_proj() != nullptr, "is_block_proj");
print_property(node->is_block_start(), "is_block_start");
}
void PrintProperties::print_lrg_properties(const LRG &lrg, const char *buffer) {
print_property(true, "mask", buffer);
print_property(true, "mask_size", lrg.mask_size());
@ -651,61 +704,7 @@ void IdealGraphPrinter::visit_node(Node* n, bool edges) {
assert(s2.size() < sizeof(buffer), "size in range");
print_prop("dump_spec", buffer);
const TypePtr* adr_type = node->adr_type();
if (adr_type != nullptr && C->have_alias_type(adr_type)) {
Compile::AliasType* at = C->alias_type(adr_type);
if (at != nullptr) {
print_prop("alias_index", at->index());
// The value of at->field(), if present, is already dumped in the
// "source"/"destination" properties.
const Type* element = at->element();
if (element != nullptr) {
stringStream element_stream;
element->dump_on(&element_stream);
print_prop("alias_element", element_stream.freeze());
}
if (at->is_rewritable()) {
print_prop("alias_is_rewritable", "true");
}
if (at->is_volatile()) {
print_prop("alias_is_volatile", "true");
}
if (at->general_index() != at->index()) {
print_prop("alias_general_index", at->general_index());
}
}
}
if (node->is_block_proj()) {
print_prop("is_block_proj", "true");
}
if (node->is_block_start()) {
print_prop("is_block_start", "true");
}
// Dump escape analysis state for relevant nodes.
if (node->is_Allocate()) {
AllocateNode* alloc = node->as_Allocate();
if (alloc->_is_scalar_replaceable) {
print_prop("is_scalar_replaceable", "true");
}
if (alloc->_is_non_escaping) {
print_prop("is_non_escaping", "true");
}
if (alloc->does_not_escape_thread()) {
print_prop("does_not_escape_thread", "true");
}
}
if (node->is_SafePoint() && node->as_SafePoint()->has_ea_local_in_scope()) {
print_prop("has_ea_local_in_scope", "true");
}
if (node->is_CallJava() && node->as_CallJava()->arg_escape()) {
print_prop("arg_escape", "true");
}
if (node->is_Initialize() && node->as_Initialize()->does_not_escape()) {
print_prop("does_not_escape", "true");
}
print_node.print_node_details(node);
const char *short_name = "short_name";
if (strcmp(node->Name(), "Parm") == 0 && node->as_Proj()->_con >= TypeFunc::Parms) {

View File

@ -221,12 +221,12 @@ public:
// Convert a machine register to a machine register type, so-as to
// properly match spill code.
const int *_register_save_type;
#ifdef ASSERT
// Maps from machine register to boolean; true if machine register can
// be holding a call argument in some signature.
static bool can_be_java_arg( int reg );
// Maps from machine register to boolean; true if machine register holds
// a spillable argument.
static bool is_spillable_arg( int reg );
#endif
// Number of integer live ranges that constitute high register pressure
static uint int_pressure_limit();
// Number of float live ranges that constitute high register pressure
@ -443,9 +443,6 @@ public:
// The Method-klass-holder may be passed in the inline_cache_reg
// and then expanded into the inline_cache_reg and a method_ptr register
// Interpreter's Frame Pointer Register
static OptoReg::Name interpreter_frame_pointer_reg();
// Java-Native calling convention
// (what you use when intercalling between Java and C++ code)

View File

@ -582,7 +582,6 @@ bool MemNode::detect_ptr_independence(Node* p1, AllocateNode* a1,
return false;
}
// Find an arraycopy ac that produces the memory state represented by parameter mem.
// Return ac if
// (a) can_see_stored_value=true and ac must have set the value for this load or if
@ -697,178 +696,32 @@ ArrayCopyNode* MemNode::find_array_copy_clone(Node* ld_alloc, Node* mem) const {
// (Currently, only LoadNode::Ideal has steps (c), (d). More later.)
//
Node* MemNode::find_previous_store(PhaseValues* phase) {
Node* ctrl = in(MemNode::Control);
Node* adr = in(MemNode::Address);
intptr_t offset = 0;
Node* base = AddPNode::Ideal_base_and_offset(adr, phase, offset);
AllocateNode* alloc = AllocateNode::Ideal_allocation(base);
AccessAnalyzer analyzer(phase, this);
const TypePtr* adr_type = this->adr_type();
if (adr_type == nullptr) {
// This means the access is dead
return phase->C->top();
} else if (adr_type->base() == TypePtr::AnyPtr) {
assert(adr_type->ptr() == TypePtr::Null, "MemNode should never access a wide memory");
// Give up, this will upset Compile::get_alias_index
return nullptr;
}
int alias_idx = phase->C->get_alias_index(adr_type);
assert(alias_idx != Compile::AliasIdxTop, "must not be a dead node");
assert(alias_idx != Compile::AliasIdxBot || !phase->C->do_aliasing(), "must not be a very wide access");
if (offset == Type::OffsetBot)
return nullptr; // cannot unalias unless there are precise offsets
const bool adr_maybe_raw = check_if_adr_maybe_raw(adr);
const TypeOopPtr *addr_t = adr->bottom_type()->isa_oopptr();
intptr_t size_in_bytes = memory_size();
Node* mem = in(MemNode::Memory); // start searching here...
int cnt = 50; // Cycle limiter
for (;;) { // While we can dance past unrelated stores...
if (--cnt < 0) break; // Caught in cycle or a complicated dance?
Node* prev = mem;
if (mem->is_Store()) {
Node* st_adr = mem->in(MemNode::Address);
intptr_t st_offset = 0;
Node* st_base = AddPNode::Ideal_base_and_offset(st_adr, phase, st_offset);
if (st_base == nullptr) {
// inscrutable pointer
break;
}
// If the bases are the same and the offsets are the same, it seems that this is the exact
// store we are looking for, the caller will check if the type of the store matches using
// MemNode::can_see_stored_value
if (st_base == base && st_offset == offset) {
return mem; // (b) found the store that this access observes
}
// If it is provable that the memory accessed by mem does not overlap the memory accessed by
// this, we may walk past mem.
// For raw accesses, 2 accesses are independent if they have the same base and the offsets
// say that they do not overlap.
// For heap accesses, 2 accesses are independent if either the bases are provably different
// at runtime or the offsets say that the accesses do not overlap.
if ((adr_maybe_raw || check_if_adr_maybe_raw(st_adr)) && st_base != base) {
// Raw accesses can only be provably independent if they have the same base
break;
}
// If the offsets say that the accesses do not overlap, then it is provable that mem and this
// do not overlap. For example, a LoadI from Object+8 is independent from a StoreL into
// Object+12, no matter what the bases are.
if (st_offset != offset && st_offset != Type::OffsetBot) {
const int MAX_STORE = MAX2(BytesPerLong, (int)MaxVectorSize);
assert(mem->as_Store()->memory_size() <= MAX_STORE, "");
if (st_offset >= offset + size_in_bytes ||
st_offset <= offset - MAX_STORE ||
st_offset <= offset - mem->as_Store()->memory_size()) {
// Success: The offsets are provably independent.
// (You may ask, why not just test st_offset != offset and be done?
// The answer is that stores of different sizes can co-exist
// in the same sequence of RawMem effects. We sometimes initialize
// a whole 'tile' of array elements with a single jint or jlong.)
mem = mem->in(MemNode::Memory);
continue; // (a) advance through the independent store
}
}
// Same base and overlapping offsets, it seems provable that the accesses overlap, give up
if (st_base == base) {
break;
}
// Try to prove that 2 different base nodes at compile time are different values at runtime
bool known_independent = false;
if (detect_ptr_independence(base, alloc, st_base, AllocateNode::Ideal_allocation(st_base), phase)) {
known_independent = true;
}
if (known_independent) {
mem = mem->in(MemNode::Memory);
continue; // (a) advance through the independent store
}
} else if (mem->is_Proj() && mem->in(0)->is_Initialize()) {
InitializeNode* st_init = mem->in(0)->as_Initialize();
AllocateNode* st_alloc = st_init->allocation();
if (st_alloc == nullptr) {
break; // something degenerated
}
bool known_identical = false;
bool known_independent = false;
if (alloc == st_alloc) {
known_identical = true;
} else if (alloc != nullptr) {
known_independent = true;
} else if (all_controls_dominate(this, st_alloc)) {
known_independent = true;
}
if (known_independent) {
// The bases are provably independent: Either they are
// manifestly distinct allocations, or else the control
// of this load dominates the store's allocation.
if (alias_idx == Compile::AliasIdxRaw) {
mem = st_alloc->in(TypeFunc::Memory);
} else {
mem = st_init->memory(alias_idx);
}
continue; // (a) advance through independent store memory
}
// (b) at this point, if we are not looking at a store initializing
// the same allocation we are loading from, we lose.
if (known_identical) {
// From caller, can_see_stored_value will consult find_captured_store.
return mem; // let caller handle steps (c), (d)
}
} else if (find_previous_arraycopy(phase, alloc, mem, false) != nullptr) {
if (prev != mem) {
// Found an arraycopy but it doesn't affect that load
continue;
}
// Found an arraycopy that may affect that load
return mem;
} else if (mem->is_MergeMem()) {
mem = mem->as_MergeMem()->memory_at(alias_idx);
continue;
} else if (addr_t != nullptr && addr_t->is_known_instance_field()) {
// Can't use optimize_simple_memory_chain() since it needs PhaseGVN.
if (mem->is_Proj() && mem->in(0)->is_Call()) {
// ArrayCopyNodes processed here as well.
CallNode *call = mem->in(0)->as_Call();
if (!call->may_modify(addr_t, phase)) {
mem = call->in(TypeFunc::Memory);
continue; // (a) advance through independent call memory
}
} else if (mem->is_Proj() && mem->in(0)->is_MemBar()) {
ArrayCopyNode* ac = nullptr;
if (ArrayCopyNode::may_modify(addr_t, mem->in(0)->as_MemBar(), phase, ac)) {
break;
}
mem = mem->in(0)->in(TypeFunc::Memory);
continue; // (a) advance through independent MemBar memory
} else if (mem->is_ClearArray()) {
if (ClearArrayNode::step_through(&mem, (uint)addr_t->instance_id(), phase)) {
// (the call updated 'mem' value)
continue; // (a) advance through independent allocation memory
} else {
// Can not bypass initialization of the instance
// we are looking for.
return mem;
}
}
Node* mem = in(MemNode::Memory); // start searching here...
int cnt = 50; // Cycle limiter
for (;; cnt--) {
// While we can dance past unrelated stores...
if (phase->type(mem) == Type::TOP) {
// Encounter a dead node
return phase->C->top();
} else if (cnt <= 0) {
// Caught in cycle or a complicated dance?
return nullptr;
} else if (mem->is_Phi()) {
return nullptr;
}
// Unless there is an explicit 'continue', we must bail out here,
// because 'mem' is an inscrutable memory state (e.g., a call).
break;
AccessAnalyzer::AccessIndependence independence = analyzer.detect_access_independence(mem);
if (independence.independent) {
// (a) advance through the independent store
mem = independence.mem;
assert(mem != nullptr, "must not be nullptr");
} else {
// (b) found the store that this access observes if this is not null
// Otherwise, give up if it is null
return independence.mem;
}
}
return nullptr; // bail out
@ -918,6 +771,174 @@ uint8_t MemNode::barrier_data(const Node* n) {
return 0;
}
AccessAnalyzer::AccessAnalyzer(PhaseValues* phase, MemNode* n)
: _phase(phase), _n(n), _memory_size(n->memory_size()), _alias_idx(-1) {
Node* adr = _n->in(MemNode::Address);
_offset = 0;
_base = AddPNode::Ideal_base_and_offset(adr, _phase, _offset);
_maybe_raw = MemNode::check_if_adr_maybe_raw(adr);
_alloc = AllocateNode::Ideal_allocation(_base);
_adr_type = _n->adr_type();
if (_adr_type != nullptr && _adr_type->base() != TypePtr::AnyPtr) {
// Avoid the cases that will upset Compile::get_alias_index
_alias_idx = _phase->C->get_alias_index(_adr_type);
assert(_alias_idx != Compile::AliasIdxTop, "must not be a dead node");
assert(_alias_idx != Compile::AliasIdxBot || !phase->C->do_aliasing(), "must not be a very wide access");
}
}
// Decide whether the memory accessed by '_n' and 'other' may overlap. This function may be used
// when we want to walk the memory graph to fold a load, or when we want to hoist a load above a
// loop when there are no stores that may overlap with the load inside the loop.
AccessAnalyzer::AccessIndependence AccessAnalyzer::detect_access_independence(Node* other) const {
assert(_phase->type(other) == Type::MEMORY, "must be a memory node %s", other->Name());
assert(!other->is_Phi(), "caller must handle Phi");
if (_adr_type == nullptr) {
// This means the access is dead
return {false, _phase->C->top()};
} else if (_adr_type->base() == TypePtr::AnyPtr) {
// An example for this case is an access into the memory address 0 performed using Unsafe
assert(_adr_type->ptr() == TypePtr::Null, "MemNode should never access a wide memory");
return {false, nullptr};
}
if (_offset == Type::OffsetBot) {
// cannot unalias unless there are precise offsets
return {false, nullptr};
}
const TypeOopPtr* adr_oop_type = _adr_type->isa_oopptr();
Node* prev = other;
if (other->is_Store()) {
Node* st_adr = other->in(MemNode::Address);
intptr_t st_offset = 0;
Node* st_base = AddPNode::Ideal_base_and_offset(st_adr, _phase, st_offset);
if (st_base == nullptr) {
// inscrutable pointer
return {false, nullptr};
}
// If the bases are the same and the offsets are the same, it seems that this is the exact
// store we are looking for, the caller will check if the type of the store matches using
// MemNode::can_see_stored_value
if (st_base == _base && st_offset == _offset) {
return {false, other};
}
// If it is provable that the memory accessed by 'other' does not overlap the memory accessed
// by '_n', we may walk past 'other'.
// For raw accesses, 2 accesses are independent if they have the same base and the offsets
// say that they do not overlap.
// For heap accesses, 2 accesses are independent if either the bases are provably different
// at runtime or the offsets say that the accesses do not overlap.
if ((_maybe_raw || MemNode::check_if_adr_maybe_raw(st_adr)) && st_base != _base) {
// Raw accesses can only be provably independent if they have the same base
return {false, nullptr};
}
// If the offsets say that the accesses do not overlap, then it is provable that 'other' and
// '_n' do not overlap. For example, a LoadI from Object+8 is independent from a StoreL into
// Object+12, no matter what the bases are.
if (st_offset != _offset && st_offset != Type::OffsetBot) {
const int MAX_STORE = MAX2(BytesPerLong, (int)MaxVectorSize);
assert(other->as_Store()->memory_size() <= MAX_STORE, "");
if (st_offset >= _offset + _memory_size ||
st_offset <= _offset - MAX_STORE ||
st_offset <= _offset - other->as_Store()->memory_size()) {
// Success: The offsets are provably independent.
// (You may ask, why not just test st_offset != offset and be done?
// The answer is that stores of different sizes can co-exist
// in the same sequence of RawMem effects. We sometimes initialize
// a whole 'tile' of array elements with a single jint or jlong.)
return {true, other->in(MemNode::Memory)};
}
}
// Same base and overlapping offsets, it seems provable that the accesses overlap, give up
if (st_base == _base) {
return {false, nullptr};
}
// Try to prove that 2 different base nodes at compile time are different values at runtime
bool known_independent = false;
if (MemNode::detect_ptr_independence(_base, _alloc, st_base, AllocateNode::Ideal_allocation(st_base), _phase)) {
known_independent = true;
}
if (known_independent) {
return {true, other->in(MemNode::Memory)};
}
} else if (other->is_Proj() && other->in(0)->is_Initialize()) {
InitializeNode* st_init = other->in(0)->as_Initialize();
AllocateNode* st_alloc = st_init->allocation();
if (st_alloc == nullptr) {
// Something degenerated
return {false, nullptr};
}
bool known_identical = false;
bool known_independent = false;
if (_alloc == st_alloc) {
known_identical = true;
} else if (_alloc != nullptr) {
known_independent = true;
} else if (MemNode::all_controls_dominate(_n, st_alloc)) {
known_independent = true;
}
if (known_independent) {
// The bases are provably independent: Either they are
// manifestly distinct allocations, or else the control
// of _n dominates the store's allocation.
if (_alias_idx == Compile::AliasIdxRaw) {
other = st_alloc->in(TypeFunc::Memory);
} else {
other = st_init->memory(_alias_idx);
}
return {true, other};
}
// If we are not looking at a store initializing the same
// allocation we are loading from, we lose.
if (known_identical) {
// From caller, can_see_stored_value will consult find_captured_store.
return {false, other};
}
} else if (_n->find_previous_arraycopy(_phase, _alloc, other, false) != nullptr) {
// Find an arraycopy that may or may not affect the MemNode
return {prev != other, other};
} else if (other->is_MergeMem()) {
return {true, other->as_MergeMem()->memory_at(_alias_idx)};
} else if (adr_oop_type != nullptr && adr_oop_type->is_known_instance_field()) {
// Can't use optimize_simple_memory_chain() since it needs PhaseGVN.
if (other->is_Proj() && other->in(0)->is_Call()) {
// ArrayCopyNodes processed here as well.
CallNode* call = other->in(0)->as_Call();
if (!call->may_modify(adr_oop_type, _phase)) {
return {true, call->in(TypeFunc::Memory)};
}
} else if (other->is_Proj() && other->in(0)->is_MemBar()) {
ArrayCopyNode* ac = nullptr;
if (!ArrayCopyNode::may_modify(adr_oop_type, other->in(0)->as_MemBar(), _phase, ac)) {
return {true, other->in(0)->in(TypeFunc::Memory)};
}
} else if (other->is_ClearArray()) {
if (ClearArrayNode::step_through(&other, (uint)adr_oop_type->instance_id(), _phase)) {
// (the call updated 'other' value)
return {true, other};
} else {
// Can not bypass initialization of the instance
// we are looking for.
return {false, other};
}
}
}
return {false, nullptr};
}
//=============================================================================
// Should LoadNode::Ideal() attempt to remove control edges?
bool LoadNode::can_remove_control() const {

View File

@ -26,6 +26,7 @@
#ifndef SHARE_OPTO_MEMNODE_HPP
#define SHARE_OPTO_MEMNODE_HPP
#include "memory/allocation.hpp"
#include "opto/multnode.hpp"
#include "opto/node.hpp"
#include "opto/opcodes.hpp"
@ -46,6 +47,8 @@ private:
bool _unsafe_access; // Access of unsafe origin.
uint8_t _barrier_data; // Bit field with barrier information
friend class AccessAnalyzer;
protected:
#ifdef ASSERT
const TypePtr* _adr_type; // What kind of memory is being addressed?
@ -172,6 +175,45 @@ public:
#endif
};
// Analyze a MemNode to try to prove that it is independent from other memory accesses
class AccessAnalyzer : StackObj {
private:
PhaseValues* const _phase;
MemNode* const _n;
Node* _base;
intptr_t _offset;
const int _memory_size;
bool _maybe_raw;
AllocateNode* _alloc;
const TypePtr* _adr_type;
int _alias_idx;
public:
AccessAnalyzer(PhaseValues* phase, MemNode* n);
// The result of deciding whether a memory node 'other' writes into the memory which '_n'
// observes.
class AccessIndependence {
public:
// Whether 'other' writes into the memory which '_n' observes. This value is conservative, that
// is, it is only true when it is provable that the memory accessed by the nodes is
// non-overlapping.
bool independent;
// If 'independent' is true, this is the memory input of 'other' that corresponds to the memory
// location that '_n' observes. For example, if 'other' is a StoreNode, then 'mem' is its
// memory input, if 'other' is a MergeMemNode, then 'mem' is the memory input corresponding to
// the alias class of '_n'.
// If 'independent' is false,
// - 'mem' is non-nullptr if it seems that 'other' writes to the exact memory location '_n'
// observes.
// - 'mem' is nullptr otherwise.
Node* mem;
};
AccessIndependence detect_access_independence(Node* other) const;
};
//------------------------------LoadNode---------------------------------------
// Load value; requires Memory and Address
class LoadNode : public MemNode {

View File

@ -1539,15 +1539,20 @@ Node* URShiftINode::Ideal(PhaseGVN* phase, bool can_reshape) {
Node *add = in(1);
if (in1_op == Op_AddI) {
Node *lshl = add->in(1);
Node *y = add->in(2);
if (lshl->Opcode() != Op_LShiftI) {
lshl = add->in(2);
y = add->in(1);
}
// Compare shift counts by value, not by node pointer, to also match a not-yet-normalized
// negative constant (e.g. -1 vs 31)
int lshl_con = 0;
if (lshl->Opcode() == Op_LShiftI &&
const_shift_count(phase, lshl, &lshl_con) &&
(lshl_con & (BitsPerJavaInteger - 1)) == con) {
Node *y_z = phase->transform( new URShiftINode(add->in(2),in(2)) );
Node *sum = phase->transform( new AddINode( lshl->in(1), y_z ) );
return new AndINode( sum, phase->intcon(mask) );
Node *y_z = phase->transform(new URShiftINode(y, in(2)));
Node *sum = phase->transform(new AddINode(lshl->in(1), y_z));
return new AndINode(sum, phase->intcon(mask));
}
}
@ -1699,13 +1704,18 @@ Node* URShiftLNode::Ideal(PhaseGVN* phase, bool can_reshape) {
const TypeInt *t2 = phase->type(in(2))->isa_int();
if (add->Opcode() == Op_AddL) {
Node *lshl = add->in(1);
Node *y = add->in(2);
if (lshl->Opcode() != Op_LShiftL) {
lshl = add->in(2);
y = add->in(1);
}
// Compare shift counts by value, not by node pointer, to also match a not-yet-normalized
// negative constant (e.g. -1 vs 63)
int lshl_con = 0;
if (lshl->Opcode() == Op_LShiftL &&
const_shift_count(phase, lshl, &lshl_con) &&
(lshl_con & (BitsPerJavaLong - 1)) == con) {
Node* y_z = phase->transform(new URShiftLNode(add->in(2), in(2)));
Node* y_z = phase->transform(new URShiftLNode(y, in(2)));
Node* sum = phase->transform(new AddLNode(lshl->in(1), y_z));
return new AndLNode(sum, phase->longcon(mask));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,7 @@
#ifndef SHARE_OPTO_PHASETYPE_HPP
#define SHARE_OPTO_PHASETYPE_HPP
#include "memory/allocation.hpp"
#include "utilities/bitMap.inline.hpp"
#include "utilities/stringUtils.hpp"

View File

@ -1529,7 +1529,7 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec
GrowableArray<JavaThread*>* wantList = nullptr;
ObjectMonitor* mon = mark.has_monitor()
? ObjectSynchronizer::read_monitor(current_thread, hobj(), mark)
? ObjectSynchronizer::read_monitor(hobj(), mark)
: nullptr;
if (mon != nullptr) {

View File

@ -553,6 +553,7 @@ static SpecialFlag const special_jvm_flags[] = {
{ "ParallelRefProcEnabled", JDK_Version::jdk(26), JDK_Version::jdk(27), JDK_Version::jdk(28) },
{ "ParallelRefProcBalancingEnabled", JDK_Version::jdk(26), JDK_Version::jdk(27), JDK_Version::jdk(28) },
{ "MaxRAM", JDK_Version::jdk(26), JDK_Version::jdk(27), JDK_Version::jdk(28) },
{ "NewSizeThreadIncrease", JDK_Version::undefined(), JDK_Version::jdk(27), JDK_Version::jdk(28) },
#ifdef ASSERT
{ "DummyObsoleteTestFlag", JDK_Version::undefined(), JDK_Version::jdk(18), JDK_Version::undefined() },

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,7 +26,7 @@
#define SHARE_RUNTIME_ATOMICACCESS_HPP
#include "cppstdlib/type_traits.hpp"
#include "memory/allocation.hpp"
#include "memory/allStatic.hpp"
#include "metaprogramming/enableIf.hpp"
#include "metaprogramming/primitiveConversions.hpp"
#include "runtime/orderAccess.hpp"
@ -829,7 +829,7 @@ class AtomicAccess::PlatformBitops
{};
template <ScopedFenceType T>
class ScopedFenceGeneral: public StackObj {
class ScopedFenceGeneral {
public:
void prefix() {}
void postfix() {}

View File

@ -1686,7 +1686,7 @@ bool Deoptimization::relock_objects(JavaThread* thread, GrowableArray<MonitorInf
assert(mon_info->owner()->is_locked(), "object must be locked now");
assert(obj->mark().has_monitor(), "must be");
assert(!deoptee_thread->lock_stack().contains(obj()), "must be");
assert(ObjectSynchronizer::read_monitor(thread, obj(), obj->mark())->has_owner(deoptee_thread), "must be");
assert(ObjectSynchronizer::read_monitor(obj(), obj->mark())->has_owner(deoptee_thread), "must be");
}
}
}

View File

@ -1,7 +1,7 @@
/*
* Copyright (c) 2022, Red Hat, Inc. All rights reserved.
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
* Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -254,7 +254,7 @@ inline void OMCache::set_monitor(ObjectMonitor *monitor) {
oop obj = monitor->object_peek();
assert(obj != nullptr, "must be alive");
assert(monitor == ObjectSynchronizer::get_monitor_from_table(JavaThread::current(), obj), "must exist in table");
assert(monitor == ObjectSynchronizer::get_monitor_from_table(obj), "must exist in table");
OMCacheEntry to_insert = {obj, monitor};

View File

@ -854,7 +854,7 @@ bool ObjectMonitor::deflate_monitor(Thread* current) {
}
if (UseObjectMonitorTable) {
ObjectSynchronizer::deflate_monitor(current, obj, this);
ObjectSynchronizer::deflate_monitor(obj, this);
} else if (obj != nullptr) {
// Install the old mark word if nobody else has already done it.
install_displaced_markword_in_object(obj);
@ -2541,19 +2541,19 @@ bool ObjectMonitor::try_spin(JavaThread* current) {
// -----------------------------------------------------------------------------
// wait_set management ...
ObjectWaiter::ObjectWaiter(JavaThread* current) {
_next = nullptr;
_prev = nullptr;
_thread = current;
_monitor = nullptr;
_notifier_tid = 0;
_recursions = 0;
TState = TS_RUN;
_is_wait = false;
_at_reenter = false;
_interrupted = false;
_do_timed_park = false;
_active = false;
ObjectWaiter::ObjectWaiter(JavaThread* current)
: _next(nullptr),
_prev(nullptr),
_thread(current),
_monitor(nullptr),
_notifier_tid(0),
_recursions(0),
TState(TS_RUN),
_is_wait(false),
_at_reenter(false),
_interrupted(false),
_do_timed_park(false),
_active(false) {
}
const char* ObjectWaiter::getTStateName(ObjectWaiter::TStates state) {

View File

@ -46,7 +46,7 @@
//
// When you want to find a monitor associated with an object, you extract the
// hash value of the object. Then calculate an index by taking the hash value
// and bit-wise AND it with the capacity mask (e.g. size-1) of the OMT. Now
// and bit-wise AND it with the capacity mask (i.e., size-1) of the OMT. Now
// use that index into the OMT's array of pointers. If the pointer is non
// null, check if it's a monitor pointer that is associated with the object.
// If so you're done. If the pointer is non null, but associated with another
@ -55,7 +55,7 @@
// means that the monitor is simply not in the OMT.
//
// If the size of the pointer array is significantly larger than the number of
// pointers in it, the chance of finding the monitor in the hash index
// pointers in it, the chance of finding the monitor at the hash index
// (without any further linear searching) is quite high. It is also straight
// forward to generate C2 code for this, which for the fast path doesn't
// contain any branching at all. See: C2_MacroAssembler::fast_lock().
@ -69,10 +69,10 @@
// old monitor pointers from the old table to the new.
//
// But since the OMT is a concurrent hash table and things needs to work for
// other clients of the OMT while we grow it, it's gets a bit more
// other clients of the OMT while we grow it, it gets a bit more
// complicated.
//
// Both the new and (potentially several) old table(s) may exist at the same
// The new and (potentially several) old table(s) may exist at the same
// time. The newest is always called the "current", and the older ones are
// singly linked using a "prev" pointer.
//
@ -82,7 +82,8 @@
//
// After that we start to go through all the indexes in the old table. If the
// index is empty (the pointer is null) we put a "tombstone" into that index,
// which will prevent any future concurrent insert ending up in that index.
// which will prevent any future concurrent insert from ending up in that
// index.
//
// If the index contains a monitor pointer, we insert that monitor pointer
// into the OMT which can be considered as one generation newer. If the index
@ -92,11 +93,11 @@
// that is not null, not a tombstone and not removed, is considered to be a
// pointer to a monitor.
//
// When all the monitor pointers from an old OMT has been transferred to the
// When all the monitor pointers from an old OMT have been transferred to the
// new OMT, the old table is unlinked.
//
// This copying from an old OMT to one generation newer OMT, will continue
// until all the monitor pointers from old OMTs has been transferred to the
// until all the monitor pointers from old OMTs have been transferred to the
// newest "current" OMT.
//
// The memory for old, unlinked OMTs will be freed after a thread-local
@ -255,7 +256,7 @@ public:
}
ObjectMonitor* prepare_insert(oop obj, intptr_t hash) {
// Acquire any tomb stones and relocations if prev transitioned to null.
// Acquire any tombstones and relocations if prev transitioned to null.
Table* prev = AtomicAccess::load_acquire(&_prev);
if (prev != nullptr) {
ObjectMonitor* result = prev->prepare_insert(obj, hash);
@ -273,7 +274,7 @@ public:
if (entry == empty()) {
// Found an empty slot to install the new monitor in.
// To avoid concurrent inserts succeeding, place a tomb stone here.
// To avoid concurrent inserts succeeding, place a tombstone here.
Entry result = AtomicAccess::cmpxchg(bucket, entry, tombstone(), memory_order_relaxed);
if (result == entry) {
// Success! Nobody will try to insert here again, except reinsert from rehashing.
@ -515,7 +516,7 @@ void ObjectMonitorTable::create() {
_curr = new Table(128, nullptr);
}
ObjectMonitor* ObjectMonitorTable::monitor_get(Thread* current, oop obj) {
ObjectMonitor* ObjectMonitorTable::monitor_get(oop obj) {
const intptr_t hash = obj->mark().hash();
Table* curr = AtomicAccess::load_acquire(&_curr);
ObjectMonitor* monitor = curr->get(obj, hash);
@ -562,7 +563,7 @@ ObjectMonitorTable::Table* ObjectMonitorTable::grow_table(Table* curr) {
return result;
}
ObjectMonitor* ObjectMonitorTable::monitor_put_get(Thread* current, ObjectMonitor* monitor, oop obj) {
ObjectMonitor* ObjectMonitorTable::monitor_put_get(ObjectMonitor* monitor, oop obj) {
const intptr_t hash = obj->mark().hash();
Table* curr = AtomicAccess::load_acquire(&_curr);
@ -577,7 +578,7 @@ ObjectMonitor* ObjectMonitorTable::monitor_put_get(Thread* current, ObjectMonito
}
}
void ObjectMonitorTable::remove_monitor_entry(Thread* current, ObjectMonitor* monitor) {
void ObjectMonitorTable::remove_monitor_entry(ObjectMonitor* monitor) {
oop obj = monitor->object_peek();
if (obj == nullptr) {
// Defer removal until subsequent rebuilding.
@ -586,7 +587,7 @@ void ObjectMonitorTable::remove_monitor_entry(Thread* current, ObjectMonitor* mo
const intptr_t hash = obj->mark().hash();
Table* curr = AtomicAccess::load_acquire(&_curr);
curr->remove(obj, curr->as_entry(monitor), hash);
assert(monitor_get(current, obj) != monitor, "should have been removed");
assert(monitor_get(obj) != monitor, "should have been removed");
}
// Before handshake; rehash and unlink tables.

View File

@ -61,11 +61,11 @@ public:
} SpecialPointerValues;
static void create();
static ObjectMonitor* monitor_get(Thread* current, oop obj);
static ObjectMonitor* monitor_put_get(Thread* current, ObjectMonitor* monitor, oop obj);
static ObjectMonitor* monitor_get(oop obj);
static ObjectMonitor* monitor_put_get(ObjectMonitor* monitor, oop obj);
static void rebuild(GrowableArray<Table*>* delete_list);
static void destroy(GrowableArray<Table*>* delete_list);
static void remove_monitor_entry(Thread* current, ObjectMonitor* monitor);
static void remove_monitor_entry(ObjectMonitor* monitor);
// Compiler support
static address current_table_address();

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