Merge branch 'master' into opt-drem-8309636

This commit is contained in:
katkerem 2026-03-30 17:45:12 +01:00
commit 64fdfe71ca
87 changed files with 2528 additions and 714 deletions

View File

@ -37,13 +37,13 @@ runs:
- name: 'Check cache for already built JTReg'
id: get-cached
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: jtreg/installed
key: jtreg-${{ steps.version.outputs.value }}
- name: 'Checkout the JTReg source'
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
repository: openjdk/jtreg
ref: jtreg-${{ steps.version.outputs.value }}
@ -61,7 +61,7 @@ runs:
if: (steps.get-cached.outputs.cache-hit != 'true')
- name: 'Upload JTReg artifact'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: bundles-jtreg-${{ steps.version.outputs.value }}
path: jtreg/installed

View File

@ -66,7 +66,7 @@ runs:
shell: bash
- name: 'Upload build logs'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: failure-logs-${{ inputs.platform }}${{ inputs.debug-suffix }}
path: failure-logs
@ -74,7 +74,7 @@ runs:
# This is the best way I found to abort the job with an error message
- name: 'Notify about build failures'
uses: actions/github-script@v7
uses: actions/github-script@v8
with:
script: core.setFailed('Build failed. See summary for details.')
if: steps.check.outputs.failure == 'true'

View File

@ -65,7 +65,7 @@ runs:
- name: 'Check cache for BootJDK'
id: get-cached-bootjdk
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: bootjdk/jdk
key: boot-jdk-${{ inputs.platform }}-${{ steps.sha256.outputs.value }}

View File

@ -54,14 +54,14 @@ runs:
steps:
- name: 'Download bundles artifact'
id: download-bundles
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
name: bundles-${{ inputs.platform }}${{ inputs.debug-suffix }}
path: bundles
continue-on-error: true
- name: 'Download bundles artifact (retry)'
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
name: bundles-${{ inputs.platform }}${{ inputs.debug-suffix }}
path: bundles
@ -69,7 +69,7 @@ runs:
- name: 'Download static bundles artifact'
id: download-static-bundles
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
name: bundles-${{ inputs.platform }}${{ inputs.debug-suffix }}${{ inputs.static-suffix }}
path: bundles

View File

@ -40,7 +40,7 @@ runs:
var: GTEST_VERSION
- name: 'Checkout GTest source'
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
repository: google/googletest
ref: 'v${{ steps.version.outputs.value }}'

View File

@ -41,7 +41,7 @@ runs:
- name: 'Download JTReg artifact'
id: download-jtreg
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
name: bundles-jtreg-${{ steps.version.outputs.value }}
path: jtreg/installed

View File

@ -31,7 +31,7 @@ runs:
steps:
- name: 'Install MSYS2'
id: msys2
uses: msys2/setup-msys2@v2.28.0
uses: msys2/setup-msys2@v2.31.0
with:
install: 'autoconf tar unzip zip make'
path-type: minimal

View File

@ -87,7 +87,7 @@ runs:
shell: bash
- name: 'Upload bundles artifact'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: bundles-${{ inputs.platform }}${{ inputs.debug-suffix }}${{ inputs.static-suffix }}${{ inputs.bundle-suffix }}
path: bundles

View File

@ -74,7 +74,7 @@ jobs:
steps:
- name: 'Checkout the JDK source'
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: 'Install toolchain and dependencies'
run: |

View File

@ -94,7 +94,7 @@ jobs:
steps:
- name: 'Checkout the JDK source'
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: 'Get the BootJDK'
id: bootjdk
@ -122,7 +122,7 @@ jobs:
- name: 'Check cache for sysroot'
id: get-cached-sysroot
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: sysroot
key: sysroot-${{ matrix.debian-arch }}-${{ hashFiles('./.github/workflows/build-cross-compile.yml') }}

View File

@ -84,7 +84,7 @@ jobs:
steps:
- name: 'Checkout the JDK source'
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: 'Get the BootJDK'
id: bootjdk

View File

@ -75,7 +75,7 @@ jobs:
steps:
- name: 'Checkout the JDK source'
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: 'Get the BootJDK'
id: bootjdk

View File

@ -83,7 +83,7 @@ jobs:
steps:
- name: 'Checkout the JDK source'
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: 'Get MSYS2'
uses: ./.github/actions/get-msys2

View File

@ -75,7 +75,7 @@ jobs:
steps:
- name: 'Checkout the scripts'
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
sparse-checkout: |
.github

View File

@ -128,7 +128,7 @@ jobs:
steps:
- name: 'Checkout the JDK source'
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: 'Get MSYS2'
uses: ./.github/actions/get-msys2
@ -239,7 +239,7 @@ jobs:
if: always()
- name: 'Upload test results'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
path: results
name: ${{ steps.package.outputs.artifact-name }}
@ -247,7 +247,7 @@ jobs:
# This is the best way I found to abort the job with an error message
- name: 'Notify about test failures'
uses: actions/github-script@v7
uses: actions/github-script@v8
with:
script: core.setFailed('${{ steps.run-tests.outputs.error-message }}')
if: steps.run-tests.outputs.failure == 'true'

View File

@ -36,16 +36,16 @@ include $(TOPDIR)/make/ToolsJdk.gmk
LAUNCHER_SRC := $(TOPDIR)/src/java.base/share/native/launcher
ifeq ($(call isTargetOs, aix), true)
ADD_PLATFORM_INCLUDE_DIR := -I$(TOPDIR)/src/java.base/aix/native/include
endif
LAUNCHER_CFLAGS += -I$(TOPDIR)/src/java.base/share/native/launcher \
-I$(TOPDIR)/src/java.base/share/native/libjli \
$(ADD_PLATFORM_INCLUDE_DIR) \
-I$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjli \
-I$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/native/libjli \
#
ifeq ($(call isTargetOs, aix), true)
LAUNCHER_CFLAGS += -I$(TOPDIR)/src/java.base/aix/native/include
endif
MACOSX_PLIST_DIR := $(TOPDIR)/src/java.base/macosx/native/launcher
JAVA_MANIFEST := $(TOPDIR)/src/java.base/windows/native/launcher/java.manifest

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2021, 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/registerMap.hpp"
address RegisterMap::pd_location(VMReg base_reg, int slot_idx) const {
if (base_reg->is_VectorRegister()) {
// Not all physical slots belonging to a VectorRegister have corresponding
// valid VMReg locations in the RegisterMap.
// (See RegisterSaver::push_frame_reg_args_and_save_live_registers.)
// However, the slots are always saved to the stack in a contiguous region
// of memory so we can calculate the address of the upper slots by
// offsetting from the base address.
assert(base_reg->is_concrete(), "must pass base reg");
address base_location = location(base_reg, nullptr);
if (base_location != nullptr) {
intptr_t offset_in_bytes = slot_idx * VMRegImpl::stack_slot_size;
return base_location + offset_in_bytes;
} else {
return nullptr;
}
} else {
return location(base_reg->next(slot_idx), nullptr);
}
}

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2013 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
@ -35,9 +35,7 @@
// Since there is none, we just return null.
address pd_location(VMReg reg) const { return nullptr; }
address pd_location(VMReg base_reg, int slot_idx) const {
return location(base_reg->next(slot_idx), nullptr);
}
address pd_location(VMReg base_reg, int slot_idx) const;
// no PD state to clear or copy:
void pd_clear() {}

View File

