mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-02 19:20:19 +00:00
Merge branch 'master' into opt-drem-8309636
This commit is contained in:
commit
64fdfe71ca
6
.github/actions/build-jtreg/action.yml
vendored
6
.github/actions/build-jtreg/action.yml
vendored
@ -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
|
||||
|
||||
4
.github/actions/do-build/action.yml
vendored
4
.github/actions/do-build/action.yml
vendored
@ -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'
|
||||
|
||||
2
.github/actions/get-bootjdk/action.yml
vendored
2
.github/actions/get-bootjdk/action.yml
vendored
@ -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 }}
|
||||
|
||||
6
.github/actions/get-bundles/action.yml
vendored
6
.github/actions/get-bundles/action.yml
vendored
@ -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
|
||||
|
||||
2
.github/actions/get-gtest/action.yml
vendored
2
.github/actions/get-gtest/action.yml
vendored
@ -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 }}'
|
||||
|
||||
2
.github/actions/get-jtreg/action.yml
vendored
2
.github/actions/get-jtreg/action.yml
vendored
@ -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
|
||||
|
||||
2
.github/actions/get-msys2/action.yml
vendored
2
.github/actions/get-msys2/action.yml
vendored
@ -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
|
||||
|
||||
2
.github/actions/upload-bundles/action.yml
vendored
2
.github/actions/upload-bundles/action.yml
vendored
@ -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
|
||||
|
||||
2
.github/workflows/build-alpine-linux.yml
vendored
2
.github/workflows/build-alpine-linux.yml
vendored
@ -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: |
|
||||
|
||||
4
.github/workflows/build-cross-compile.yml
vendored
4
.github/workflows/build-cross-compile.yml
vendored
@ -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') }}
|
||||
|
||||
2
.github/workflows/build-linux.yml
vendored
2
.github/workflows/build-linux.yml
vendored
@ -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
|
||||
|
||||
2
.github/workflows/build-macos.yml
vendored
2
.github/workflows/build-macos.yml
vendored
@ -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
|
||||
|
||||
2
.github/workflows/build-windows.yml
vendored
2
.github/workflows/build-windows.yml
vendored
@ -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
|
||||
|
||||
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@ -75,7 +75,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 'Checkout the scripts'
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
sparse-checkout: |
|
||||
.github
|
||||
|
||||
6
.github/workflows/test.yml
vendored
6
.github/workflows/test.yml
vendored
@ -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'
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
46
src/hotspot/cpu/ppc/registerMap_ppc.cpp
Normal file
46
src/hotspot/cpu/ppc/registerMap_ppc.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
@ -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() {}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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");
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -81,7 +81,6 @@ extern char **environ;
|
||||
*/
|
||||
#define MODE_FORK 1
|
||||
#define MODE_POSIX_SPAWN 2
|
||||
#define MODE_VFORK 3
|
||||
|
||||
typedef struct _ChildStuff
|
||||
{
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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"];
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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.
|
||||
*
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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")
|
||||
|
||||
@ -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 {
|
||||
|
||||
356
test/hotspot/jtreg/runtime/contended/MixedPrimitives.java
Normal file
356
test/hotspot/jtreg/runtime/contended/MixedPrimitives.java
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
43
test/hotspot/jtreg/runtime/interpreter/JsrLogging.jasm
Normal file
43
test/hotspot/jtreg/runtime/interpreter/JsrLogging.jasm
Normal 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;
|
||||
}
|
||||
}
|
||||
@ -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");
|
||||
}
|
||||
}
|
||||
323
test/jdk/com/sun/jndi/ldap/LdapTCCLTest.java
Normal file
323
test/jdk/com/sun/jndi/ldap/LdapTCCLTest.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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.*;
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
59
test/jdk/java/lang/ProcessBuilder/RejectVFORKMode.java
Normal file
59
test/jdk/java/lang/ProcessBuilder/RejectVFORKMode.java
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
196
test/jdk/tools/launcher/MethodFinderTest.java
Normal file
196
test/jdk/tools/launcher/MethodFinderTest.java
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
@ -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 {}
|
||||
@ -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) {
|
||||
}
|
||||
}
|
||||
116
test/langtools/tools/javac/lexer/AsciiSubCharTest.java
Normal file
116
test/langtools/tools/javac/lexer/AsciiSubCharTest.java
Normal 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());
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user