@ -102,7 +102,7 @@ class RegisterSaver {
// During deoptimization only the result registers need to be restored
// all the other values have already been extracted.
static void restore_result_registers(MacroAssembler* masm, int frame_size_in_bytes);
static void restore_result_registers(MacroAssembler* masm, int frame_size_in_bytes, bool save_vectors);
// Constants and data structures:
@ -349,7 +349,7 @@ OopMap* RegisterSaver::push_frame_reg_args_and_save_live_registers(MacroAssemble
}
// Note that generate_oop_map in the following loop is only used for the
// polling_page_vectors_safepoint_handler_blob.
// polling_page_vectors_safepoint_handler_blob and the deopt_blob.
// The order in which the vector contents are stored depends on Endianess and
// the utilized instructions (PowerArchitecturePPC64).
assert(is_aligned(offset, StackAlignmentInBytes), "should be");
@ -361,6 +361,7 @@ OopMap* RegisterSaver::push_frame_reg_args_and_save_live_registers(MacroAssemble
__ stxvp(as_VectorRegister(reg_num).to_vsr(), offset, R1_SP);
// Note: The contents were read in the same order (see loadV16_Power9 node in ppc.ad).
// RegisterMap::pd_location only uses the first VMReg for each VectorRegister.
if (generate_oop_map) {
map->set_callee_saved(VMRegImpl::stack2reg(offset >> 2),
RegisterSaver_LiveVecRegs[i LITTLE_ENDIAN_ONLY(+1) ].vmreg);
@ -380,6 +381,7 @@ OopMap* RegisterSaver::push_frame_reg_args_and_save_live_registers(MacroAssemble
__ stxvd2x(as_VectorRegister(reg_num)->to_vsr(), R31, R1_SP);
}
// Note: The contents were read in the same order (see loadV16_Power8 / loadV16_Power9 node in ppc.ad).
// RegisterMap::pd_location only uses the first VMReg for each VectorRegister.
if (generate_oop_map) {
VMReg vsr = RegisterSaver_LiveVecRegs[i].vmreg;
map->set_callee_saved(VMRegImpl::stack2reg(offset >> 2), vsr);
@ -566,10 +568,14 @@ void RegisterSaver::restore_argument_registers_and_pop_frame(MacroAssembler*masm
}
// Restore the registers that might be holding a result.
void RegisterSaver::restore_result_registers(MacroAssembler* masm, int frame_size_in_bytes) {
void RegisterSaver::restore_result_registers(MacroAssembler* masm, int frame_size_in_bytes, bool save_vectors) {
const int regstosave_num = sizeof(RegisterSaver_LiveRegs) /
sizeof(RegisterSaver::LiveRegType);
const int register_save_size = regstosave_num * reg_size; // VS registers not relevant here.
const int vecregstosave_num = save_vectors ? (sizeof(RegisterSaver_LiveVecRegs) /
sizeof(RegisterSaver::LiveRegType))
: 0;
const int register_save_size = regstosave_num * reg_size + vecregstosave_num * vec_reg_size;
const int register_save_offset = frame_size_in_bytes - register_save_size;
// restore all result registers (ints and floats)
@ -598,7 +604,7 @@ void RegisterSaver::restore_result_registers(MacroAssembler* masm, int frame_siz
offset += reg_size;
}
assert(offset == frame_size_in_bytes, "consistency check");
assert(offset == frame_size_in_bytes - (save_vectors ? vecregstosave_num * vec_reg_size : 0), "consistency check");
}
// Is vector's size (in bytes) bigger than a size saved by default?
@ -2909,7 +2915,8 @@ void SharedRuntime::generate_deopt_blob() {
map = RegisterSaver::push_frame_reg_args_and_save_live_registers(masm,
&first_frame_size_in_bytes,
/*generate_oop_map=*/ true,
RegisterSaver::return_pc_is_lr);
RegisterSaver::return_pc_is_lr,
/*save_vectors*/ SuperwordUseVSX);
assert(map != nullptr, "OopMap must have been created");
__ li(exec_mode_reg, Deoptimization::Unpack_deopt);
@ -2943,7 +2950,8 @@ void SharedRuntime::generate_deopt_blob() {
RegisterSaver::push_frame_reg_args_and_save_live_registers(masm,
&first_frame_size_in_bytes,
/*generate_oop_map=*/ false,
RegisterSaver::return_pc_is_pre_saved);
RegisterSaver::return_pc_is_pre_saved,
/*save_vectors*/ SuperwordUseVSX);
// Deopt during an exception. Save exec mode for unpack_frames.
__ li(exec_mode_reg, Deoptimization::Unpack_exception);
@ -2958,7 +2966,8 @@ void SharedRuntime::generate_deopt_blob() {
RegisterSaver::push_frame_reg_args_and_save_live_registers(masm,
&first_frame_size_in_bytes,
/*generate_oop_map=*/ false,
RegisterSaver::return_pc_is_pre_saved);
RegisterSaver::return_pc_is_pre_saved,
/*save_vectors*/ SuperwordUseVSX);
__ li(exec_mode_reg, Deoptimization::Unpack_reexecute);
#endif
@ -2984,7 +2993,7 @@ void SharedRuntime::generate_deopt_blob() {
// Restore only the result registers that have been saved
// by save_volatile_registers(...).
RegisterSaver::restore_result_registers(masm, first_frame_size_in_bytes);
RegisterSaver::restore_result_registers(masm, first_frame_size_in_bytes, /*save_vectors*/ SuperwordUseVSX);
// reload the exec mode from the UnrollBlock (it might have changed)
__ lwz(exec_mode_reg, in_bytes(Deoptimization::UnrollBlock::unpack_kind_offset()), unroll_block_reg);

View File

@ -25,6 +25,7 @@
#include "asm/assembler.inline.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "compiler/compilerDefinitions.inline.hpp"
#include "compiler/disassembler.hpp"
#include "jvm.h"
#include "memory/resourceArea.hpp"
@ -105,7 +106,7 @@ void VM_Version::initialize() {
if (PowerArchitecturePPC64 >= 9) {
// Performance is good since Power9.
if (FLAG_IS_DEFAULT(SuperwordUseVSX)) {
if (FLAG_IS_DEFAULT(SuperwordUseVSX) && CompilerConfig::is_c2_enabled()) {
FLAG_SET_ERGO(SuperwordUseVSX, true);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2024 SAP SE. All rights reserved.
* Copyright (c) 2012, 2026 SAP SE. All rights reserved.
* Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -426,6 +426,10 @@ int dladdr(void* addr, Dl_info* info) {
}
int JVM_dladdr(void* addr, Dl_info* info) {
return dladdr(addr, info);
}
/////////////////////////////////////////////////////////////////////////////
// Native callstack dumping

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
@ -62,6 +62,19 @@
#define JVM_X_OK X_OK
#define JVM_F_OK F_OK
#if defined(AIX)
#include "jni_md.h"
#include "dl_info.h"
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT int JVM_dladdr(void* addr, Dl_info* info);
#ifdef __cplusplus
}
#endif
#endif
/*
* File I/O
*/

View File

@ -2528,12 +2528,6 @@ LONG Handle_Exception(struct _EXCEPTION_POINTERS* exceptionInfo,
return EXCEPTION_CONTINUE_EXECUTION;
}
// Used for PostMortemDump
extern "C" void safepoints();
extern "C" void find(int x);
extern "C" void events();
// According to Windows API documentation, an illegal instruction sequence should generate
// the 0xC000001C exception code. However, real world experience shows that occasionnaly
// the execution of an illegal instruction can generate the exception code 0xC000001E. This

View File

@ -32,7 +32,6 @@
#include "oops/methodCounters.hpp"
#include "oops/methodData.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/icache.hpp"
#include "runtime/safepointVerifiers.hpp"
#include "utilities/align.hpp"
#include "utilities/copy.hpp"
@ -745,9 +744,6 @@ void CodeBuffer::copy_code_to(CodeBlob* dest_blob) {
// Done moving code bytes; were they the right size?
assert((int)align_up(dest.total_content_size(), oopSize) == dest_blob->content_size(), "sanity");
// Flush generated code
ICache::invalidate_range(dest_blob->code_begin(), dest_blob->code_size());
}
// Move all my code into another code buffer. Consult applicable

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 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
@ -596,11 +596,13 @@ void FieldLayoutBuilder::regular_field_sorting() {
}
}
void FieldLayoutBuilder::insert_contended_padding(LayoutRawBlock* slot) {
LayoutRawBlock* FieldLayoutBuilder::insert_contended_padding(LayoutRawBlock* slot) {
LayoutRawBlock* padding = nullptr;
if (ContendedPaddingWidth > 0) {
LayoutRawBlock* padding = new LayoutRawBlock(LayoutRawBlock::PADDING, ContendedPaddingWidth);
padding = new LayoutRawBlock(LayoutRawBlock::PADDING, ContendedPaddingWidth);
_layout->insert(slot, padding);
}
return padding;
}
// Computation of regular classes layout is an evolution of the previous default layout
@ -620,10 +622,14 @@ void FieldLayoutBuilder::compute_regular_layout() {
regular_field_sorting();
if (_is_contended) {
_layout->set_start(_layout->last_block());
// insertion is currently easy because the current strategy doesn't try to fill holes
// in super classes layouts => the _start block is by consequence the _last_block
insert_contended_padding(_layout->start());
_layout->set_start(_layout->last_block());
LayoutRawBlock* padding = insert_contended_padding(_layout->start());
if (padding != nullptr) {
// Setting the padding block as start ensures we do not insert past it.
_layout->set_start(padding);
}
need_tail_padding = true;
}
@ -639,7 +645,13 @@ void FieldLayoutBuilder::compute_regular_layout() {
for (int i = 0; i < _contended_groups.length(); i++) {
FieldGroup* cg = _contended_groups.at(i);
LayoutRawBlock* start = _layout->last_block();
insert_contended_padding(start);
LayoutRawBlock* padding = insert_contended_padding(start);
// Do not insert fields past the padding block.
if (padding != nullptr) {
start = padding;
}
_layout->add(cg->primitive_fields(), start);
_layout->add(cg->oop_fields(), start);
need_tail_padding = true;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 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
@ -250,7 +250,7 @@ class FieldLayoutBuilder : public ResourceObj {
void build_layout();
void compute_regular_layout();
void insert_contended_padding(LayoutRawBlock* slot);
LayoutRawBlock* insert_contended_padding(LayoutRawBlock* slot);
private:
void prologue();

View File

@ -40,6 +40,7 @@
#include "prims/forte.hpp"
#include "prims/jvmtiExport.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/icache.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/javaFrameAnchor.hpp"
#include "runtime/jniHandles.inline.hpp"
@ -78,8 +79,10 @@ const BufferBlob::Vptr BufferBlob::_vpntr;
const RuntimeStub::Vptr RuntimeStub::_vpntr;
const SingletonBlob::Vptr SingletonBlob::_vpntr;
const DeoptimizationBlob::Vptr DeoptimizationBlob::_vpntr;
const SafepointBlob::Vptr SafepointBlob::_vpntr;
#ifdef COMPILER2
const ExceptionBlob::Vptr ExceptionBlob::_vpntr;
const UncommonTrapBlob::Vptr UncommonTrapBlob::_vpntr;
#endif // COMPILER2
const UpcallStub::Vptr UpcallStub::_vpntr;
@ -324,6 +327,9 @@ RuntimeBlob::RuntimeBlob(
align_up(cb->total_relocation_size(), oopSize))
{
cb->copy_code_and_locs_to(this);
// Flush generated code
ICache::invalidate_range(code_begin(), code_size());
}
void RuntimeBlob::free(RuntimeBlob* blob) {
@ -382,7 +388,7 @@ void RuntimeBlob::trace_new_stub(RuntimeBlob* stub, const char* name1, const cha
// Implementation of BufferBlob
BufferBlob::BufferBlob(const char* name, CodeBlobKind kind, int size, uint16_t header_size)
: RuntimeBlob(name, kind, size, header_size)
: RuntimeBlob(name, kind, size, header_size)
{}
BufferBlob* BufferBlob::create(const char* name, uint buffer_size) {
@ -617,8 +623,8 @@ DeoptimizationBlob::DeoptimizationBlob(
int unpack_with_reexecution_offset,
int frame_size
)
: SingletonBlob("DeoptimizationBlob", CodeBlobKind::Deoptimization, cb,
size, sizeof(DeoptimizationBlob), frame_size, oop_maps)
: SingletonBlob("DeoptimizationBlob", CodeBlobKind::Deoptimization, cb,
size, sizeof(DeoptimizationBlob), frame_size, oop_maps)
{
_unpack_offset = unpack_offset;
_unpack_with_exception = unpack_with_exception_offset;
@ -667,8 +673,8 @@ UncommonTrapBlob::UncommonTrapBlob(
OopMapSet* oop_maps,
int frame_size
)
: SingletonBlob("UncommonTrapBlob", CodeBlobKind::UncommonTrap, cb,
size, sizeof(UncommonTrapBlob), frame_size, oop_maps)
: SingletonBlob("UncommonTrapBlob", CodeBlobKind::UncommonTrap, cb,
size, sizeof(UncommonTrapBlob), frame_size, oop_maps)
{}
@ -699,8 +705,8 @@ ExceptionBlob::ExceptionBlob(
OopMapSet* oop_maps,
int frame_size
)
: SingletonBlob("ExceptionBlob", CodeBlobKind::Exception, cb,
size, sizeof(ExceptionBlob), frame_size, oop_maps)
: SingletonBlob("ExceptionBlob", CodeBlobKind::Exception, cb,
size, sizeof(ExceptionBlob), frame_size, oop_maps)
{}
@ -733,8 +739,8 @@ SafepointBlob::SafepointBlob(
OopMapSet* oop_maps,
int frame_size
)
: SingletonBlob("SafepointBlob", CodeBlobKind::Safepoint, cb,
size, sizeof(SafepointBlob), frame_size, oop_maps)
: SingletonBlob(cb->name(), CodeBlobKind::Safepoint, cb,
size, sizeof(SafepointBlob), frame_size, oop_maps)
{}
@ -751,7 +757,7 @@ SafepointBlob* SafepointBlob::create(
blob = new (size) SafepointBlob(cb, size, oop_maps, frame_size);
}
trace_new_stub(blob, "SafepointBlob");
trace_new_stub(blob, "SafepointBlob - ", blob->name());
return blob;
}
@ -891,7 +897,7 @@ void CodeBlob::dump_for_addr(address addr, outputStream* st, bool verbose) const
}
}
if (is_nmethod()) {
nmethod* nm = (nmethod*)this;
nmethod* nm = as_nmethod();
ResourceMark rm;
st->print(INTPTR_FORMAT " is at entry_point+%d in (nmethod*)" INTPTR_FORMAT,
p2i(addr), (int)(addr - nm->entry_point()), p2i(nm));
@ -927,7 +933,7 @@ void RuntimeStub::print_on_impl(outputStream* st) const {
RuntimeBlob::print_on_impl(st);
st->print("Runtime Stub (" INTPTR_FORMAT "): ", p2i(this));
st->print_cr("%s", name());
Disassembler::decode((RuntimeBlob*)this, st);
Disassembler::decode((CodeBlob*)this, st);
}
void RuntimeStub::print_value_on_impl(outputStream* st) const {
@ -938,7 +944,7 @@ void SingletonBlob::print_on_impl(outputStream* st) const {
ttyLocker ttyl;
RuntimeBlob::print_on_impl(st);
st->print_cr("%s", name());
Disassembler::decode((RuntimeBlob*)this, st);
Disassembler::decode((CodeBlob*)this, st);
}
void SingletonBlob::print_value_on_impl(outputStream* st) const {
@ -956,7 +962,7 @@ void UpcallStub::print_on_impl(outputStream* st) const {
oop recv = JNIHandles::resolve(_receiver);
st->print("Receiver MH=");
recv->print_on(st);
Disassembler::decode((RuntimeBlob*)this, st);
Disassembler::decode((CodeBlob*)this, st);
}
void UpcallStub::print_value_on_impl(outputStream* st) const {

View File

@ -98,7 +98,9 @@ enum class CodeBlobKind : u1 {
class UpcallStub; // for as_upcall_stub()
class RuntimeStub; // for as_runtime_stub()
class JavaFrameAnchor; // for UpcallStub::jfa_for_frame
class BufferBlob;
class AdapterBlob;
class SingletonBlob;
class ExceptionBlob;
class DeoptimizationBlob;
class SafepointBlob;
@ -185,8 +187,19 @@ public:
// Typing
bool is_nmethod() const { return _kind == CodeBlobKind::Nmethod; }
bool is_buffer_blob() const { return _kind == CodeBlobKind::Buffer; }
// we may want to check for an actual buffer blob or subtype instance
bool is_buffer_blob(bool strict=true) const {
if (strict) {
return _kind == CodeBlobKind::Buffer;
} else {
return (_kind == CodeBlobKind::Buffer ||
_kind == CodeBlobKind::Adapter ||
_kind == CodeBlobKind::Vtable ||
_kind == CodeBlobKind::MHAdapter);
}
}
bool is_runtime_stub() const { return _kind == CodeBlobKind::RuntimeStub; }
// singleton blobs are never directly implemented
bool is_deoptimization_stub() const { return _kind == CodeBlobKind::Deoptimization; }
#ifdef COMPILER2
bool is_uncommon_trap_stub() const { return _kind == CodeBlobKind::UncommonTrap; }
@ -196,6 +209,12 @@ public:
bool is_exception_stub() const { return false; }
#endif
bool is_safepoint_stub() const { return _kind == CodeBlobKind::Safepoint; }
bool is_singleton_blob() const {
return (is_deoptimization_stub() ||
is_uncommon_trap_stub() ||
is_exception_stub() ||
is_safepoint_stub());
}
bool is_adapter_blob() const { return _kind == CodeBlobKind::Adapter; }
bool is_vtable_blob() const { return _kind == CodeBlobKind::Vtable; }
bool is_method_handles_adapter_blob() const { return _kind == CodeBlobKind::MHAdapter; }
@ -205,8 +224,12 @@ public:
nmethod* as_nmethod_or_null() const { return is_nmethod() ? (nmethod*) this : nullptr; }
nmethod* as_nmethod() const { assert(is_nmethod(), "must be nmethod"); return (nmethod*) this; }
CodeBlob* as_codeblob() const { return (CodeBlob*) this; }
// we may want to force an actual buffer blob or subtype instance
BufferBlob* as_buffer_blob(bool strict = true) const { assert(is_buffer_blob(), "must be %sbuffer blob", (strict ? "strict " : "")); return (BufferBlob*) this; }
AdapterBlob* as_adapter_blob() const { assert(is_adapter_blob(), "must be adapter blob"); return (AdapterBlob*) this; }
ExceptionBlob* as_exception_blob() const { assert(is_exception_stub(), "must be exception stub"); return (ExceptionBlob*) this; }
// this will always return a subtype instance
SingletonBlob* as_singleton_blob() const { assert(is_singleton_blob(), "must be singleton blob"); return (SingletonBlob*) this; }
DeoptimizationBlob* as_deoptimization_blob() const { assert(is_deoptimization_stub(), "must be deopt stub"); return (DeoptimizationBlob*) this; }
SafepointBlob* as_safepoint_blob() const { assert(is_safepoint_stub(), "must be safepoint stub"); return (SafepointBlob*) this; }
UpcallStub* as_upcall_stub() const { assert(is_upcall_stub(), "must be upcall stub"); return (UpcallStub*) this; }
@ -387,10 +410,10 @@ class BufferBlob: public RuntimeBlob {
class Vptr : public RuntimeBlob::Vptr {
void print_on(const CodeBlob* instance, outputStream* st) const override {
((const BufferBlob*)instance)->print_on_impl(st);
instance->as_buffer_blob(false)->print_on_impl(st);
}
void print_value_on(const CodeBlob* instance, outputStream* st) const override {
((const BufferBlob*)instance)->print_value_on_impl(st);
instance->as_buffer_blob(false)->print_value_on_impl(st);
}
};
@ -486,10 +509,17 @@ class RuntimeStub: public RuntimeBlob {
address entry_point() const { return code_begin(); }
void post_restore_impl() {
trace_new_stub(this, "RuntimeStub - ", name());
}
void print_on_impl(outputStream* st) const;
void print_value_on_impl(outputStream* st) const;
class Vptr : public RuntimeBlob::Vptr {
void post_restore(CodeBlob* instance) const override {
instance->as_runtime_stub()->post_restore_impl();
}
void print_on(const CodeBlob* instance, outputStream* st) const override {
instance->as_runtime_stub()->print_on_impl(st);
}
@ -531,10 +561,10 @@ class SingletonBlob: public RuntimeBlob {
class Vptr : public RuntimeBlob::Vptr {
void print_on(const CodeBlob* instance, outputStream* st) const override {
((const SingletonBlob*)instance)->print_on_impl(st);
instance->as_singleton_blob()->print_on_impl(st);
}
void print_value_on(const CodeBlob* instance, outputStream* st) const override {
((const SingletonBlob*)instance)->print_value_on_impl(st);
instance->as_singleton_blob()->print_value_on_impl(st);
}
};
@ -605,20 +635,28 @@ class DeoptimizationBlob: public SingletonBlob {
_uncommon_trap_offset = offset;
assert(contains(code_begin() + _uncommon_trap_offset), "must be PC inside codeblob");
}
address uncommon_trap() const { return code_begin() + _uncommon_trap_offset; }
address uncommon_trap() const { return (EnableJVMCI ? code_begin() + _uncommon_trap_offset : nullptr); }
void set_implicit_exception_uncommon_trap_offset(int offset) {
_implicit_exception_uncommon_trap_offset = offset;
assert(contains(code_begin() + _implicit_exception_uncommon_trap_offset), "must be PC inside codeblob");
}
address implicit_exception_uncommon_trap() const { return code_begin() + _implicit_exception_uncommon_trap_offset; }
address implicit_exception_uncommon_trap() const { return (EnableJVMCI ? code_begin() + _implicit_exception_uncommon_trap_offset : nullptr); }
#endif // INCLUDE_JVMCI
void post_restore_impl() {
trace_new_stub(this, "DeoptimizationBlob");
}
void print_value_on_impl(outputStream* st) const;
class Vptr : public SingletonBlob::Vptr {
void post_restore(CodeBlob* instance) const override {
instance->as_deoptimization_blob()->post_restore_impl();
}
void print_value_on(const CodeBlob* instance, outputStream* st) const override {
((const DeoptimizationBlob*)instance)->print_value_on_impl(st);
instance->as_deoptimization_blob()->print_value_on_impl(st);
}
};
@ -648,6 +686,16 @@ class UncommonTrapBlob: public SingletonBlob {
OopMapSet* oop_maps,
int frame_size
);
void post_restore_impl() {
trace_new_stub(this, "UncommonTrapBlob");
}
class Vptr : public SingletonBlob::Vptr {
void post_restore(CodeBlob* instance) const override {
instance->as_uncommon_trap_blob()->post_restore_impl();
}
};
static const Vptr _vpntr;
};
@ -678,7 +726,7 @@ class ExceptionBlob: public SingletonBlob {
class Vptr : public SingletonBlob::Vptr {
void post_restore(CodeBlob* instance) const override {
((ExceptionBlob*)instance)->post_restore_impl();
instance->as_exception_blob()->post_restore_impl();
}
};
@ -708,6 +756,17 @@ class SafepointBlob: public SingletonBlob {
OopMapSet* oop_maps,
int frame_size
);
void post_restore_impl() {
trace_new_stub(this, "SafepointBlob - ", name());
}
class Vptr : public SingletonBlob::Vptr {
void post_restore(CodeBlob* instance) const override {
instance->as_safepoint_blob()->post_restore_impl();
}
};
static const Vptr _vpntr;
};
//----------------------------------------------------------------------------------------------------

View File

@ -66,6 +66,7 @@
#include "runtime/flags/flagSetting.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/icache.hpp"
#include "runtime/jniHandles.inline.hpp"
#include "runtime/orderAccess.hpp"
#include "runtime/os.hpp"
@ -1253,6 +1254,9 @@ void nmethod::post_init() {
finalize_relocations();
// Flush generated code
ICache::invalidate_range(code_begin(), code_size());
Universe::heap()->register_nmethod(this);
DEBUG_ONLY(Universe::heap()->verify_nmethod(this));
@ -1584,8 +1588,6 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) {
// Attempt to start using the copy
if (nm_copy->make_in_use()) {
ICache::invalidate_range(nm_copy->code_begin(), nm_copy->code_size());
methodHandle mh(Thread::current(), nm_copy->method());
nm_copy->method()->set_code(mh, nm_copy);

View File

@ -121,10 +121,11 @@ void ShenandoahGenerationalControlThread::check_for_request(ShenandoahGCRequest&
assert(request.generation != nullptr, "Must know which generation to use for degenerated cycle");
}
} else {
if (request.cause == GCCause::_shenandoah_concurrent_gc) {
// This is a regulator request. It is also possible that the regulator "canceled" an old mark,
// so we can clear that here. This clear operation will only clear the cancellation if it is
// a regulator request.
if (request.cause == GCCause::_shenandoah_concurrent_gc || ShenandoahCollectorPolicy::is_explicit_gc(request.cause)) {
// This is a regulator request or an explicit gc request. Note that an explicit gc request is allowed to
// "upgrade" a regulator request. It is possible that the regulator "canceled" an old mark, so we must
// clear that cancellation here or the explicit gc cycle will erroneously detect it as a cancellation.
// This clear operation will only clear the cancellation if it was set by regulator request.
_heap->clear_cancellation(GCCause::_shenandoah_concurrent_gc);
}
request.generation = _requested_generation;

View File

@ -52,9 +52,9 @@ class BytecodePrinter {
Bytecodes::Code _code;
address _next_pc; // current decoding position
int _flags;
bool _is_linked;
bool _use_cp_cache;
bool is_linked() const { return _is_linked; }
bool use_cp_cache() const { return _use_cp_cache; }
void align() { _next_pc = align_up(_next_pc, sizeof(jint)); }
int get_byte() { return *(jbyte*) _next_pc++; } // signed
int get_index_u1() { return *(address)_next_pc++; } // returns 0x00 - 0xff as an int
@ -69,7 +69,7 @@ class BytecodePrinter {
bool is_wide() const { return _is_wide; }
Bytecodes::Code raw_code() const { return Bytecodes::Code(_code); }
ConstantPool* constants() const { return method()->constants(); }
ConstantPoolCache* cpcache() const { assert(is_linked(), "must be"); return constants()->cache(); }
ConstantPoolCache* cpcache() const { assert(use_cp_cache(), "must be"); return constants()->cache(); }
void print_constant(int i, outputStream* st);
void print_cpcache_entry(int cpc_index, outputStream* st);
@ -94,8 +94,9 @@ class BytecodePrinter {
ResourceMark rm;
bool method_changed = _current_method != method();
_current_method = method();
_is_linked = method->method_holder()->is_linked();
assert(_is_linked, "this function must be called on methods that are already executing");
_use_cp_cache = method->constants()->cache() != nullptr;
assert(method->method_holder()->is_linked(),
"this function must be called on methods that are already executing");
if (method_changed) {
// Note 1: This code will not work as expected with true MT/MP.
@ -150,7 +151,8 @@ class BytecodePrinter {
// BytecodeStream, which will skip wide bytecodes.
void trace(const methodHandle& method, address bcp, outputStream* st) {
_current_method = method();
_is_linked = method->method_holder()->is_linked();
// This may be called during linking after bytecodes are rewritten to point to the cpCache.
_use_cp_cache = method->constants()->cache() != nullptr;
ResourceMark rm;
Bytecodes::Code code = Bytecodes::code_at(method(), bcp);
// Set is_wide
@ -301,7 +303,7 @@ void BytecodePrinter::print_invokedynamic(int indy_index, int cp_index, outputSt
if (ClassPrinter::has_mode(_flags, ClassPrinter::PRINT_DYNAMIC)) {
print_bsm(cp_index, st);
if (is_linked()) {
if (use_cp_cache()) {
ResolvedIndyEntry* indy_entry = constants()->resolved_indy_entry_at(indy_index);
st->print(" ResolvedIndyEntry: ");
indy_entry->print_on(st);
@ -365,7 +367,7 @@ void BytecodePrinter::print_attributes(int bci, outputStream* st) {
{
int cp_index;
if (Bytecodes::uses_cp_cache(raw_code())) {
assert(is_linked(), "fast ldc bytecode must be in linked classes");
assert(use_cp_cache(), "fast ldc bytecode must be in linked classes");
int obj_index = get_index_u1();
cp_index = constants()->object_to_cp_index(obj_index);
} else {
@ -380,7 +382,7 @@ void BytecodePrinter::print_attributes(int bci, outputStream* st) {
{
int cp_index;
if (Bytecodes::uses_cp_cache(raw_code())) {
assert(is_linked(), "fast ldc bytecode must be in linked classes");
assert(use_cp_cache(), "fast ldc bytecode must be in linked classes");
int obj_index = get_native_index_u2();
cp_index = constants()->object_to_cp_index(obj_index);
} else {
@ -510,7 +512,7 @@ void BytecodePrinter::print_attributes(int bci, outputStream* st) {
case Bytecodes::_getfield:
{
int cp_index;
if (is_linked()) {
if (use_cp_cache()) {
int field_index = get_native_index_u2();
cp_index = cpcache()->resolved_field_entry_at(field_index)->constant_pool_index();
} else {
@ -525,7 +527,7 @@ void BytecodePrinter::print_attributes(int bci, outputStream* st) {
case Bytecodes::_invokestatic:
{
int cp_index;
if (is_linked()) {
if (use_cp_cache()) {
int method_index = get_native_index_u2();
ResolvedMethodEntry* method_entry = cpcache()->resolved_method_entry_at(method_index);
cp_index = method_entry->constant_pool_index();
@ -533,7 +535,7 @@ void BytecodePrinter::print_attributes(int bci, outputStream* st) {
if (raw_code() == Bytecodes::_invokehandle &&
ClassPrinter::has_mode(_flags, ClassPrinter::PRINT_METHOD_HANDLE)) {
assert(is_linked(), "invokehandle is only in rewritten methods");
assert(use_cp_cache(), "invokehandle is only in rewritten methods");
method_entry->print_on(st);
if (method_entry->has_appendix()) {
st->print(" appendix: ");
@ -550,7 +552,7 @@ void BytecodePrinter::print_attributes(int bci, outputStream* st) {
case Bytecodes::_invokeinterface:
{
int cp_index;
if (is_linked()) {
if (use_cp_cache()) {
int method_index = get_native_index_u2();
cp_index = cpcache()->resolved_method_entry_at(method_index)->constant_pool_index();
} else {
@ -566,7 +568,7 @@ void BytecodePrinter::print_attributes(int bci, outputStream* st) {
{
int indy_index;
int cp_index;
if (is_linked()) {
if (use_cp_cache()) {
indy_index = get_native_index_u4();
cp_index = constants()->resolved_indy_entry_at(indy_index)->constant_pool_index();
} else {

View File

@ -410,6 +410,15 @@ JVM_ENTRY_NO_ENV(jlong, jfr_host_total_swap_memory(JNIEnv* env, jclass jvm))
return static_cast<jlong>(total_swap_space);
JVM_END
JVM_ENTRY_NO_ENV(jlong, jfr_host_memory_usage(JNIEnv* env, jclass jvm))
physical_memory_size_type memory_usage = 0;
if (!os::Machine::used_memory(memory_usage)) {
// Return -1 to signal failure to get memory usage.
return static_cast<jlong>(-1);
}
return static_cast<jlong>(memory_usage);
JVM_END
JVM_ENTRY_NO_ENV(void, jfr_emit_data_loss(JNIEnv* env, jclass jvm, jlong bytes))
EventDataLoss::commit(bytes, min_jlong);
JVM_END

View File

@ -163,6 +163,8 @@ jlong JNICALL jfr_host_total_memory(JNIEnv* env, jclass jvm);
jlong JNICALL jfr_host_total_swap_memory(JNIEnv* env, jclass jvm);
jlong JNICALL jfr_host_memory_usage(JNIEnv* env, jclass jvm);
void JNICALL jfr_emit_data_loss(JNIEnv* env, jclass jvm, jlong bytes);
jlong JNICALL jfr_register_stack_filter(JNIEnv* env, jclass jvm, jobjectArray classes, jobjectArray methods);

View File

@ -101,6 +101,7 @@ JfrJniMethodRegistration::JfrJniMethodRegistration(JNIEnv* env) {
(char*)"isContainerized", (char*)"()Z", (void*) jfr_is_containerized,
(char*)"hostTotalMemory", (char*)"()J", (void*) jfr_host_total_memory,
(char*)"hostTotalSwapMemory", (char*)"()J", (void*) jfr_host_total_swap_memory,
(char*)"hostMemoryUsage", (char*)"()J", (void*) jfr_host_memory_usage,
(char*)"emitDataLoss", (char*)"(J)V", (void*)jfr_emit_data_loss,
(char*)"registerStackFilter", (char*)"([Ljava/lang/String;[Ljava/lang/String;)J", (void*)jfr_register_stack_filter,
(char*)"unregisterStackFilter", (char*)"(J)V", (void*)jfr_unregister_stack_filter,

View File

@ -2500,7 +2500,9 @@ static bool can_subword_truncate(Node* in, const Type* type) {
switch (opc) {
case Op_AbsI:
case Op_DivI:
case Op_UDivI:
case Op_ModI:
case Op_UModI:
case Op_MinI:
case Op_MaxI:
case Op_CMoveI:

View File

@ -1026,12 +1026,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
return;
}
// Normalize
while ((significand & 1) == 0) { // i.e., significand is even
significand >>= 1;
exponent++;
}
int scl = 0;
int nTrailingZeros = Long.numberOfTrailingZeros(significand);
significand >>= nTrailingZeros;
exponent += nTrailingZeros;
// Calculate intVal and scale
int scl = 0;
BigInteger rb;
long compactVal = sign * significand;
if (exponent == 0) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
@ -27,6 +27,7 @@ package jdk.internal.misc;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Objects;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
@ -88,21 +89,27 @@ public class MethodFinder {
mainMethod = JLA.findMethod(cls, false, "main", String[].class);
}
if (mainMethod == null || !isValidMainMethod(mainMethod)) {
if (mainMethod == null || !isValidMainMethod(cls, mainMethod)) {
mainMethod = JLA.findMethod(cls, false, "main");
}
if (mainMethod == null || !isValidMainMethod(mainMethod)) {
if (mainMethod == null || !isValidMainMethod(cls, mainMethod)) {
return null;
}
return mainMethod;
}
private static boolean isValidMainMethod(Method mainMethodCandidate) {
private static boolean isValidMainMethod(Class<?> initialClass, Method mainMethodCandidate) {
return mainMethodCandidate.getReturnType() == void.class &&
!Modifier.isPrivate(mainMethodCandidate.getModifiers());
!Modifier.isPrivate(mainMethodCandidate.getModifiers()) &&
(Modifier.isPublic(mainMethodCandidate.getModifiers()) ||
Modifier.isProtected(mainMethodCandidate.getModifiers()) ||
isInSameRuntimePackage(initialClass, mainMethodCandidate.getDeclaringClass()));
}
private static boolean isInSameRuntimePackage(Class<?> c1, Class<?> c2) {
return Objects.equals(c1.getPackageName(), c2.getPackageName()) &&
c1.getClassLoader() == c2.getClassLoader();
}
}

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
@ -112,9 +112,10 @@ public class X509Factory extends CertificateFactorySpi {
if (cert != null) {
return cert;
}
cert = new X509CertImpl(encoding);
addToCache(certCache, cert.getEncodedInternal(), cert);
return cert;
// Build outside lock
X509CertImpl newCert = new X509CertImpl(encoding);
byte[] enc = newCert.getEncodedInternal();
return addIfNotPresent(certCache, enc, newCert);
}
/**
@ -156,7 +157,7 @@ public class X509Factory extends CertificateFactorySpi {
* @throws CertificateException if failures occur while obtaining the DER
* encoding for certificate data.
*/
public static synchronized X509CertImpl intern(X509Certificate c)
public static X509CertImpl intern(X509Certificate c)
throws CertificateException {
if (c == null) {
return null;
@ -168,18 +169,23 @@ public class X509Factory extends CertificateFactorySpi {
} else {
encoding = c.getEncoded();
}
X509CertImpl newC = getFromCache(certCache, encoding);
if (newC != null) {
return newC;
// First check under per-cache lock
X509CertImpl cached = getFromCache(certCache, encoding);
if (cached != null) {
return cached;
}
// Build outside lock
X509CertImpl newC;
byte[] enc;
if (isImpl) {
newC = (X509CertImpl)c;
newC = (X509CertImpl) c;
enc = encoding;
} else {
newC = new X509CertImpl(encoding);
encoding = newC.getEncodedInternal();
enc = newC.getEncodedInternal();
}
addToCache(certCache, encoding, newC);
return newC;
return addIfNotPresent(certCache, enc, newC);
}
/**
@ -192,7 +198,7 @@ public class X509Factory extends CertificateFactorySpi {
* @throws CRLException if failures occur while obtaining the DER
* encoding for CRL data.
*/
public static synchronized X509CRLImpl intern(X509CRL c)
public static X509CRLImpl intern(X509CRL c)
throws CRLException {
if (c == null) {
return null;
@ -204,39 +210,47 @@ public class X509Factory extends CertificateFactorySpi {
} else {
encoding = c.getEncoded();
}
X509CRLImpl newC = getFromCache(crlCache, encoding);
if (newC != null) {
return newC;
X509CRLImpl cached = getFromCache(crlCache, encoding);
if (cached != null) {
return cached;
}
X509CRLImpl newC;
byte[] enc;
if (isImpl) {
newC = (X509CRLImpl)c;
newC = (X509CRLImpl) c;
enc = encoding;
} else {
newC = new X509CRLImpl(encoding);
encoding = newC.getEncodedInternal();
enc = newC.getEncodedInternal();
}
addToCache(crlCache, encoding, newC);
return newC;
return addIfNotPresent(crlCache, enc, newC);
}
/**
* Get the X509CertImpl or X509CRLImpl from the cache.
*/
private static synchronized <K,V> V getFromCache(Cache<K,V> cache,
byte[] encoding) {
Object key = new Cache.EqualByteArray(encoding);
return cache.get(key);
private static <V> V getFromCache(Cache<Object, V> cache, byte[] encoding) {
return cache.get(new Cache.EqualByteArray(encoding));
}
/**
* Add the X509CertImpl or X509CRLImpl to the cache.
*/
private static synchronized <V> void addToCache(Cache<Object, V> cache,
byte[] encoding, V value) {
private static <V> V addIfNotPresent(Cache<Object, V> cache, byte[] encoding, V value) {
if (encoding.length > ENC_MAX_LENGTH) {
return;
return value;
}
Object key = new Cache.EqualByteArray(encoding);
cache.put(key, value);
// Synchronize only to make the "check + insert" decision atomic.
synchronized (cache) {
V existing = cache.get(key);
if (existing != null) {
return existing;
}
cache.put(key, value);
return value;
}
}
/**
@ -389,13 +403,14 @@ public class X509Factory extends CertificateFactorySpi {
try {
byte[] encoding = readOneBlock(is);
if (encoding != null) {
X509CRLImpl crl = getFromCache(crlCache, encoding);
if (crl != null) {
return crl;
X509CRLImpl cached = getFromCache(crlCache, encoding);
if (cached != null) {
return cached;
}
crl = new X509CRLImpl(encoding);
addToCache(crlCache, crl.getEncodedInternal(), crl);
return crl;
// Build outside lock
X509CRLImpl crl = new X509CRLImpl(encoding);
byte[] enc = crl.getEncodedInternal();
return addIfNotPresent(crlCache, enc, crl);
} else {
throw new IOException("Empty input");
}

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.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -82,8 +82,7 @@ final class ProcessImpl extends Process {
private static enum LaunchMechanism {
// order IS important!
FORK,
POSIX_SPAWN,
VFORK
POSIX_SPAWN
}
/**
@ -98,29 +97,16 @@ final class ProcessImpl extends Process {
try {
// Should be value of a LaunchMechanism enum
LaunchMechanism lm = LaunchMechanism.valueOf(s.toUpperCase(Locale.ROOT));
switch (OperatingSystem.current()) {
case LINUX: {
// All options are valid for Linux, but VFORK is deprecated and results
// in a warning
if (lm == LaunchMechanism.VFORK) {
System.err.println("VFORK MODE DEPRECATED");
System.err.println("""
The VFORK launch mechanism has been deprecated for being dangerous.
It will be removed in a future java version. Either remove the
jdk.lang.Process.launchMechanism property (preferred) or use FORK mode
instead (-Djdk.lang.Process.launchMechanism=FORK).
""");
}
return lm;
}
case AIX:
case MACOS:
if (lm != LaunchMechanism.VFORK) {
return lm; // All but VFORK are valid
}
break;
String launchMechanism = s.toUpperCase(Locale.ROOT);
if (launchMechanism.equals("VFORK") && OperatingSystem.isLinux()) {
launchMechanism = "FORK";
System.err.println(String.format("""
The VFORK launch mechanism has been removed. Switching to %s instead.
Please remove the jdk.lang.Process.launchMechanism property (preferred)
or use FORK mode instead (-Djdk.lang.Process.launchMechanism=FORK).%n
""", launchMechanism));
}
return LaunchMechanism.valueOf(launchMechanism);
} catch (IllegalArgumentException e) {
}
@ -266,7 +252,6 @@ final class ProcessImpl extends Process {
* <pre>
* 1 - fork(2) and exec(2)
* 2 - posix_spawn(3P)
* 3 - vfork(2) and exec(2)
* </pre>
* @param fds an array of three file descriptors.
* Indexes 0, 1, and 2 correspond to standard input,

View File

@ -60,51 +60,33 @@
* changing paths...
* - then exec(2) the target binary
*
* There are three ways to fork off:
* On the OS-side are three ways to fork off, but we only use two of them:
*
* A) fork(2). Portable and safe (no side effects) but may fail with ENOMEM on
* all Unices when invoked from a VM with a high memory footprint. On Unices
* with strict no-overcommit policy this problem is most visible.
* A) fork(2). Portable and safe (no side effects) but could fail on very ancient
* Unices that don't employ COW on fork(2). The modern platforms we support
* (Linux, MacOS, AIX) all do. It may have a small performance penalty compared
* to modern posix_spawn(3) implementations - see below.
* fork(2) can be used by specifying -Djdk.lang.Process.launchMechanism=FORK when starting
* the (parent process) JVM.
*
* This is because forking the VM will first create a child process with
* theoretically the same memory footprint as the parent - even if you plan
* to follow up with exec'ing a tiny binary. In reality techniques like
* copy-on-write etc mitigate the problem somewhat but we still run the risk
* of hitting system limits.
* B) vfork(2): Portable and fast but very unsafe. For details, see JDK-8357090.
* We supported this mode in older releases but removed support for it in JDK 27.
* Modern posix_spawn(3) implementations use techniques similar to vfork(2), but
* in a much safer way
*
* For a Linux centric description of this problem, see the documentation on
* /proc/sys/vm/overcommit_memory in Linux proc(5).
*
* B) vfork(2): Portable and fast but very unsafe. It bypasses the memory
* problems related to fork(2) by starting the child in the memory image of
* the parent. Things that can go wrong include:
* - Programming errors in the child process before the exec(2) call may
* trash memory in the parent process, most commonly the stack of the
* thread invoking vfork.
* - Signals received by the child before the exec(2) call may be at best
* misdirected to the parent, at worst immediately kill child and parent.
*
* This is mitigated by very strict rules about what one is allowed to do in
* the child process between vfork(2) and exec(2), which is basically nothing.
* However, we always broke this rule by doing the pre-exec work between
* vfork(2) and exec(2).
*
* Also note that vfork(2) has been deprecated by the OpenGroup, presumably
* because of its many dangers.
*
* C) clone(2): This is a Linux specific call which gives the caller fine
* grained control about how exactly the process fork is executed. It is
* powerful, but Linux-specific.
*
* Aside from these three possibilities there is a forth option: posix_spawn(3).
* Where fork/vfork/clone all fork off the process and leave pre-exec work and
* calling exec(2) to the user, posix_spawn(3) offers the user fork+exec-like
* functionality in one package, similar to CreateProcess() on Windows.
*
* It is not a system call in itself, but usually a wrapper implemented within
* the libc in terms of one of (fork|vfork|clone)+exec - so whether or not it
* has advantages over calling the naked (fork|vfork|clone) functions depends
* on how posix_spawn(3) is implemented.
* C) posix_spawn(3): Where fork/vfork/clone all fork off the process and leave
* pre-exec work and calling exec(2) to the user, posix_spawn(3) offers the user
* fork+exec-like functionality in one package, similar to CreateProcess() on Windows.
* It is not a system call, but a wrapper implemented in user-space libc in terms
* of one of (fork|vfork|clone)+exec - so whether or not it has advantages over calling
* the naked (fork|vfork|clone) functions depends on how posix_spawn(3) is implemented.
* Modern posix_spawn(3) implementations, on Linux, use clone(2) with CLONE_VM | CLONE_VFORK,
* giving us the best ratio between performance and safety.
* Note however, that posix_spawn(3) can be buggy, depending on the libc implementation.
* E.g., on MacOS, it is still fully not POSIX-compliant. Therefore, we need to retain the
* FORK mode as a backup.
* Posix_spawn mode is used by default, but can be explicitly enabled using
* -Djdk.lang.Process.launchMechanism=POSIX_SPAWN when starting the (parent process) JVM.
*
* Note that when using posix_spawn(3), we exec twice: first a tiny binary called
* the jspawnhelper, then in the jspawnhelper we do the pre-exec work and exec a
@ -117,58 +99,14 @@
* --- Linux-specific ---
*
* How does glibc implement posix_spawn?
* (see: sysdeps/posix/spawni.c for glibc < 2.24,
* sysdeps/unix/sysv/linux/spawni.c for glibc >= 2.24):
*
* 1) Before glibc 2.4 (released 2006), posix_spawn(3) used just fork(2)/exec(2).
* This would be bad for the JDK since we would risk the known memory issues with
* fork(2). But since this only affects glibc variants which have long been
* phased out by modern distributions, this is irrelevant.
* Before glibc 2.4 (released 2006), posix_spawn(3) used just fork(2)/exec(2). From
* glibc 2.4 up to and including 2.23, it used either fork(2) or vfork(2). None of these
* versions still matter.
*
* 2) Between glibc 2.4 and glibc 2.23, posix_spawn uses either fork(2) or
* vfork(2) depending on how exactly the user called posix_spawn(3):
*
* <quote>
* The child process is created using vfork(2) instead of fork(2) when
* either of the following is true:
*
* * the spawn-flags element of the attributes object pointed to by
* attrp contains the GNU-specific flag POSIX_SPAWN_USEVFORK; or
*
* * file_actions is NULL and the spawn-flags element of the attributes
* object pointed to by attrp does not contain
* POSIX_SPAWN_SETSIGMASK, POSIX_SPAWN_SETSIGDEF,
* POSIX_SPAWN_SETSCHEDPARAM, POSIX_SPAWN_SETSCHEDULER,
* POSIX_SPAWN_SETPGROUP, or POSIX_SPAWN_RESETIDS.
* </quote>
*
* Due to the way the JDK calls posix_spawn(3), it would therefore call vfork(2).
* So we would avoid the fork(2) memory problems. However, there still remains the
* risk associated with vfork(2). But it is smaller than were we to call vfork(2)
* directly since we use the jspawnhelper, moving all pre-exec work off to after
* the first exec, thereby reducing the vulnerable time window.
*
* 3) Since glibc >= 2.24, glibc uses clone+exec:
*
* new_pid = CLONE (__spawni_child, STACK (stack, stack_size), stack_size,
* CLONE_VM | CLONE_VFORK | SIGCHLD, &args);
*
* This is even better than (2):
*
* CLONE_VM means we run in the parent's memory image, as with (2)
* CLONE_VFORK means parent waits until we exec, as with (2)
*
* However, error possibilities are further reduced since:
* - posix_spawn(3) passes a separate stack for the child to run on, eliminating
* the danger of trashing the forking thread's stack in the parent process.
* - posix_spawn(3) takes care to temporarily block all incoming signals to the
* child process until the first exec(2) has been called,
*
* TL;DR
* Calling posix_spawn(3) for glibc
* (2) < 2.24 is not perfect but still better than using plain vfork(2), since
* the chance of an error happening is greatly reduced
* (3) >= 2.24 is the best option - portable, fast and as safe as possible.
* Since glibc >= 2.24, glibc uses clone+exec with CLONE_VM | CLONE_VFORK to emulate vfork
* performance but without the inherent dangers (we run inside the parent's memory image
* and stop the parent for as long as it takes the child process to exec).
*
* ---
*
@ -180,7 +118,6 @@
*
* </Linux-specific>
*
*
* Based on the above analysis, we are currently defaulting to posix_spawn()
* on all Unices including Linux.
*/
@ -489,28 +426,6 @@ static int copystrings(char *buf, int offset, const char * const *arg) {
__attribute_noinline__
#endif
/* vfork(2) is deprecated on Darwin */
#ifndef __APPLE__
static pid_t
vforkChild(ChildStuff *c) {
volatile pid_t resultPid;
/*
* We separate the call to vfork into a separate function to make
* very sure to keep stack of child from corrupting stack of parent,
* as suggested by the scary gcc warning:
* warning: variable 'foo' might be clobbered by 'longjmp' or 'vfork'
*/
resultPid = vfork();
if (resultPid == 0) {
childProcess(c);
}
assert(resultPid != 0); /* childProcess never returns */
return resultPid;
}
#endif
static pid_t
forkChild(ChildStuff *c) {
pid_t resultPid;
@ -734,11 +649,6 @@ spawnChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath)
static pid_t
startChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) {
switch (c->mode) {
/* vfork(2) is deprecated on Darwin*/
#ifndef __APPLE__
case MODE_VFORK:
return vforkChild(c);
#endif
case MODE_FORK:
return forkChild(c);
case MODE_POSIX_SPAWN:
@ -872,9 +782,6 @@ Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env,
if (resultPid < 0) {
char * failMessage = "unknown";
switch (c->mode) {
case MODE_VFORK:
failMessage = "vfork failed";
break;
case MODE_FORK:
failMessage = "fork failed";
break;

View File

@ -271,31 +271,6 @@ initVectorFromBlock(const char**vector, const char* block, int count)
vector[count] = NULL;
}
/**
* Exec FILE as a traditional Bourne shell script (i.e. one without #!).
* If we could do it over again, we would probably not support such an ancient
* misfeature, but compatibility wins over sanity. The original support for
* this was imported accidentally from execvp().
*/
static void
execve_as_traditional_shell_script(const char *file,
const char *argv[],
const char *const envp[])
{
/* Use the extra word of space provided for us in argv by caller. */
const char *argv0 = argv[0];
const char *const *end = argv;
while (*end != NULL)
++end;
memmove(argv+2, argv+1, (end-argv) * sizeof(*end));
argv[0] = "/bin/sh";
argv[1] = file;
execve(argv[0], (char **) argv, (char **) envp);
/* Can't even exec /bin/sh? Big trouble, but let's soldier on... */
memmove(argv+1, argv+2, (end-argv) * sizeof(*end));
argv[0] = argv0;
}
/**
* Like execve(2), except that in case of ENOEXEC, FILE is assumed to
* be a shell script and the system default shell is invoked to run it.
@ -305,16 +280,9 @@ execve_with_shell_fallback(int mode, const char *file,
const char *argv[],
const char *const envp[])
{
if (mode == MODE_VFORK) {
/* shared address space; be very careful. */
execve(file, (char **) argv, (char **) envp);
if (errno == ENOEXEC)
execve_as_traditional_shell_script(file, argv, envp);
} else {
/* unshared address space; we can mutate environ. */
environ = (char **) envp;
execvp(file, (char **) argv);
}
/* unshared address space; we can mutate environ. */
environ = (char **) envp;
execvp(file, (char **) argv);
}
/**
@ -430,7 +398,7 @@ childProcess(void *arg)
#endif
/* File descriptor setup for non-Posix-spawn mode */
if (p->mode != MODE_POSIX_SPAWN) {
if (p->mode == MODE_FORK) {
/* Close the parent sides of the pipes.
Closing pipe fds here is redundant, since markDescriptorsCloseOnExec()
@ -482,7 +450,7 @@ childProcess(void *arg)
/* We moved the fail pipe fd */
fail_pipe_fd = FAIL_FILENO;
} /* end: FORK/VFORK mode */
} /* end: FORK mode */
assert(fail_pipe_fd == FAIL_FILENO);
@ -508,12 +476,10 @@ childProcess(void *arg)
goto WhyCantJohnnyExec;
}
// Reset any mask signals from parent, but not in VFORK mode
if (p->mode != MODE_VFORK) {
sigset_t unblock_signals;
sigemptyset(&unblock_signals);
sigprocmask(SIG_SETMASK, &unblock_signals, NULL);
}
// Reset any mask signals from parent
sigset_t unblock_signals;
sigemptyset(&unblock_signals);
sigprocmask(SIG_SETMASK, &unblock_signals, NULL);
// Children should be started with default signal disposition for SIGPIPE
if (signal(SIGPIPE, SIG_DFL) == SIG_ERR) {

View File

@ -81,7 +81,6 @@ extern char **environ;
*/
#define MODE_FORK 1
#define MODE_POSIX_SPAWN 2
#define MODE_VFORK 3
typedef struct _ChildStuff
{

View File

@ -1,87 +0,0 @@
/*
* 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include <stdio.h>
#include <string.h>
#include <sys/ldr.h>
#include <errno.h>
#include "porting_aix.h"
static unsigned char dladdr_buffer[0x8000];
static void fill_dll_info(void) {
int rc = loadquery(L_GETINFO,dladdr_buffer, sizeof(dladdr_buffer));
if (rc == -1) {
fprintf(stderr, "loadquery failed (%d %s)", errno, strerror(errno));
fflush(stderr);
}
}
static int dladdr_dont_reload(void* addr, Dl_info* info) {
const struct ld_info* p = (struct ld_info*) dladdr_buffer;
memset((void *)info, 0, sizeof(Dl_info));
for (;;) {
if (addr >= p->ldinfo_textorg &&
(char*)addr < (char*)(p->ldinfo_textorg) + p->ldinfo_textsize) {
info->dli_fname = p->ldinfo_filename;
return 1;
}
if (!p->ldinfo_next) {
break;
}
p = (struct ld_info*)(((char*)p) + p->ldinfo_next);
}
return 0;
}
#ifdef __cplusplus
extern "C"
#endif
int dladdr(void *addr, Dl_info *info) {
static int loaded = 0;
if (!loaded) {
fill_dll_info();
loaded = 1;
}
if (!addr) {
return 0;
}
/* Address could be AIX function descriptor? */
void* const addr0 = *( (void**) addr );
int rc = dladdr_dont_reload(addr, info);
if (rc == 0) {
rc = dladdr_dont_reload(addr0, info);
if (rc == 0) {
fill_dll_info(); /* refill, maybe loadquery info is outdated */
rc = dladdr_dont_reload(addr, info);
if (rc == 0) {
rc = dladdr_dont_reload(addr0, info);
}
}
}
return rc;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 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
@ -36,6 +36,18 @@
return NSAccessibilityCheckBoxRole;
}
- (NSAccessibilitySubrole _Nullable)accessibilitySubrole
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
if (env != NULL) {
NSString *javaRole = [self javaRole];
if ([javaRole isEqualToString:@"togglebutton"]) {
return NSAccessibilityToggleSubrole;
}
}
return [super accessibilitySubrole];
}
- (id _Nonnull) accessibilityValue
{
AWT_ASSERT_APPKIT_THREAD;

View File

@ -136,6 +136,7 @@ static jobject sAccessibilityClass = NULL;
[rolesMap setObject:@"StaticTextAccessibility" forKey:@"label"];
[rolesMap setObject:@"RadiobuttonAccessibility" forKey:@"radiobutton"];
[rolesMap setObject:@"CheckboxAccessibility" forKey:@"checkbox"];
[rolesMap setObject:@"CheckboxAccessibility" forKey:@"togglebutton"];
[rolesMap setObject:@"SliderAccessibility" forKey:@"slider"];
[rolesMap setObject:@"ScrollAreaAccessibility" forKey:@"scrollpane"];
[rolesMap setObject:@"ScrollBarAccessibility" forKey:@"scrollbar"];

View File

@ -537,6 +537,10 @@ public class MotifLookAndFeel extends BasicLookAndFeel
@SuppressWarnings("deprecation")
final int metaMask = KeyEvent.META_MASK;
Object commonInputMap = new UIDefaults.LazyInputMap(new Object[] {
"SPACE", "pressed",
"released SPACE", "released"
});
Object[] defaults = {
"Desktop.background", table.get("desktop"),
@ -593,20 +597,13 @@ public class MotifLookAndFeel extends BasicLookAndFeel
"Button.foreground", table.get("controlText"),
"Button.select", table.get("controlLightShadow"),
"Button.font", dialogPlain12,
"Button.focusInputMap", new UIDefaults.LazyInputMap(new Object[] {
"SPACE", "pressed",
"released SPACE", "released"
}),
"Button.focusInputMap", commonInputMap,
"CheckBox.textIconGap", 8,
"CheckBox.margin", new InsetsUIResource(4, 2, 4, 2),
"CheckBox.icon", checkBoxIcon,
"CheckBox.focus", table.get("activeCaptionBorder"),
"CheckBox.focusInputMap",
new UIDefaults.LazyInputMap(new Object[] {
"SPACE", "pressed",
"released SPACE", "released"
}),
"CheckBox.focusInputMap", commonInputMap,
"RadioButton.margin", new InsetsUIResource(4, 2, 4, 2),
"RadioButton.textIconGap", 8,
@ -615,22 +612,14 @@ public class MotifLookAndFeel extends BasicLookAndFeel
"RadioButton.icon", radioButtonIcon,
"RadioButton.focus", table.get("activeCaptionBorder"),
"RadioButton.icon", radioButtonIcon,
"RadioButton.focusInputMap",
new UIDefaults.LazyInputMap(new Object[] {
"SPACE", "pressed",
"released SPACE", "released"
}),
"RadioButton.focusInputMap", commonInputMap,
"ToggleButton.border", toggleButtonBorder,
"ToggleButton.background", table.get("control"),
"ToggleButton.foreground", table.get("controlText"),
"ToggleButton.focus", table.get("controlText"),
"ToggleButton.select", table.get("controlLightShadow"),
"ToggleButton.focusInputMap",
new UIDefaults.LazyInputMap(new Object[] {
"SPACE", "pressed",
"released SPACE", "released"
}),
"ToggleButton.focusInputMap", commonInputMap,
// Menus
"Menu.border", menuMarginBorder,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2020, 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
@ -34,7 +34,6 @@ import java.beans.PropertyChangeSupport;
import java.util.Locale;
import sun.awt.AWTAccessor;
import sun.awt.AppContext;
/**
* {@code AccessibleContext} represents the minimum information all accessible
@ -84,24 +83,8 @@ public abstract class AccessibleContext {
*/
protected AccessibleContext() {}
/**
* The {@code AppContext} that should be used to dispatch events for this
* {@code AccessibleContext}.
*/
private volatile AppContext targetAppContext;
static {
AWTAccessor.setAccessibleContextAccessor(new AWTAccessor.AccessibleContextAccessor() {
@Override
public void setAppContext(AccessibleContext accessibleContext, AppContext appContext) {
accessibleContext.targetAppContext = appContext;
}
@Override
public AppContext getAppContext(AccessibleContext accessibleContext) {
return accessibleContext.targetAppContext;
}
@Override
public Object getNativeAXResource(AccessibleContext accessibleContext) {
return accessibleContext.nativeAXResource;

View File

@ -706,6 +706,11 @@ public class MetalLookAndFeel extends BasicLookAndFeel
// DEFAULTS TABLE
//
Object commonInputMap = new UIDefaults.LazyInputMap(new Object[] {
"SPACE", "pressed",
"released SPACE", "released"
});
Object[] defaults = {
// *** Auditory Feedback
"AuditoryCues.defaultCueList", defaultCueList,
@ -791,6 +796,8 @@ public class MetalLookAndFeel extends BasicLookAndFeel
}),
// Buttons
"Button.defaultButtonFollowsFocus", Boolean.FALSE,
"Button.disabledText", inactiveControlTextColor,
@ -798,10 +805,8 @@ public class MetalLookAndFeel extends BasicLookAndFeel
"Button.border", buttonBorder,
"Button.font", controlTextValue,
"Button.focus", focusColor,
"Button.focusInputMap", new UIDefaults.LazyInputMap(new Object[] {
"SPACE", "pressed",
"released SPACE", "released"
}),
"Button.focusInputMap", commonInputMap,
// Button default margin is (2, 14, 2, 14), defined in
// BasicLookAndFeel via "Button.margin" UI property.
@ -810,11 +815,8 @@ public class MetalLookAndFeel extends BasicLookAndFeel
"CheckBox.font", controlTextValue,
"CheckBox.focus", focusColor,
"CheckBox.icon",(LazyValue) t -> MetalIconFactory.getCheckBoxIcon(),
"CheckBox.focusInputMap",
new UIDefaults.LazyInputMap(new Object[] {
"SPACE", "pressed",
"released SPACE", "released"
}),
"CheckBox.focusInputMap", commonInputMap,
// margin is 2 all the way around, BasicBorders.RadioButtonBorder
// (checkbox uses RadioButtonBorder) is 2 all the way around too.
"CheckBox.totalInsets", new Insets(4, 4, 4, 4),
@ -824,11 +826,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel
"RadioButton.icon",(LazyValue) t -> MetalIconFactory.getRadioButtonIcon(),
"RadioButton.font", controlTextValue,
"RadioButton.focus", focusColor,
"RadioButton.focusInputMap",
new UIDefaults.LazyInputMap(new Object[] {
"SPACE", "pressed",
"released SPACE", "released"
}),
"RadioButton.focusInputMap", commonInputMap,
// margin is 2 all the way around, BasicBorders.RadioButtonBorder
// is 2 all the way around too.
"RadioButton.totalInsets", new Insets(4, 4, 4, 4),
@ -838,11 +836,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel
"ToggleButton.focus", focusColor,
"ToggleButton.border", toggleButtonBorder,
"ToggleButton.font", controlTextValue,
"ToggleButton.focusInputMap",
new UIDefaults.LazyInputMap(new Object[] {
"SPACE", "pressed",
"released SPACE", "released"
}),
"ToggleButton.focusInputMap", commonInputMap,
// File View

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
@ -115,7 +115,6 @@ module java.desktop {
// qualified exports may be inserted at build time
// see make/GensrcModuleInfo.gmk
exports sun.awt to
jdk.accessibility,
jdk.unsupported.desktop;
exports java.awt.dnd.peer to jdk.unsupported.desktop;

View File

@ -755,8 +755,6 @@ public final class AWTAccessor {
* An accessor object for the AccessibleContext class
*/
public interface AccessibleContextAccessor {
void setAppContext(AccessibleContext accessibleContext, AppContext appContext);
AppContext getAppContext(AccessibleContext accessibleContext);
Object getNativeAXResource(AccessibleContext accessibleContext);
void setNativeAXResource(AccessibleContext accessibleContext, Object value);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 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
@ -36,7 +36,7 @@
#include <sys/utsname.h>
#ifdef AIX
#include "porting_aix.h" /* For the 'dladdr' function. */
#define dladdr JVM_dladdr
#endif
#ifdef DEBUG

View File

@ -57,6 +57,8 @@ import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.security.sasl.SaslException;
import jdk.internal.misc.InnocuousThread;
/**
* A thread that creates a connection to an LDAP server.
* After the connection, the thread reads from the connection.
@ -112,9 +114,6 @@ import javax.security.sasl.SaslException;
* for v2.
* %%% made public for access by LdapSasl %%%
*
* @author Vincent Ryan
* @author Rosanna Lee
* @author Jagane Sundar
*/
public final class Connection implements Runnable {
@ -254,7 +253,7 @@ public final class Connection implements Runnable {
throw ce;
}
worker = new Thread(this);
worker = InnocuousThread.newSystemThread("LDAP Connection", this);
worker.setDaemon(true);
worker.start();
}
@ -912,7 +911,7 @@ public final class Connection implements Runnable {
//
////////////////////////////////////////////////////////////////////////////
@Override
public void run() {
byte inbuf[]; // Buffer for reading incoming bytes
int inMsgId; // Message id of incoming response

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2024, 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
@ -36,13 +36,13 @@ import javax.naming.event.NamingListener;
import javax.naming.ldap.UnsolicitedNotificationEvent;
import javax.naming.ldap.UnsolicitedNotificationListener;
import jdk.internal.misc.InnocuousThread;
/**
* Package private class used by EventSupport to dispatch events.
* This class implements an event queue, and a dispatcher thread that
* dequeues and dispatches events from the queue.
*
* Pieces stolen from sun.misc.Queue.
*
* @author Bill Shannon (from javax.mail.event)
* @author Rosanna Lee (modified for JNDI-related events)
*/
@ -71,7 +71,7 @@ final class EventQueue implements Runnable {
// package private
EventQueue() {
qThread = new Thread(this);
qThread = InnocuousThread.newSystemThread("LDAP Event Dispatcher", this);
qThread.setDaemon(true); // not a user thread
qThread.start();
}
@ -141,6 +141,7 @@ final class EventQueue implements Runnable {
/**
* Pull events off the queue and dispatch them.
*/
@Override
public void run() {
QueueElement qe;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2024, 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
@ -33,6 +33,7 @@ import javax.naming.ldap.LdapName;
import java.util.Vector;
import com.sun.jndi.toolkit.ctx.Continuation;
import jdk.internal.misc.InnocuousThread;
/**
* Gathers information to generate events by using the Persistent Search
@ -86,7 +87,7 @@ final class NamingEventNotifier implements Runnable {
namingListeners = new Vector<>();
namingListeners.addElement(firstListener);
worker = new Thread(this);
worker = InnocuousThread.newSystemThread("LDAP Event Notifier", this);
worker.setDaemon(true); // not a user thread
worker.start();
}
@ -111,6 +112,7 @@ final class NamingEventNotifier implements Runnable {
* For each result, create the appropriate NamingEvent and
* queue to be dispatched to listeners.
*/
@Override
public void run() {
try {
Continuation cont = new Continuation();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -120,9 +120,6 @@ import com.sun.java.accessibility.util.AccessibilityEventMonitor;
import com.sun.java.accessibility.util.EventQueueMonitor;
import com.sun.java.accessibility.util.SwingEventMonitor;
import com.sun.java.accessibility.util.Translator;
import sun.awt.AWTAccessor;
import sun.awt.AppContext;
import sun.awt.SunToolkit;
/*
* Note: This class has to be public. It's loaded from the VM like this:
@ -5292,7 +5289,6 @@ public final class AccessBridge {
ac = a.getAccessibleContext();
}
if (ac != null) {
InvocationUtils.registerAccessibleContext(ac, AppContext.getAppContext());
accessBridge.debugString("[INFO]: AccessibleContext: " + ac);
String propertyName = e.getPropertyName();
@ -5385,11 +5381,9 @@ public final class AccessBridge {
if (e.getOldValue() instanceof AccessibleContext) {
oldAC = (AccessibleContext) e.getOldValue();
InvocationUtils.registerAccessibleContext(oldAC, AppContext.getAppContext());
}
if (e.getNewValue() instanceof AccessibleContext) {
newAC = (AccessibleContext) e.getNewValue();
InvocationUtils.registerAccessibleContext(newAC, AppContext.getAppContext());
}
accessBridge.debugString("[INFO]: - about to call propertyChildChange() old AC: " + oldAC + "new AC: " + newAC);
accessBridge.propertyChildChange(e, ac, oldAC, newAC);
@ -5455,8 +5449,6 @@ public final class AccessBridge {
prevAC = newAC;
accessBridge.debugString("[INFO]: - about to call propertyActiveDescendentChange() AC: " + ac + " old AC: " + oldAC + "new AC: " + newAC);
InvocationUtils.registerAccessibleContext(oldAC, AppContext.getAppContext());
InvocationUtils.registerAccessibleContext(newAC, AppContext.getAppContext());
accessBridge.propertyActiveDescendentChange(e, ac, oldAC, newAC);
}
@ -5493,14 +5485,12 @@ public final class AccessBridge {
// selected. The menu itself is selected.
FocusEvent e = new FocusEvent(penult, FocusEvent.FOCUS_GAINED);
AccessibleContext context = penult.getAccessibleContext();
InvocationUtils.registerAccessibleContext(context, SunToolkit.targetToAppContext(penult));
accessBridge.focusGained(e, context);
} else if (penult instanceof JPopupMenu) {
// This is a popup with an item selected
FocusEvent e =
new FocusEvent(last, FocusEvent.FOCUS_GAINED);
AccessibleContext focusedAC = last.getAccessibleContext();
InvocationUtils.registerAccessibleContext(focusedAC, SunToolkit.targetToAppContext(last));
accessBridge.debugString("[INFO]: - about to call focusGained() AC: " + focusedAC);
accessBridge.focusGained(e, focusedAC);
}
@ -5511,7 +5501,6 @@ public final class AccessBridge {
FocusEvent e = new FocusEvent(focusOwner,
FocusEvent.FOCUS_GAINED);
AccessibleContext focusedAC = focusOwner.getAccessibleContext();
InvocationUtils.registerAccessibleContext(focusedAC, SunToolkit.targetToAppContext(focusOwner));
accessBridge.debugString("[INFO]: - about to call focusGained() AC: " + focusedAC);
accessBridge.focusGained(e, focusedAC);
}
@ -5524,7 +5513,6 @@ public final class AccessBridge {
if (a != null) {
accessBridge.debugString("[INFO]: - about to call focusLost() AC: " + a.getAccessibleContext());
AccessibleContext context = a.getAccessibleContext();
InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
accessBridge.focusLost(e, context);
}
}
@ -5538,7 +5526,6 @@ public final class AccessBridge {
Accessible a = Translator.getAccessible(e.getSource());
if (a != null) {
AccessibleContext context = a.getAccessibleContext();
InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
accessBridge.caretUpdate(e, context);
}
}
@ -5553,7 +5540,6 @@ public final class AccessBridge {
Accessible a = Translator.getAccessible(e.getSource());
if (a != null) {
AccessibleContext context = a.getAccessibleContext();
InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
accessBridge.mouseClicked(e, context);
}
}
@ -5564,7 +5550,6 @@ public final class AccessBridge {
Accessible a = Translator.getAccessible(e.getSource());
if (a != null) {
AccessibleContext context = a.getAccessibleContext();
InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
accessBridge.mouseEntered(e, context);
}
}
@ -5575,7 +5560,6 @@ public final class AccessBridge {
Accessible a = Translator.getAccessible(e.getSource());
if (a != null) {
AccessibleContext context = a.getAccessibleContext();
InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
accessBridge.mouseExited(e, context);
}
}
@ -5586,7 +5570,6 @@ public final class AccessBridge {
Accessible a = Translator.getAccessible(e.getSource());
if (a != null) {
AccessibleContext context = a.getAccessibleContext();
InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
accessBridge.mousePressed(e, context);
}
}
@ -5597,7 +5580,6 @@ public final class AccessBridge {
Accessible a = Translator.getAccessible(e.getSource());
if (a != null) {
AccessibleContext context = a.getAccessibleContext();
InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
accessBridge.mouseReleased(e, context);
}
}
@ -5611,7 +5593,6 @@ public final class AccessBridge {
Accessible a = Translator.getAccessible(e.getSource());
if (a != null) {
AccessibleContext context = a.getAccessibleContext();
InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
accessBridge.menuCanceled(e, context);
}
}
@ -5622,7 +5603,6 @@ public final class AccessBridge {
Accessible a = Translator.getAccessible(e.getSource());
if (a != null) {
AccessibleContext context = a.getAccessibleContext();
InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
accessBridge.menuDeselected(e, context);
}
}
@ -5633,7 +5613,6 @@ public final class AccessBridge {
Accessible a = Translator.getAccessible(e.getSource());
if (a != null) {
AccessibleContext context = a.getAccessibleContext();
InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
accessBridge.menuSelected(e, context);
}
}
@ -5644,7 +5623,6 @@ public final class AccessBridge {
Accessible a = Translator.getAccessible(e.getSource());
if (a != null) {
AccessibleContext context = a.getAccessibleContext();
InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
accessBridge.popupMenuCanceled(e, context);
}
}
@ -5655,7 +5633,6 @@ public final class AccessBridge {
Accessible a = Translator.getAccessible(e.getSource());
if (a != null) {
AccessibleContext context = a.getAccessibleContext();
InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
accessBridge.popupMenuWillBecomeInvisible(e, context);
}
}
@ -5666,7 +5643,6 @@ public final class AccessBridge {
Accessible a = Translator.getAccessible(e.getSource());
if (a != null) {
AccessibleContext context = a.getAccessibleContext();
InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
accessBridge.popupMenuWillBecomeVisible(e, context);
}
}
@ -7227,8 +7203,7 @@ public final class AccessBridge {
private static class InvocationUtils {
/**
* Invokes a {@code Callable} in the {@code AppContext} of the given {@code Accessible}
* and waits for it to finish blocking the caller thread.
* Invokes a {@code Callable} and waits for it to finish blocking the caller thread.
*
* @param callable the {@code Callable} to invoke
* @param accessibleTable the {@code AccessibleExtendedTable} which would be used to find the right context
@ -7246,8 +7221,7 @@ public final class AccessBridge {
}
/**
* Invokes a {@code Callable} in the {@code AppContext} of the given {@code Accessible}
* and waits for it to finish blocking the caller thread.
* Invokes a {@code Callable} and waits for it to finish blocking the caller thread.
*
* @param callable the {@code Callable} to invoke
* @param accessible the {@code Accessible} which would be used to find the right context
@ -7269,8 +7243,7 @@ public final class AccessBridge {
}
/**
* Invokes a {@code Callable} in the {@code AppContext} of the given {@code Component}
* and waits for it to finish blocking the caller thread.
* Invokes a {@code Callable} and waits for it to finish blocking the caller thread.
*
* @param callable the {@code Callable} to invoke
* @param component the {@code Component} which would be used to find the right context
@ -7281,12 +7254,11 @@ public final class AccessBridge {
*/
public static <T> T invokeAndWait(final Callable<T> callable,
final Component component) {
return invokeAndWait(callable, SunToolkit.targetToAppContext(component));
return invokeAndWait(callable);
}
/**
* Invokes a {@code Callable} in the {@code AppContext} mapped to the given {@code AccessibleContext}
* and waits for it to finish blocking the caller thread.
* Invokes a {@code Callable} and waits for it to finish blocking the caller thread.
*
* @param callable the {@code Callable} to invoke
* @param accessibleContext the {@code AccessibleContext} which would be used to determine the right
@ -7297,45 +7269,26 @@ public final class AccessBridge {
*/
public static <T> T invokeAndWait(final Callable<T> callable,
final AccessibleContext accessibleContext) {
AppContext targetContext = AWTAccessor.getAccessibleContextAccessor()
.getAppContext(accessibleContext);
if (targetContext != null) {
return invokeAndWait(callable, targetContext);
} else {
// Normally this should not happen, unmapped context provided and
// the target AppContext is unknown.
// Try to recover in case the context is a translator.
if (accessibleContext instanceof Translator) {
Object source = ((Translator)accessibleContext).getSource();
if (source instanceof Component) {
return invokeAndWait(callable, (Component)source);
}
}
}
throw new RuntimeException("Unmapped AccessibleContext used to dispatch event: " + accessibleContext);
return invokeAndWait(callable);
}
private static <T> T invokeAndWait(final Callable<T> callable,
final AppContext targetAppContext) {
private static <T> T invokeAndWait(final Callable<T> callable) {
final CallableWrapper<T> wrapper = new CallableWrapper<T>(callable);
try {
invokeAndWait(wrapper, targetAppContext);
invokeAndWait(wrapper);
T result = wrapper.getResult();
updateAppContextMap(result, targetAppContext);
return result;
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
private static void invokeAndWait(final Runnable runnable,
final AppContext appContext)
private static void invokeAndWait(final Runnable runnable)
throws InterruptedException, InvocationTargetException {
EventQueue eq = SunToolkit.getSystemEventQueueImplPP(appContext);
Object lock = new Object();
Toolkit source = Toolkit.getDefaultToolkit();
EventQueue eq = source.getSystemEventQueue();
InvocationEvent event =
new InvocationEvent(source, runnable, lock, true);
synchronized (lock) {
@ -7349,26 +7302,6 @@ public final class AccessBridge {
}
}
/**
* Maps the {@code AccessibleContext} to the {@code AppContext} which should be used
* to dispatch events related to the {@code AccessibleContext}
* @param accessibleContext the {@code AccessibleContext} for the mapping
* @param targetContext the {@code AppContext} for the mapping
*/
public static void registerAccessibleContext(final AccessibleContext accessibleContext,
final AppContext targetContext) {
if (accessibleContext != null) {
AWTAccessor.getAccessibleContextAccessor().setAppContext(accessibleContext, targetContext);
}
}
private static <T> void updateAppContextMap(final T accessibleContext,
final AppContext targetContext) {
if (accessibleContext instanceof AccessibleContext) {
registerAccessibleContext((AccessibleContext)accessibleContext, targetContext);
}
}
private static class CallableWrapper<T> implements Runnable {
private final Callable<T> callable;
private volatile T object;

View File

@ -53,6 +53,7 @@ public abstract class Printer implements Type.Visitor<String, Locale>, Symbol.Vi
List<Type> seenCaptured = List.nil();
static final int PRIME = 997; // largest prime less than 1000
private boolean printingMethodArgs;
protected Printer() { }
@ -195,6 +196,9 @@ public abstract class Printer implements Type.Visitor<String, Locale>, Symbol.Vi
}
private String printAnnotations(Type t, boolean prefix) {
if (printingMethodArgs) {
return "";
}
StringBuilder sb = new StringBuilder();
List<Attribute.TypeCompound> annos = t.getAnnotationMirrors();
if (!annos.isEmpty()) {
@ -337,27 +341,28 @@ public abstract class Printer implements Type.Visitor<String, Locale>, Symbol.Vi
* @return localized string representation
*/
protected String printMethodArgs(List<Type> args, boolean varArgs, Locale locale) {
if (!varArgs) {
return visitTypes(args, locale);
} else {
StringBuilder buf = new StringBuilder();
while (args.tail.nonEmpty()) {
buf.append(visit(args.head, locale));
args = args.tail;
buf.append(',');
}
if (args.head.hasTag(TypeTag.ARRAY)) {
buf.append(visit(((ArrayType) args.head).elemtype, locale));
if (args.head.getAnnotationMirrors().nonEmpty()) {
buf.append(' ');
buf.append(args.head.getAnnotationMirrors());
buf.append(' ');
}
buf.append("...");
boolean prev = printingMethodArgs;
printingMethodArgs = true;
try {
if (!varArgs) {
return visitTypes(args, locale);
} else {
buf.append(visit(args.head, locale));
StringBuilder buf = new StringBuilder();
while (args.tail.nonEmpty()) {
buf.append(visit(args.head, locale));
args = args.tail;
buf.append(',');
}
if (args.head.hasTag(TypeTag.ARRAY)) {
buf.append(visit(((ArrayType) args.head).elemtype, locale));
buf.append("...");
} else {
buf.append(visit(args.head, locale));
}
return buf.toString();
}
return buf.toString();
} finally {
printingMethodArgs = prev;
}
}

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
@ -1000,7 +1000,7 @@ public class JavaTokenizer extends UnicodeReader {
scanIdent();
} else if (digit(pos, 10) >= 0) {
scanNumber(pos, 10);
} else if (is((char)EOI) || !isAvailable()) {
} else if (is((char)EOI) && position() + 1 == length() || !isAvailable()) {
tk = TokenKind.EOF;
pos = position();
} else {

View File

@ -50,4 +50,9 @@ public final class ContainerMemoryUsageEvent extends AbstractPeriodicEvent {
@Description("Amount of physical memory and swap space, in bytes, that is currently allocated in the current container")
@DataAmount
public long swapMemoryUsage;
@Label("Host Memory Usage")
@Description("Amount of physical memory, in bytes, that is currently allocated in the host system")
@DataAmount
public long hostMemoryUsage;
}

View File

@ -181,6 +181,7 @@ public final class JDKEvents {
event.memoryFailCount = containerMetrics.getMemoryFailCount();
event.memoryUsage = containerMetrics.getMemoryUsage();
event.swapMemoryUsage = containerMetrics.getMemoryAndSwapUsage();
event.hostMemoryUsage = JVM.hostMemoryUsage();
event.commit();
}
}

View File

@ -657,6 +657,12 @@ public final class JVM {
*/
public static native long hostTotalSwapMemory();
/**
* Returns the amount of memory used in the host system whether or not this
* JVM runs in a container.
*/
public static native long hostMemoryUsage();
/**
* Emit a jdk.DataLoss event for the specified amount of bytes.
*

View File

@ -56,6 +56,7 @@ compiler/c2/irTests/TestDuplicateBackedge.java 8318904 generic-all
compiler/codecache/jmx/PoolsIndependenceTest.java 8264632 macosx-all
compiler/vectorapi/TestVectorReallocation.java 8381315 generic-x64
compiler/vectorapi/reshape/TestVectorReinterpret.java 8320897,8348519 aix-ppc64,linux-ppc64le,linux-s390x
compiler/vectorapi/VectorRebracket128Test.java 8330538 generic-all

View File

@ -68,6 +68,7 @@ public class TestVMProcess {
this.cmds = new ArrayList<>();
TestFrameworkSocket socket = new TestFrameworkSocket();
try (socket) {
socket.start();
prepareTestVMFlags(additionalFlags, socket, testClass, helperClasses, defaultWarmup,
allowNotCompilable, testClassesOnBootClassPath);
start();

View File

@ -42,9 +42,13 @@ public class TestFrameworkSocket implements AutoCloseable {
private final int serverSocketPort;
private final ServerSocket serverSocket;
private boolean running;
private final ExecutorService executor;
private Future<JavaMessages> javaFuture;
private final ExecutorService acceptExecutor;
private final ExecutorService clientExecutor;
// Make these volatile such that the main thread can observe an update written by the worker threads in the executor
// services to avoid stale values.
private volatile boolean running;
private volatile Future<JavaMessages> javaFuture;
public TestFrameworkSocket() {
try {
@ -54,29 +58,53 @@ public class TestFrameworkSocket implements AutoCloseable {
throw new TestFrameworkException("Failed to create TestFramework server socket", e);
}
serverSocketPort = serverSocket.getLocalPort();
executor = Executors.newCachedThreadPool();
acceptExecutor = Executors.newSingleThreadExecutor();
clientExecutor = Executors.newCachedThreadPool();
if (TestFramework.VERBOSE) {
System.out.println("TestFramework server socket uses port " + serverSocketPort);
}
start();
}
public String getPortPropertyFlag() {
return "-D" + SERVER_PORT_PROPERTY + "=" + serverSocketPort;
}
private void start() {
public void start() {
running = true;
executor.submit(this::acceptLoop);
CountDownLatch calledAcceptLoopLatch = new CountDownLatch(1);
startAcceptLoop(calledAcceptLoopLatch);
}
private void startAcceptLoop(CountDownLatch calledAcceptLoopLatch) {
acceptExecutor.submit(() -> acceptLoop(calledAcceptLoopLatch));
waitUntilAcceptLoopRuns(calledAcceptLoopLatch);
}
private void waitUntilAcceptLoopRuns(CountDownLatch calledAcceptLoopLatch) {
try {
if (!calledAcceptLoopLatch.await(10, TimeUnit.SECONDS)) {
throw new IllegalStateException("acceptLoop did not start in time");
}
} catch (Exception e) {
throw new TestFrameworkException("Could not start TestFrameworkSocket", e);
}
}
/**
* Main loop to wait for new client connections and handling them upon connection request.
*/
private void acceptLoop() {
private void acceptLoop(CountDownLatch calledAcceptLoopLatch) {
calledAcceptLoopLatch.countDown();
while (running) {
try {
acceptNewClientConnection();
} catch (SocketException e) {
if (!running || serverSocket.isClosed()) {
// Normal shutdown
return;
}
running = false;
throw new TestFrameworkException("Server socket error", e);
} catch (TestFrameworkException e) {
running = false;
throw e;
@ -101,7 +129,7 @@ public class TestFrameworkSocket implements AutoCloseable {
* over that connection.
*/
private void submitTask(Socket client, BufferedReader reader) {
javaFuture = executor.submit(new TestVmMessageReader(client, reader));
javaFuture = clientExecutor.submit(new TestVmMessageReader(client, reader));
}
@Override
@ -112,7 +140,8 @@ public class TestFrameworkSocket implements AutoCloseable {
} catch (IOException e) {
throw new TestFrameworkException("Could not close socket", e);
}
executor.shutdown();
acceptExecutor.shutdown();
clientExecutor.shutdown();
}
public TestVMData testVmData(String hotspotPidFileName, boolean allowNotCompilable) {

View File

@ -26,12 +26,13 @@ package compiler.vectorapi;
import compiler.lib.ir_framework.*;
import jdk.incubator.vector.*;
import jtreg.SkippedException;
/**
* @test
* @bug 8378312
* @bug 8378312 8378902
* @library /test/lib /
* @summary VectorAPI: libraryUnaryOp and libraryBinaryOp should be intrinsified.
* @summary VectorAPI: libraryUnaryOp and libraryBinaryOp should be intrinsified. This test would be run on SVML/SLEEF supported platforms only.
* @modules jdk.incubator.vector
*
* @run driver compiler.vectorapi.TestVectorLibraryUnaryOpAndBinaryOp
@ -53,7 +54,24 @@ public class TestVectorLibraryUnaryOpAndBinaryOp {
vec.lanewise(VectorOperators.HYPOT, 1.0f);
}
private static void checkVectorMathLib() {
try {
// Check jsvml first
System.loadLibrary("jsvml");
} catch (UnsatisfiedLinkError _) {
try {
// Check sleef if jsvml not found
System.loadLibrary("sleef");
} catch (UnsatisfiedLinkError _) {
// This test is run on unsupported platform - should be skipped
throw new SkippedException("SVML / SLEEF not found");
}
}
}
public static void main(String[] args) {
checkVectorMathLib();
TestFramework testFramework = new TestFramework();
testFramework.addFlags("--add-modules=jdk.incubator.vector")
.start();

View File

@ -0,0 +1,414 @@
/*
* 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.
*
*/
package compiler.vectorapi;
import java.util.Arrays;
import compiler.lib.ir_framework.*;
import jdk.incubator.vector.ByteVector;
import jdk.incubator.vector.ShortVector;
import jdk.incubator.vector.IntVector;
import jdk.incubator.vector.LongVector;
import jdk.incubator.vector.FloatVector;
import jdk.incubator.vector.DoubleVector;
import jdk.incubator.vector.VectorSpecies;
import static jdk.test.lib.Asserts.*;
/**
* @test
* @bug 8380565
* @library /test/lib /
* @summary Test deoptimization involving vector reallocation
* @modules jdk.incubator.vector
* @requires vm.opt.final.MaxVectorSize == null | vm.opt.final.MaxVectorSize >= 16
*
* @run driver compiler.vectorapi.TestVectorReallocation
*/
public class TestVectorReallocation {
private static final VectorSpecies<Byte> B_SPECIES = ByteVector.SPECIES_PREFERRED;
private static final VectorSpecies<Short> S_SPECIES = ShortVector.SPECIES_PREFERRED;
private static final VectorSpecies<Integer> I_SPECIES = IntVector.SPECIES_PREFERRED;
private static final VectorSpecies<Long> L_SPECIES = LongVector.SPECIES_PREFERRED;
private static final VectorSpecies<Float> F_SPECIES = FloatVector.SPECIES_PREFERRED;
private static final VectorSpecies<Double> D_SPECIES = DoubleVector.SPECIES_PREFERRED;
private static final int B_LENGTH = B_SPECIES.length();
private static final int S_LENGTH = S_SPECIES.length();
private static final int I_LENGTH = I_SPECIES.length();
private static final int L_LENGTH = L_SPECIES.length();
private static final int F_LENGTH = F_SPECIES.length();
private static final int D_LENGTH = D_SPECIES.length();
// The input arrays for the @Test methods match the length of the preferred species for each type
private static byte[] b_a;
private static short[] s_a;
private static int[] i_a;
private static long[] l_a;
private static float[] f_a;
private static double[] d_a;
// The output arrays for the @Test methods
private static byte[] b_r;
private static short[] s_r;
private static int[] i_r;
private static long[] l_r;
private static float[] f_r;
private static double[] d_r;
public static void main(String[] args) {
TestFramework.runWithFlags("--add-modules=jdk.incubator.vector");
}
// The test methods annotated with @Test are warmed up by the framework. The calls are indirect
// through the runner methods annotated with @Run. Note that each @Test method has its own instance of
// the test class TestVectorReallocation as receiver of the calls.
//
// The @Test methods just copy the elements of the input array (0, 1, 2, 3, ...) to the output array
// by means of a vector add operation. The added value is computed but actually always zero. The
// computation is done in a loop with a virtual call that is inlined based on class hierarchy analysis
// when the method gets compiled.
//
// The final call after warmup of the now compiled @Test method is performed concurrently in a second
// thread. Before the variable `loopIterations` is set very high such that the loop runs practically
// infinitely. While the loop is running, a class with an overridden version of the method `value`
// (called in the loop) is loaded. This invalidates the result of the class hierarchy analysis that
// there is just one implementation of the method and causes deoptimization where the vector `v0` used
// in the @Test method is reallocated from a register to the java heap. Finally it is verified that
// input and ouput arrays are equal.
//
// NB: each @Test needs its own Zero class for the desired result of the class hierarchy analysis.
volatile boolean enteredLoop;
volatile long loopIterations;
void sharedRunner(RunInfo runInfo, Runnable test, Runnable loadOverridingClass, Runnable verify) {
enteredLoop = false;
if (runInfo.isWarmUp()) {
loopIterations = 100;
test.run();
} else {
loopIterations = 1L << 60; // basically infinite
Thread t = Thread.ofPlatform().start(test);
waitUntilLoopEntered();
loadOverridingClass.run(); // invalidates inlining causing deoptimization/reallocation of v0
loopIterations = 0;
waitUntilLoopLeft();
joinThread(t);
verify.run(); // verify that input and ouput arrays are equal
}
}
/////////////////////////////////////////////////////////////////////////////////////
// byte
static class ByteZero {
volatile byte zero;
byte value() {
return zero;
}
}
volatile ByteZero byteZero = new ByteZero();
@Run(test = "byteIdentityWithReallocation")
void byteIdentityWithReallocation_runner(RunInfo runInfo) {
sharedRunner(runInfo, () -> byteIdentityWithReallocation(), () -> {
// Loading the class with the overridden method will cause deoptimization and reallocation of v0
byteZero = new ByteZero() {
@Override
byte value() {
return super.value(); // override but doing the same
}
};
},
() -> assertTrue(Arrays.equals(b_a, b_r), "Input/Output arrays differ"));
}
@Test
@IR(counts = {IRNode.ADD_VB, " >0 "})
void byteIdentityWithReallocation() {
ByteVector v0 = ByteVector.fromArray(B_SPECIES, b_a, 0);
byte zeroSum = 0;
enteredLoop = true;
for (long i = 0; i < loopIterations; i++) {
zeroSum += byteZero.value(); // inlined based on class hierarchy analysis
}
v0.add(zeroSum).intoArray(b_r, 0);
enteredLoop = false;
}
/////////////////////////////////////////////////////////////////////////////////////
// short
static class ShortZero {
volatile short zero;
short value() {
return zero;
}
}
volatile ShortZero shortZero = new ShortZero();
@Run(test = "shortIdentityWithReallocation")
void shortIdentityWithReallocation_runner(RunInfo runInfo) {
sharedRunner(runInfo, () -> shortIdentityWithReallocation(), () -> {
// Loading the class with the overridden method will cause deoptimization and reallocation of v0
shortZero = new ShortZero() {
@Override
short value() {
return super.value(); // override but doing the same
}
};
},
() -> assertTrue(Arrays.equals(s_a, s_r), "Input/Output arrays differ"));
}
@Test
@IR(counts = {IRNode.ADD_VS, " >0 "})
void shortIdentityWithReallocation() {
ShortVector v0 = ShortVector.fromArray(S_SPECIES, s_a, 0);
short zeroSum = 0;
enteredLoop = true;
for (long i = 0; i < loopIterations; i++) {
zeroSum += shortZero.value(); // inlined based on class hierarchy analysis
}
v0.add(zeroSum).intoArray(s_r, 0);
enteredLoop = false;
}
/////////////////////////////////////////////////////////////////////////////////////
// int
static class IntZero {
volatile int zero;
int value() {
return zero;
}
}
volatile IntZero intZero = new IntZero();
@Run(test = "intIdentityWithReallocation")
void intIdentityWithReallocation_runner(RunInfo runInfo) {
sharedRunner(runInfo, () -> intIdentityWithReallocation(), () -> {
// Loading the class with the overridden method will cause deoptimization and reallocation of v0
intZero = new IntZero() {
@Override
int value() {
return super.value(); // override but doing the same
}
};
},
() -> assertTrue(Arrays.equals(i_a, i_r), "Input/Output arrays differ"));
}
@Test
@IR(counts = {IRNode.ADD_VI, " >0 "})
void intIdentityWithReallocation() {
IntVector v0 = IntVector.fromArray(I_SPECIES, i_a, 0);
int zeroSum = 0;
enteredLoop = true;
for (long i = 0; i < loopIterations; i++) {
zeroSum += intZero.value(); // inlined based on class hierarchy analysis
}
v0.add(zeroSum).intoArray(i_r, 0);
enteredLoop = false;
}
/////////////////////////////////////////////////////////////////////////////////////
// long
static class LongZero {
volatile long zero;
long value() {
return zero;
}
}
volatile LongZero longZero = new LongZero();
@Run(test = "longIdentityWithReallocation")
void longIdentityWithReallocation_runner(RunInfo runInfo) {
sharedRunner(runInfo, () -> longIdentityWithReallocation(), () -> {
// Loading the class with the overridden method will cause deoptimization and reallocation of v0
longZero = new LongZero() {
@Override
long value() {
return super.value(); // override but doing the same
}
};
},
() -> assertTrue(Arrays.equals(l_a, l_r), "Input/Output arrays differ"));
}
@Test
@IR(counts = {IRNode.ADD_VL, " >0 "})
void longIdentityWithReallocation() {
LongVector v0 = LongVector.fromArray(L_SPECIES, l_a, 0);
long zeroSum = 0;
enteredLoop = true;
for (long i = 0; i < loopIterations; i++) {
zeroSum += longZero.value(); // inlined based on class hierarchy analysis
}
v0.add(zeroSum).intoArray(l_r, 0);
enteredLoop = false;
}
/////////////////////////////////////////////////////////////////////////////////////
// float
static class FloatZero {
volatile float zero;
float value() {
return zero;
}
}
volatile FloatZero floatZero = new FloatZero();
@Run(test = "floatIdentityWithReallocation")
void floatIdentityWithReallocation_runner(RunInfo runInfo) {
sharedRunner(runInfo, () -> floatIdentityWithReallocation(), () -> {
// Loading the class with the overridden method will cause deoptimization and reallocation of v0
floatZero = new FloatZero() {
@Override
float value() {
return super.value(); // override but doing the same
}
};
},
() -> assertTrue(Arrays.equals(f_a, f_r), "Input/Output arrays differ"));
}
@Test
@IR(counts = {IRNode.ADD_VF, " >0 "})
void floatIdentityWithReallocation() {
FloatVector v0 = FloatVector.fromArray(F_SPECIES, f_a, 0);
float zeroSum = 0;
enteredLoop = true;
for (long i = 0; i < loopIterations; i++) {
zeroSum += floatZero.value(); // inlined based on class hierarchy analysis
}
v0.add(zeroSum).intoArray(f_r, 0);
enteredLoop = false;
}
/////////////////////////////////////////////////////////////////////////////////////
// double
static class DoubleZero {
volatile double zero;
double value() {
return zero;
}
}
volatile DoubleZero doubleZero = new DoubleZero();
@Run(test = "doubleIdentityWithReallocation")
void doubleIdentityWithReallocation_runner(RunInfo runInfo) {
sharedRunner(runInfo, () -> doubleIdentityWithReallocation(), () -> {
// Loading the class with the overridden method will cause deoptimization and reallocation of v0
doubleZero = new DoubleZero() {
@Override
double value() {
return super.value(); // override but doing the same
}
};
},
() -> assertTrue(Arrays.equals(d_a, d_r), "Input/Output arrays differ"));
}
@Test
@IR(counts = {IRNode.ADD_VD, " >0 "})
void doubleIdentityWithReallocation() {
DoubleVector v0 = DoubleVector.fromArray(D_SPECIES, d_a, 0);
double zeroSum = 0;
enteredLoop = true;
for (long i = 0; i < loopIterations; i++) {
zeroSum += doubleZero.value(); // inlined based on class hierarchy analysis
}
v0.add(zeroSum).intoArray(d_r, 0);
enteredLoop = false;
}
/////////////////////////////////////////////////////////////////////////////////////
private void waitUntilLoopEntered() {
while (!enteredLoop) {
sleep(10);
}
}
private void waitUntilLoopLeft() {
while (enteredLoop) {
sleep(10);
}
}
private static void sleep(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) { /* ignore */ }
}
private static void joinThread(Thread t) {
try {
t.join();
} catch (InterruptedException e) { /* ignore */ }
}
static {
b_a = new byte[B_LENGTH];
s_a = new short[S_LENGTH];
i_a = new int[I_LENGTH];
l_a = new long[L_LENGTH];
f_a = new float[F_LENGTH];
d_a = new double[D_LENGTH];
b_r = new byte[B_LENGTH];
s_r = new short[S_LENGTH];
i_r = new int[I_LENGTH];
l_r = new long[L_LENGTH];
f_r = new float[F_LENGTH];
d_r = new double[D_LENGTH];
for (int i = 0; i < b_a.length ; i++) {
b_a[i] = (byte)i;
}
for (int i = 0; i < s_a.length ; i++) {
s_a[i] = (short)i;
}
for (int i = 0; i < i_a.length ; i++) {
i_a[i] = i;
}
for (int i = 0; i < l_a.length ; i++) {
l_a[i] = i;
}
for (int i = 0; i < f_a.length ; i++) {
f_a[i] = i;
}
for (int i = 0; i < d_a.length ; i++) {
d_a[i] = i;
}
}
}

View File

@ -29,7 +29,7 @@ import compiler.lib.generators.*;
/*
* @test
* @bug 8350177 8362171 8369881 8342095
* @bug 8350177 8362171 8369881 8342095 8380988
* @summary Ensure that truncation of subword vectors produces correct results
* @library /test/lib /
* @run driver compiler.vectorization.TestSubwordTruncation
@ -448,6 +448,50 @@ public class TestSubwordTruncation {
}
}
@Test
@IR(counts = { IRNode.UMOD_I, ">0" })
@Arguments(setup = "setupByteArray")
public Object[] testUMod(final byte[] in) {
int n = G.next().intValue();
for (int i = 1; i < SIZE; i++) {
in[i] = (byte) Integer.remainderUnsigned(n, i);
}
return new Object[] { Integer.valueOf(n), in };
}
@Check(test = "testUMod")
public void checkTestUMod(Object[] vals) {
int n = (Integer) vals[0];
byte[] res = (byte[]) vals[1];
for (int i = 1; i < SIZE; i++) {
byte val = (byte) Integer.remainderUnsigned(n, i);
Asserts.assertEQ(res[i], val);
}
}
@Test
@IR(counts = { IRNode.UDIV_I, ">0" })
@Arguments(setup = "setupByteArray")
public Object[] testUDiv(final byte[] in) {
int n = G.next().intValue();
for (int i = 1; i < SIZE; i++) {
in[i] = (byte) Integer.divideUnsigned(n, i);
}
return new Object[] { Integer.valueOf(n), in };
}
@Check(test = "testUDiv")
public void checkTestUDiv(Object[] vals) {
int n = (Integer) vals[0];
byte[] res = (byte[]) vals[1];
for (int i = 1; i < SIZE; i++) {
byte val = (byte) Integer.divideUnsigned(n, i);
Asserts.assertEQ(res[i], val);
}
}
@Test
@IR(counts = { IRNode.CMP_LT_MASK, ">0" })
@Arguments(setup = "setupByteArray")

View File

@ -162,6 +162,7 @@ public class TestJFREvents {
String memoryFailCountFld = "memoryFailCount";
String memoryUsageFld = "memoryUsage";
String swapMemoryUsageFld = "swapMemoryUsage";
String hostMemoryUsageFld = "hostMemoryUsage";
DockerTestUtils.dockerRunJava(
commonDockerOpts()
@ -169,7 +170,8 @@ public class TestJFREvents {
.shouldHaveExitValue(0)
.shouldContain(memoryFailCountFld)
.shouldContain(memoryUsageFld)
.shouldContain(swapMemoryUsageFld);
.shouldContain(swapMemoryUsageFld)
.shouldContain(hostMemoryUsageFld);
}
private static void testIOUsage() throws Exception {

View File

@ -0,0 +1,356 @@
/*
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* 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.
*/
import java.lang.Class;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import jdk.internal.misc.Unsafe;
import jdk.internal.vm.annotation.Contended;
/*
* @test
* @summary \@Contended with different sized primitive types
* @modules java.base/jdk.internal.misc
* @modules java.base/jdk.internal.vm.annotation
* @run main/othervm -XX:-RestrictContended MixedPrimitives
*/
public class MixedPrimitives {
private static final Unsafe U = Unsafe.getUnsafe();
private static final int ADDRESS_SIZE;
private static final int HEADER_SIZE;
static {
// When running with CompressedOops on 64-bit platform, the address size
// reported by Unsafe is still 8, while the real reference fields are 4 bytes long.
// Try to guess the reference field size with this naive trick.
try {
long off1 = U.objectFieldOffset(CompressedOopsClass.class.getField("obj1"));
long off2 = U.objectFieldOffset(CompressedOopsClass.class.getField("obj2"));
ADDRESS_SIZE = (int) Math.abs(off2 - off1);
HEADER_SIZE = (int) Math.min(off1, off2);
} catch (NoSuchFieldException e) {
throw new ExceptionInInitializerError(e);
}
}
static class CompressedOopsClass {
public Object obj1;
public Object obj2;
}
public static boolean arePaddedPairwise(Class klass, String field1, String field2) throws Exception {
Field f1 = klass.getDeclaredField(field1);
Field f2 = klass.getDeclaredField(field2);
if (isStatic(f1) != isStatic(f2)) {
return true; // these guys are in naturally disjoint locations
}
int diff = offset(f1) - offset(f2);
if (diff < 0) {
// f1 is first
return (offset(f2) - (offset(f1) + getSize(f1))) > 64;
} else {
// f2 is first
return (offset(f1) - (offset(f2) + getSize(f2))) > 64;
}
}
public static boolean isPadded(Class klass, String field1) throws Exception {
Field f1 = klass.getDeclaredField(field1);
if (isStatic(f1)) {
return offset(f1) > 128 + 64;
}
return offset(f1) > 64;
}
public static boolean sameLayout(Class klass1, Class klass2) throws Exception {
try {
for (Field f1 : klass1.getDeclaredFields()) {
Field f2 = klass2.getDeclaredField(f1.getName());
if (offset(f1) != offset(f2)) {
return false;
}
}
for (Field f2 : klass1.getDeclaredFields()) {
Field f1 = klass2.getDeclaredField(f2.getName());
if (offset(f1) != offset(f2)) {
return false;
}
}
} catch (Exception e) {
System.err.println("Failed getting layout from class: " + e.getMessage());
return false;
}
return true;
}
public static boolean isStatic(Field field) {
return Modifier.isStatic(field.getModifiers());
}
public static int offset(Field field) {
if (isStatic(field)) {
return (int) U.staticFieldOffset(field);
} else {
return (int) U.objectFieldOffset(field);
}
}
public static int getSize(Field field) {
Class type = field.getType();
if (type == byte.class) { return 1; }
if (type == boolean.class) { return 1; }
if (type == short.class) { return 2; }
if (type == char.class) { return 2; }
if (type == int.class) { return 4; }
if (type == float.class) { return 4; }
if (type == long.class) { return 8; }
if (type == double.class) { return 8; }
return ADDRESS_SIZE;
}
public static void main(String[] args) throws Exception {
int failures = 0;
failures += Test1.checkLayout();
failures += Test2.checkLayout();
failures += Test3.checkLayout();
failures += Test4.checkLayout();
failures += Test5.checkLayout();
failures += Test6.checkLayout();
failures += Test7.checkLayout();
failures += Test8.checkLayout();
failures += Test9.checkLayout();
if (!sameLayout(Test4.class, Test7.class)) {
System.err.println("Test4 and Test7 have different layouts");
failures += 1;
}
if (!sameLayout(Test5.class, Test6.class)) {
System.err.println("Test5 and Test6 have different layouts");
failures += 1;
}
if (!sameLayout(Test8.class, Test9.class)) {
System.err.println("Test8 and Test9 have different layouts");
failures += 1;
}
System.out.println(failures == 0 ? "Test PASSES" : "Test FAILS");
if (failures > 0) {
throw new Error("Test failed. Incurred " + failures + " failures.");
}
}
// naturally packed
public static class Test1 {
private long long1;
private int int1;
private short short1;
public static int checkLayout() throws Exception {
if (arePaddedPairwise(Test1.class, "long1", "int1") ||
arePaddedPairwise(Test1.class, "long1", "short1") ||
arePaddedPairwise(Test1.class, "int1", "short1") ||
isPadded(Test1.class, "long1") ||
isPadded(Test1.class, "int1") ||
isPadded(Test1.class, "short1")) {
System.err.println("Test1 failed");
return 1;
}
return 0;
}
}
// long1 is padded
public static class Test2 {
@Contended private long long1;
private int int1;
private short short1;
public static int checkLayout() throws Exception {
if (!arePaddedPairwise(Test2.class, "long1", "int1") ||
!arePaddedPairwise(Test2.class, "long1", "short1") ||
arePaddedPairwise(Test2.class, "int1", "short1") ||
!isPadded(Test2.class, "long1") ||
isPadded(Test2.class, "int1") ||
isPadded(Test2.class, "short1")) {
System.err.println("Test2 failed");
return 1;
}
return 0;
}
}
// both fields are padded
public static class Test3 {
@Contended private long long1;
@Contended private int int1;
@Contended private short short1;
public static int checkLayout() throws Exception {
if (!arePaddedPairwise(Test3.class, "long1", "int1") ||
!arePaddedPairwise(Test3.class, "long1", "short1") ||
!arePaddedPairwise(Test3.class, "int1", "short1") ||
!isPadded(Test3.class, "long1") ||
!isPadded(Test3.class, "int1") ||
!isPadded(Test3.class, "short1")) {
System.err.println("Test3 failed");
return 1;
}
return 0;
}
}
// fields are padded in the singular group
public static class Test4 {
@Contended("sameGroup") private long long1;
@Contended("sameGroup") private int int1;
@Contended("sameGroup") private short short1;
public static int checkLayout() throws Exception {
if (arePaddedPairwise(Test4.class, "long1", "int1") ||
arePaddedPairwise(Test4.class, "long1", "short1") ||
arePaddedPairwise(Test4.class, "int1", "short1") ||
!isPadded(Test4.class, "long1") ||
!isPadded(Test4.class, "int1") ||
!isPadded(Test4.class, "short1")) {
System.err.println("Test4 failed");
return 1;
}
return 0;
}
}
// fields are padded in disjoint groups
public static class Test5 {
@Contended("diffGroup1") private long long1;
@Contended("diffGroup2") private int int1;
@Contended("diffGroup3") private short short1;
public static int checkLayout() throws Exception {
if (!arePaddedPairwise(Test5.class, "long1", "int1") ||
!arePaddedPairwise(Test5.class, "long1", "short1") ||
!arePaddedPairwise(Test5.class, "int1", "short1") ||
!isPadded(Test5.class, "long1") ||
!isPadded(Test5.class, "int1") ||
!isPadded(Test5.class, "short1")) {
System.err.println("Test5 failed");
return 1;
}
return 0;
}
}
// fields are padded in disjoint groups
public static class Test6 {
@Contended private long long1;
@Contended("diffGroup2") private int int1;
@Contended("diffGroup3") private short short1;
public static int checkLayout() throws Exception {
if (!arePaddedPairwise(Test6.class, "long1", "int1") ||
!arePaddedPairwise(Test6.class, "long1", "short1") ||
!arePaddedPairwise(Test6.class, "int1", "short1") ||
!isPadded(Test6.class, "long1") ||
!isPadded(Test6.class, "int1") ||
!isPadded(Test6.class, "short1")) {
System.err.println("Test6 failed");
return 1;
}
return 0;
}
}
// fields are padded in the singular group
@Contended
public static class Test7 {
private long long1;
private int int1;
private short short1;
public static int checkLayout() throws Exception {
if (arePaddedPairwise(Test7.class, "long1", "int1") ||
arePaddedPairwise(Test7.class, "long1", "short1") ||
arePaddedPairwise(Test7.class, "int1", "short1") ||
!isPadded(Test7.class, "long1") ||
!isPadded(Test7.class, "int1") ||
!isPadded(Test7.class, "short1")) {
System.err.println("Test7 failed");
return 1;
}
return 0;
}
}
// all fields are padded as the group, and one field is padded specifically
@Contended
public static class Test8 {
@Contended private long long1;
private int int1;
private short short1;
public static int checkLayout() throws Exception {
if (!arePaddedPairwise(Test8.class, "long1", "int1") ||
!arePaddedPairwise(Test8.class, "long1", "short1") ||
arePaddedPairwise(Test8.class, "int1", "short1") ||
!isPadded(Test8.class, "long1") ||
!isPadded(Test8.class, "int1") ||
!isPadded(Test8.class, "short1")) {
System.err.println("Test8 failed");
return 1;
}
return 0;
}
}
// all fields are padded as the group, and one field is padded specifically
@Contended
public static class Test9 {
@Contended("group") private long long1;
private int int1;
private short short1;
public static int checkLayout() throws Exception {
if (!arePaddedPairwise(Test9.class, "long1", "int1") ||
!arePaddedPairwise(Test9.class, "long1", "short1") ||
arePaddedPairwise(Test9.class, "int1", "short1") ||
!isPadded(Test9.class, "long1") ||
!isPadded(Test9.class, "int1") ||
!isPadded(Test9.class, "short1")) {
System.err.println("Test9 failed");
return 1;
}
return 0;
}
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* 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.
*
*/
public super class JsrLogging version 49:0
{
static Field i:I;
public static Method test:"()V"
stack 3 locals 1
{
nop;
jsr LABEL;
bipush 66;
LABEL:
bipush 55;
putstatic Field i:"I";
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
ldc String "hello";
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
return;
}
}

View File

@ -1,12 +1,10 @@
/*
* Copyright (c) 2012, 2026 SAP SE. All rights reserved.
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
* 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
@ -21,20 +19,22 @@
* 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.
*
*/
/*
* Aix' own version of dladdr().
* This function tries to mimic dladdr(3) on Linux
* (see http://linux.die.net/man/3/dladdr)
* dladdr(3) is not POSIX but a GNU extension, and is not available on AIX.
*
* @test
* @bug 8380686
* @summary Ensure logging works while processing jsr while linking.
* @library /test/lib
* @compile JsrLogging.jasm
* @run main/othervm -Xlog:generateoopmap=debug JsrLoggingTest
*/
#include "dl_info.h"
#ifdef __cplusplus
extern "C"
#endif
int dladdr(void *addr, Dl_info *info);
public class JsrLoggingTest {
public static void main(String[] args) {
for (int i = 0; i < 10; ++i) {
JsrLogging.test();
}
System.out.println("PASSED");
}
}

View File

@ -0,0 +1,323 @@
/*
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* 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.
*/
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collection;
import java.util.Collections;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.event.EventContext;
import javax.naming.event.NamingEvent;
import javax.naming.event.NamingExceptionEvent;
import javax.naming.event.ObjectChangeListener;
import jdk.test.lib.net.URIBuilder;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static java.nio.charset.StandardCharsets.US_ASCII;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.fail;
/*
* @test
* @bug 8273874
* @summary Verify that the system threads that LdapContext creates for its internal
* use do not hold on to the application specific context classloaders
* @comment The test uses ThreadGroup.enumerate() to find live threads and check their
* context classsloader, ThreadGroup of virtual threads don't enumerate threads,
* so we skip this test when the main thread is a virtual thread.
* @requires test.thread.factory != "Virtual"
* @library lib/ /test/lib
* @build BaseLdapServer
* LdapMessage
* jdk.test.lib.net.URIBuilder
* @run junit ${test.main.class}
*/
class LdapTCCLTest {
private static final String LOOKUP_NAME = "CN=duke";
private static final byte BER_TYPE_LDAP_SEQUENCE = 0x30;
private static final byte BER_TYPE_INTEGER = 0x02;
private static final byte BER_TYPE_OCTET_STRING = 0x04;
private static final byte BER_TYPE_ENUM = 0x0a;
private static final byte BER_TYPE_LDAP_SEARCH_RESULT_ENTRY_OP = 0x64;
private static final byte BER_TYPE_LDAP_SEARCH_RESULT_DONE_OP = 0x65;
private static final byte LDAP_SEARCH_RESULT_DONE_SUCCESS = 0x00;
private static Server server;
private static Hashtable<String, String> envProps;
@BeforeAll
static void beforeAll() throws Exception {
server = new Server();
server.start();
System.err.println("server started at " + server.getInetAddress()
+ ":" + server.getPort());
final Hashtable<String, String> props = new Hashtable<>();
props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
final String providerUrl = URIBuilder.newBuilder()
.scheme("ldap")
.host(server.getInetAddress().getHostAddress())
.port(server.getPort())
.build().toString();
props.put(Context.PROVIDER_URL, providerUrl);
// explicitly set LDAP version to 3 to prevent LDAP BIND requests
// during LdapCtx instantiation
props.put("java.naming.ldap.version", "3");
envProps = props;
}
@AfterAll
static void afterAll() throws Exception {
if (server != null) {
System.err.println("stopping server " + server.getInetAddress()
+ ":" + server.getPort());
server.close();
}
}
/*
* Sets a test specific Thread context classloader and then creates a InitialContext
* backed by a LdapCtxFactory and looks up an arbitrary name. The test then verifies
* that none of the live Threads (including any created for the internal LDAP connection
* management) have their context classloader set to the test specific classloader.
*/
@Test
void testLdapCtxCreation() throws Exception {
try (final URLClassLoader urlc = new URLClassLoader(new URL[0])) {
final ClassLoader previous = Thread.currentThread().getContextClassLoader();
Context ctx = null;
try {
// switch the TCCL to a test specific one
Thread.currentThread().setContextClassLoader(urlc);
// create the LDAP Context and initiate a lookup()
// to allow for the underlying LDAP connection management
// infrastructure to create the necessary Thread(s)
ctx = new InitialContext(envProps);
System.err.println("issuing ldap request against "
+ envProps.get(Context.PROVIDER_URL) + " using context " + ctx);
final Object result = ctx.lookup(LOOKUP_NAME);
System.err.println("lookup returned " + result);
assertNotNull(result, "Context.lookup() returned null");
// verify that none of the live Thread(s) other than the current Thread
// have their TCCL set to the one set by the test. i.e. verify that the
// context classloader hasn't leaked into Thread(s) that may have been
// created by the LDAP connection management code.
assertTCCL(urlc, Collections.singleton(Thread.currentThread()));
} finally {
if (ctx != null) {
ctx.close();
}
Thread.currentThread().setContextClassLoader(previous);
}
}
}
/*
* Sets a test specific Thread context classloader and then creates a InitialContext
* backed by a LdapCtxFactory and adds a NamingListener. The test then verifies
* that none of the live Threads (including any newly created ones during the
* NamingListener registration) have their context classloader set to the test
* specific classloader.
*/
@Test
void testAddNamingListener() throws Exception {
try (final URLClassLoader urlc = new URLClassLoader(new URL[0])) {
final ClassLoader previous = Thread.currentThread().getContextClassLoader();
EventContext ctx = null;
try {
// switch the TCCL to a test specific one
Thread.currentThread().setContextClassLoader(urlc);
ctx = (EventContext) (new InitialContext(envProps).lookup(LOOKUP_NAME));
// add a NamingListener to exercise the Thread creation in the internals
// of LdapCtx
ctx.addNamingListener(LOOKUP_NAME, EventContext.OBJECT_SCOPE, new Listener());
// verify that none of the live Thread(s) other than the current Thread
// have their TCCL set to the one set by the test. i.e. verify that the
// context classloader hasn't leaked into Thread(s) that may have been
// created by the LDAP naming listener code.
assertTCCL(urlc, Collections.singleton(Thread.currentThread()));
} finally {
if (ctx != null) {
ctx.close();
}
Thread.currentThread().setContextClassLoader(previous);
}
}
}
/*
* Verifies that none of the live threads have their context classloader set to
* the given "notExpected" classloader.
*/
private static void assertTCCL(final ClassLoader notExpected,
final Collection<Thread> threadsToIgnore) {
ThreadGroup topMostThreadGroup = Thread.currentThread().getThreadGroup();
assertNotNull(topMostThreadGroup,
"ThreadGroup for current thread " + Thread.currentThread() + " was null");
while (topMostThreadGroup.getParent() != null) {
topMostThreadGroup = topMostThreadGroup.getParent();
}
// recursively enumerate the threads in the top most thread group
final Thread[] threads = new Thread[1024];
final int numThreads = topMostThreadGroup.enumerate(threads);
// verify the threads
int numFailedThreads = 0;
final StringBuilder diagnosticMsg = new StringBuilder();
for (int i = 0; i < numThreads; i++) {
final Thread t = threads[i];
if (threadsToIgnore.contains(t)) {
continue; // skip verification of the thread
}
System.err.println("verifying " + t);
if (t.getContextClassLoader() == notExpected) {
// Thread has an unexpected context classloader
numFailedThreads++;
// for debugging track the stacktrace of the thread
// that failed the check
diagnosticMsg.append("FAILED - ").append(t)
.append(" is using unexpected context classloader: ")
.append(notExpected)
.append(", its current activity is:\n");
for (StackTraceElement ste : t.getStackTrace()) {
diagnosticMsg.append("\t").append(ste).append("\n");
}
}
}
if (numFailedThreads > 0) {
// for debugging print out the stacktrace of the
// Thread(s) that failed the check
System.err.println(diagnosticMsg);
fail(numFailedThreads + " Thread(s) had unexpected context classloader "
+ notExpected);
}
}
private static final class Server extends BaseLdapServer {
private Server() throws IOException {
super();
}
// handles and responds to the incoming LDAP request
@Override
protected void handleRequest(final Socket socket,
final LdapMessage request,
final OutputStream out) throws IOException {
switch (request.getOperation()) {
case SEARCH_REQUEST: {
System.err.println("responding to SEARCH_REQUEST with id: "
+ request.getMessageID() + " on socket " + socket);
// write out a search response
final byte[] rsp = makeSearchResponse((byte) request.getMessageID(), LOOKUP_NAME);
out.write(rsp);
out.flush();
System.err.println("wrote response for message: " + request.getMessageID());
break;
}
default: {
throw new IOException("unexpected operation type: " + request.getOperation()
+ ", request: " + request);
}
}
}
// constructs and returns a byte[] response containing the following (in that order):
// - Search Result Entry
// - Search Result Done
private static byte[] makeSearchResponse(final byte msgId, final String dn)
throws IOException {
final ByteArrayOutputStream bout = new ByteArrayOutputStream();
final byte msgIdLen = 1;
// write the BER elements
// each BER element is 3 parts:
// Type, length, value
// Search Result Entry BER element (refer to LDAPv3 wire format for details)
bout.write(BER_TYPE_LDAP_SEQUENCE);
bout.write(dn.length() + 9);
bout.write(new byte[]{BER_TYPE_INTEGER, msgIdLen, msgId});
bout.write(BER_TYPE_LDAP_SEARCH_RESULT_ENTRY_OP);
bout.write(dn.length() + 2);
bout.write(BER_TYPE_OCTET_STRING);
bout.write(dn.length());
bout.write(dn.getBytes(US_ASCII));
bout.write(BER_TYPE_LDAP_SEQUENCE);
// 0 length for the LDAP sequence, implying no attributes in this Search Result Entry
bout.write(0);
bout.write(makeSearchResultDone(msgId));
return bout.toByteArray();
}
// Search Result Done BER element (refer to LDAPv3 wire format for details)
private static byte[] makeSearchResultDone(final byte msgId) throws IOException {
final ByteArrayOutputStream bout = new ByteArrayOutputStream();
final byte msgIdLen = 1;
final String matchedDN = "";
bout.write(BER_TYPE_LDAP_SEQUENCE);
bout.write(matchedDN.length() + 12);
bout.write(new byte[]{BER_TYPE_INTEGER, msgIdLen, msgId});
bout.write(BER_TYPE_LDAP_SEARCH_RESULT_DONE_OP);
bout.write(7);
bout.write(new byte[]{BER_TYPE_ENUM, 1, LDAP_SEARCH_RESULT_DONE_SUCCESS});
// the matched DN
bout.write(BER_TYPE_OCTET_STRING);
bout.write(matchedDN.length());
bout.write(matchedDN.getBytes(US_ASCII));
// 0 length implies no diagnostic message
bout.write(new byte[]{BER_TYPE_OCTET_STRING, 0});
return bout.toByteArray();
}
}
private static final class Listener implements ObjectChangeListener {
@Override
public void namingExceptionThrown(final NamingExceptionEvent evt) {
System.err.println("namingExceptionThrown() called for " + evt);
}
@Override
public void objectChanged(final NamingEvent evt) {
System.err.println("objectChanged() called for " + evt);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 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
@ -37,7 +37,7 @@ import javax.print.attribute.standard.Destination;
/*
* @test
* @bug 4223328
* @bug 4223328 4138921
* @summary Printer graphics must throw expected exceptions
* @key printer
* @run main PrintNullString
@ -106,12 +106,8 @@ public class PrintNullString implements Printable {
g2d.drawString("caught expected NPE for null iterator, int", 20, 120);
}
try {
g2d.drawString(emptyIterator, 20, 140);
throw new RuntimeException("FAILURE: No IAE for empty iterator, int");
} catch (IllegalArgumentException e) {
g2d.drawString("caught expected IAE for empty iterator, int", 20, 140);
}
g2d.drawString(emptyIterator, 20, 140);
g2d.drawString("OK for empty iterator, int", 20, 140);
// API 4: null & empty drawString(Iterator, float, int);
try {
@ -121,12 +117,8 @@ public class PrintNullString implements Printable {
g2d.drawString("caught expected NPE for null iterator, float", 20, 160);
}
try {
g2d.drawString(emptyIterator, 20.0f, 180.0f);
throw new RuntimeException("FAILURE: No IAE for empty iterator, float");
} catch (IllegalArgumentException e) {
g2d.drawString("caught expected IAE for empty iterator, float", 20, 180);
}
g2d.drawString(emptyIterator, 20.0f, 180.0f);
g2d.drawString("OK for empty iterator, float", 20.0f, 100.f);
return PAGE_EXISTS;
}

View File

@ -50,16 +50,6 @@
* @run main/othervm/native/timeout=360 -Djdk.lang.Process.launchMechanism=fork Basic
*/
/*
* @test id=VFORK
* @modules java.base/java.lang:open
* java.base/java.io:open
* java.base/jdk.internal.misc
* @requires (os.family == "linux")
* @library /test/lib
* @run main/othervm/timeout=300 -Djdk.lang.Process.launchMechanism=vfork Basic
*/
import java.lang.ProcessBuilder.Redirect;
import java.lang.ProcessHandle;
import static java.lang.ProcessBuilder.Redirect.*;

View File

@ -42,16 +42,6 @@
* @run main/othervm/manual -Djdk.lang.Process.launchMechanism=FORK ConcNativeForkTest
*/
/*
* @test id=VFORK
* @bug 8377907
* @summary Test that demonstrates the hanging-parent-on-native-concurrent-forks problem
* @requires os.family == "linux"
* @requires vm.flagless
* @library /test/lib
* @run main/othervm/manual -Djdk.lang.Process.launchMechanism=VFORK ConcNativeForkTest
*/
public class ConcNativeForkTest {
// How this works:

View File

@ -38,14 +38,6 @@
* @run main/othervm/native -Djdk.lang.Process.launchMechanism=fork -agentlib:FDLeaker FDLeakTest
*/
/**
* @test id=vfork
* @summary Check that we don't leak FDs to child processes
* @requires os.family == "linux"
* @library /test/lib
* @run main/othervm/native -Djdk.lang.Process.launchMechanism=vfork -agentlib:FDLeaker FDLeakTest
*/
import jdk.test.lib.process.ProcessTools;
public class FDLeakTest {
// This test has two native parts:

View File

@ -32,14 +32,6 @@ import java.io.*;
* @run main/othervm -Djdk.lang.Process.launchMechanism=fork NonPipelineLeaksFD
*/
/*
* @test id=VFORK
* @summary Check that we don't accumulate leaked FDs in the parent process
* @requires os.family == "linux"
* @library /test/lib
* @run main/othervm -Djdk.lang.Process.launchMechanism=vfork NonPipelineLeaksFD
*/
/*
* @test id=POSIX_SPAWN
* @summary Check that we don't accumulate leaked FDs in the parent process

View File

@ -32,16 +32,6 @@
* @run main/othervm/native -Djdk.lang.Process.launchMechanism=FORK PipesCloseOnExecTest
*/
/*
* @test id=VFORK
* @bug 8377907
* @summary Check that we don't open pipes without CLOEXCEC
* @requires os.family == "linux"
* @requires vm.flagless
* @library /test/lib
* @run main/othervm/native -Djdk.lang.Process.launchMechanism=VFORK PipesCloseOnExecTest
*/
/*
* @test id=POSIX_SPAWN
* @bug 8377907

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2026, IBM Corp.
* 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.
*/
/*
* @test
* @bug 8357089
* @summary Check that specifying VFORK correctly falls back to FORK with a clear warning to stderr.
* @requires (os.family == "linux")
* @library /test/lib
* @run main RejectVFORKMode GRANDPARENT
*/
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class RejectVFORKMode {
public static void main(String[] args) throws Exception {
switch (args[0]) {
case "PARENT" -> {
ProcessBuilder pb = new ProcessBuilder("sh", "-c", "echo 'Child Process'; exit 12;");
// This should result in a (written to this process' stderr) warning about VFORK mode.
// But child should have been started successfully.
OutputAnalyzer outputAnalyzer = ProcessTools.executeCommand(pb);
outputAnalyzer.shouldHaveExitValue(12);
outputAnalyzer.shouldContain("Child Process");
System.exit(0);
}
case "GRANDPARENT" -> {
ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Djdk.lang.Process.launchMechanism=VFORK", RejectVFORKMode.class.getName(), "PARENT");
OutputAnalyzer outputAnalyzer = ProcessTools.executeCommand(pb);
outputAnalyzer.shouldHaveExitValue(0);
outputAnalyzer.shouldContain("The VFORK launch mechanism has been removed. Switching to FORK instead.");
}
default -> throw new RuntimeException("Bad arg");
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2025, 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,15 +39,6 @@
* @run main/othervm/native -Djdk.lang.Process.launchMechanism=fork -agentlib:ChangeSignalDisposition TestChildSignalDisposition
*/
/**
* @test id=vfork
* @bug 8364611
* @summary Check that childs start with SIG_DFL as SIGPIPE disposition
* @requires os.family == "linux"
* @library /test/lib
* @run main/othervm/native -Djdk.lang.Process.launchMechanism=vfork -agentlib:ChangeSignalDisposition TestChildSignalDisposition
*/
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class TestChildSignalDisposition {

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* 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.
*/
import javax.swing.JToggleButton;
import javax.swing.JFrame;
/*
* @test
* @key headful
* @bug 8379347
* @summary manual test for VoiceOver reading JToggleButtons correctly
* @requires os.family == "mac"
* @library /java/awt/regtesthelpers
* @build PassFailJFrame
* @run main/manual VoiceOverToggleButtonRole
*/
public class VoiceOverToggleButtonRole {
public static void main(String[] args) throws Exception {
String INSTRUCTIONS = """
INSTRUCTIONS (Mac-only):
1. Open VoiceOver
2. Move the VoiceOver cursor over the JToggleButton.
3. Observe how VoiceOver identifies the toggle button.
Expected behavior: VoiceOver should identify it as a
"toggle button" initially. (VO does still say "to select
or deselect this checkbox", though.)
If you select the link using "Accessibility Inspector":
it should identify its subrole as AXToggle.
""";
PassFailJFrame.builder()
.title("VoiceOverToggleButtonRole Instruction")
.instructions(INSTRUCTIONS)
.columns(40)
.testUI(VoiceOverToggleButtonRole::createUI)
.build()
.awaitAndCheck();
}
private static JFrame createUI() {
JFrame frame = new JFrame();
frame.getContentPane().add(new JToggleButton("JToggleButton"));
frame.pack();
return frame;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
@ -28,11 +28,12 @@ import java.util.function.Consumer;
/**
* @test
* @bug 8329420
* @bug 8329420 8377004
* @summary test execution priority and behavior of main methods
* @run main/timeout=480 InstanceMainTest
*/
public class InstanceMainTest extends TestHelper {
private static String JAVA_VERSION = System.getProperty("java.specification.version");
private static final String[] SOURCES = new String[] {
// static dominating with args
@ -227,11 +228,7 @@ public class InstanceMainTest extends TestHelper {
private static void testExecutionOrder() throws Exception {
for (TestCase testCase : EXECUTION_ORDER) {
performTest(testCase.sourceCode, testCase.enablePreview(), tr -> {
if (!Objects.equals(testCase.expectedOutput, tr.testOutput)) {
throw new AssertionError("Unexpected output, " +
"expected: " + testCase.expectedOutput +
", actual: " + tr.testOutput);
}
assertEquals(testCase.expectedOutput, tr.testOutput);
});
}
}
@ -350,20 +347,227 @@ public class InstanceMainTest extends TestHelper {
private static void performTest(String source, boolean enablePreview, Consumer<TestResult> validator) throws Exception {
Path mainClass = Path.of("MainClass.java");
Files.writeString(mainClass, source);
var version = System.getProperty("java.specification.version");
var previewRuntime = enablePreview ? "--enable-preview" : "-DtestNoPreview";
var previewCompile = enablePreview ? "--enable-preview" : "-XDtestNoPreview";
var trSource = doExec(javaCmd, previewRuntime, "--source", version, "MainClass.java");
var trSource = doExec(javaCmd, previewRuntime, "--source", JAVA_VERSION, "MainClass.java");
validator.accept(trSource);
compile(previewCompile, "--source", version, "MainClass.java");
compile(previewCompile, "--source", JAVA_VERSION, "MainClass.java");
String cp = mainClass.toAbsolutePath().getParent().toString();
var trCompile = doExec(javaCmd, previewRuntime, "--class-path", cp, "MainClass");
validator.accept(trCompile);
}
private static void testInheritance() throws Exception {
Path testInheritance = Path.of("testInheritance");
Path src = testInheritance.resolve("src");
Path classes = testInheritance.resolve("classes");
Path mainClass = src.resolve("Main.java");
Path libClass = src.resolve("p").resolve("Lib.java");
Files.createDirectories(libClass.getParent());
Files.writeString(mainClass,
"""
import p.Lib;
public class Main extends Lib {
public void main() {
System.err.println("Main!");
}
}
""");
{
Files.writeString(libClass,
"""
package p;
public class Lib {
void main(String... args) {
System.err.println("Lib!");
}
}
""");
compile("--release", JAVA_VERSION, "-d", classes.toString(), mainClass.toString(), libClass.toString());
var tr = doExec(javaCmd, "--class-path", classes.toString(), "Main");
assertEquals(List.of("Main!"), tr.testOutput);
}
{
Files.writeString(libClass,
"""
package p;
public class Lib {
protected void main(String... args) {
System.err.println("Lib!");
}
}
""");
compile("--release", JAVA_VERSION, "-d", classes.toString(), mainClass.toString(), libClass.toString());
var tr = doExec(javaCmd, "--class-path", classes.toString(), "Main");
assertEquals(List.of("Lib!"), tr.testOutput);
}
{
Files.writeString(libClass,
"""
package p;
public class Lib {
public void main(String... args) {
System.err.println("Lib!");
}
}
""");
compile("--release", JAVA_VERSION, "-d", classes.toString(), mainClass.toString(), libClass.toString());
var tr = doExec(javaCmd, "--class-path", classes.toString(), "Main");
assertEquals(List.of("Lib!"), tr.testOutput);
}
{
Files.writeString(mainClass,
"""
package p;
public class Main extends Lib {
public void main() {
System.err.println("Main!");
}
}
""");
Files.writeString(libClass,
"""
package p;
public class Lib {
void main(String... args) {
System.err.println("Lib!");
}
}
""");
compile("--release", JAVA_VERSION, "-d", classes.toString(), mainClass.toString(), libClass.toString());
var tr = doExec(javaCmd, "--class-path", classes.toString(), "p.Main");
assertEquals(List.of("Lib!"), tr.testOutput);
}
{
Files.writeString(mainClass,
"""
package p;
public class Main implements Lib {
public void main() {
System.err.println("Main!");
}
}
""");
Files.writeString(libClass,
"""
package p;
public interface Lib {
public default void main(String... args) {
System.err.println("Lib!");
}
}
""");
compile("--release", JAVA_VERSION, "-d", classes.toString(), mainClass.toString(), libClass.toString());
var tr = doExec(javaCmd, "--class-path", classes.toString(), "p.Main");
assertEquals(List.of("Lib!"), tr.testOutput);
}
{
Files.writeString(mainClass,
"""
package p;
public class Main implements Lib {
public void main() {
System.err.println("Main!");
}
}
""");
Files.writeString(libClass,
"""
package p;
public interface Lib {
public static void main(String... args) {
System.err.println("Lib!");
}
}
""");
compile("--release", JAVA_VERSION, "-d", classes.toString(), mainClass.toString(), libClass.toString());
var tr = doExec(javaCmd, "--class-path", classes.toString(), "p.Main");
assertEquals(List.of("Main!"), tr.testOutput);
}
{
Files.writeString(mainClass,
"""
package p;
public class Main extends AbstractClass implements Lib {
}
abstract class AbstractClass {
public void main(String... args) {
System.err.println("Correct.");
}
}
""");
Files.writeString(libClass,
"""
package p;
public interface Lib {
default void main(String... args) {
System.err.println("Incorrect!");
}
}
""");
compile("--release", JAVA_VERSION, "-d", classes.toString(), mainClass.toString(), libClass.toString());
var tr = doExec(javaCmd, "--class-path", classes.toString(), "p.Main");
assertEquals(List.of("Correct."), tr.testOutput);
}
{
Files.writeString(mainClass,
"""
package p;
public class Main extends AbstractClass implements Lib {
}
abstract class AbstractClass {
public void main() {
System.err.println("Incorrect!");
}
}
""");
Files.writeString(libClass,
"""
package p;
public interface Lib {
default void main(String... args) {
System.err.println("Correct.");
}
}
""");
compile("--release", JAVA_VERSION, "-d", classes.toString(), mainClass.toString(), libClass.toString());
var tr = doExec(javaCmd, "--class-path", classes.toString(), "p.Main");
assertEquals(List.of("Correct."), tr.testOutput);
}
}
private static void assertEquals(List<String> expected, List<String> actual) {
if (!Objects.equals(expected, actual)) {
throw new AssertionError("Unexpected output, " +
"expected: " + expected +
", actual: " + actual);
}
}
public static void main(String... args) throws Exception {
testMethodOrder();
testExecutionOrder();
testExecutionErrors();
testInheritance();
}
}

View File

@ -0,0 +1,196 @@
/*
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* 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.
*/
/**
* @test
* @bug 8377004
* @summary Whitebox test for MethodFinder
* @modules java.base/jdk.internal.misc
* jdk.compiler
* jdk.zipfs
* @run junit MethodFinderTest
*/
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import jdk.internal.misc.MethodFinder;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class MethodFinderTest {
private static final String JAVA_VERSION = System.getProperty("java.specification.version");
@Test
public void testDistinctClassLoaders() throws Exception {
Path base = Path.of("testDistinctClassLoaders");
Path libSrc = base.resolve("libSrc");
Path libClasses = base.resolve("libClasses");
Path libJava = libSrc.resolve("p").resolve("Lib.java");
Files.createDirectories(libJava.getParent());
Files.writeString(libJava,
"""
package p;
public class Lib {
void main(String... args) {
System.err.println("Lib!");
}
}
""");
TestHelper.compile("--release", JAVA_VERSION, "-d", libClasses.toString(), libJava.toString());
Path mainSrc = base.resolve("mainSrc");
Path mainClasses = base.resolve("mainClasses");
Path mainJava = mainSrc.resolve("p").resolve("Main.java");
Files.createDirectories(mainJava.getParent());
Files.writeString(mainJava,
"""
package p;
public class Main extends Lib {
public void main() {
System.err.println("Main!");
}
}
""");
TestHelper.compile("--release", JAVA_VERSION, "--class-path", libClasses.toString(), "-d", mainClasses.toString(), mainJava.toString());
{
ClassLoader cl = new URLClassLoader(new URL[] {
libClasses.toUri().toURL(),
mainClasses.toUri().toURL()
});
Class<?> mainClass = cl.loadClass("p.Main");
Method mainMethod = MethodFinder.findMainMethod(mainClass);
//p.Main and p.Lib are in the same runtime package:
assertEquals("p.Lib", mainMethod.getDeclaringClass().getName());
}
{
ClassLoader libCl = new URLClassLoader(new URL[] {
libClasses.toUri().toURL(),
});
ClassLoader mainCl = new URLClassLoader(new URL[] {
mainClasses.toUri().toURL()
}, libCl);
Class<?> mainClass = mainCl.loadClass("p.Main");
Method mainMethod = MethodFinder.findMainMethod(mainClass);
//p.Main and p.Lib are in the different runtime packages:
assertEquals("p.Main", mainMethod.getDeclaringClass().getName());
}
}
@Test
public void testWrongEquals() throws Exception {
Path base = Path.of("testDistinctClassLoaders");
Path libSrc = base.resolve("libSrc");
Path libClasses = base.resolve("libClasses");
Path libJava = libSrc.resolve("p").resolve("Lib.java");
Files.createDirectories(libJava.getParent());
Files.writeString(libJava,
"""
package p;
public class Lib {
void main(String... args) {
System.err.println("Lib!");
}
}
""");
TestHelper.compile("--release", JAVA_VERSION, "-d", libClasses.toString(), libJava.toString());
Path mainSrc = base.resolve("mainSrc");
Path mainClasses = base.resolve("mainClasses");
Path mainJava = mainSrc.resolve("p").resolve("Main.java");
Files.createDirectories(mainJava.getParent());
Files.writeString(mainJava,
"""
package p;
public class Main extends Lib {
public void main() {
System.err.println("Main!");
}
}
""");
TestHelper.compile("--release", JAVA_VERSION, "--class-path", libClasses.toString(), "-d", mainClasses.toString(), mainJava.toString());
{
ClassLoader cl = new URLClassLoader(new URL[] {
libClasses.toUri().toURL(),
mainClasses.toUri().toURL()
});
Class<?> mainClass = cl.loadClass("p.Main");
Method mainMethod = MethodFinder.findMainMethod(mainClass);
//p.Main and p.Lib are in the same runtime package:
assertEquals("p.Lib", mainMethod.getDeclaringClass().getName());
}
{
class WrongEquals extends URLClassLoader {
public WrongEquals(URL[] urls) {
super(urls);
}
public WrongEquals(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
@Override
public boolean equals(Object obj) {
return obj instanceof WrongEquals;
}
}
ClassLoader libCl = new WrongEquals(new URL[] {
libClasses.toUri().toURL(),
});
ClassLoader mainCl = new WrongEquals(new URL[] {
mainClasses.toUri().toURL()
}, libCl);
Class<?> mainClass = mainCl.loadClass("p.Main");
Method mainMethod = MethodFinder.findMainMethod(mainClass);
//p.Main and p.Lib are in the different runtime packages:
assertEquals("p.Main", mainMethod.getDeclaringClass().getName());
}
}
}

View File

@ -0,0 +1,47 @@
/*
* @test /nodynamiccopyright/
* @summary Omit type-use annotations from diagnostics
* @compile/fail/ref=MethodArguments.out -XDrawDiagnostics MethodArguments.java p/A.java p/B.java
*/
import java.util.List;
import p.A;
import p.B;
public final class MethodArguments {
public static void main(String[] args) {
// error non-static.cant.be.ref:
// non-static ... cannot be referenced from a static context
B.one("bar");
B b = new B();
// error ref.ambiguous:
// reference to ... is ambiguous
// ...
// both ... and ... match
b.one(null);
// error report.access:
// ... has private access in ...
b.two("foo");
// ... has protected access in ...
b.three("foo");
// error not.def.public.cant.access:
// ... is not public in ... cannot be accessed from outside package
b.four("foo");
}
void five(@A String s) {
}
void five(@A String s) {
}
void six(List<@A String> s) {
}
void six(List<@A String> s) {
}
}

View File

@ -0,0 +1,8 @@
MethodArguments.java:39:8: compiler.err.already.defined: kindname.method, five(java.lang.String), kindname.class, MethodArguments
MethodArguments.java:45:8: compiler.err.already.defined: kindname.method, six(java.util.List<java.lang.String>), kindname.class, MethodArguments
MethodArguments.java:15:6: compiler.err.non-static.cant.be.ref: kindname.method, one(java.lang.String)
MethodArguments.java:23:6: compiler.err.ref.ambiguous: one, kindname.method, one(java.lang.String), p.B, kindname.method, one(java.lang.Integer), p.B
MethodArguments.java:27:6: compiler.err.report.access: two(java.lang.String), private, p.B
MethodArguments.java:29:6: compiler.err.report.access: three(java.lang.String), protected, p.B
MethodArguments.java:33:6: compiler.err.not.def.public.cant.access: four(java.lang.String), p.B
7 errors

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2026, Google LLC. 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.
*/
package p;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target(ElementType.TYPE_USE)
public @interface A {}

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2026, Google LLC. 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.
*/
package p;
public class B {
public void one(@A String s) {
}
public void one(@A Integer i) {
}
private void two(@A String s) {
}
protected void three(@A String s) {
}
void four(@A String s) {
}
}

View File

@ -0,0 +1,116 @@
/*
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* 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.
*/
/**
* @test
* @bug 8371873
* @summary Check for proper handling of trailing ASCII SUB character
* @library /tools/lib
* @modules
* jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* @build toolbox.ToolBox toolbox.JavacTask
* @run junit AsciiSubCharTest
*/
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import toolbox.JavacTask;
import toolbox.Task;
import toolbox.ToolBox;
public class AsciiSubCharTest {
ToolBox tb = new ToolBox();
Path base;
@Test
public void testTrailingAsciiSubIsIgnored() throws Exception {
Path classes = base.resolve("classes");
Files.createDirectories(classes);
new JavacTask(tb)
.options("-d", classes.toString())
.sources("""
public class Test {
void main(String... args) { IO.println("\u001A"); }
}
\u001A""")
.run()
.writeAll();
}
@Test
public void testMultipleTrailingAsciiSubAreReported() throws Exception {
Path classes = base.resolve("classes");
Files.createDirectories(classes);
List<String> out = new JavacTask(tb)
.options("-d", classes.toString(), "-XDrawDiagnostics", "-nowarn")
.sources("""
public class Test {
void main(String... args) { IO.println("\u001A"); }
}
\u001A\u001A""")
.run(Task.Expect.FAIL)
.writeAll()
.getOutputLines(Task.OutputKind.DIRECT);
tb.checkEqual(out, List.of(
"Test.java:4:1: compiler.err.illegal.char: \\u001a",
"Test.java:4:2: compiler.err.premature.eof",
"2 errors"));
}
@Test
public void test8371873() throws Exception {
Path classes = base.resolve("classes");
Files.createDirectories(classes);
List<String> out = new JavacTask(tb)
.options("-d", classes.toString(), "-XDrawDiagnostics", "-nowarn")
.sources("""
public class Test {
void main(String... args) { IO.println("\u001A"); }
}
\u001A\u0001""")
.run(Task.Expect.FAIL)
.writeAll()
.getOutputLines(Task.OutputKind.DIRECT);
tb.checkEqual(out, List.of(
"Test.java:4:1: compiler.err.illegal.char: \\u001a",
"Test.java:4:2: compiler.err.illegal.char: \\u0001",
"Test.java:4:3: compiler.err.premature.eof",
"3 errors"));
}
@BeforeEach
public void setUp(TestInfo info) {
base = Paths.get(".")
.resolve(info.getTestMethod()
.orElseThrow()
.getName());
}
}