Even for 32-bit builds, it is recommended to use a 64-bit build
machine, and instead create a 32-bit target using
--with-target-bits=32.
+
Note: The Windows 32-bit x86 port is deprecated and may be removed in a future release.
Building on aarch64
At a minimum, a machine with 8 cores is advisable, as well as 8 GB of
RAM. (The more cores to use, the more memory you need.) At least 6 GB of
@@ -353,22 +355,22 @@
Operating System
-
Operating system
-
Vendor/version used
+
Operating system
+
Vendor/version used
-
Linux
-
Oracle Enterprise Linux 6.4 / 7.6
+
Linux
+
Oracle Enterprise Linux 6.4 / 7.6
-
macOS
-
Mac OS X 10.13 (High Sierra)
+
macOS
+
Mac OS X 10.13 (High Sierra)
-
Windows
-
Windows Server 2012 R2
+
Windows
+
Windows Server 2012 R2
@@ -399,6 +401,7 @@
Windows
use --with-msvcr-dll=/cygdrive/c/msvcr100.dll rather than
--with-msvcr-dll=c:\msvcr100.dll. For details on this
conversion, see the section on Fixpath.
+
Note: The Windows 32-bit x86 port is deprecated and may be removed in a future release.
Cygwin
A functioning Cygwin environment
is required for building the JDK on Windows. If you have a 64-bit OS, we
@@ -677,6 +680,19 @@
FreeType
Use --with-freetype-include=<path> and
--with-freetype-lib=<path> if configure
does not automatically locate the platform FreeType files.
To install on an apt-based Linux, try running
+sudo apt-get install libfontconfig-dev.
+
To install on an rpm-based Linux, try running
+sudo yum install fontconfig-devel.
+
+
Use --with-fontconfig-include=<path> and
+--with-fontconfig=<path> if configure
+does not automatically locate the platform Fontconfig files.
CUPS
CUPS, Common UNIX Printing System
header files are required on all platforms, except Windows. Often these
@@ -1195,27 +1211,27 @@
Cross
-
Supported devkit targets
+
Supported devkit targets
-
x86_64-linux-gnu
+
x86_64-linux-gnu
-
aarch64-linux-gnu
+
aarch64-linux-gnu
-
arm-linux-gnueabihf
+
arm-linux-gnueabihf
-
ppc64-linux-gnu
+
ppc64-linux-gnu
-
ppc64le-linux-gnu
+
ppc64le-linux-gnu
-
s390x-linux-gnu
+
s390x-linux-gnu
@@ -1417,112 +1433,119 @@
Cross compiling with
Architectures that are known to successfully cross-compile like this
are:
+
+
+
+
+
+
+
-
Target
-
Debian tree
-
Debian arch
-
--openjdk-target=...
+
Target
+
Debian tree
+
Debian arch
+
--openjdk-target=...
--with-jvm-variants=...
-
x86
-
buster
-
i386
-
i386-linux-gnu
+
x86
+
buster
+
i386
+
i386-linux-gnu
(all)
-
arm
-
buster
-
armhf
-
arm-linux-gnueabihf
+
arm
+
buster
+
armhf
+
arm-linux-gnueabihf
(all)
-
aarch64
-
buster
-
arm64
-
aarch64-linux-gnu
+
aarch64
+
buster
+
arm64
+
aarch64-linux-gnu
(all)
-
ppc64le
-
buster
-
ppc64el
-
powerpc64le-linux-gnu
+
ppc64le
+
buster
+
ppc64el
+
powerpc64le-linux-gnu
(all)
-
s390x
-
buster
-
s390x
-
s390x-linux-gnu
+
s390x
+
buster
+
s390x
+
s390x-linux-gnu
(all)
-
mipsle
-
buster
-
mipsel
-
mipsel-linux-gnu
+
mipsle
+
buster
+
mipsel
+
mipsel-linux-gnu
zero
-
mips64le
-
buster
-
mips64el
-
mips64el-linux-gnueabi64
+
mips64le
+
buster
+
mips64el
+
mips64el-linux-gnueabi64
zero
-
armel
-
buster
-
arm
-
arm-linux-gnueabi
+
armel
+
buster
+
arm
+
arm-linux-gnueabi
zero
-
ppc
-
sid
-
powerpc
-
powerpc-linux-gnu
+
ppc
+
sid
+
powerpc
+
powerpc-linux-gnu
zero
-
ppc64be
-
sid
-
ppc64
-
powerpc64-linux-gnu
+
ppc64be
+
sid
+
ppc64
+
powerpc64-linux-gnu
(all)
-
m68k
-
sid
-
m68k
-
m68k-linux-gnu
+
m68k
+
sid
+
m68k
+
m68k-linux-gnu
zero
-
alpha
-
sid
-
alpha
-
alpha-linux-gnu
+
alpha
+
sid
+
alpha
+
alpha-linux-gnu
zero
-
sh4
-
sid
-
sh4
-
sh4-linux-gnu
+
sh4
+
sid
+
sh4
+
sh4-linux-gnu
zero
-
riscv64
-
sid
-
riscv64
-
riscv64-linux-gnu
+
riscv64
+
sid
+
riscv64
+
riscv64-linux-gnu
(all)
diff --git a/doc/building.md b/doc/building.md
index 142ff7daf36..d6d89d7887f 100644
--- a/doc/building.md
+++ b/doc/building.md
@@ -126,6 +126,8 @@ space is required.
Even for 32-bit builds, it is recommended to use a 64-bit build machine, and
instead create a 32-bit target using `--with-target-bits=32`.
+Note: The Windows 32-bit x86 port is deprecated and may be removed in a future release.
+
### Building on aarch64
At a minimum, a machine with 8 cores is advisable, as well as 8 GB of RAM.
@@ -162,11 +164,11 @@ This table lists the OS versions used by Oracle when building the JDK. Such
information is always subject to change, but this table is up to date at the
time of writing.
- Operating system Vendor/version used
- ----------------- -------------------------------------------------------
- Linux Oracle Enterprise Linux 6.4 / 7.6
- macOS Mac OS X 10.13 (High Sierra)
- Windows Windows Server 2012 R2
+| Operating system | Vendor/version used |
+| ----------------- | ---------------------------------- |
+| Linux | Oracle Enterprise Linux 6.4 / 7.6 |
+| macOS | Mac OS X 10.13 (High Sierra) |
+| Windows | Windows Server 2012 R2 |
The double version numbers for Linux are due to the hybrid model
used at Oracle, where header files and external libraries from an older version
@@ -199,6 +201,8 @@ rule also applies to input to the build system, e.g. in arguments to
`--with-msvcr-dll=c:\msvcr100.dll`. For details on this conversion, see the section
on [Fixpath](#fixpath).
+Note: The Windows 32-bit x86 port is deprecated and may be removed in a future release.
+
#### Cygwin
A functioning [Cygwin](http://www.cygwin.com/) environment is required for
@@ -471,6 +475,19 @@ rather than bundling the JDK's own copy.
Use `--with-freetype-include=` and `--with-freetype-lib=`
if `configure` does not automatically locate the platform FreeType files.
+### Fontconfig
+
+Fontconfig from [freedesktop.org Fontconfig](http://fontconfig.org) is required
+on all platforms except Windows and macOS.
+
+ * To install on an apt-based Linux, try running `sudo apt-get install
+ libfontconfig-dev`.
+ * To install on an rpm-based Linux, try running `sudo yum install
+ fontconfig-devel`.
+
+Use `--with-fontconfig-include=` and `--with-fontconfig=`
+if `configure` does not automatically locate the platform Fontconfig files.
+
### CUPS
CUPS, [Common UNIX Printing System](http://www.cups.org) header files are
@@ -970,14 +987,14 @@ https://sourceware.org/autobook/autobook/autobook_17.html). If no
targets are given, a native toolchain for the current platform will be
created. Currently, at least the following targets are known to work:
- Supported devkit targets
- -------------------------
- x86_64-linux-gnu
- aarch64-linux-gnu
- arm-linux-gnueabihf
- ppc64-linux-gnu
- ppc64le-linux-gnu
- s390x-linux-gnu
+| Supported devkit targets |
+| ------------------------ |
+| x86_64-linux-gnu |
+| aarch64-linux-gnu |
+| arm-linux-gnueabihf |
+| ppc64-linux-gnu |
+| ppc64le-linux-gnu |
+| s390x-linux-gnu |
`BASE_OS` must be one of "OEL6" for Oracle Enterprise Linux 6 or
"Fedora" (if not specified "OEL6" will be the default). If the base OS
@@ -1204,22 +1221,22 @@ it might require a little nudge with:
Architectures that are known to successfully cross-compile like this are:
- Target Debian tree Debian arch `--openjdk-target=...` `--with-jvm-variants=...`
- ------------ ------------ ------------- ------------------------ --------------
- x86 buster i386 i386-linux-gnu (all)
- arm buster armhf arm-linux-gnueabihf (all)
- aarch64 buster arm64 aarch64-linux-gnu (all)
- ppc64le buster ppc64el powerpc64le-linux-gnu (all)
- s390x buster s390x s390x-linux-gnu (all)
- mipsle buster mipsel mipsel-linux-gnu zero
- mips64le buster mips64el mips64el-linux-gnueabi64 zero
- armel buster arm arm-linux-gnueabi zero
- ppc sid powerpc powerpc-linux-gnu zero
- ppc64be sid ppc64 powerpc64-linux-gnu (all)
- m68k sid m68k m68k-linux-gnu zero
- alpha sid alpha alpha-linux-gnu zero
- sh4 sid sh4 sh4-linux-gnu zero
- riscv64 sid riscv64 riscv64-linux-gnu (all)
+| Target | Debian tree | Debian arch | `--openjdk-target=...` | `--with-jvm-variants=...` |
+| ------------ | ------------ | ------------- | ------------------------ | ------------------------- |
+| x86 | buster | i386 | i386-linux-gnu | (all) |
+| arm | buster | armhf | arm-linux-gnueabihf | (all) |
+| aarch64 | buster | arm64 | aarch64-linux-gnu | (all) |
+| ppc64le | buster | ppc64el | powerpc64le-linux-gnu | (all) |
+| s390x | buster | s390x | s390x-linux-gnu | (all) |
+| mipsle | buster | mipsel | mipsel-linux-gnu | zero |
+| mips64le | buster | mips64el | mips64el-linux-gnueabi64 | zero |
+| armel | buster | arm | arm-linux-gnueabi | zero |
+| ppc | sid | powerpc | powerpc-linux-gnu | zero |
+| ppc64be | sid | ppc64 | powerpc64-linux-gnu | (all) |
+| m68k | sid | m68k | m68k-linux-gnu | zero |
+| alpha | sid | alpha | alpha-linux-gnu | zero |
+| sh4 | sid | sh4 | sh4-linux-gnu | zero |
+| riscv64 | sid | riscv64 | riscv64-linux-gnu | (all) |
### Building for ARM/aarch64
diff --git a/make/CompileInterimLangtools.gmk b/make/CompileInterimLangtools.gmk
index 51263fde3bd..bbc2d103696 100644
--- a/make/CompileInterimLangtools.gmk
+++ b/make/CompileInterimLangtools.gmk
@@ -98,6 +98,7 @@ define SetupInterimModule
EXCLUDES := sun javax/tools/snippet-files, \
EXCLUDE_FILES := $(TOPDIR)/src/$1/share/classes/module-info.java \
$(TOPDIR)/src/$1/share/classes/javax/tools/ToolProvider.java \
+ $(TOPDIR)/src/$1/share/classes/com/sun/tools/javac/launcher/Main.java \
Standard.java, \
EXTRA_FILES := $(BUILDTOOLS_OUTPUTDIR)/gensrc/$1.interim/module-info.java \
$($1.interim_EXTRA_FILES), \
diff --git a/make/Docs.gmk b/make/Docs.gmk
index b7014b12acc..183318ec435 100644
--- a/make/Docs.gmk
+++ b/make/Docs.gmk
@@ -110,7 +110,6 @@ JAVA_WARNINGS_ARE_ERRORS ?= -Werror
JAVADOC_OPTIONS := -use -keywords -notimestamp \
-encoding ISO-8859-1 -docencoding UTF-8 -breakiterator \
-splitIndex --system none -javafx --expand-requires transitive \
- --enable-preview -source $(JDK_SOURCE_TARGET_VERSION) \
--override-methods=summary \
--no-external-specs-page
@@ -118,7 +117,6 @@ JAVADOC_OPTIONS := -use -keywords -notimestamp \
# development cycle.
REFERENCE_OPTIONS := -XDignore.symbol.file=true -use -keywords -notimestamp \
-encoding ISO-8859-1 -breakiterator -splitIndex --system none \
- --enable-preview -source $(JDK_SOURCE_TARGET_VERSION) \
-html5 -javafx --expand-requires transitive \
--no-external-specs-page
diff --git a/make/Global.gmk b/make/Global.gmk
index 618e9ca2439..b41c4051cfa 100644
--- a/make/Global.gmk
+++ b/make/Global.gmk
@@ -125,6 +125,11 @@ test-prebuilt:
$(MAKE) --no-print-directory -r -R -I make/common/ -f make/RunTestsPrebuilt.gmk \
test-prebuilt CUSTOM_MAKE_DIR=$(CUSTOM_MAKE_DIR) TEST="$(TEST)" )
+test-prebuilt-with-exit-code:
+ @( cd $(topdir) && \
+ $(MAKE) --no-print-directory -r -R -I make/common/ -f make/RunTestsPrebuilt.gmk \
+ test-prebuilt-with-exit-code CUSTOM_MAKE_DIR=$(CUSTOM_MAKE_DIR) TEST="$(TEST)" )
+
# Alias for backwards compatibility
run-test-prebuilt: test-prebuilt
diff --git a/make/RunTests.gmk b/make/RunTests.gmk
index aba7b3a78f6..770b81af8ac 100644
--- a/make/RunTests.gmk
+++ b/make/RunTests.gmk
@@ -595,16 +595,7 @@ define SetupRunMicroTestBody
endif
# Set library path for native dependencies
- $1_JMH_JVM_ARGS := -Djava.library.path=$$(TEST_IMAGE_DIR)/micro/native \
- --add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED \
- --add-exports java.base/jdk.internal.org.objectweb.asm.tree=ALL-UNNAMED \
- --add-exports java.base/jdk.internal.classfile=ALL-UNNAMED \
- --add-exports java.base/jdk.internal.classfile.attribute=ALL-UNNAMED \
- --add-exports java.base/jdk.internal.classfile.constantpool=ALL-UNNAMED \
- --add-exports java.base/jdk.internal.classfile.instruction=ALL-UNNAMED \
- --add-exports java.base/jdk.internal.classfile.java.lang.constant=ALL-UNNAMED \
- --add-exports java.base/jdk.internal.classfile.components=ALL-UNNAMED \
- --add-exports java.base/jdk.internal.classfile.impl=ALL-UNNAMED
+ $1_JMH_JVM_ARGS := -Djava.library.path=$$(TEST_IMAGE_DIR)/micro/native
ifneq ($$(MICRO_VM_OPTIONS)$$(MICRO_JAVA_OPTIONS), )
$1_JMH_JVM_ARGS += $$(MICRO_VM_OPTIONS) $$(MICRO_JAVA_OPTIONS)
diff --git a/make/RunTestsPrebuilt.gmk b/make/RunTestsPrebuilt.gmk
index 85c6bae6399..ca20ccf26ad 100644
--- a/make/RunTestsPrebuilt.gmk
+++ b/make/RunTestsPrebuilt.gmk
@@ -295,6 +295,11 @@ test-prebuilt:
@cd $(TOPDIR) && $(MAKE) $(MAKE_ARGS) -f make/RunTests.gmk run-test \
TEST="$(TEST)"
+test-prebuilt-with-exit-code: test-prebuilt
+ @if test -f $(MAKESUPPORT_OUTPUTDIR)/exit-with-error ; then \
+ exit 1 ; \
+ fi
+
all: test-prebuilt
.PHONY: default all test-prebuilt
diff --git a/make/autoconf/buildjdk-spec.gmk.in b/make/autoconf/buildjdk-spec.gmk.in
index 524f35f417c..3e7c4a39f60 100644
--- a/make/autoconf/buildjdk-spec.gmk.in
+++ b/make/autoconf/buildjdk-spec.gmk.in
@@ -103,3 +103,7 @@ JVM_FEATURES_server := cds compiler1 compiler2 g1gc serialgc
override EXTRA_CFLAGS :=
override EXTRA_CXXFLAGS :=
override EXTRA_LDFLAGS :=
+
+# hsdis is not needed
+HSDIS_BACKEND := none
+ENABLE_HSDIS_BUNDLING := false
diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4
index e9959196acb..f8fbe14cc38 100644
--- a/make/autoconf/flags-cflags.m4
+++ b/make/autoconf/flags-cflags.m4
@@ -51,6 +51,14 @@ AC_DEFUN([FLAGS_SETUP_SHARED_LIBS],
SET_SHARED_LIBRARY_NAME='-Wl,-install_name,@rpath/[$]1'
SET_SHARED_LIBRARY_MAPFILE='-Wl,-exported_symbols_list,[$]1'
+ elif test "x$OPENJDK_TARGET_OS" = xaix; then
+ # Linking is different on aix
+ SHARED_LIBRARY_FLAGS="-shared -Wl,-bM:SRE -Wl,-bnoentry"
+ SET_EXECUTABLE_ORIGIN=""
+ SET_SHARED_LIBRARY_ORIGIN=''
+ SET_SHARED_LIBRARY_NAME=''
+ SET_SHARED_LIBRARY_MAPFILE=''
+
else
# Default works for linux, might work on other platforms as well.
SHARED_LIBRARY_FLAGS='-shared'
@@ -206,7 +214,6 @@ AC_DEFUN([FLAGS_SETUP_WARNINGS],
WARNINGS_ENABLE_ALL="-Wall -Wextra -Wformat=2 $WARNINGS_ENABLE_ADDITIONAL"
DISABLED_WARNINGS="unknown-warning-option unused-parameter unused"
-
;;
xlc)
@@ -284,9 +291,15 @@ AC_DEFUN([FLAGS_SETUP_OPTIMIZATION],
C_O_FLAG_NONE="${C_O_FLAG_NONE} ${DISABLE_FORTIFY_CFLAGS}"
fi
elif test "x$TOOLCHAIN_TYPE" = xclang; then
- C_O_FLAG_HIGHEST_JVM="-O3"
- C_O_FLAG_HIGHEST="-O3"
- C_O_FLAG_HI="-O3"
+ if test "x$OPENJDK_TARGET_OS" = xaix; then
+ C_O_FLAG_HIGHEST_JVM="-O3 -finline-functions"
+ C_O_FLAG_HIGHEST="-O3 -finline-functions"
+ C_O_FLAG_HI="-O3 -finline-functions"
+ else
+ C_O_FLAG_HIGHEST_JVM="-O3"
+ C_O_FLAG_HIGHEST="-O3"
+ C_O_FLAG_HI="-O3"
+ fi
C_O_FLAG_NORM="-O2"
C_O_FLAG_DEBUG_JVM="-O0"
C_O_FLAG_SIZE="-Os"
@@ -458,6 +471,9 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
# so for debug we build with '-qpic=large -bbigtoc'.
DEBUG_CFLAGS_JVM="-qpic=large"
fi
+ if test "x$TOOLCHAIN_TYPE" = xclang && test "x$OPENJDK_TARGET_OS" = xaix; then
+ DEBUG_CFLAGS_JVM="-fpic -mcmodel=large"
+ fi
fi
if test "x$DEBUG_LEVEL" != xrelease; then
@@ -493,6 +509,12 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
-fvisibility=hidden -fno-strict-aliasing -fno-omit-frame-pointer"
fi
+ if test "x$TOOLCHAIN_TYPE" = xclang && test "x$OPENJDK_TARGET_OS" = xaix; then
+ # clang compiler on aix needs -ffunction-sections
+ TOOLCHAIN_CFLAGS_JVM="$TOOLCHAIN_CFLAGS_JVM -ffunction-sections -ftls-model -fno-math-errno -fstack-protector"
+ TOOLCHAIN_CFLAGS_JDK="-ffunction-sections -fsigned-char -fstack-protector"
+ fi
+
if test "x$TOOLCHAIN_TYPE" = xgcc; then
TOOLCHAIN_CFLAGS_JVM="$TOOLCHAIN_CFLAGS_JVM -fstack-protector"
TOOLCHAIN_CFLAGS_JDK="-pipe -fstack-protector"
@@ -601,6 +623,9 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
PICFLAG="-fPIC"
PIEFLAG="-fPIE"
+ elif test "x$TOOLCHAIN_TYPE" = xclang && test "x$OPENJDK_TARGET_OS" = xaix; then
+ JVM_PICFLAG="-fpic -mcmodel=large -Wl,-bbigtoc
+ JDK_PICFLAG="-fpic
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
# '-qpic' defaults to 'qpic=small'. This means that the compiler generates only
# one instruction for accessing the TOC. If the TOC grows larger than 64K, the linker
@@ -746,6 +771,9 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP],
$1_CFLAGS_CPU_JDK="${$1_CFLAGS_CPU_JDK} -fno-omit-frame-pointer"
fi
fi
+ if test "x$OPENJDK_TARGET_OS" = xaix; then
+ $1_CFLAGS_CPU="-mcpu=pwr8"
+ fi
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
if test "x$FLAGS_CPU" = xppc64; then
diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4
index dcfc8eb4a51..69cbc479804 100644
--- a/make/autoconf/flags-ldflags.m4
+++ b/make/autoconf/flags-ldflags.m4
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2023, 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
@@ -79,7 +79,11 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER],
elif test "x$TOOLCHAIN_TYPE" = xclang; then
BASIC_LDFLAGS_JVM_ONLY="-mno-omit-leaf-frame-pointer -mstack-alignment=16 \
-fPIC"
-
+ if test "x$OPENJDK_TARGET_OS" = xaix; then
+ BASIC_LDFLAGS="-Wl,-b64 -Wl,-brtl -Wl,-bnorwexec -Wl,-bnolibpath -Wl,-bnoexpall \
+ -Wl,-bernotok -Wl,-bdatapsize:64k -Wl,-btextpsize:64k -Wl,-bstackpsize:64k"
+ BASIC_LDFLAGS_JVM_ONLY="$BASIC_LDFLAGS_JVM_ONLY -Wl,-lC_r -Wl,-bbigtoc"
+ fi
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
BASIC_LDFLAGS="-b64 -brtl -bnolibpath -bnoexpall -bernotok -btextpsize:64K \
-bdatapsize:64K -bstackpsize:64K"
@@ -92,7 +96,8 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER],
BASIC_LDFLAGS_JVM_ONLY="-opt:icf,8 -subsystem:windows"
fi
- if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
+ if (test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang) \
+ && test "x$OPENJDK_TARGET_OS" != xaix; then
if test -n "$HAS_NOEXECSTACK"; then
BASIC_LDFLAGS="$BASIC_LDFLAGS -Wl,-z,noexecstack"
fi
@@ -120,6 +125,14 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER],
if test "x$DEBUG_LEVEL" != xrelease; then
DEBUGLEVEL_LDFLAGS_JVM_ONLY="$DEBUGLEVEL_LDFLAGS_JVM_ONLY -bbigtoc"
fi
+
+ elif test "x$TOOLCHAIN_TYPE" = xclang && test "x$OPENJDK_TARGET_OS" = xaix; then
+ # We need '-fpic' or '-fpic -mcmodel=large -Wl,-bbigtoc' if the TOC overflows.
+ # Hotspot now overflows its 64K TOC (currently only for debug),
+ # so we build with '-fpic -mcmodel=large -Wl,-bbigtoc'.
+ if test "x$DEBUG_LEVEL" != xrelease; then
+ DEBUGLEVEL_LDFLAGS_JVM_ONLY="$DEBUGLEVEL_LDFLAGS_JVM_ONLY -Wl,-bbigtoc"
+ fi
fi
# Setup LDFLAGS for linking executables
diff --git a/make/autoconf/platform.m4 b/make/autoconf/platform.m4
index 4a13dad24b5..134e7bb395b 100644
--- a/make/autoconf/platform.m4
+++ b/make/autoconf/platform.m4
@@ -657,6 +657,22 @@ AC_DEFUN_ONCE([PLATFORM_SETUP_OPENJDK_BUILD_AND_TARGET],
PLATFORM_SET_MODULE_TARGET_OS_VALUES
PLATFORM_SET_RELEASE_FILE_OS_VALUES
PLATFORM_SETUP_LEGACY_VARS
+ PLATFORM_CHECK_DEPRECATION
+])
+
+AC_DEFUN_ONCE([PLATFORM_CHECK_DEPRECATION],
+[
+ AC_ARG_ENABLE(deprecated-ports, [AS_HELP_STRING([--enable-deprecated-ports@<:@=yes/no@:>@],
+ [Suppress the error when configuring for a deprecated port @<:@no@:>@])])
+ AC_REQUIRE([PLATFORM_EXTRACT_TARGET_AND_BUILD])
+ if test "x$OPENJDK_TARGET_OS" = xwindows && test "x$OPENJDK_TARGET_CPU" = xx86; then
+ if test "x$enable_deprecated_ports" = "xyes"; then
+ AC_MSG_WARN([The Windows 32-bit x86 port is deprecated and may be removed in a future release.])
+ else
+ AC_MSG_ERROR(m4_normalize([The Windows 32-bit x86 port is deprecated and may be removed in a future release.
+ Use --enable-deprecated-ports=yes to suppress this error.]))
+ fi
+ fi
])
AC_DEFUN_ONCE([PLATFORM_SETUP_OPENJDK_BUILD_OS_VERSION],
diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4
index adb4e182dcc..c89aab11d4b 100644
--- a/make/autoconf/toolchain.m4
+++ b/make/autoconf/toolchain.m4
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2023, 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
@@ -40,7 +40,7 @@ VALID_TOOLCHAINS_all="gcc clang xlc microsoft"
# These toolchains are valid on different platforms
VALID_TOOLCHAINS_linux="gcc clang"
VALID_TOOLCHAINS_macosx="clang"
-VALID_TOOLCHAINS_aix="xlc"
+VALID_TOOLCHAINS_aix="xlc clang"
VALID_TOOLCHAINS_windows="microsoft"
# Toolchain descriptions
@@ -53,7 +53,7 @@ TOOLCHAIN_DESCRIPTION_xlc="IBM XL C/C++"
TOOLCHAIN_MINIMUM_VERSION_clang="3.5"
TOOLCHAIN_MINIMUM_VERSION_gcc="6.0"
TOOLCHAIN_MINIMUM_VERSION_microsoft="19.28.0.0" # VS2019 16.8, aka MSVC 14.28
-TOOLCHAIN_MINIMUM_VERSION_xlc=""
+TOOLCHAIN_MINIMUM_VERSION_xlc="16.1.0.0011"
# Minimum supported linker versions, empty means unspecified
TOOLCHAIN_MINIMUM_LD_VERSION_gcc="2.18"
@@ -234,6 +234,25 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETERMINE_TOOLCHAIN_TYPE],
# First toolchain type in the list is the default
DEFAULT_TOOLCHAIN=${VALID_TOOLCHAINS%% *}
+ # On AIX the default toolchain depends on the installed (found) compiler
+ # xlclang++ -> xlc toolchain
+ # ibm-clang++_r -> clang toolchain
+ # The compiler is searched on the PATH and TOOLCHAIN_PATH
+ # xlclang++ has precedence over ibm-clang++_r if both are installed
+ if test "x$OPENJDK_TARGET_OS" = xaix; then
+ DEFAULT_TOOLCHAIN="clang"
+ if test "x$TOOLCHAIN_PATH" != x; then
+ if test -e ${TOOLCHAIN_PATH}/xlclang++; then
+ DEFAULT_TOOLCHAIN="xlc"
+ fi
+ else
+ UTIL_LOOKUP_PROGS(XLCLANG_TEST_PATH, xlclang++)
+ if test "x$XLCLANG_TEST_PATH" != x; then
+ DEFAULT_TOOLCHAIN="xlc"
+ fi
+ fi
+ fi
+
if test "x$with_toolchain_type" = xlist; then
# List all toolchains
AC_MSG_NOTICE([The following toolchains are valid on this platform:])
@@ -263,22 +282,40 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETERMINE_TOOLCHAIN_TYPE],
if test "x$TOOLCHAIN_PATH" != x; then
XLC_TEST_PATH=${TOOLCHAIN_PATH}/
fi
-
- XLCLANG_VERSION_OUTPUT=`${XLC_TEST_PATH}xlclang++ -qversion 2>&1 | $HEAD -n 1`
- $ECHO "$XLCLANG_VERSION_OUTPUT" | $GREP "IBM XL C/C++ for AIX" > /dev/null
- if test $? -eq 0; then
- AC_MSG_NOTICE([xlclang++ output: $XLCLANG_VERSION_OUTPUT])
+ if test "x$TOOLCHAIN_TYPE" = xclang; then
+ TOOLCHAIN_DESCRIPTION_clang="IBM Open XL C/C++"
+ XLCLANG_VERSION_OUTPUT=`${XLC_TEST_PATH}ibm-clang++_r --version 2>&1 | $HEAD -n 1`
+ $ECHO "$XLCLANG_VERSION_OUTPUT" | $GREP "IBM Open XL C/C++ for AIX" > /dev/null
+ if test $? -eq 0; then
+ AC_MSG_NOTICE([ibm-clang++_r output: $XLCLANG_VERSION_OUTPUT])
+ else
+ AC_MSG_ERROR([ibm-clang++_r version output check failed, output: $XLCLANG_VERSION_OUTPUT])
+ fi
else
- AC_MSG_ERROR([xlclang++ version output check failed, output: $XLCLANG_VERSION_OUTPUT])
+ XLCLANG_VERSION_OUTPUT=`${XLC_TEST_PATH}xlclang++ -qversion 2>&1 | $HEAD -n 1`
+ $ECHO "$XLCLANG_VERSION_OUTPUT" | $GREP "IBM XL C/C++ for AIX" > /dev/null
+ if test $? -eq 0; then
+ AC_MSG_NOTICE([xlclang++ output: $XLCLANG_VERSION_OUTPUT])
+ else
+ AC_MSG_ERROR([xlclang++ version output check failed, output: $XLCLANG_VERSION_OUTPUT])
+ fi
fi
fi
- TOOLCHAIN_CC_BINARY_clang="clang"
+ if test "x$OPENJDK_TARGET_OS" = xaix; then
+ TOOLCHAIN_CC_BINARY_clang="ibm-clang_r"
+ else
+ TOOLCHAIN_CC_BINARY_clang="clang"
+ fi
TOOLCHAIN_CC_BINARY_gcc="gcc"
TOOLCHAIN_CC_BINARY_microsoft="cl"
TOOLCHAIN_CC_BINARY_xlc="xlclang"
- TOOLCHAIN_CXX_BINARY_clang="clang++"
+ if test "x$OPENJDK_TARGET_OS" = xaix; then
+ TOOLCHAIN_CXX_BINARY_clang="ibm-clang++_r"
+ else
+ TOOLCHAIN_CXX_BINARY_clang="clang++"
+ fi
TOOLCHAIN_CXX_BINARY_gcc="g++"
TOOLCHAIN_CXX_BINARY_microsoft="cl"
TOOLCHAIN_CXX_BINARY_xlc="xlclang++"
@@ -384,7 +421,7 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_COMPILER_VERSION],
# Collapse compiler output into a single line
COMPILER_VERSION_STRING=`$ECHO $COMPILER_VERSION_OUTPUT`
COMPILER_VERSION_NUMBER=`$ECHO $COMPILER_VERSION_OUTPUT | \
- $SED -e 's/^.*, V\(@<:@1-9@:>@@<:@0-9.@:>@*\).*$/\1/'`
+ $SED -e 's/^.*Version: \(@<:@1-9@:>@@<:@0-9.@:>@*\).*$/\1/'`
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
# There is no specific version flag, but all output starts with a version string.
# First line typically looks something like:
@@ -632,7 +669,7 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETECT_TOOLCHAIN_CORE],
if test "x$TOOLCHAIN_MINIMUM_VERSION" != x; then
TOOLCHAIN_CHECK_COMPILER_VERSION(VERSION: $TOOLCHAIN_MINIMUM_VERSION,
IF_OLDER_THAN: [
- AC_MSG_WARN([You are using $TOOLCHAIN_TYPE older than $TOOLCHAIN_MINIMUM_VERSION. This is not a supported configuration.])
+ AC_MSG_WARN([You are using $TOOLCHAIN_TYPE $CC_VERSION_NUMBER which is older than $TOOLCHAIN_MINIMUM_VERSION. This is not a supported configuration.])
]
)
fi
@@ -966,7 +1003,11 @@ AC_DEFUN_ONCE([TOOLCHAIN_MISC_CHECKS],
# Setup hotspot lecagy names for toolchains
HOTSPOT_TOOLCHAIN_TYPE=$TOOLCHAIN_TYPE
if test "x$TOOLCHAIN_TYPE" = xclang; then
- HOTSPOT_TOOLCHAIN_TYPE=gcc
+ if test "x$OPENJDK_TARGET_OS" = xaix; then
+ HOTSPOT_TOOLCHAIN_TYPE=xlc
+ else
+ HOTSPOT_TOOLCHAIN_TYPE=gcc
+ fi
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
HOTSPOT_TOOLCHAIN_TYPE=visCPP
fi
diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js
index 2c6742c94e7..117b5aaf157 100644
--- a/make/conf/jib-profiles.js
+++ b/make/conf/jib-profiles.js
@@ -599,10 +599,11 @@ var getJibProfilesProfiles = function (input, common, data) {
"linux-aarch64-zero": {
target_os: "linux",
target_cpu: "aarch64",
- dependencies: ["devkit", "gtest"],
+ dependencies: ["devkit", "gtest", "libffi"],
configure_args: concat(common.configure_args_64bit, [
"--with-zlib=system",
"--with-jvm-variants=zero",
+ "--with-libffi=" + input.get("libffi", "home_path"),
"--enable-libffi-bundling"
])
},
@@ -611,10 +612,11 @@ var getJibProfilesProfiles = function (input, common, data) {
target_os: "linux",
target_cpu: "x86",
build_cpu: "x64",
- dependencies: ["devkit", "gtest"],
+ dependencies: ["devkit", "gtest", "libffi"],
configure_args: concat(common.configure_args_32bit, [
"--with-zlib=system",
"--with-jvm-variants=zero",
+ "--with-libffi=" + input.get("libffi", "home_path"),
"--enable-libffi-bundling"
])
}
@@ -1272,7 +1274,7 @@ var getJibProfilesDependencies = function (input, common) {
libffi: {
organization: common.organization,
- module: "libffi-" + input.build_platform,
+ module: "libffi-" + input.target_platform,
ext: "tar.gz",
revision: "3.4.2+1.0"
},
diff --git a/make/data/charsetmapping/DoubleByte-X.java.template b/make/data/charsetmapping/DoubleByte-X.java.template
index 20bc9fdc8de..38f1d1be5fd 100644
--- a/make/data/charsetmapping/DoubleByte-X.java.template
+++ b/make/data/charsetmapping/DoubleByte-X.java.template
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -56,10 +56,10 @@ public class $NAME_CLZ$ extends Charset
return new DoubleByte.Encoder$ENCTYPE$(this, $ENC_REPLACEMENT$ EncodeHolder.c2b, EncodeHolder.c2bIndex, $ASCIICOMPATIBLE$);
}
- static class DecodeHolder {
+ public static class DecodeHolder {
$B2C$
- static final char[][] b2c = new char[b2cStr.length][];
- static final char[] b2cSB;
+ public static final char[][] b2c = new char[b2cStr.length][];
+ public static final char[] b2cSB;
static {
for (int i = 0; i < b2cStr.length; i++) {
@@ -72,9 +72,9 @@ public class $NAME_CLZ$ extends Charset
}
}
- static class EncodeHolder {
- static final char[] c2b = new char[$C2BLENGTH$];
- static final char[] c2bIndex = new char[0x100];
+ public static class EncodeHolder {
+ public static final char[] c2b = new char[$C2BLENGTH$];
+ public static final char[] c2bIndex = new char[0x100];
static {
$NONROUNDTRIP_B2C$
diff --git a/make/data/charsetmapping/stdcs-linux b/make/data/charsetmapping/stdcs-linux
index b9e80ca6455..25f46489710 100644
--- a/make/data/charsetmapping/stdcs-linux
+++ b/make/data/charsetmapping/stdcs-linux
@@ -2,13 +2,11 @@
# generate these charsets into sun.nio.cs
#
Big5
-Big5_Solaris
Big5_HKSCS
EUC_CN
EUC_KR
EUC_JP
EUC_JP_LINUX
-EUC_JP_Open
EUC_TW
GBK
ISO_8859_11
@@ -16,12 +14,9 @@ ISO_8859_3
ISO_8859_6
ISO_8859_8
Johab
-PCK
TIS_620
JIS_X_0201
JIS_X_0208
JIS_X_0212
-JIS_X_0208_Solaris
-JIS_X_0212_Solaris
MS932
SJIS
diff --git a/make/data/hotspot-symbols/symbols-unix b/make/data/hotspot-symbols/symbols-unix
index c08ce4590fc..5cf6662cba8 100644
--- a/make/data/hotspot-symbols/symbols-unix
+++ b/make/data/hotspot-symbols/symbols-unix
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, 2023, 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
@@ -181,6 +181,7 @@ JVM_NewArray
JVM_NewInstanceFromConstructor
JVM_NewMultiArray
JVM_PhantomReferenceRefersTo
+JVM_PrintWarningAtDynamicAgentLoad
JVM_RaiseSignal
JVM_RawMonitorCreate
JVM_RawMonitorDestroy
@@ -217,6 +218,8 @@ JVM_DefineModule
JVM_SetBootLoaderUnnamedModule
# Virtual thread notifications for JVMTI
+JVM_VirtualThreadStart
+JVM_VirtualThreadEnd
JVM_VirtualThreadMount
JVM_VirtualThreadUnmount
JVM_VirtualThreadHideFrames
diff --git a/make/devkit/createLibffiBundle.sh b/make/devkit/createLibffiBundle.sh
index 62d714a5148..100dcc1fe0d 100644
--- a/make/devkit/createLibffiBundle.sh
+++ b/make/devkit/createLibffiBundle.sh
@@ -81,6 +81,7 @@ cd $LIBFFI_DIR
if [ ! -e $LIBFFI_DIR/configure ]; then
bash ./autogen.sh
fi
+# For Linux/x86, add --build=i686-pc-linux-gnu CFLAGS=-m32 CXXFLAGS=-m32 LDFLAGS=-m32
bash ./configure --prefix=$INSTALL_DIR CC=$DEVKIT_DIR/bin/gcc CXX=$DEVKIT_DIR/bin/g++
# Run with nice to keep system usable during build.
@@ -91,6 +92,7 @@ mkdir -p $IMAGE_DIR
if [ ! -e $IMAGE_DIR/lib/libffi.so ]; then
echo "Copying libffi.so* to image"
mkdir -p $IMAGE_DIR/lib
+ # For Linux/x86 it's under /lib/ instead of /lib64/
cp -a $INSTALL_DIR/lib64/libffi.so* $IMAGE_DIR/lib/
fi
if [ ! -e $IMAGE_DIR/include/ ]; then
diff --git a/make/hotspot/gensrc/GensrcAdlc.gmk b/make/hotspot/gensrc/GensrcAdlc.gmk
index 5c8989e3efd..427a0dfd34b 100644
--- a/make/hotspot/gensrc/GensrcAdlc.gmk
+++ b/make/hotspot/gensrc/GensrcAdlc.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2023, 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,8 +37,13 @@ ifeq ($(call check-jvm-feature, compiler2), true)
ifeq ($(call isBuildOs, linux), true)
ADLC_CFLAGS := -fno-exceptions -DLINUX
else ifeq ($(call isBuildOs, aix), true)
- ADLC_LDFLAGS += -q64
- ADLC_CFLAGS := -qnortti -qeh -q64 -DAIX
+ ifeq ($(TOOLCHAIN_TYPE), clang)
+ ADLC_LDFLAGS += -m64
+ ADLC_CFLAGS := -fno-rtti -fexceptions -ffunction-sections -m64 -DAIX -mcpu=pwr8
+ else
+ ADLC_LDFLAGS += -q64
+ ADLC_CFLAGS := -qnortti -qeh -q64 -DAIX
+ endif
else ifeq ($(call isBuildOs, windows), true)
ADLC_LDFLAGS += -nologo
ADLC_CFLAGS := -nologo -EHsc
@@ -167,6 +172,8 @@ ifeq ($(call check-jvm-feature, compiler2), true)
ifeq ($(call check-jvm-feature, zgc), true)
AD_SRC_FILES += $(call uniq, $(wildcard $(foreach d, $(AD_SRC_ROOTS), \
+ $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/x/x_$(HOTSPOT_TARGET_CPU).ad \
+ $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/x/x_$(HOTSPOT_TARGET_CPU_ARCH).ad \
$d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/z/z_$(HOTSPOT_TARGET_CPU).ad \
$d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/z/z_$(HOTSPOT_TARGET_CPU_ARCH).ad \
)))
diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk
index e73d8702c28..adb964d0538 100644
--- a/make/hotspot/lib/CompileJvm.gmk
+++ b/make/hotspot/lib/CompileJvm.gmk
@@ -168,10 +168,14 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJVM, \
DISABLED_WARNINGS_clang_management.cpp := missing-field-initializers, \
DISABLED_WARNINGS_clang_notificationThread.cpp := bitwise-instead-of-logical, \
DISABLED_WARNINGS_clang_os_posix.cpp := mismatched-tags missing-field-initializers, \
+ DISABLED_WARNINGS_clang_aix_os_posix.cpp := format-nonliteral, \
DISABLED_WARNINGS_clang_postaloc.cpp := tautological-undefined-compare, \
DISABLED_WARNINGS_clang_serviceThread.cpp := bitwise-instead-of-logical, \
DISABLED_WARNINGS_clang_vm_version_x86.cpp := missing-field-initializers, \
DISABLED_WARNINGS_clang_zTracer.cpp := undefined-var-template, \
+ DISABLED_WARNINGS_clang_aix_debug.cpp := format-nonliteral, \
+ DISABLED_WARNINGS_clang_aix_jvm.cpp := format-nonliteral, \
+ DISABLED_WARNINGS_clang_aix_osThread_aix.cpp := tautological-undefined-compare, \
DISABLED_WARNINGS_xlc := $(DISABLED_WARNINGS_xlc), \
DISABLED_WARNINGS_microsoft := $(DISABLED_WARNINGS_microsoft), \
ASFLAGS := $(JVM_ASFLAGS), \
diff --git a/make/hotspot/lib/JvmFeatures.gmk b/make/hotspot/lib/JvmFeatures.gmk
index 1e24475ea46..cbe60fde205 100644
--- a/make/hotspot/lib/JvmFeatures.gmk
+++ b/make/hotspot/lib/JvmFeatures.gmk
@@ -149,6 +149,7 @@ endif
ifneq ($(call check-jvm-feature, zgc), true)
JVM_CFLAGS_FEATURES += -DINCLUDE_ZGC=0
JVM_EXCLUDE_PATTERNS += gc/z
+ JVM_EXCLUDE_PATTERNS += gc/x
endif
ifneq ($(call check-jvm-feature, shenandoahgc), true)
diff --git a/make/hotspot/lib/JvmOverrideFiles.gmk b/make/hotspot/lib/JvmOverrideFiles.gmk
index 377018cdb51..b50d6f8bb36 100644
--- a/make/hotspot/lib/JvmOverrideFiles.gmk
+++ b/make/hotspot/lib/JvmOverrideFiles.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2023, 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
@@ -109,7 +109,11 @@ else ifeq ($(call isTargetOs, macosx), true)
endif
else ifeq ($(call isTargetOs, aix), true)
- BUILD_LIBJVM_synchronizer.cpp_CXXFLAGS := -qnoinline
+ ifeq ($(TOOLCHAIN_TYPE), clang)
+ BUILD_LIBJVM_synchronizer.cpp_CXXFLAGS := -fno-inline
+ else
+ BUILD_LIBJVM_synchronizer.cpp_CXXFLAGS := -qnoinline
+ endif
BUILD_LIBJVM_sharedRuntimeTrans.cpp_CXXFLAGS := $(CXX_O_FLAG_NONE)
# Disable aggressive optimizations for functions in sharedRuntimeTrig.cpp
# and sharedRuntimeTrans.cpp on ppc64.
diff --git a/make/jdk/src/classes/build/tools/generatelsrequivmaps/EquivMapsGenerator.java b/make/jdk/src/classes/build/tools/generatelsrequivmaps/EquivMapsGenerator.java
index 79597f4d8b2..5af0c268096 100644
--- a/make/jdk/src/classes/build/tools/generatelsrequivmaps/EquivMapsGenerator.java
+++ b/make/jdk/src/classes/build/tools/generatelsrequivmaps/EquivMapsGenerator.java
@@ -60,7 +60,9 @@ public static void main(String[] args) throws Exception {
}
copyrightYear = Integer.parseInt(args[2]);
readLSRfile(args[0]);
+ // Builds the maps from the IANA data
generateEquivalentMap();
+ // Writes the maps out to LocaleEquivalentMaps.java
generateSourceCode(args[1]);
}
@@ -213,63 +215,6 @@ private static String[] createLangArray(int index, String[] subtags) {
return list.toArray(new String[list.size()]);
}
- private static String generateValuesString(String[] values) {
- String outputStr = "";
- for (int i = 0; i < values.length; i++) {
- if (i != values.length - 1) {
- outputStr = outputStr + "\"" + values[i] + "\", ";
- } else {
- outputStr = outputStr + "\"" + values[i] + "\"";
- }
-
- }
- return outputStr;
- }
-
- private static final String COPYRIGHT = "/*\n"
- + " * Copyright (c) 2012, %d, Oracle and/or its affiliates. All rights reserved.\n"
- + " * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n"
- + " *\n"
- + " * This code is free software; you can redistribute it and/or modify it\n"
- + " * under the terms of the GNU General Public License version 2 only, as\n"
- + " * published by the Free Software Foundation. Oracle designates this\n"
- + " * particular file as subject to the \"Classpath\" exception as provided\n"
- + " * by Oracle in the LICENSE file that accompanied this code.\n"
- + " *\n"
- + " * This code is distributed in the hope that it will be useful, but WITHOUT\n"
- + " * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n"
- + " * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n"
- + " * version 2 for more details (a copy is included in the LICENSE file that\n"
- + " * accompanied this code).\n"
- + " *\n"
- + " * You should have received a copy of the GNU General Public License version\n"
- + " * 2 along with this work; if not, write to the Free Software Foundation,\n"
- + " * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n"
- + " *\n"
- + " * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n"
- + " * or visit www.oracle.com if you need additional information or have any\n"
- + " * questions.\n"
- + "*/\n\n";
-
- private static final String headerText =
- "package sun.util.locale;\n\n"
- + "import java.util.HashMap;\n"
- + "import java.util.Map;\n\n"
- + "final class LocaleEquivalentMaps {\n\n"
- + " static final Map singleEquivMap;\n"
- + " static final Map multiEquivsMap;\n"
- + " static final Map regionVariantEquivMap;\n\n"
- + " static {\n"
- + " singleEquivMap = HashMap.newHashMap(";
-
- private static final String footerText =
- " }\n\n"
- + "}";
-
- private static String getOpenJDKCopyright() {
- return String.format(Locale.US, COPYRIGHT, copyrightYear);
- }
-
/**
* The input lsr data file is in UTF-8, so theoretically for the characters
* beyond US-ASCII, the generated Java String literals need to be Unicode
@@ -277,53 +222,132 @@ private static String getOpenJDKCopyright() {
* the case since we don't use "description", "comment" or alike.
*/
private static void generateSourceCode(String fileName) {
-
try (BufferedWriter writer = Files.newBufferedWriter(
Paths.get(fileName))) {
writer.write(getOpenJDKCopyright());
- writer.write(headerText
- + sortedLanguageMap1.size() + ");\n"
- + " multiEquivsMap = HashMap.newHashMap("
- + sortedLanguageMap2.size() + ");\n"
- + " regionVariantEquivMap = HashMap.newHashMap("
- + sortedRegionVariantMap.size() + ");\n\n"
- + " // This is an auto-generated file and should not be manually edited.\n"
- + " // LSR Revision: " + LSRrevisionDate);
+ writer.write(HEADER_TEXT);
+ writer.write(getMapsText());
+ writer.write(getLSRText());
+ writeEquiv(writer, "singleEquivMap", sortedLanguageMap1);
writer.newLine();
+ writeMultiEquiv(writer);
+ writer.newLine();
+ writeEquiv(writer, "regionVariantEquivMap", sortedRegionVariantMap);
+ writer.write(FOOTER_TEXT);
+ } catch (IOException ex) {
+ ex.printStackTrace(System.err);
+ System.exit(1);
+ }
+ }
- for (String key : sortedLanguageMap1.keySet()) {
- String value = sortedLanguageMap1.get(key);
- writer.write(" singleEquivMap.put(\""
- + key + "\", \"" + value + "\");");
- writer.newLine();
- }
+ private static String getOpenJDKCopyright() {
+ return String.format(Locale.US, COPYRIGHT, copyrightYear);
+ }
- writer.newLine();
- for (String key : sortedLanguageMap2.keySet()) {
- String[] values = sortedLanguageMap2.get(key);
-
- if (values.length >= 2) {
- writer.write(" multiEquivsMap.put(\""
- + key + "\", new String[] {"
- + generateValuesString(values) + "});");
- writer.newLine();
+ private static final String COPYRIGHT =
+ """
+ /*
+ * Copyright (c) 2012, %d, 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.
+ *
+ * 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.
+ */
+
+ """;
+
+ private static final String HEADER_TEXT =
+ """
+ package sun.util.locale;
+
+ import java.util.HashMap;
+ import java.util.Map;
+
+ final class LocaleEquivalentMaps {
+
+ static final Map singleEquivMap;
+ static final Map multiEquivsMap;
+ static final Map regionVariantEquivMap;
+
+ """;
+
+ private static final String FOOTER_TEXT =
+ """
}
+
}
+ """;
+
+ private static String getMapsText() {
+ return """
+ static {
+ singleEquivMap = HashMap.newHashMap(%s);
+ multiEquivsMap = HashMap.newHashMap(%s);
+ regionVariantEquivMap = HashMap.newHashMap(%s);
+
+ """.formatted(
+ sortedLanguageMap1.size(),
+ sortedLanguageMap2.size(),
+ sortedRegionVariantMap.size());
+ }
- writer.newLine();
- for (String key : sortedRegionVariantMap.keySet()) {
- String value = sortedRegionVariantMap.get(key);
- writer.write(" regionVariantEquivMap.put(\""
- + key + "\", \"" + value + "\");");
+ private static final String getLSRText(){
+ return """
+ // This is an auto-generated file and should not be manually edited.
+ // LSR Revision: %s
+ """.formatted(LSRrevisionDate);
+ }
+
+ private static void writeMultiEquiv(BufferedWriter writer) throws IOException {
+ for (String key : sortedLanguageMap2.keySet()) {
+ String[] values = sortedLanguageMap2.get(key);
+ if (values.length >= 2) {
+ writer.write(String.format(
+ " multiEquivsMap.put(\"%s\", new String[] {%s});"
+ , key, generateValuesString(values)));
writer.newLine();
}
-
- writer.write(footerText);
- } catch (IOException ex) {
- ex.printStackTrace(System.err);
- System.exit(1);
}
+ }
+ // Use for writing an equivlancy map with one value
+ private static void writeEquiv(BufferedWriter writer, String name, Map map) throws IOException {
+ for (String key : map.keySet()) {
+ String value = map.get(key);
+ writer.write(String.format(
+ " %s.put(\"%s\", \"%s\");"
+ , name, key, value));
+ writer.newLine();
+ }
}
+ private static String generateValuesString(String[] values) {
+ String outputStr = "";
+ for (int i = 0; i < values.length; i++) {
+ if (i != values.length - 1) {
+ outputStr = String.format("%s\"%s\", ", outputStr, values[i]);
+ } else {
+ outputStr = String.format("%s\"%s\"", outputStr, values[i]);
+ }
+
+ }
+ return outputStr;
+ }
}
diff --git a/make/jdk/src/classes/build/tools/taglet/SealedGraph.java b/make/jdk/src/classes/build/tools/taglet/SealedGraph.java
index df719d6fce6..787789fa0d0 100644
--- a/make/jdk/src/classes/build/tools/taglet/SealedGraph.java
+++ b/make/jdk/src/classes/build/tools/taglet/SealedGraph.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2023, 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
@@ -145,11 +145,15 @@ String graph(TypeElement rootClass, Set exports) {
static void traverse(State state, TypeElement node, Set exports) {
state.addNode(node);
- for (TypeElement subNode : permittedSubclasses(node, exports)) {
- if (isInPublicApi(node, exports) && isInPublicApi(subNode, exports)) {
- state.addEdge(node, subNode);
+ if (!(node.getModifiers().contains(Modifier.SEALED) || node.getModifiers().contains(Modifier.FINAL))) {
+ state.addNonSealedEdge(node);
+ } else {
+ for (TypeElement subNode : permittedSubclasses(node, exports)) {
+ if (isInPublicApi(node, exports) && isInPublicApi(subNode, exports)) {
+ state.addEdge(node, subNode);
+ }
+ traverse(state, subNode, exports);
}
- traverse(state, subNode, exports);
}
}
@@ -158,13 +162,31 @@ private final class State {
private static final String LABEL = "label";
private static final String TOOLTIP = "tooltip";
private static final String LINK = "href";
- private static final String STYLE = "style";
private final TypeElement rootNode;
private final StringBuilder builder;
- private final Map> nodeStyleMap;
+ private final Map> nodeStyleMap;
+
+ private int nonSealedHierarchyCount = 0;
+
+ private sealed interface StyleItem {
+ String valueString();
+
+ record PlainString(String text) implements StyleItem {
+ @Override
+ public String valueString() {
+ return "\"" + text + "\"";
+ }
+ }
+ record HtmlString(String text) implements StyleItem {
+ @Override
+ public String valueString() {
+ return "<" + text + ">";
+ }
+ }
+ }
public State(TypeElement rootNode) {
this.rootNode = rootNode;
@@ -188,13 +210,9 @@ public State(TypeElement rootNode) {
public void addNode(TypeElement node) {
var styles = nodeStyleMap.computeIfAbsent(id(node), n -> new LinkedHashMap<>());
- styles.put(LABEL, node.getSimpleName().toString());
- styles.put(TOOLTIP, node.getQualifiedName().toString());
- styles.put(LINK, relativeLink(node));
- if (!(node.getModifiers().contains(Modifier.SEALED) || node.getModifiers().contains(Modifier.FINAL))) {
- // This indicates that the hierarchy is not closed
- styles.put(STYLE, "dashed");
- }
+ styles.put(LABEL, new StyleItem.PlainString(node.getSimpleName().toString()));
+ styles.put(TOOLTIP, new StyleItem.PlainString(node.getQualifiedName().toString()));
+ styles.put(LINK, new StyleItem.PlainString(relativeLink(node)));
}
// A permitted class must be in the same package or in the same module.
@@ -223,12 +241,32 @@ public void addEdge(TypeElement node, TypeElement subNode) {
.append(lineSeparator());
}
+ public void addNonSealedEdge(TypeElement node) {
+ // prepare open node
+ var openNodeId = "open node #" + nonSealedHierarchyCount++;
+ var styles = nodeStyleMap.computeIfAbsent(openNodeId, n -> new LinkedHashMap<>());
+ styles.put(LABEL, new StyleItem.HtmlString("<any>"));
+ styles.put(TOOLTIP, new StyleItem.PlainString("Non-sealed Hierarchy"));
+
+ // add link to parent node
+ builder.append(" ")
+ .append('"')
+ .append(openNodeId)
+ .append('"')
+ .append(" -> ")
+ .append(quotedId(node))
+ .append(" ")
+ .append("[style=\"dashed\"]")
+ .append(";")
+ .append(lineSeparator());
+ }
+
public String render() {
nodeStyleMap.forEach((nodeName, styles) -> {
builder.append(" ")
.append('"').append(nodeName).append("\" ")
.append(styles.entrySet().stream()
- .map(e -> e.getKey() + "=\"" + e.getValue() + "\"")
+ .map(e -> e.getKey() + "=" + e.getValue().valueString())
.collect(joining(" ", "[", "]")))
.append(lineSeparator());
});
@@ -265,16 +303,17 @@ private static List permittedSubclasses(TypeElement node, Set exports) {
- return (exports.contains(packageName(typeElement.getQualifiedName().toString())) ||
- exports.contains(packageName(typeElement.getSuperclass().toString()))) &&
- typeElement.getModifiers().contains(Modifier.PUBLIC);
+ var packageName = packageName(typeElement);
+ return packageName.isPresent() && exports.contains(packageName.get()) &&
+ typeElement.getModifiers().contains(Modifier.PUBLIC);
}
- private static String packageName(String name) {
- int lastDot = name.lastIndexOf('.');
- return lastDot < 0
- ? ""
- : name.substring(0, lastDot);
+ private static Optional packageName(TypeElement element) {
+ return switch (element.getNestingKind()) {
+ case TOP_LEVEL -> Optional.of(((PackageElement) element.getEnclosingElement()).getQualifiedName().toString());
+ case ANONYMOUS, LOCAL -> Optional.empty();
+ case MEMBER -> packageName((TypeElement) element.getEnclosingElement());
+ };
}
}
}
diff --git a/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java b/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java
index 5e3cd01a4b8..03cb62429c1 100644
--- a/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java
+++ b/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2023, 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
@@ -2384,7 +2384,8 @@ private boolean readAttribute(ClassFile cf, FeatureDescription feature, Attribut
MethodDescription method = (MethodDescription) feature;
method.methodParameters = new ArrayList<>();
for (MethodParameters_attribute.Entry e : params.method_parameter_table) {
- String name = cf.constant_pool.getUTF8Value(e.name_index);
+ String name = e.name_index == 0 ? null
+ : cf.constant_pool.getUTF8Value(e.name_index);
MethodDescription.MethodParam param =
new MethodDescription.MethodParam(e.flags, name);
method.methodParameters.add(param);
diff --git a/make/modules/java.base/Java.gmk b/make/modules/java.base/Java.gmk
index 11fa2cac4fa..90350557b37 100644
--- a/make/modules/java.base/Java.gmk
+++ b/make/modules/java.base/Java.gmk
@@ -27,9 +27,7 @@ DISABLED_WARNINGS_java += this-escape
DOCLINT += -Xdoclint:all/protected \
'-Xdoclint/package:java.*,javax.*'
-JAVAC_FLAGS += -XDstringConcat=inline \
- --enable-preview
-DISABLED_WARNINGS_java += preview
+JAVAC_FLAGS += -XDstringConcat=inline
COPY += .icu .dat .spp .nrm content-types.properties \
hijrah-config-Hijrah-umalqura_islamic-umalqura.properties
CLEAN += intrinsic.properties
diff --git a/make/modules/java.base/gensrc/GensrcMisc.gmk b/make/modules/java.base/gensrc/GensrcMisc.gmk
index b2bae11baa3..e37aa50d41c 100644
--- a/make/modules/java.base/gensrc/GensrcMisc.gmk
+++ b/make/modules/java.base/gensrc/GensrcMisc.gmk
@@ -50,11 +50,33 @@ $(eval $(call SetupTextFileProcessing, BUILD_VERSION_JAVA, \
@@VENDOR_URL_VM_BUG@@ => $(VENDOR_URL_VM_BUG), \
))
+
+# Normalize OPENJDK_TARGET_CPU name to match jdk.internal.util.Architecture enum
+ifneq ($(filter $(OPENJDK_TARGET_CPU), ppc64le), )
+ OPENJDK_TARGET_ARCH_CANONICAL = ppc64
+else ifneq ($(filter $(OPENJDK_TARGET_CPU), s390x), )
+ OPENJDK_TARGET_ARCH_CANONICAL = s390
+else ifneq ($(filter $(OPENJDK_TARGET_CPU), x86_64 amd64), )
+ OPENJDK_TARGET_ARCH_CANONICAL = x64
+else
+ OPENJDK_TARGET_ARCH_CANONICAL := $(OPENJDK_TARGET_CPU)
+endif
+
+# Normalize OPENJDK_TARGET_OS operating system name to match jdk.internal.util.OperatingSystem enum
+ifeq ($(OPENJDK_TARGET_OS), macosx)
+ OPENJDK_TARGET_OS_CANONICAL = macos
+else
+ OPENJDK_TARGET_OS_CANONICAL := $(OPENJDK_TARGET_OS)
+endif
+
$(eval $(call SetupTextFileProcessing, BUILD_PLATFORMPROPERTIES_JAVA, \
- SOURCE_FILES := $(TOPDIR)/src/java.base/share/classes/jdk/internal/util/OperatingSystemProps.java.template, \
- OUTPUT_FILE := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/util/OperatingSystemProps.java, \
+ SOURCE_FILES := $(TOPDIR)/src/java.base/share/classes/jdk/internal/util/PlatformProps.java.template, \
+ OUTPUT_FILE := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/util/PlatformProps.java, \
REPLACEMENTS := \
- @@OPENJDK_TARGET_OS@@ => $(OPENJDK_TARGET_OS), \
+ @@OPENJDK_TARGET_OS@@ => $(OPENJDK_TARGET_OS_CANONICAL) ; \
+ @@OPENJDK_TARGET_CPU@@ => $(OPENJDK_TARGET_ARCH_CANONICAL) ; \
+ @@OPENJDK_TARGET_CPU_ENDIAN@@ => $(OPENJDK_TARGET_CPU_ENDIAN) ; \
+ @@OPENJDK_TARGET_CPU_BITS@@ => $(OPENJDK_TARGET_CPU_BITS), \
))
TARGETS += $(BUILD_VERSION_JAVA) $(BUILD_PLATFORMPROPERTIES_JAVA)
diff --git a/make/modules/java.desktop/lib/Awt2dLibraries.gmk b/make/modules/java.desktop/lib/Awt2dLibraries.gmk
index a0d70333108..a083af114bd 100644
--- a/make/modules/java.desktop/lib/Awt2dLibraries.gmk
+++ b/make/modules/java.desktop/lib/Awt2dLibraries.gmk
@@ -240,6 +240,14 @@ ifeq ($(call isTargetOs, windows macosx), false)
DISABLED_WARNINGS_gcc_XRBackendNative.c := maybe-uninitialized, \
DISABLED_WARNINGS_gcc_XToolkit.c := unused-result, \
DISABLED_WARNINGS_gcc_XWindow.c := unused-function, \
+ DISABLED_WARNINGS_clang_aix := deprecated-non-prototype, \
+ DISABLED_WARNINGS_clang_aix_awt_Taskbar.c := parentheses, \
+ DISABLED_WARNINGS_clang_aix_OGLPaints.c := format-nonliteral, \
+ DISABLED_WARNINGS_clang_aix_OGLBufImgOps.c := format-nonliteral, \
+ DISABLED_WARNINGS_clang_aix_gtk2_interface.c := parentheses logical-op-parentheses, \
+ DISABLED_WARNINGS_clang_aix_gtk3_interface.c := parentheses logical-op-parentheses, \
+ DISABLED_WARNINGS_clang_aix_sun_awt_X11_GtkFileDialogPeer.c := parentheses, \
+ DISABLED_WARNINGS_clang_aix_awt_InputMethod.c := sign-compare, \
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN) \
-L$(INSTALL_LIBRARIES_HERE), \
@@ -446,16 +454,19 @@ else
# Early re-canonizing has to be disabled to workaround an internal XlC compiler error
# when building libharfbuzz
ifeq ($(call isTargetOs, aix), true)
+ ifneq ($(TOOLCHAIN_TYPE), clang)
HARFBUZZ_CFLAGS += -qdebug=necan
+ endif
endif
# hb-ft.cc is not presently needed, and requires freetype 2.4.2 or later.
LIBFONTMANAGER_EXCLUDE_FILES += libharfbuzz/hb-ft.cc
HARFBUZZ_DISABLED_WARNINGS_gcc := missing-field-initializers strict-aliasing \
- unused-result
+ unused-result array-bounds
# noexcept-type required for GCC 7 builds. Not required for GCC 8+.
- HARFBUZZ_DISABLED_WARNINGS_CXX_gcc := class-memaccess noexcept-type
+ # expansion-to-defined required for GCC 9 builds. Not required for GCC 10+.
+ HARFBUZZ_DISABLED_WARNINGS_CXX_gcc := class-memaccess noexcept-type expansion-to-defined dangling-reference
HARFBUZZ_DISABLED_WARNINGS_clang := missing-field-initializers range-loop-analysis
HARFBUZZ_DISABLED_WARNINGS_microsoft := 4267 4244
@@ -692,6 +703,20 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false)
endif
endif
+ # The external libpng submitted in the jdk is a reduced version
+ # which does not contain .png_init_filter_functions_vsx.
+ # Therefore we need to disable PNG_POWERPC_VSX_OPT explicitly by setting
+ # it to 0. If this define is not set, it would be automatically set to 2,
+ # because
+ # "#if defined(__PPC64__) && defined(__ALTIVEC__) && defined(__VSX__)"
+ # expands to true. This would results in the fact that
+ # .png_init_filter_functions_vsx is needed in libpng.
+ ifeq ($(call isTargetOs, aix), true)
+ ifeq ($(TOOLCHAIN_TYPE), clang)
+ LIBSPLASHSCREEN_CFLAGS += -DPNG_POWERPC_VSX_OPT=0
+ endif
+ endif
+
ifeq ($(call isTargetOs, macosx), true)
LIBSPLASHSCREEN_CFLAGS += -DWITH_MACOSX
diff --git a/test/hotspot/jtreg/vmTestbase/gc/ArrayJuggle/Juggle04/TEST.properties b/make/modules/java.xml/Copy.gmk
similarity index 58%
rename from test/hotspot/jtreg/vmTestbase/gc/ArrayJuggle/Juggle04/TEST.properties
rename to make/modules/java.xml/Copy.gmk
index 04b22a107ac..3b6c66e42c5 100644
--- a/test/hotspot/jtreg/vmTestbase/gc/ArrayJuggle/Juggle04/TEST.properties
+++ b/make/modules/java.xml/Copy.gmk
@@ -1,10 +1,12 @@
#
-# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023, 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.
+# 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
@@ -20,4 +22,16 @@
# or visit www.oracle.com if you need additional information or have any
# questions.
#
-exclusiveAccess.dirs=.
+
+include CopyCommon.gmk
+
+################################################################################
+
+XML_LIB_SRC := $(TOPDIR)/src/java.xml/share/conf
+
+$(CONF_DST_DIR)/jaxp.properties: $(XML_LIB_SRC)/jaxp.properties
+ $(call install-file)
+
+TARGETS := $(CONF_DST_DIR)/jaxp.properties
+
+################################################################################
diff --git a/make/modules/jdk.internal.le/Lib.gmk b/make/modules/jdk.internal.le/Lib.gmk
index 6770e511989..42a2010527a 100644
--- a/make/modules/jdk.internal.le/Lib.gmk
+++ b/make/modules/jdk.internal.le/Lib.gmk
@@ -27,14 +27,16 @@ include LibCommon.gmk
################################################################################
-ifeq ($(call isTargetOs, windows), true)
+ifeq ($(call isTargetOs, linux macosx windows), true)
$(eval $(call SetupJdkLibrary, BUILD_LIBLE, \
NAME := le, \
+ TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
OPTIMIZATION := LOW, \
- CFLAGS := $(CFLAGS_JDKLIB), \
+ CFLAGS := $(CXXFLAGS_JDKLIB), \
LDFLAGS := $(LDFLAGS_JDKLIB), \
- LIBS := $(JDKLIB_LIBS) user32.lib, \
+ LIBS_unix := $(JDKLIB_LIBS) $(LIBCXX), \
+ LIBS_windows := $(JDKLIB_LIBS) user32.lib, \
))
TARGETS += $(BUILD_LIBLE)
diff --git a/make/modules/jdk.jartool/Java.gmk b/make/modules/jdk.jartool/Java.gmk
index 016c2bc0c9f..1cf56a317e7 100644
--- a/make/modules/jdk.jartool/Java.gmk
+++ b/make/modules/jdk.jartool/Java.gmk
@@ -25,5 +25,3 @@
DISABLED_WARNINGS_java += missing-explicit-ctor
JAVAC_FLAGS += -XDstringConcat=inline
-JAVAC_FLAGS += --enable-preview
-DISABLED_WARNINGS_java += preview
diff --git a/make/modules/jdk.jfr/Java.gmk b/make/modules/jdk.jfr/Java.gmk
index c39e21a7173..207256fde20 100644
--- a/make/modules/jdk.jfr/Java.gmk
+++ b/make/modules/jdk.jfr/Java.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2020, 2023, 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
@@ -24,5 +24,5 @@
#
DISABLED_WARNINGS_java += exports
-COPY := .xsd .xml .dtd
+COPY := .xsd .xml .dtd .ini
JAVAC_FLAGS := -XDstringConcat=inline
diff --git a/make/test/BuildMicrobenchmark.gmk b/make/test/BuildMicrobenchmark.gmk
index 1ae5e3c328b..e4d6ebc9a52 100644
--- a/make/test/BuildMicrobenchmark.gmk
+++ b/make/test/BuildMicrobenchmark.gmk
@@ -100,7 +100,6 @@ $(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \
--add-exports java.base/jdk.internal.classfile.attribute=ALL-UNNAMED \
--add-exports java.base/jdk.internal.classfile.constantpool=ALL-UNNAMED \
--add-exports java.base/jdk.internal.classfile.instruction=ALL-UNNAMED \
- --add-exports java.base/jdk.internal.classfile.java.lang.constant=ALL-UNNAMED \
--add-exports java.base/jdk.internal.classfile.components=ALL-UNNAMED \
--add-exports java.base/jdk.internal.classfile.impl=ALL-UNNAMED \
--add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED \
diff --git a/make/test/BuildTestLib.gmk b/make/test/BuildTestLib.gmk
index b9f03209df4..72f777ec6c1 100644
--- a/make/test/BuildTestLib.gmk
+++ b/make/test/BuildTestLib.gmk
@@ -36,7 +36,7 @@ TEST_LIB_SUPPORT := $(SUPPORT_OUTPUTDIR)/test/lib
$(eval $(call SetupJavaCompilation, BUILD_WB_JAR, \
TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \
- SRC := $(TEST_LIB_SOURCE_DIR)/jdk/test/whitebox/parser, \
+ SRC := $(TEST_LIB_SOURCE_DIR)/jdk/test/whitebox/, \
BIN := $(TEST_LIB_SUPPORT)/wb_classes, \
JAR := $(TEST_LIB_SUPPORT)/wb.jar, \
DISABLED_WARNINGS := deprecation removal preview, \
@@ -53,7 +53,12 @@ $(eval $(call SetupJavaCompilation, BUILD_TEST_LIB_JAR, \
HEADERS := $(TEST_LIB_SUPPORT)/test-lib_headers, \
JAR := $(TEST_LIB_SUPPORT)/test-lib.jar, \
DISABLED_WARNINGS := try deprecation rawtypes unchecked serial cast removal preview, \
- JAVAC_FLAGS := --enable-preview, \
+ JAVAC_FLAGS := --add-exports java.base/sun.security.util=ALL-UNNAMED \
+ --add-exports java.base/jdk.internal.classfile=ALL-UNNAMED \
+ --add-exports java.base/jdk.internal.classfile.attribute=ALL-UNNAMED \
+ --add-exports java.base/jdk.internal.classfile.constantpool=ALL-UNNAMED \
+ --add-exports java.base/jdk.internal.module=ALL-UNNAMED \
+ --enable-preview, \
))
TARGETS += $(BUILD_TEST_LIB_JAR)
diff --git a/make/test/JtregNativeHotspot.gmk b/make/test/JtregNativeHotspot.gmk
index 1d58c72554d..5d998a4d4b1 100644
--- a/make/test/JtregNativeHotspot.gmk
+++ b/make/test/JtregNativeHotspot.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2015, 2023, 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
@@ -99,11 +99,6 @@ NSK_GC_LOCK_JVMTI_INCLUDES := \
-I$(VM_TESTBASE_DIR)/nsk/share/native \
-I$(VM_TESTBASE_DIR)/nsk/share/jni
-NSK_GC_LOCK_MALLOC_INCLUDES := \
- -I$(VM_TESTBASE_DIR)/nsk/share/gc/lock/malloc \
- -I$(VM_TESTBASE_DIR)/nsk/share/native \
- -I$(VM_TESTBASE_DIR)/nsk/share/jni
-
NSK_GC_LOCK_JNI_INCLUDES := \
-I$(VM_TESTBASE_DIR)/nsk/share/gc/lock/jni \
-I$(VM_TESTBASE_DIR)/nsk/share/native \
@@ -179,8 +174,6 @@ BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libnativeAndMH := $(MLVM_STRESS_INCLUDES)
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libJVMTIAllocLocker := $(NSK_GC_LOCK_JVMTI_INCLUDES)
-BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libMallocLocker := $(NSK_GC_LOCK_MALLOC_INCLUDES)
-
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libBooleanArrayCriticalLocker := $(NSK_GC_LOCK_JNI_INCLUDES)
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libByteArrayCriticalLocker := $(NSK_GC_LOCK_JNI_INCLUDES)
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libCharArrayCriticalLocker := $(NSK_GC_LOCK_JNI_INCLUDES)
@@ -874,7 +867,7 @@ BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exesigtest := -ljvm
ifeq ($(call isTargetOs, windows), true)
BUILD_HOTSPOT_JTREG_EXECUTABLES_CFLAGS_exeFPRegs := -MT
- BUILD_HOTSPOT_JTREG_EXCLUDE += exesigtest.c libterminatedThread.c libTestJNI.c libCompleteExit.c libTestPsig.c libnativeStack.c
+ BUILD_HOTSPOT_JTREG_EXCLUDE += exesigtest.c libterminatedThread.c libTestJNI.c libCompleteExit.c libTestPsig.c libnativeStack.c exeGetCreatedJavaVMs.c
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libatExit := jvm.lib
BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exedaemonDestroy := jvm.lib
else
@@ -1516,6 +1509,7 @@ else
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libatExit += -ljvm
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libCompleteExit += -lpthread
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libnativeStack += -lpthread
+ BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exeGetCreatedJavaVMs := -ljvm -lpthread
endif
ifeq ($(ASAN_ENABLED), true)
diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h
index d18c8d1f6de..f1e2c35891a 100644
--- a/src/hotspot/share/include/jvm.h
+++ b/src/hotspot/share/include/jvm.h
@@ -276,7 +276,7 @@ JNIEXPORT void JNICALL
JVM_Yield(JNIEnv *env, jclass threadClass);
JNIEXPORT void JNICALL
-JVM_Sleep(JNIEnv *env, jclass threadClass, jlong millis);
+JVM_Sleep(JNIEnv *env, jclass threadClass, jlong nanos);
JNIEXPORT jobject JNICALL
JVM_CurrentCarrierThread(JNIEnv *env, jclass threadClass);
@@ -1144,10 +1144,16 @@ JVM_GetEnclosingMethodInfo(JNIEnv* env, jclass ofClass);
* Virtual thread support.
*/
JNIEXPORT void JNICALL
-JVM_VirtualThreadMount(JNIEnv* env, jobject vthread, jboolean hide, jboolean first_mount);
+JVM_VirtualThreadStart(JNIEnv* env, jobject vthread);
JNIEXPORT void JNICALL
-JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean hide, jboolean last_unmount);
+JVM_VirtualThreadEnd(JNIEnv* env, jobject vthread);
+
+JNIEXPORT void JNICALL
+JVM_VirtualThreadMount(JNIEnv* env, jobject vthread, jboolean hide);
+
+JNIEXPORT void JNICALL
+JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean hide);
JNIEXPORT void JNICALL
JVM_VirtualThreadHideFrames(JNIEnv* env, jobject vthread, jboolean hide);
@@ -1158,6 +1164,12 @@ JVM_VirtualThreadHideFrames(JNIEnv* env, jobject vthread, jboolean hide);
JNIEXPORT jint JNICALL
JVM_GetClassFileVersion(JNIEnv *env, jclass current);
+/*
+ * Return JNI_TRUE if warnings are printed when agents are dynamically loaded.
+ */
+JNIEXPORT jboolean JNICALL
+JVM_PrintWarningAtDynamicAgentLoad(void);
+
/*
* This structure is used by the launcher to get the default thread
* stack size from the VM using JNI_GetDefaultJavaVMInitArgs() with a
diff --git a/src/java.base/aix/classes/sun/nio/ch/AixPollPort.java b/src/java.base/aix/classes/sun/nio/ch/AixPollPort.java
index ab830424317..4f5bda557c6 100644
--- a/src/java.base/aix/classes/sun/nio/ch/AixPollPort.java
+++ b/src/java.base/aix/classes/sun/nio/ch/AixPollPort.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -27,6 +27,7 @@
package sun.nio.ch;
import java.nio.channels.spi.AsynchronousChannelProvider;
+import sun.nio.ch.Pollset;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
@@ -34,7 +35,6 @@
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
-import jdk.internal.misc.Unsafe;
/**
* AsynchronousChannelGroup implementation based on the AIX pollset framework.
@@ -42,33 +42,11 @@
final class AixPollPort
extends Port
{
- private static final Unsafe unsafe = Unsafe.getUnsafe();
-
static {
IOUtil.load();
- init();
+ Pollset.init();
}
- /**
- * struct pollfd {
- * int fd;
- * short events;
- * short revents;
- * }
- */
- private static final int SIZEOF_POLLFD = eventSize();
- private static final int OFFSETOF_EVENTS = eventsOffset();
- private static final int OFFSETOF_REVENTS = reventsOffset();
- private static final int OFFSETOF_FD = fdOffset();
-
- // opcodes
- private static final int PS_ADD = 0x0;
- private static final int PS_MOD = 0x1;
- private static final int PS_DELETE = 0x2;
-
- // maximum number of events to poll at a time
- private static final int MAX_POLL_EVENTS = 512;
-
// pollset ID
private final int pollset;
@@ -88,6 +66,9 @@ final class AixPollPort
// address of the poll array passed to pollset_poll
private final long address;
+ // maximum number of events to poll at a time
+ private static final int MAX_EVENTS_TO_POLL = 512;
+
// encapsulates an event for a channel
static class Event {
final PollableChannel channel;
@@ -142,16 +123,16 @@ static class ControlEvent {
super(provider, pool);
// open pollset
- this.pollset = pollsetCreate();
+ this.pollset = Pollset.pollsetCreate();
// create socket pair for wakeup mechanism
int[] sv = new int[2];
try {
- socketpair(sv);
+ Pollset.socketpair(sv);
// register one end with pollset
- pollsetCtl(pollset, PS_ADD, sv[0], Net.POLLIN);
+ Pollset.pollsetCtl(pollset, Pollset.PS_ADD, sv[0], Net.POLLIN);
} catch (IOException x) {
- pollsetDestroy(pollset);
+ Pollset.pollsetDestroy(pollset);
throw x;
}
this.sp = sv;
@@ -159,21 +140,21 @@ static class ControlEvent {
// create socket pair for pollset control mechanism
sv = new int[2];
try {
- socketpair(sv);
+ Pollset.socketpair(sv);
// register one end with pollset
- pollsetCtl(pollset, PS_ADD, sv[0], Net.POLLIN);
+ Pollset.pollsetCtl(pollset, Pollset.PS_ADD, sv[0], Net.POLLIN);
} catch (IOException x) {
- pollsetDestroy(pollset);
+ Pollset.pollsetDestroy(pollset);
throw x;
}
this.ctlSp = sv;
// allocate the poll array
- this.address = allocatePollArray(MAX_POLL_EVENTS);
+ this.address = Pollset.allocatePollArray(MAX_EVENTS_TO_POLL);
// create the queue and offer the special event to ensure that the first
// threads polls
- this.queue = new ArrayBlockingQueue(MAX_POLL_EVENTS);
+ this.queue = new ArrayBlockingQueue(MAX_EVENTS_TO_POLL);
this.queue.offer(NEED_TO_POLL);
}
@@ -191,19 +172,19 @@ private void implClose() {
return;
closed = true;
}
- freePollArray(address);
- close0(sp[0]);
- close0(sp[1]);
- close0(ctlSp[0]);
- close0(ctlSp[1]);
- pollsetDestroy(pollset);
+ Pollset.freePollArray(address);
+ Pollset.close0(sp[0]);
+ Pollset.close0(sp[1]);
+ Pollset.close0(ctlSp[0]);
+ Pollset.close0(ctlSp[1]);
+ Pollset.pollsetDestroy(pollset);
}
- private void wakeup() {
+ void wakeup() {
if (wakeupCount.incrementAndGet() == 1) {
// write byte to socketpair to force wakeup
try {
- interrupt(sp[1]);
+ Pollset.interrupt(sp[1]);
} catch (IOException x) {
throw new AssertionError(x);
}
@@ -258,7 +239,7 @@ private void queueControlEvent(ControlEvent ev) {
controlQueue.add(ev);
// write byte to socketpair to force wakeup
try {
- interrupt(ctlSp[1]);
+ Pollset.interrupt(ctlSp[1]);
} catch (IOException x) {
throw new AssertionError(x);
}
@@ -299,9 +280,9 @@ private void processControlQueue() {
Iterator iter = controlQueue.iterator();
while (iter.hasNext()) {
ControlEvent ev = iter.next();
- pollsetCtl(pollset, PS_DELETE, ev.fd(), 0);
+ Pollset.pollsetCtl(pollset, Pollset.PS_DELETE, ev.fd(), 0);
if (!ev.removeOnly()) {
- ev.setError(pollsetCtl(pollset, PS_MOD, ev.fd(), ev.events()));
+ ev.setError(Pollset.pollsetCtl(pollset, Pollset.PS_MOD, ev.fd(), ev.events()));
}
iter.remove();
}
@@ -325,7 +306,8 @@ private Event poll() throws IOException {
int n;
controlLock.lock();
try {
- n = pollsetPoll(pollset, address, MAX_POLL_EVENTS);
+ n = Pollset.pollsetPoll(pollset, address,
+ MAX_EVENTS_TO_POLL, Pollset.PS_NO_TIMEOUT);
} finally {
controlLock.unlock();
}
@@ -338,14 +320,14 @@ private Event poll() throws IOException {
fdToChannelLock.readLock().lock();
try {
while (n-- > 0) {
- long eventAddress = getEvent(address, n);
- int fd = getDescriptor(eventAddress);
+ long eventAddress = Pollset.getEvent(address, n);
+ int fd = Pollset.getDescriptor(eventAddress);
// To emulate one shot semantic we need to remove
// the file descriptor here.
if (fd != sp[0] && fd != ctlSp[0]) {
synchronized (controlQueue) {
- pollsetCtl(pollset, PS_DELETE, fd, 0);
+ Pollset.pollsetCtl(pollset, Pollset.PS_DELETE, fd, 0);
}
}
@@ -353,7 +335,7 @@ private Event poll() throws IOException {
if (fd == sp[0]) {
if (wakeupCount.decrementAndGet() == 0) {
// no more wakeups so drain pipe
- drain1(sp[0]);
+ Pollset.drain1(sp[0]);
}
// queue special event if there are more events
@@ -368,7 +350,7 @@ private Event poll() throws IOException {
// wakeup to process control event
if (fd == ctlSp[0]) {
synchronized (controlQueue) {
- drain1(ctlSp[0]);
+ Pollset.drain1(ctlSp[0]);
processControlQueue();
}
if (n > 0) {
@@ -379,7 +361,7 @@ private Event poll() throws IOException {
PollableChannel channel = fdToChannel.get(fd);
if (channel != null) {
- int events = getRevents(eventAddress);
+ int events = Pollset.getRevents(eventAddress);
Event ev = new Event(channel, events);
// n-1 events are queued; This thread handles
@@ -467,75 +449,4 @@ public void run() {
}
}
}
-
- /**
- * Allocates a poll array to handle up to {@code count} events.
- */
- private static long allocatePollArray(int count) {
- return unsafe.allocateMemory(count * SIZEOF_POLLFD);
- }
-
- /**
- * Free a poll array
- */
- private static void freePollArray(long address) {
- unsafe.freeMemory(address);
- }
-
- /**
- * Returns event[i];
- */
- private static long getEvent(long address, int i) {
- return address + (SIZEOF_POLLFD*i);
- }
-
- /**
- * Returns event->fd
- */
- private static int getDescriptor(long eventAddress) {
- return unsafe.getInt(eventAddress + OFFSETOF_FD);
- }
-
- /**
- * Returns event->events
- */
- private static int getEvents(long eventAddress) {
- return unsafe.getChar(eventAddress + OFFSETOF_EVENTS);
- }
-
- /**
- * Returns event->revents
- */
- private static int getRevents(long eventAddress) {
- return unsafe.getChar(eventAddress + OFFSETOF_REVENTS);
- }
-
- // -- Native methods --
-
- private static native void init();
-
- private static native int eventSize();
-
- private static native int eventsOffset();
-
- private static native int reventsOffset();
-
- private static native int fdOffset();
-
- private static native int pollsetCreate() throws IOException;
-
- private static native int pollsetCtl(int pollset, int opcode, int fd, int events);
-
- private static native int pollsetPoll(int pollset, long pollAddress, int numfds)
- throws IOException;
-
- private static native void pollsetDestroy(int pollset);
-
- private static native void socketpair(int[] sv) throws IOException;
-
- private static native void interrupt(int fd) throws IOException;
-
- private static native void drain1(int fd) throws IOException;
-
- private static native void close0(int fd);
}
diff --git a/src/java.base/aix/classes/sun/nio/ch/Pollset.java b/src/java.base/aix/classes/sun/nio/ch/Pollset.java
new file mode 100644
index 00000000000..ddd46d5b524
--- /dev/null
+++ b/src/java.base/aix/classes/sun/nio/ch/Pollset.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 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. 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.
+ */
+
+package sun.nio.ch;
+
+import java.io.IOException;
+import jdk.internal.misc.Unsafe;
+
+public class Pollset {
+
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+ /**
+ * struct pollfd {
+ * int fd;
+ * short events;
+ * short revents;
+ * }
+ */
+ public static final int SIZEOF_POLLFD = eventSize();
+ public static final int OFFSETOF_EVENTS = eventsOffset();
+ public static final int OFFSETOF_REVENTS = reventsOffset();
+ public static final int OFFSETOF_FD = fdOffset();
+
+ // opcodes
+ public static final int PS_ADD = 0x0;
+ public static final int PS_MOD = 0x1;
+ public static final int PS_DELETE = 0x2;
+
+ // event
+ public static final int PS_POLLPRI = 0x4;
+
+ // revent errcodes
+ public static final char PS_POLLNVAL = 0x8000;
+ public static final char PS_POLLERR = 0x4000;
+
+ public static final int PS_NO_TIMEOUT = -1;
+
+ /**
+ * Allocates a poll array to handle up to {@code count} events.
+ */
+ public static long allocatePollArray(int count) {
+ return unsafe.allocateMemory(count * SIZEOF_POLLFD);
+ }
+
+ /**
+ * Free a poll array
+ */
+ public static void freePollArray(long address) {
+ unsafe.freeMemory(address);
+ }
+
+ /**
+ * Returns event[i];
+ */
+ public static long getEvent(long address, int i) {
+ return address + (SIZEOF_POLLFD * i);
+ }
+
+ /**
+ * Returns event->fd
+ */
+ public static int getDescriptor(long eventAddress) {
+ return unsafe.getInt(eventAddress + OFFSETOF_FD);
+ }
+
+ /**
+ * Returns event->events
+ */
+ public static int getEvents(long eventAddress) {
+ return unsafe.getChar(eventAddress + OFFSETOF_EVENTS);
+ }
+
+ /**
+ * Returns event->revents
+ */
+ public static char getRevents(long eventAddress) {
+ return unsafe.getChar(eventAddress + OFFSETOF_REVENTS);
+ }
+
+ public static boolean isReventsError(long eventAddress) {
+ char revents = getRevents(eventAddress);
+ return (revents & PS_POLLNVAL) != 0 || (revents & PS_POLLERR) != 0;
+ }
+
+ // -- Native methods --
+ public static native int pollsetCreate() throws IOException;
+ public static native int pollsetCtl(int pollset, int opcode, int fd, int events);
+ public static native int pollsetPoll(int pollset, long pollAddress, int numfds, int timeout)
+ throws IOException;
+ public static native void pollsetDestroy(int pollset);
+ public static native void init();
+ public static native int eventSize();
+ public static native int eventsOffset();
+ public static native int reventsOffset();
+ public static native int fdOffset();
+ public static native void socketpair(int[] sv) throws IOException;
+ public static native void interrupt(int fd) throws IOException;
+ public static native void drain1(int fd) throws IOException;
+ public static native void close0(int fd);
+}
diff --git a/src/java.base/aix/classes/sun/nio/ch/PollsetPoller.java b/src/java.base/aix/classes/sun/nio/ch/PollsetPoller.java
index ab3fcea4abb..1aecbf7d57a 100644
--- a/src/java.base/aix/classes/sun/nio/ch/PollsetPoller.java
+++ b/src/java.base/aix/classes/sun/nio/ch/PollsetPoller.java
@@ -1,5 +1,6 @@
/*
- * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 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
@@ -25,6 +26,8 @@
package sun.nio.ch;
import java.io.IOException;
+import java.time.Instant;
+import sun.nio.ch.Pollset;
/**
* Poller implementation based on the AIX Pollset library.
@@ -32,32 +35,74 @@
class PollsetPoller extends Poller {
+ private static final int MAX_EVENTS_TO_POLL;
+
+ static {
+ Pollset.init(); /* Dynamically loads pollset C functions */
+ MAX_EVENTS_TO_POLL = 512;
+ }
+
+ private final int setid;
+ private final long pollBuffer;
+
PollsetPoller(boolean read) throws IOException {
super(read);
+ this.setid = Pollset.pollsetCreate();
+ this.pollBuffer = Pollset.allocatePollArray(MAX_EVENTS_TO_POLL);
}
@Override
int fdVal() {
- // Stub
- throw new UnsupportedOperationException("Unimplemented on AIX");
+ return setid;
}
@Override
- void implRegister(int fdVal) throws IOException {
- // Stub
- throw new UnsupportedOperationException("Unimplemented on AIX");
+ void implRegister(int fd) throws IOException {
+ int ret = Pollset.pollsetCtl(setid, Pollset.PS_MOD, fd,
+ Pollset.PS_POLLPRI | (this.reading() ? Net.POLLIN : Net.POLLOUT));
+ if (ret != 0) {
+ throw new IOException("Unable to register fd " + fd);
+ }
}
@Override
- void implDeregister(int fdVal) {
- // Stub
- throw new UnsupportedOperationException("Unimplemented on AIX");
+ void implDeregister(int fd) {
+ int ret = Pollset.pollsetCtl(setid, Pollset.PS_DELETE, fd, 0);
+ assert ret == 0;
}
+ /**
+ * Main poll method. The AIX Pollset library does not appear to pick up changes to the pollset
+ * (the set of fds being polled) while blocked on a call to this method. These changes happen
+ * regularly in the poll-loop thread and update thread from Poller.java.
+ * To address this difficulty, we break poll calls into 100ms sub-calls and emulate the timout.
+ */
@Override
int poll(int timeout) throws IOException {
- // Stub
- throw new UnsupportedOperationException("Unimplemented on AIX");
+ int n;
+ switch (timeout) {
+ case 0:
+ n = pollInner(0);
+ break;
+ case Pollset.PS_NO_TIMEOUT:
+ do { n = pollInner(100); } while (n == 0);
+ break;
+ default:
+ Instant end = Instant.now().plusMillis(timeout);
+ do { n = pollInner(100); } while (n == 0 && Instant.now().isBefore(end));
+ break;
+ }
+ return n;
+ }
+
+ int pollInner(int subInterval) throws IOException {
+ int n = Pollset.pollsetPoll(setid, pollBuffer, MAX_EVENTS_TO_POLL, subInterval);
+ for (int i=0; i
-#include
-#include
-#include
-#include
-#include
-#include
#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
/* Initially copied from src/solaris/native/sun/nio/ch/nio_util.h */
#define RESTARTABLE(_cmd, _result) do { \
@@ -58,7 +57,7 @@ static pollset_ctl_func* _pollset_ctl = NULL;
static pollset_poll_func* _pollset_poll = NULL;
JNIEXPORT void JNICALL
-Java_sun_nio_ch_AixPollPort_init(JNIEnv* env, jclass this) {
+Java_sun_nio_ch_Pollset_init(JNIEnv* env, jclass this) {
_pollset_create = (pollset_create_func*) dlsym(RTLD_DEFAULT, "pollset_create");
_pollset_destroy = (pollset_destroy_func*) dlsym(RTLD_DEFAULT, "pollset_destroy");
_pollset_ctl = (pollset_ctl_func*) dlsym(RTLD_DEFAULT, "pollset_ctl");
@@ -70,27 +69,27 @@ Java_sun_nio_ch_AixPollPort_init(JNIEnv* env, jclass this) {
}
JNIEXPORT jint JNICALL
-Java_sun_nio_ch_AixPollPort_eventSize(JNIEnv* env, jclass this) {
+Java_sun_nio_ch_Pollset_eventSize(JNIEnv* env, jclass this) {
return sizeof(struct pollfd);
}
JNIEXPORT jint JNICALL
-Java_sun_nio_ch_AixPollPort_eventsOffset(JNIEnv* env, jclass this) {
+Java_sun_nio_ch_Pollset_eventsOffset(JNIEnv* env, jclass this) {
return offsetof(struct pollfd, events);
}
JNIEXPORT jint JNICALL
-Java_sun_nio_ch_AixPollPort_reventsOffset(JNIEnv* env, jclass this) {
+Java_sun_nio_ch_Pollset_reventsOffset(JNIEnv* env, jclass this) {
return offsetof(struct pollfd, revents);
}
JNIEXPORT jint JNICALL
-Java_sun_nio_ch_AixPollPort_fdOffset(JNIEnv* env, jclass this) {
+Java_sun_nio_ch_Pollset_fdOffset(JNIEnv* env, jclass this) {
return offsetof(struct pollfd, fd);
}
JNIEXPORT jint JNICALL
-Java_sun_nio_ch_AixPollPort_pollsetCreate(JNIEnv *env, jclass c) {
+Java_sun_nio_ch_Pollset_pollsetCreate(JNIEnv *env, jclass c) {
/* pollset_create can take the maximum number of fds, but we
* cannot predict this number so we leave it at OPEN_MAX. */
pollset_t ps = _pollset_create(-1);
@@ -101,7 +100,7 @@ Java_sun_nio_ch_AixPollPort_pollsetCreate(JNIEnv *env, jclass c) {
}
JNIEXPORT jint JNICALL
-Java_sun_nio_ch_AixPollPort_pollsetCtl(JNIEnv *env, jclass c, jint ps,
+Java_sun_nio_ch_Pollset_pollsetCtl(JNIEnv *env, jclass c, jint ps,
jint opcode, jint fd, jint events) {
struct poll_ctl event;
int res;
@@ -116,26 +115,27 @@ Java_sun_nio_ch_AixPollPort_pollsetCtl(JNIEnv *env, jclass c, jint ps,
}
JNIEXPORT jint JNICALL
-Java_sun_nio_ch_AixPollPort_pollsetPoll(JNIEnv *env, jclass c,
- jint ps, jlong address, jint numfds) {
+Java_sun_nio_ch_Pollset_pollsetPoll(JNIEnv *env, jclass c,
+ jint ps, jlong address, jint numfds, jint timeout) {
struct pollfd *events = jlong_to_ptr(address);
int res;
- RESTARTABLE(_pollset_poll(ps, events, numfds, -1), res);
+ RESTARTABLE(_pollset_poll(ps, events, numfds, timeout), res);
if (res < 0) {
+ perror("pollset_poll failed");
JNU_ThrowIOExceptionWithLastError(env, "pollset_poll failed");
}
return res;
}
JNIEXPORT void JNICALL
-Java_sun_nio_ch_AixPollPort_pollsetDestroy(JNIEnv *env, jclass c, jint ps) {
+Java_sun_nio_ch_Pollset_pollsetDestroy(JNIEnv *env, jclass c, jint ps) {
int res;
RESTARTABLE(_pollset_destroy((pollset_t)ps), res);
}
JNIEXPORT void JNICALL
-Java_sun_nio_ch_AixPollPort_socketpair(JNIEnv* env, jclass clazz, jintArray sv) {
+Java_sun_nio_ch_Pollset_socketpair(JNIEnv* env, jclass clazz, jintArray sv) {
int sp[2];
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) {
JNU_ThrowIOExceptionWithLastError(env, "socketpair failed");
@@ -148,7 +148,7 @@ Java_sun_nio_ch_AixPollPort_socketpair(JNIEnv* env, jclass clazz, jintArray sv)
}
JNIEXPORT void JNICALL
-Java_sun_nio_ch_AixPollPort_interrupt(JNIEnv *env, jclass c, jint fd) {
+Java_sun_nio_ch_Pollset_interrupt(JNIEnv *env, jclass c, jint fd) {
int res;
int buf[1];
buf[0] = 1;
@@ -159,7 +159,7 @@ Java_sun_nio_ch_AixPollPort_interrupt(JNIEnv *env, jclass c, jint fd) {
}
JNIEXPORT void JNICALL
-Java_sun_nio_ch_AixPollPort_drain1(JNIEnv *env, jclass cl, jint fd) {
+Java_sun_nio_ch_Pollset_drain1(JNIEnv *env, jclass cl, jint fd) {
int res;
char buf[1];
RESTARTABLE(read(fd, buf, 1), res);
@@ -169,7 +169,7 @@ Java_sun_nio_ch_AixPollPort_drain1(JNIEnv *env, jclass cl, jint fd) {
}
JNIEXPORT void JNICALL
-Java_sun_nio_ch_AixPollPort_close0(JNIEnv *env, jclass c, jint fd) {
+Java_sun_nio_ch_Pollset_close0(JNIEnv *env, jclass c, jint fd) {
int res;
RESTARTABLE(close(fd), res);
}
diff --git a/src/java.base/macosx/classes/apple/security/KeychainStore.java b/src/java.base/macosx/classes/apple/security/KeychainStore.java
index f5284c33e9d..83c4265423a 100644
--- a/src/java.base/macosx/classes/apple/security/KeychainStore.java
+++ b/src/java.base/macosx/classes/apple/security/KeychainStore.java
@@ -69,7 +69,7 @@ static class TrustedCertEntry {
Certificate cert;
long certRef; // SecCertificateRef for this key
- // Each KeyStore.TrustedCertificateEntry have 2 attributes:
+ // Each KeyStore.TrustedCertificateEntry has 2 attributes:
// 1. "trustSettings" -> trustSettings.toString()
// 2. "2.16.840.1.113894.746875.1.1" -> trustedKeyUsageValue
// The 1st one is mainly for debugging use. The 2nd one is similar
@@ -652,7 +652,6 @@ public void engineStore(OutputStream stream, char[] password)
_releaseKeychainItemRef(((TrustedCertEntry)entry).certRef);
}
} else {
- Certificate certElem;
KeyEntry keyEntry = (KeyEntry)entry;
if (keyEntry.chain != null) {
@@ -804,8 +803,26 @@ private void createTrustedCertEntry(String alias, List inputTrust,
tce.cert = cert;
tce.certRef = keychainItemRef;
+ // Check whether a certificate with same alias already exists and is the same
+ // If yes, we can return here - the existing entry must have the same
+ // properties and trust settings
+ if (entries.contains(alias.toLowerCase())) {
+ int uniqueVal = 1;
+ String originalAlias = alias;
+ var co = entries.get(alias.toLowerCase());
+ while (co != null) {
+ if (co instanceof TrustedCertEntry tco) {
+ if (tco.cert.equals(tce.cert)) {
+ return;
+ }
+ }
+ alias = originalAlias + " " + uniqueVal++;
+ co = entries.get(alias.toLowerCase());
+ }
+ }
+
tce.trustSettings = new ArrayList<>();
- Map tmpMap = new LinkedHashMap<>();
+ Map tmpMap = new LinkedHashMap<>();
for (int i = 0; i < inputTrust.size(); i++) {
if (inputTrust.get(i) == null) {
tce.trustSettings.add(tmpMap);
@@ -828,9 +845,10 @@ private void createTrustedCertEntry(String alias, List inputTrust,
} catch (Exception e) {
isSelfSigned = false;
}
+
if (tce.trustSettings.isEmpty()) {
if (isSelfSigned) {
- // If a self-signed certificate has an empty trust settings,
+ // If a self-signed certificate has trust settings without specific entries,
// trust it for all purposes
tce.trustedKeyUsageValue = KnownOIDs.anyExtendedKeyUsage.value();
} else {
@@ -843,11 +861,19 @@ private void createTrustedCertEntry(String alias, List inputTrust,
for (var oneTrust : tce.trustSettings) {
var result = oneTrust.get("kSecTrustSettingsResult");
// https://developer.apple.com/documentation/security/sectrustsettingsresult?language=objc
- // 1 = kSecTrustSettingsResultTrustRoot, 2 = kSecTrustSettingsResultTrustAsRoot
+ // 1 = kSecTrustSettingsResultTrustRoot, 2 = kSecTrustSettingsResultTrustAsRoot,
+ // 3 = kSecTrustSettingsResultDeny
// If missing, a default value of kSecTrustSettingsResultTrustRoot is assumed
- // for self-signed certificates (see doc for SecTrustSettingsCopyTrustSettings).
+ // (see doc for SecTrustSettingsCopyTrustSettings).
// Note that the same SecPolicyOid can appear in multiple trust settings
// for different kSecTrustSettingsAllowedError and/or kSecTrustSettingsPolicyString.
+
+ // If we find explicit distrust in some record, we ignore the certificate
+ if ("3".equals(result)) {
+ return;
+ }
+
+ // Trust, if explicitly trusted or result is null and certificate is self signed
if ((result == null && isSelfSigned)
|| "1".equals(result) || "2".equals(result)) {
// When no kSecTrustSettingsPolicy, it means everything
@@ -867,20 +893,13 @@ private void createTrustedCertEntry(String alias, List inputTrust,
tce.trustedKeyUsageValue = values.toString();
}
}
+
// Make a creation date.
if (creationDate != 0)
tce.date = new Date(creationDate);
else
tce.date = new Date();
- int uniqueVal = 1;
- String originalAlias = alias;
-
- while (entries.containsKey(alias.toLowerCase())) {
- alias = originalAlias + " " + uniqueVal;
- uniqueVal++;
- }
-
entries.put(alias.toLowerCase(), tce);
} catch (Exception e) {
// The certificate will be skipped.
diff --git a/src/java.base/macosx/classes/jdk/internal/loader/ClassLoaderHelper.java b/src/java.base/macosx/classes/jdk/internal/loader/ClassLoaderHelper.java
index 2e0e15e69a2..a780146f446 100644
--- a/src/java.base/macosx/classes/jdk/internal/loader/ClassLoaderHelper.java
+++ b/src/java.base/macosx/classes/jdk/internal/loader/ClassLoaderHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023, 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,21 +27,14 @@
import java.io.File;
import java.util.ArrayList;
-import sun.security.action.GetPropertyAction;
+
+import jdk.internal.util.OSVersion;
class ClassLoaderHelper {
- private static final boolean hasDynamicLoaderCache;
- static {
- String osVersion = GetPropertyAction.privilegedGetProperty("os.version");
- // dynamic linker cache support on os.version >= 11.x
- int major = 11;
- int i = osVersion.indexOf('.');
- try {
- major = Integer.parseInt(i < 0 ? osVersion : osVersion.substring(0, i));
- } catch (NumberFormatException e) {}
- // SDK 10.15 and earlier always reports 10.16 instead of 11.x.x
- hasDynamicLoaderCache = major >= 11 || osVersion.equals("10.16");
- }
+
+ // SDK 10.15 and earlier always reports 10.16 instead of 11.x.x
+ private static final boolean hasDynamicLoaderCache = OSVersion.current()
+ .compareTo(new OSVersion(10, 16)) >= 0;
private ClassLoaderHelper() {}
diff --git a/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m b/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m
index 38362709d27..b4e19a27995 100644
--- a/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m
+++ b/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m
@@ -381,6 +381,35 @@ static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore)
#define ADDNULL(list) (*env)->CallBooleanMethod(env, list, jm_listAdd, NULL)
+
+static void addTrustSettingsToInputTrust(JNIEnv *env, jmethodID jm_listAdd, CFArrayRef trustSettings, jobject inputTrust)
+{
+ CFIndex count = CFArrayGetCount(trustSettings);
+ for (int i = 0; i < count; i++) {
+ CFDictionaryRef oneTrust = (CFDictionaryRef) CFArrayGetValueAtIndex(trustSettings, i);
+ CFIndex size = CFDictionaryGetCount(oneTrust);
+ const void * keys [size];
+ const void * values [size];
+ CFDictionaryGetKeysAndValues(oneTrust, keys, values);
+ for (int j = 0; j < size; j++) {
+ NSString* s = [NSString stringWithFormat:@"%@", keys[j]];
+ ADD(inputTrust, s);
+ s = [NSString stringWithFormat:@"%@", values[j]];
+ ADD(inputTrust, s);
+ }
+ SecPolicyRef certPolicy;
+ certPolicy = (SecPolicyRef)CFDictionaryGetValue(oneTrust, kSecTrustSettingsPolicy);
+ if (certPolicy != NULL) {
+ CFDictionaryRef policyDict = SecPolicyCopyProperties(certPolicy);
+ ADD(inputTrust, @"SecPolicyOid");
+ NSString* s = [NSString stringWithFormat:@"%@", CFDictionaryGetValue(policyDict, @"SecPolicyOid")];
+ ADD(inputTrust, s);
+ CFRelease(policyDict);
+ }
+ ADDNULL(inputTrust);
+ }
+}
+
static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore)
{
// Search the user keychain list for all X509 certificates.
@@ -435,46 +464,40 @@ static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore)
goto errOut;
}
- // Only add certificates with trusted settings
- CFArrayRef trustSettings;
- if (SecTrustSettingsCopyTrustSettings(certRef, kSecTrustSettingsDomainUser, &trustSettings)
- == errSecItemNotFound) {
- continue;
- }
-
// See KeychainStore::createTrustedCertEntry for content of inputTrust
- jobject inputTrust = (*env)->NewObject(env, jc_arrayListClass, jm_arrayListCons);
- if (inputTrust == NULL) {
+ // We load trust settings from domains kSecTrustSettingsDomainUser and kSecTrustSettingsDomainAdmin
+ // kSecTrustSettingsDomainSystem is ignored because it seems to only contain data for root certificates
+ jobject inputTrust = NULL;
+ CFArrayRef trustSettings = NULL;
+
+ // Load user trustSettings into inputTrust
+ if (SecTrustSettingsCopyTrustSettings(certRef, kSecTrustSettingsDomainUser, &trustSettings) == errSecSuccess && trustSettings != NULL) {
+ inputTrust = (*env)->NewObject(env, jc_arrayListClass, jm_arrayListCons);
+ if (inputTrust == NULL) {
+ CFRelease(trustSettings);
+ goto errOut;
+ }
+ addTrustSettingsToInputTrust(env, jm_listAdd, trustSettings, inputTrust);
CFRelease(trustSettings);
- goto errOut;
}
-
- // Dump everything inside trustSettings into inputTrust
- CFIndex count = CFArrayGetCount(trustSettings);
- for (int i = 0; i < count; i++) {
- CFDictionaryRef oneTrust = (CFDictionaryRef) CFArrayGetValueAtIndex(trustSettings, i);
- CFIndex size = CFDictionaryGetCount(oneTrust);
- const void * keys [size];
- const void * values [size];
- CFDictionaryGetKeysAndValues(oneTrust, keys, values);
- for (int j = 0; j < size; j++) {
- NSString* s = [NSString stringWithFormat:@"%@", keys[j]];
- ADD(inputTrust, s);
- s = [NSString stringWithFormat:@"%@", values[j]];
- ADD(inputTrust, s);
+ // Load admin trustSettings into inputTrust
+ trustSettings = NULL;
+ if (SecTrustSettingsCopyTrustSettings(certRef, kSecTrustSettingsDomainAdmin, &trustSettings) == errSecSuccess && trustSettings != NULL) {
+ if (inputTrust == NULL) {
+ inputTrust = (*env)->NewObject(env, jc_arrayListClass, jm_arrayListCons);
}
- SecPolicyRef certPolicy;
- certPolicy = (SecPolicyRef)CFDictionaryGetValue(oneTrust, kSecTrustSettingsPolicy);
- if (certPolicy != NULL) {
- CFDictionaryRef policyDict = SecPolicyCopyProperties(certPolicy);
- ADD(inputTrust, @"SecPolicyOid");
- NSString* s = [NSString stringWithFormat:@"%@", CFDictionaryGetValue(policyDict, @"SecPolicyOid")];
- ADD(inputTrust, s);
- CFRelease(policyDict);
+ if (inputTrust == NULL) {
+ CFRelease(trustSettings);
+ goto errOut;
}
- ADDNULL(inputTrust);
+ addTrustSettingsToInputTrust(env, jm_listAdd, trustSettings, inputTrust);
+ CFRelease(trustSettings);
+ }
+
+ // Only add certificates with trust settings
+ if (inputTrust == NULL) {
+ continue;
}
- CFRelease(trustSettings);
// Find the creation date.
jlong creationDate = getModDateFromItem(env, theItem);
diff --git a/src/java.base/share/classes/com/sun/crypto/provider/AESCrypt.java b/src/java.base/share/classes/com/sun/crypto/provider/AESCrypt.java
index e6de2814e99..9bbc8c16764 100644
--- a/src/java.base/share/classes/com/sun/crypto/provider/AESCrypt.java
+++ b/src/java.base/share/classes/com/sun/crypto/provider/AESCrypt.java
@@ -1061,37 +1061,6 @@ void init(boolean decrypting, String algorithm, byte[] key)
this.K = sessionK[(decrypting? 1:0)];
}
- /**
- * Expand an int[(ROUNDS+1)][4] into int[(ROUNDS+1)*4].
- * For decryption round keys, need to rotate right by 4 ints.
- * @param kr The round keys for encryption or decryption.
- * @param decrypting True if 'kr' is for decryption and false otherwise.
- */
- private static final int[] expandToSubKey(int[][] kr, boolean decrypting) {
- int total = kr.length;
- int[] expK = new int[total*4];
- if (decrypting) {
- // decrypting, rotate right by 4 ints
- // i.e. i==0
- for(int j=0; j<4; j++) {
- expK[j] = kr[total-1][j];
- }
- for(int i=1; i>> 24) & 0xFF] ^
- U2[(tt >>> 16) & 0xFF] ^
- U3[(tt >>> 8) & 0xFF] ^
- U4[ tt & 0xFF];
+ int idx = r*BC + j;
+ tt = Kd[idx];
+ Kd[idx] = U1[(tt >>> 24) & 0xFF] ^
+ U2[(tt >>> 16) & 0xFF] ^
+ U3[(tt >>> 8) & 0xFF] ^
+ U4[ tt & 0xFF];
}
}
- // assemble the encryption (Ke) and decryption (Kd) round keys
- // and expand them into arrays of ints.
- int[] expandedKe = expandToSubKey(Ke, false); // decrypting==false
- int[] expandedKd = expandToSubKey(Kd, true); // decrypting==true
+ // For decryption round keys, need to rotate right by 4 ints.
+ // Do that without allocating and zeroing the small buffer.
+ int KdTail_0 = Kd[Kd.length - 4];
+ int KdTail_1 = Kd[Kd.length - 3];
+ int KdTail_2 = Kd[Kd.length - 2];
+ int KdTail_3 = Kd[Kd.length - 1];
+ System.arraycopy(Kd, 0, Kd, 4, Kd.length - 4);
+ Kd[0] = KdTail_0;
+ Kd[1] = KdTail_1;
+ Kd[2] = KdTail_2;
+ Kd[3] = KdTail_3;
+
Arrays.fill(tk, 0);
- for (int[] ia: Ke) {
- Arrays.fill(ia, 0);
- }
- for (int[] ia: Kd) {
- Arrays.fill(ia, 0);
- }
ROUNDS_12 = (ROUNDS>=12);
ROUNDS_14 = (ROUNDS==14);
limit = ROUNDS*4;
@@ -1444,8 +1417,11 @@ private void makeSessionKey(byte[] k) throws InvalidKeyException {
// erase the previous values in sessionK
Arrays.fill(sessionK[0], 0);
Arrays.fill(sessionK[1], 0);
+ } else {
+ sessionK = new int[2][];
}
- sessionK = new int[][] { expandedKe, expandedKd };
+ sessionK[0] = Ke;
+ sessionK[1] = Kd;
}
/**
diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Cipher.java b/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Cipher.java
index 84bd6521345..857cf52d3b6 100644
--- a/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Cipher.java
+++ b/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Cipher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2023, 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
@@ -87,6 +87,7 @@ abstract class ChaCha20Cipher extends CipherSpi {
// The counter
private static final long MAX_UINT32 = 0x00000000FFFFFFFFL;
private long finalCounterValue;
+ private long initCounterValue;
private long counter;
// The base state is created at initialization time as a 16-int array
@@ -336,7 +337,9 @@ protected void engineInit(int opmode, Key key,
}
ChaCha20ParameterSpec chaParams = (ChaCha20ParameterSpec)params;
newNonce = chaParams.getNonce();
- counter = ((long)chaParams.getCounter()) & 0x00000000FFFFFFFFL;
+ initCounterValue = ((long)chaParams.getCounter()) &
+ 0x00000000FFFFFFFFL;
+ counter = initCounterValue;
break;
case MODE_AEAD:
if (!(params instanceof IvParameterSpec)) {
@@ -545,9 +548,12 @@ private void init(int opmode, Key key, byte[] newNonce)
}
// Make sure that the provided key and nonce are unique before
- // assigning them to the object.
+ // assigning them to the object. Key and nonce uniqueness
+ // protection is for encryption operations only.
byte[] newKeyBytes = getEncodedKey(key);
- checkKeyAndNonce(newKeyBytes, newNonce);
+ if (opmode == Cipher.ENCRYPT_MODE) {
+ checkKeyAndNonce(newKeyBytes, newNonce);
+ }
if (this.keyBytes != null) {
Arrays.fill(this.keyBytes, (byte)0);
}
@@ -704,9 +710,8 @@ protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)
} catch (ShortBufferException | KeyException exc) {
throw new RuntimeException(exc);
} finally {
- // Regardless of what happens, the cipher cannot be used for
- // further processing until it has been freshly initialized.
- initialized = false;
+ // Reset the cipher's state to post-init values.
+ resetStartState();
}
return output;
}
@@ -742,9 +747,8 @@ protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,
} catch (KeyException ke) {
throw new RuntimeException(ke);
} finally {
- // Regardless of what happens, the cipher cannot be used for
- // further processing until it has been freshly initialized.
- initialized = false;
+ // Reset the cipher's state to post-init values.
+ resetStartState();
}
return bytesUpdated;
}
@@ -1170,6 +1174,23 @@ private void authWriteLengths(long aLen, long dLen, byte[] buf) {
asLongLittleEndian.set(buf, Long.BYTES, dLen);
}
+ /**
+ * reset the Cipher's state to the values it had after
+ * the initial init() call.
+ *
+ * Note: The cipher's internal "initialized" field is set differently
+ * for ENCRYPT_MODE and DECRYPT_MODE in order to allow DECRYPT_MODE
+ * ciphers to reuse the key/nonce/counter values. This kind of reuse
+ * is disallowed in ENCRYPT_MODE.
+ */
+ private void resetStartState() {
+ keyStrLimit = 0;
+ keyStrOffset = 0;
+ counter = initCounterValue;
+ aadDone = false;
+ initialized = (direction == Cipher.DECRYPT_MODE);
+ }
+
/**
* Interface for the underlying processing engines for ChaCha20
*/
@@ -1275,7 +1296,8 @@ public int getOutputSize(int inLength, boolean isFinal) {
private EngineAEADEnc() throws InvalidKeyException {
initAuthenticator();
- counter = 1;
+ initCounterValue = 1;
+ counter = initCounterValue;
}
@Override
@@ -1347,7 +1369,8 @@ public int getOutputSize(int inLen, boolean isFinal) {
private EngineAEADDec() throws InvalidKeyException {
initAuthenticator();
- counter = 1;
+ initCounterValue = 1;
+ counter = initCounterValue;
cipherBuf = new ByteArrayOutputStream(CIPHERBUF_BASE);
tag = new byte[TAG_LENGTH];
}
diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHKEM.java b/src/java.base/share/classes/com/sun/crypto/provider/DHKEM.java
new file mode 100644
index 00000000000..01a6e38d2aa
--- /dev/null
+++ b/src/java.base/share/classes/com/sun/crypto/provider/DHKEM.java
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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 com.sun.crypto.provider;
+
+import sun.security.jca.JCAUtil;
+import sun.security.ssl.HKDF;
+import sun.security.util.*;
+
+import javax.crypto.*;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
+import java.security.*;
+import java.security.interfaces.*;
+import java.security.spec.*;
+import java.util.Arrays;
+import java.util.Objects;
+
+// Implementing DHKEM defined inside https://www.rfc-editor.org/rfc/rfc9180.html,
+// without the AuthEncap and AuthDecap functions
+public class DHKEM implements KEMSpi {
+
+ private static final byte[] KEM = new byte[]
+ {'K', 'E', 'M'};
+ private static final byte[] EAE_PRK = new byte[]
+ {'e', 'a', 'e', '_', 'p', 'r', 'k'};
+ private static final byte[] SHARED_SECRET = new byte[]
+ {'s', 'h', 'a', 'r', 'e', 'd', '_', 's', 'e', 'c', 'r', 'e', 't'};
+ private static final byte[] DKP_PRK = new byte[]
+ {'d', 'k', 'p', '_', 'p', 'r', 'k'};
+ private static final byte[] CANDIDATE = new byte[]
+ {'c', 'a', 'n', 'd', 'i', 'd', 'a', 't', 'e'};
+ private static final byte[] SK = new byte[]
+ {'s', 'k'};
+ private static final byte[] HPKE_V1 = new byte[]
+ {'H', 'P', 'K', 'E', '-', 'v', '1'};
+ private static final byte[] EMPTY = new byte[0];
+
+ private record Handler(Params params, SecureRandom secureRandom,
+ PrivateKey skR, PublicKey pkR)
+ implements EncapsulatorSpi, DecapsulatorSpi {
+
+ @Override
+ public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm) {
+ Objects.checkFromToIndex(from, to, params.Nsecret);
+ Objects.requireNonNull(algorithm, "null algorithm");
+ KeyPair kpE = params.generateKeyPair(secureRandom);
+ PrivateKey skE = kpE.getPrivate();
+ PublicKey pkE = kpE.getPublic();
+ byte[] pkEm = params.SerializePublicKey(pkE);
+ byte[] pkRm = params.SerializePublicKey(pkR);
+ byte[] kem_context = concat(pkEm, pkRm);
+ try {
+ byte[] dh = params.DH(skE, pkR);
+ byte[] key = params.ExtractAndExpand(dh, kem_context);
+ return new KEM.Encapsulated(
+ new SecretKeySpec(key, from, to - from, algorithm),
+ pkEm, null);
+ } catch (Exception e) {
+ throw new ProviderException("internal error", e);
+ }
+ }
+
+ @Override
+ public SecretKey engineDecapsulate(byte[] encapsulation,
+ int from, int to, String algorithm) throws DecapsulateException {
+ Objects.checkFromToIndex(from, to, params.Nsecret);
+ Objects.requireNonNull(algorithm, "null algorithm");
+ Objects.requireNonNull(encapsulation, "null encapsulation");
+ if (encapsulation.length != params.Npk) {
+ throw new DecapsulateException("incorrect encapsulation size");
+ }
+ try {
+ PublicKey pkE = params.DeserializePublicKey(encapsulation);
+ byte[] dh = params.DH(skR, pkE);
+ byte[] pkRm = params.SerializePublicKey(pkR);
+ byte[] kem_context = concat(encapsulation, pkRm);
+ byte[] key = params.ExtractAndExpand(dh, kem_context);
+ return new SecretKeySpec(key, from, to - from, algorithm);
+ } catch (IOException | InvalidKeyException e) {
+ throw new DecapsulateException("Cannot decapsulate", e);
+ } catch (Exception e) {
+ throw new ProviderException("internal error", e);
+ }
+ }
+
+ @Override
+ public int engineSecretSize() {
+ return params.Nsecret;
+ }
+
+ @Override
+ public int engineEncapsulationSize() {
+ return params.Npk;
+ }
+ }
+
+ // Not really a random. For KAT test only. It generates key pair from ikm.
+ public static class RFC9180DeriveKeyPairSR extends SecureRandom {
+
+ static final long serialVersionUID = 0L;
+
+ private final byte[] ikm;
+
+ public RFC9180DeriveKeyPairSR(byte[] ikm) {
+ super(null, null); // lightest constructor
+ this.ikm = ikm;
+ }
+
+ public KeyPair derive(Params params) {
+ try {
+ return params.deriveKeyPair(ikm);
+ } catch (Exception e) {
+ throw new UnsupportedOperationException(e);
+ }
+ }
+
+ public KeyPair derive(int kem_id) {
+ Params params = Arrays.stream(Params.values())
+ .filter(p -> p.kem_id == kem_id)
+ .findFirst()
+ .orElseThrow();
+ return derive(params);
+ }
+ }
+
+ private enum Params {
+
+ P256(0x10, 32, 32, 2 * 32 + 1,
+ "ECDH", "EC", CurveDB.P_256, "SHA-256"),
+
+ P384(0x11, 48, 48, 2 * 48 + 1,
+ "ECDH", "EC", CurveDB.P_384, "SHA-384"),
+
+ P521(0x12, 64, 66, 2 * 66 + 1,
+ "ECDH", "EC", CurveDB.P_521, "SHA-512"),
+
+ X25519(0x20, 32, 32, 32,
+ "XDH", "XDH", NamedParameterSpec.X25519, "SHA-256"),
+
+ X448(0x21, 64, 56, 56,
+ "XDH", "XDH", NamedParameterSpec.X448, "SHA-512"),
+ ;
+
+ private final int kem_id;
+ private final int Nsecret;
+ private final int Nsk;
+ private final int Npk;
+ private final String kaAlgorithm;
+ private final String keyAlgorithm;
+ private final AlgorithmParameterSpec spec;
+ private final String hkdfAlgorithm;
+
+ private final byte[] suiteId;
+
+ Params(int kem_id, int Nsecret, int Nsk, int Npk,
+ String kaAlgorithm, String keyAlgorithm, AlgorithmParameterSpec spec,
+ String hkdfAlgorithm) {
+ this.kem_id = kem_id;
+ this.spec = spec;
+ this.Nsecret = Nsecret;
+ this.Nsk = Nsk;
+ this.Npk = Npk;
+ this.kaAlgorithm = kaAlgorithm;
+ this.keyAlgorithm = keyAlgorithm;
+ this.hkdfAlgorithm = hkdfAlgorithm;
+ suiteId = concat(KEM, I2OSP(kem_id, 2));
+ }
+
+ private boolean isEC() {
+ return this == P256 || this == P384 || this == P521;
+ }
+
+ private KeyPair generateKeyPair(SecureRandom sr) {
+ if (sr instanceof RFC9180DeriveKeyPairSR r9) {
+ return r9.derive(this);
+ }
+ try {
+ KeyPairGenerator g = KeyPairGenerator.getInstance(keyAlgorithm);
+ g.initialize(spec, sr);
+ return g.generateKeyPair();
+ } catch (Exception e) {
+ throw new ProviderException("internal error", e);
+ }
+ }
+
+ private byte[] SerializePublicKey(PublicKey k) {
+ if (isEC()) {
+ ECPoint w = ((ECPublicKey) k).getW();
+ return ECUtil.encodePoint(w, ((NamedCurve) spec).getCurve());
+ } else {
+ byte[] uArray = ((XECPublicKey) k).getU().toByteArray();
+ ArrayUtil.reverse(uArray);
+ return Arrays.copyOf(uArray, Npk);
+ }
+ }
+
+ private PublicKey DeserializePublicKey(byte[] data)
+ throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
+ KeySpec keySpec;
+ if (isEC()) {
+ NamedCurve curve = (NamedCurve) this.spec;
+ keySpec = new ECPublicKeySpec(
+ ECUtil.decodePoint(data, curve.getCurve()), curve);
+ } else {
+ data = data.clone();
+ ArrayUtil.reverse(data);
+ keySpec = new XECPublicKeySpec(
+ this.spec, new BigInteger(1, data));
+ }
+ return KeyFactory.getInstance(keyAlgorithm).generatePublic(keySpec);
+ }
+
+ private byte[] DH(PrivateKey skE, PublicKey pkR)
+ throws NoSuchAlgorithmException, InvalidKeyException {
+ KeyAgreement ka = KeyAgreement.getInstance(kaAlgorithm);
+ ka.init(skE);
+ ka.doPhase(pkR, true);
+ return ka.generateSecret();
+ }
+
+ private byte[] ExtractAndExpand(byte[] dh, byte[] kem_context)
+ throws NoSuchAlgorithmException, InvalidKeyException {
+ HKDF kdf = new HKDF(hkdfAlgorithm);
+ SecretKey eae_prk = LabeledExtract(kdf, suiteId, null, EAE_PRK, dh);
+ return LabeledExpand(kdf, suiteId, eae_prk, SHARED_SECRET,
+ kem_context, Nsecret);
+ }
+
+ private PublicKey getPublicKey(PrivateKey sk)
+ throws InvalidKeyException {
+ if (!(sk instanceof InternalPrivateKey)) {
+ try {
+ KeyFactory kf = KeyFactory.getInstance(keyAlgorithm, "SunEC");
+ sk = (PrivateKey) kf.translateKey(sk);
+ } catch (Exception e) {
+ throw new InvalidKeyException("Error translating key", e);
+ }
+ }
+ if (sk instanceof InternalPrivateKey ik) {
+ try {
+ return ik.calculatePublicKey();
+ } catch (UnsupportedOperationException e) {
+ throw new InvalidKeyException("Error retrieving key", e);
+ }
+ } else {
+ // Should not happen, unless SunEC goes wrong
+ throw new ProviderException("Unknown key");
+ }
+ }
+
+ // For KAT tests only. See RFC9180DeriveKeyPairSR.
+ public KeyPair deriveKeyPair(byte[] ikm) throws Exception {
+ HKDF kdf = new HKDF(hkdfAlgorithm);
+ SecretKey dkp_prk = LabeledExtract(kdf, suiteId, null, DKP_PRK, ikm);
+ if (isEC()) {
+ NamedCurve curve = (NamedCurve) spec;
+ BigInteger sk = BigInteger.ZERO;
+ int counter = 0;
+ while (sk.signum() == 0 || sk.compareTo(curve.getOrder()) >= 0) {
+ if (counter > 255) {
+ throw new RuntimeException();
+ }
+ byte[] bytes = LabeledExpand(kdf, suiteId, dkp_prk,
+ CANDIDATE, I2OSP(counter, 1), Nsk);
+ // bitmask is defined to be 0xFF for P-256 and P-384, and 0x01 for P-521
+ if (this == Params.P521) {
+ bytes[0] = (byte) (bytes[0] & 0x01);
+ }
+ sk = new BigInteger(1, (bytes));
+ counter = counter + 1;
+ }
+ PrivateKey k = DeserializePrivateKey(sk.toByteArray());
+ return new KeyPair(getPublicKey(k), k);
+ } else {
+ byte[] sk = LabeledExpand(kdf, suiteId, dkp_prk, SK, EMPTY, Nsk);
+ PrivateKey k = DeserializePrivateKey(sk);
+ return new KeyPair(getPublicKey(k), k);
+ }
+ }
+
+ private PrivateKey DeserializePrivateKey(byte[] data) throws Exception {
+ KeySpec keySpec = isEC()
+ ? new ECPrivateKeySpec(new BigInteger(1, (data)), (NamedCurve) spec)
+ : new XECPrivateKeySpec(spec, data);
+ return KeyFactory.getInstance(keyAlgorithm).generatePrivate(keySpec);
+ }
+ }
+
+ private static SecureRandom getSecureRandom(SecureRandom userSR) {
+ return userSR != null ? userSR : JCAUtil.getSecureRandom();
+ }
+
+ @Override
+ public EncapsulatorSpi engineNewEncapsulator(
+ PublicKey pk, AlgorithmParameterSpec spec, SecureRandom secureRandom)
+ throws InvalidAlgorithmParameterException, InvalidKeyException {
+ if (pk == null) {
+ throw new InvalidKeyException("input key is null");
+ }
+ if (spec != null) {
+ throw new InvalidAlgorithmParameterException("no spec needed");
+ }
+ Params params = paramsFromKey(pk);
+ return new Handler(params, getSecureRandom(secureRandom), null, pk);
+ }
+
+ @Override
+ public DecapsulatorSpi engineNewDecapsulator(PrivateKey sk, AlgorithmParameterSpec spec)
+ throws InvalidAlgorithmParameterException, InvalidKeyException {
+ if (sk == null) {
+ throw new InvalidKeyException("input key is null");
+ }
+ if (spec != null) {
+ throw new InvalidAlgorithmParameterException("no spec needed");
+ }
+ Params params = paramsFromKey(sk);
+ return new Handler(params, null, sk, params.getPublicKey(sk));
+ }
+
+ private Params paramsFromKey(Key k) throws InvalidKeyException {
+ if (k instanceof ECKey eckey) {
+ if (ECUtil.equals(eckey.getParams(), CurveDB.P_256)) {
+ return Params.P256;
+ } else if (ECUtil.equals(eckey.getParams(), CurveDB.P_384)) {
+ return Params.P384;
+ } else if (ECUtil.equals(eckey.getParams(), CurveDB.P_521)) {
+ return Params.P521;
+ }
+ } else if (k instanceof XECKey xkey
+ && xkey.getParams() instanceof NamedParameterSpec ns) {
+ if (ns.getName().equals("X25519")) {
+ return Params.X25519;
+ } else if (ns.getName().equals("X448")) {
+ return Params.X448;
+ }
+ }
+ throw new InvalidKeyException("Unsupported key");
+ }
+
+ private static byte[] concat(byte[]... inputs) {
+ ByteArrayOutputStream o = new ByteArrayOutputStream();
+ Arrays.stream(inputs).forEach(o::writeBytes);
+ return o.toByteArray();
+ }
+
+ private static byte[] I2OSP(int n, int w) {
+ assert n < 256;
+ assert w == 1 || w == 2;
+ if (w == 1) {
+ return new byte[] { (byte) n };
+ } else {
+ return new byte[] { (byte) (n >> 8), (byte) n };
+ }
+ }
+
+ private static SecretKey LabeledExtract(HKDF kdf, byte[] suite_id,
+ byte[] salt, byte[] label, byte[] ikm) throws InvalidKeyException {
+ return kdf.extract(salt,
+ new SecretKeySpec(concat(HPKE_V1, suite_id, label, ikm), "IKM"),
+ "HKDF-PRK");
+ }
+
+ private static byte[] LabeledExpand(HKDF kdf, byte[] suite_id,
+ SecretKey prk, byte[] label, byte[] info, int L)
+ throws InvalidKeyException {
+ byte[] labeled_info = concat(I2OSP(L, 2), HPKE_V1,
+ suite_id, label, info);
+ return kdf.expand(prk, labeled_info, L, "NONE").getEncoded();
+ }
+}
diff --git a/src/java.base/share/classes/com/sun/crypto/provider/HmacPKCS12PBECore.java b/src/java.base/share/classes/com/sun/crypto/provider/HmacPKCS12PBECore.java
index 1fd6230d83b..0d999e4f512 100644
--- a/src/java.base/share/classes/com/sun/crypto/provider/HmacPKCS12PBECore.java
+++ b/src/java.base/share/classes/com/sun/crypto/provider/HmacPKCS12PBECore.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,13 +25,14 @@
package com.sun.crypto.provider;
-import java.util.Arrays;
-
-import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
-import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.PBEKeySpec;
import java.security.*;
import java.security.spec.*;
+import java.util.Arrays;
+
+import jdk.internal.access.SharedSecrets;
+import sun.security.util.PBEUtil;
/**
* This is an implementation of the HMAC algorithms as defined
@@ -108,81 +109,30 @@ public HmacPKCS12PBECore(String algorithm, int bl) throws NoSuchAlgorithmExcepti
*/
protected void engineInit(Key key, AlgorithmParameterSpec params)
throws InvalidKeyException, InvalidAlgorithmParameterException {
- char[] passwdChars;
- byte[] salt = null;
- int iCount = 0;
- if (key instanceof javax.crypto.interfaces.PBEKey) {
- javax.crypto.interfaces.PBEKey pbeKey =
- (javax.crypto.interfaces.PBEKey) key;
- passwdChars = pbeKey.getPassword();
- salt = pbeKey.getSalt(); // maybe null if unspecified
- iCount = pbeKey.getIterationCount(); // maybe 0 if unspecified
- } else if (key instanceof SecretKey) {
- byte[] passwdBytes;
- if (!(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3)) ||
- (passwdBytes = key.getEncoded()) == null) {
- throw new InvalidKeyException("Missing password");
- }
- passwdChars = new char[passwdBytes.length];
- for (int i=0; i {
- Arrays.fill(k, (byte) 0x00);
- Arrays.fill(p, '\0');
- });
+ if (key == null) {
+ Arrays.fill(passwd, '\0');
+ }
}
+ // Use the cleaner to zero the key when no longer referenced
+ final byte[] k = this.key;
+ final char[] p = this.passwd;
+ cleaner = CleanerFactory.cleaner().register(this,
+ () -> {
+ Arrays.fill(k, (byte) 0x00);
+ Arrays.fill(p, '\0');
+ });
}
private static byte[] deriveKey(final Mac prf, final byte[] password,
@@ -219,11 +210,7 @@ public boolean equals(Object obj) {
}
public byte[] getEncoded() {
- // The key is zeroized by finalize()
- // The reachability fence ensures finalize() isn't called early
- byte[] result = key.clone();
- Reference.reachabilityFence(this);
- return result;
+ return key.clone();
}
public String getAlgorithm() {
@@ -234,16 +221,12 @@ public int getIterationCount() {
return iterCount;
}
- public void clearPassword() {
- Arrays.fill(passwd, (char)0);
+ public void clear() {
+ cleaner.clean();
}
public char[] getPassword() {
- // The password is zeroized by finalize()
- // The reachability fence ensures finalize() isn't called early
- char[] result = passwd.clone();
- Reference.reachabilityFence(this);
- return result;
+ return passwd.clone();
}
public byte[] getSalt() {
diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java
index 6c2f5df6716..56059a89264 100644
--- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java
+++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
package com.sun.crypto.provider;
+import jdk.internal.access.SharedSecrets;
+
import java.util.Arrays;
import javax.crypto.SecretKey;
@@ -179,23 +181,29 @@ protected void engineInit(Key key, AlgorithmParameterSpec params)
}
PBKDF2KeyImpl s = null;
- PBKDF2Core kdf = getKDFImpl(kdfAlgo);
- byte[] derivedKey;
+ byte[] derivedKey = null;
+ SecretKeySpec cipherKey = null;
try {
+ PBKDF2Core kdf = getKDFImpl(kdfAlgo);
s = (PBKDF2KeyImpl)kdf.engineGenerateSecret(pbeSpec);
derivedKey = s.getEncoded();
+ cipherKey = new SecretKeySpec(derivedKey, kdfAlgo);
+ super.engineInit(cipherKey, null);
} catch (InvalidKeySpecException ikse) {
throw new InvalidKeyException("Cannot construct PBE key", ikse);
} finally {
- pbeSpec.clearPassword();
+ if (cipherKey != null) {
+ SharedSecrets.getJavaxCryptoSpecAccess()
+ .clearSecretKeySpec(cipherKey);
+ }
+ if (derivedKey != null) {
+ Arrays.fill(derivedKey, (byte) 0);
+ }
if (s != null) {
- s.clearPassword();
+ s.clear();
}
+ pbeSpec.clearPassword();
}
- SecretKey cipherKey = new SecretKeySpec(derivedKey, kdfAlgo);
- Arrays.fill(derivedKey, (byte)0);
-
- super.engineInit(cipherKey, null);
}
public static final class HmacSHA1 extends PBMAC1Core {
diff --git a/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java b/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java
index dd788a967be..2e5317365fd 100644
--- a/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java
+++ b/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2023, 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
@@ -83,6 +83,10 @@
*
* - HMAC-MD5, HMAC-SHA1, HMAC with SHA2 family and SHA3 family of digests
*
+ * - JCEKS KeyStore
+ *
+ * - DHKEM
+ *
*/
public final class SunJCE extends Provider {
@@ -787,6 +791,15 @@ void putEntries() {
ps("KeyStore", "JCEKS",
"com.sun.crypto.provider.JceKeyStore");
+ /*
+ * KEMs
+ */
+ attrs.clear();
+ attrs.put("ImplementedIn", "Software");
+ attrs.put("SupportedKeyClasses", "java.security.interfaces.ECKey" +
+ "|java.security.interfaces.XECKey");
+ ps("KEM", "DHKEM", "com.sun.crypto.provider.DHKEM", null, attrs);
+
/*
* SSL/TLS mechanisms
*
diff --git a/src/java.base/share/classes/java/io/BufferedReader.java b/src/java.base/share/classes/java/io/BufferedReader.java
index 6953061628e..2cd027c8bd8 100644
--- a/src/java.base/share/classes/java/io/BufferedReader.java
+++ b/src/java.base/share/classes/java/io/BufferedReader.java
@@ -47,10 +47,9 @@
* operations may be costly, such as FileReaders and InputStreamReaders. For
* example,
*
- *
- * BufferedReader in
- * = new BufferedReader(new FileReader("foo.in"));
- *
+ * {@snippet lang=java :
+ * BufferedReader in = new BufferedReader(new FileReader("foo.in"));
+ * }
*
* will buffer the input from the specified file. Without buffering, each
* invocation of read() or readLine() could cause bytes to be read from the
diff --git a/src/java.base/share/classes/java/io/BufferedWriter.java b/src/java.base/share/classes/java/io/BufferedWriter.java
index 4cb958afd74..4904f718072 100644
--- a/src/java.base/share/classes/java/io/BufferedWriter.java
+++ b/src/java.base/share/classes/java/io/BufferedWriter.java
@@ -48,10 +48,9 @@
* to wrap a BufferedWriter around any Writer whose write() operations may be
* costly, such as FileWriters and OutputStreamWriters. For example,
*
- *
- * PrintWriter out
- * = new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
- *
+ * {@snippet lang=java :
+ * PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
+ * }
*
* will buffer the PrintWriter's output to the file. Without buffering, each
* invocation of a print() method would cause characters to be converted into
diff --git a/src/java.base/share/classes/java/io/ByteArrayOutputStream.java b/src/java.base/share/classes/java/io/ByteArrayOutputStream.java
index 1052b057d17..109acce3853 100644
--- a/src/java.base/share/classes/java/io/ByteArrayOutputStream.java
+++ b/src/java.base/share/classes/java/io/ByteArrayOutputStream.java
@@ -228,19 +228,17 @@ public synchronized String toString() {
*
*
+ * {@snippet lang=java :
+ * ByteArrayOutputStream b;
+ * b.toString(StandardCharsets.UTF_8)
+ * }
*
*
* @param charsetName the name of a supported
@@ -282,9 +280,9 @@ public synchronized String toString(Charset charset) {
* copied into it. Each character c in the resulting string is
* constructed from the corresponding element b in the byte
* array such that:
- *
+ * }
*
* @deprecated This method does not properly convert bytes into characters.
* As of JDK 1.1, the preferred way to do this is via the
diff --git a/src/java.base/share/classes/java/io/CharArrayWriter.java b/src/java.base/share/classes/java/io/CharArrayWriter.java
index 0045c242cdf..f084d6245a8 100644
--- a/src/java.base/share/classes/java/io/CharArrayWriter.java
+++ b/src/java.base/share/classes/java/io/CharArrayWriter.java
@@ -152,8 +152,9 @@ public void writeTo(Writer out) throws IOException {
*
An invocation of this method of the form {@code out.append(csq)}
* behaves in exactly the same way as the invocation
*
- *
Depending on the specification of {@code toString} for the
* character sequence {@code csq}, the entire sequence may not be
@@ -184,8 +185,9 @@ public CharArrayWriter append(CharSequence csq) {
* {@code csq} is not {@code null}, behaves in
* exactly the same way as the invocation
*
- *
+ * {@snippet lang=java :
+ * out.write(csq.subSequence(start, end).toString())
+ * }
*
* @param csq
* The character sequence from which a subsequence will be
@@ -220,8 +222,9 @@ public CharArrayWriter append(CharSequence csq, int start, int end) {
*
An invocation of this method of the form {@code out.append(c)}
* behaves in exactly the same way as the invocation
*
- *
- * out.write(c)
+ * {@snippet lang=java :
+ * out.write(c)
+ * }
*
* @param c
* The 16-bit character to append
diff --git a/src/java.base/share/classes/java/io/Console.java b/src/java.base/share/classes/java/io/Console.java
index d821a476dc7..d6673861f69 100644
--- a/src/java.base/share/classes/java/io/Console.java
+++ b/src/java.base/share/classes/java/io/Console.java
@@ -86,7 +86,7 @@
* char[] passwd;
* if ((cons = System.console()) != null &&
* (passwd = cons.readPassword("[%s]", "Password:")) != null) {
- * ...
+ * code: // @replace substring="code:" replacement="..."
* java.util.Arrays.fill(passwd, ' ');
* }
* }
@@ -117,13 +117,13 @@ public PrintWriter writer() {
* This method is intended to be used by sophisticated applications, for
* example, a {@link java.util.Scanner} object which utilizes the rich
* parsing/scanning functionality provided by the {@code Scanner}:
- *
+ * A class or interface created by the invocation of
* {@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...)
* Lookup::defineHiddenClass} is a {@linkplain Class#isHidden() hidden}
* class or interface.
@@ -186,6 +189,31 @@
* a class or interface is hidden has no bearing on the characteristics
* exposed by the methods of class {@code Class}.
*
+ *
+ *
+ * A {@code class} file representing an {@linkplain #isUnnamedClass unnamed class}
+ * is generated by a Java compiler from a source file for an unnamed class.
+ * The {@code Class} object representing an unnamed class is top-level,
+ * {@linkplain #isSynthetic synthetic}, and {@code final}. While an
+ * unnamed class does not have a name in its Java source
+ * form, several of the name-related methods of {@code java.lang.Class}
+ * do return non-null and non-empty results for the {@code Class}
+ * object representing an unnamed class.
+ *
+ * Conventionally, a Java compiler, starting from a source file for an
+ * unnamed class, say {@code HelloWorld.java}, creates a
+ * similarly-named {@code class} file, {@code HelloWorld.class}, where
+ * the class stored in that {@code class} file is named {@code
+ * "HelloWorld"}, matching the base names of the source and {@code
+ * class} files.
+ *
+ * For the {@code Class} object of an unnamed class {@code
+ * HelloWorld}, the methods to get the {@linkplain #getName name} and
+ * {@linkplain #getTypeName type name} return results
+ * equal to {@code "HelloWorld"}. The {@linkplain #getSimpleName
+ * simple name} of such an unnamed class is the empty string and the
+ * {@linkplain #getCanonicalName canonical name} is {@code null}.
+ *
* @param the type of the class modeled by this {@code Class}
* object. For example, the type of {@code String.class} is {@code
* Class}. Use {@code Class>} if the class being modeled is
@@ -341,9 +369,9 @@ static String typeVarBounds(TypeVariable> typeVar) {
* interface with the given string name. Invoking this method is
* equivalent to:
*
- *
* A call to {@code forName("X")} causes the class named
* {@code X} to be initialized.
@@ -415,15 +443,15 @@ private static Class> forName(String className, Class> caller)
*
*
For example, in an instance method the expression:
*
- *
- * {@code Class.forName("Foo")}
- *
+ * {@snippet lang="java" :
+ * Class.forName("Foo")
+ * }
*
* is equivalent to:
*
- *
+ * }
*
* The latter sequence of calls is inferred to be able to throw
* the additional exception types {@link
@@ -1718,7 +1746,7 @@ public Class> getEnclosingClass() throws SecurityException {
/**
* Returns the simple name of the underlying class as given in the
* source code. An empty string is returned if the underlying class is
- * {@linkplain #isAnonymousClass() anonymous}.
+ * {@linkplain #isAnonymousClass() anonymous} or {@linkplain #isUnnamedClass() unnamed}.
* A {@linkplain #isSynthetic() synthetic class}, one not present
* in source code, can have a non-empty name including special
* characters, such as "{@code $}".
@@ -1731,6 +1759,9 @@ public Class> getEnclosingClass() throws SecurityException {
* @since 1.5
*/
public String getSimpleName() {
+ if (isUnnamedClass()) {
+ return "";
+ }
ReflectionData rd = reflectionData();
String simpleName = rd.simpleName;
if (simpleName == null) {
@@ -1780,6 +1811,7 @@ public String getTypeName() {
*
*
a {@linkplain #isLocalClass() local class}
*
a {@linkplain #isAnonymousClass() anonymous class}
+ *
an {@linkplain #isUnnamedClass() unnamed class}
*
a {@linkplain #isHidden() hidden class}
*
an array whose component type does not have a canonical name
*
@@ -1799,6 +1831,9 @@ public String getTypeName() {
* @since 1.5
*/
public String getCanonicalName() {
+ if (isUnnamedClass()) {
+ return null;
+ }
ReflectionData rd = reflectionData();
String canonicalName = rd.canonicalName;
if (canonicalName == null) {
@@ -1833,12 +1868,33 @@ private String getCanonicalName0() {
}
}
+ /**
+ * {@return {@code true} if and only if the underlying class
+ * is an unnamed class}
+ *
+ * @apiNote
+ * An unnamed class is not an {@linkplain #isAnonymousClass anonymous class}.
+ *
+ * @since 21
+ *
+ * @jls 7.3 Compilation Units
+ */
+ @PreviewFeature(feature=PreviewFeature.Feature.UNNAMED_CLASSES,
+ reflective=true)
+ public boolean isUnnamedClass() {
+ return PreviewFeatures.isEnabled() && isSynthetic()
+ && isTopLevelClass()
+ && Modifier.isFinal(getModifiers());
+ }
+
+
/**
* Returns {@code true} if and only if the underlying class
* is an anonymous class.
*
* @apiNote
* An anonymous class is not a {@linkplain #isHidden() hidden class}.
+ * An anonymous class is not an {@linkplain #isUnnamedClass() unnamed class}.
*
* @return {@code true} if and only if this class is an anonymous class.
* @since 1.5
@@ -2485,7 +2541,7 @@ public Field[] getDeclaredFields() throws SecurityException {
* @apiNote
*
The following method can be used to find the record canonical constructor:
*
- *
+ * }}
*
* @return An array of {@code RecordComponent} objects representing all the
* record components of this record class, or {@code null} if this
diff --git a/src/java.base/share/classes/java/lang/FdLibm.java b/src/java.base/share/classes/java/lang/FdLibm.java
index 5410a0a1ad6..e435bb382b9 100644
--- a/src/java.base/share/classes/java/lang/FdLibm.java
+++ b/src/java.base/share/classes/java/lang/FdLibm.java
@@ -57,7 +57,7 @@
* operations in terms of floating-point operations when convenient to
* do so.
*/
-class FdLibm {
+final class FdLibm {
// Constants used by multiple algorithms
private static final double INFINITY = Double.POSITIVE_INFINITY;
private static final double TWO24 = 0x1.0p24; // 1.67772160000000000000e+07
@@ -154,7 +154,7 @@ private static double __HI_LO(int high, int low) {
* Accuracy:
* TRIG(x) returns trig(x) nearly rounded
*/
- static class Sin {
+ static final class Sin {
private Sin() {throw new UnsupportedOperationException();}
static double compute(double x) {
@@ -267,7 +267,7 @@ static double __kernel_sin(double x, double y, int iy) {
* Accuracy:
* TRIG(x) returns trig(x) nearly rounded
*/
- static class Cos {
+ static final class Cos {
private Cos() {throw new UnsupportedOperationException();}
static double compute(double x) {
@@ -393,7 +393,7 @@ static double __kernel_cos(double x, double y) {
* Accuracy:
* TRIG(x) returns trig(x) nearly rounded
*/
- static class Tan {
+ static final class Tan {
private Tan() {throw new UnsupportedOperationException();}
static double compute(double x) {
@@ -542,7 +542,7 @@ static double __kernel_tan(double x, double y, int iy) {
* return the remainder of x rem pi/2 in y[0]+y[1]
* use __kernel_rem_pio2()
*/
- static class RemPio2 {
+ static final class RemPio2 {
/*
* Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
*/
@@ -798,7 +798,7 @@ static int __ieee754_rem_pio2(double x, double[] y) {
* it also indicates the *sign* of the result.
*
*/
- static class KernelRemPio2 {
+ static final class KernelRemPio2 {
/*
* Constants:
* The hexadecimal values are the intended ones for the following
@@ -1058,7 +1058,7 @@ static int __kernel_rem_pio2(double[] x, double[] y, int e0, int nx, int prec, f
* if |x|>1, return NaN with invalid signal.
*
*/
- static class Asin {
+ static final class Asin {
private Asin() {throw new UnsupportedOperationException();}
private static final double
@@ -1146,7 +1146,7 @@ static double compute(double x) {
*
* Function needed: sqrt
*/
- static class Acos {
+ static final class Acos {
private Acos() {throw new UnsupportedOperationException();}
private static final double
@@ -1229,7 +1229,7 @@ static double compute(double x) {
* compiler will convert from decimal to binary accurately enough
* to produce the hexadecimal values shown.
*/
- static class Atan {
+ static final class Atan {
private Atan() {throw new UnsupportedOperationException();}
private static final double atanhi[] = {
@@ -1347,7 +1347,7 @@ static double compute(double x) {
* compiler will convert from decimal to binary accurately enough
* to produce the hexadecimal values shown.
*/
- static class Atan2 {
+ static final class Atan2 {
private Atan2() {throw new UnsupportedOperationException();}
private static final double
@@ -1497,7 +1497,7 @@ static double compute(double y, double x) {
* Other methods : see the appended file at the end of the program below.
*---------------
*/
- static class Sqrt {
+ static final class Sqrt {
private Sqrt() {throw new UnsupportedOperationException();}
private static final double tiny = 1.0e-300;
@@ -1875,7 +1875,7 @@ else if (ix0 < 0)
* cbrt(x)
* Return cube root of x
*/
- public static class Cbrt {
+ static final class Cbrt {
// unsigned
private static final int B1 = 715094163; /* B1 = (682-0.03306235651)*2**20 */
private static final int B2 = 696219795; /* B2 = (664-0.03306235651)*2**20 */
@@ -1965,7 +1965,7 @@ public static double compute(double x) {
* hypot(x,y) returns sqrt(x^2 + y^2) with error less
* than 1 ulp (unit in the last place)
*/
- public static class Hypot {
+ static final class Hypot {
public static final double TWO_MINUS_600 = 0x1.0p-600;
public static final double TWO_PLUS_600 = 0x1.0p+600;
@@ -2108,7 +2108,7 @@ public static double compute(double x, double y) {
* always returns the correct integer provided it is
* representable.
*/
- public static class Pow {
+ static final class Pow {
private Pow() {
throw new UnsupportedOperationException();
}
@@ -2683,7 +2683,7 @@ static double compute(double x) {
* from decimal to binary accurately enough to produce the hexadecimal values
* shown.
*/
- static class Log10 {
+ static final class Log10 {
private static final double ivln10 = 0x1.bcb7b1526e50ep-2; // 4.34294481903251816668e-01
private static final double log10_2hi = 0x1.34413509f6p-2; // 3.01029995663611771306e-01;
@@ -2792,7 +2792,7 @@ public static double compute(double x) {
*
* See HP-15C Advanced Functions Handbook, p.193.
*/
- static class Log1p {
+ static final class Log1p {
private static final double ln2_hi = 0x1.62e42feep-1; // 6.93147180369123816490e-01
private static final double ln2_lo = 0x1.a39ef35793c76p-33; // 1.90821492927058770002e-10
private static final double Lp1 = 0x1.5555555555593p-1; // 6.666666666666735130e-01
@@ -2984,7 +2984,7 @@ public static double compute(double x) {
* compiler will convert from decimal to binary accurately enough
* to produce the hexadecimal values shown.
*/
- static class Expm1 {
+ static final class Expm1 {
private static final double huge = 1.0e+300;
private static final double tiny = 1.0e-300;
private static final double o_threshold = 0x1.62e42fefa39efp9; // 7.09782712893383973096e+02
diff --git a/src/java.base/share/classes/java/lang/MatchException.java b/src/java.base/share/classes/java/lang/MatchException.java
index e47150122c1..832d71bcb1d 100644
--- a/src/java.base/share/classes/java/lang/MatchException.java
+++ b/src/java.base/share/classes/java/lang/MatchException.java
@@ -25,48 +25,57 @@
package java.lang;
-import jdk.internal.javac.PreviewFeature;
-
/**
* Thrown to indicate an unexpected failure in pattern matching.
*
- *
{@code MatchException} may be thrown when an exhaustive pattern matching language construct
- * (such as a switch expression) encounters a value that does not match any of the provided
- * patterns at runtime. This can arise from a number of cases:
+ *
{@code MatchException} may be thrown when an exhaustive pattern matching
+ * language construct (such as a {@code switch} expression) encounters a value
+ * that does not match any of the specified patterns at run time, even though
+ * the construct has been deemed exhaustive. This is intentional and can arise
+ * from a number of cases:
+ *
*
- *
Separate compilation anomalies, where a sealed interface has a different set of permitted
- * subtypes at runtime than it had at compilation time, an enum has a different set of
- * constants at runtime than it had at compilation time, or the type hierarchy has changed
- * in incompatible ways between compile time and run time.
- *
{@code null} values and nested patterns using sealed types. If an interface or abstract
- * class {@code C} is sealed to permit {@code A} and {@code B}, then the set of record
- * patterns {@code R(A a)} and {@code R(B b)} are exhaustive on a record {@code R} whose
- * sole component is of type {@code C}, but neither of these patterns will match
- * {@code new R(null)}.
- *
Null targets and nested record patterns. Given a record type {@code R} whose sole
- * component is {@code S}, which in turn is a record whose sole component is {@code String},
- * then the nested record pattern {@code R(S(String s))} will not match {@code new R(null)}.
- *
+ *
Separate compilation anomalies, where parts of the type hierarchy that
+ * the patterns reference have been changed, but the pattern matching
+ * construct has not been recompiled. For example, if a sealed interface
+ * has a different set of permitted subtypes at run time than it had at
+ * compile time, or if an enum class has a different set of enum constants
+ * at runtime than it had at compile time, or if the type hierarchy has
+ * been changed in some incompatible way between compile time and run time.
*
- *
Match failures arising from unexpected inputs will generally throw {@code MatchException} only
- * after all patterns have been tried; even if {@code R(S(String s))} does not match
- * {@code new R(null)}, a later pattern (such as {@code R r}) may still match the target.
+ *
{@code null} values and nested patterns involving sealed classes. If,
+ * for example, an interface {@code I} is {@code sealed} with two permitted
+ * subclasses {@code A} and {@code B}, and a record class {@code R} has a
+ * single component of type {@code I}, then the two record patterns {@code
+ * R(A a)} and {@code R(B b)} together are considered to be exhaustive for
+ * the type {@code R}, but neither of these patterns will match against the
+ * result of {@code new R(null)}.
+ *
+ *
{@code null} values and nested record patterns. Given a record class
+ * {@code S} with a single component of type {@code T}, where {@code T} is
+ * another record class with a single component of type {@code String},
+ * then the nested record pattern {@code R(S(var s))} is considered
+ * exhaustive for the type {@code R} but it does not match against the
+ * result of {@code new R(null)} (whereas it does match against the result
+ * of {@code new R(new S(null))} does).
+ *
*
- *
MatchException may also be thrown when operations performed as part of pattern matching throw
- * an unexpected exception. For example, pattern matching may cause methods such as record component
- * accessors to be implicitly invoked in order to extract pattern bindings. If these methods throw
- * an exception, execution of the pattern matching construct may fail with {@code MatchException}.
- * The original exception will be set as a {@link Throwable#getCause() cause} of
- * the {@code MatchException}. No {@link Throwable#addSuppressed(java.lang.Throwable) suppressed}
- * exceptions will be recorded.
+ *
{@code MatchException} may also be thrown by the process of pattern matching
+ * a value against a pattern. For example, pattern matching involving a record
+ * pattern may require accessor methods to be implicitly invoked in order to
+ * extract the component values. If any of these accessor methods throws an
+ * exception, pattern matching completes abruptly and throws {@code
+ * MatchException}. The original exception will be set as a {@link
+ * Throwable#getCause() cause} of the {@code MatchException}. No {@link
+ * Throwable#addSuppressed(java.lang.Throwable) suppressed} exceptions will be
+ * recorded.
*
- * @jls 14.11.3 Execution of a switch Statement
+ * @jls 14.11.3 Execution of a {@code switch} Statement
* @jls 14.30.2 Pattern Matching
- * @jls 15.28.2 Run-Time Evaluation of switch Expressions
+ * @jls 15.28.2 Run-Time Evaluation of {@code switch} Expressions
*
- * @since 19
+ * @since 21
*/
-@PreviewFeature(feature=PreviewFeature.Feature.SWITCH_PATTERN_MATCHING)
public final class MatchException extends RuntimeException {
@java.io.Serial
private static final long serialVersionUID = 0L;
diff --git a/src/java.base/share/classes/java/lang/Runtime.java b/src/java.base/share/classes/java/lang/Runtime.java
index 9f87c68da75..e77bf4c41e3 100644
--- a/src/java.base/share/classes/java/lang/Runtime.java
+++ b/src/java.base/share/classes/java/lang/Runtime.java
@@ -140,19 +140,21 @@ public static Runtime getRuntime() {
private Runtime() {}
/**
- * Initiates the shutdown sequence of the Java Virtual Machine.
- * This method blocks indefinitely; it never returns or throws an exception (that is, it
- * does not complete either normally or abruptly). The argument serves as a status code;
- * by convention, a nonzero status code indicates abnormal termination.
+ * Initiates the {@linkplain ##shutdown shutdown sequence} of the Java Virtual Machine.
+ * Unless the security manager denies exiting, this method initiates the shutdown sequence
+ * (if it is not already initiated) and then blocks indefinitely. This method neither returns
+ * nor throws an exception; that is, it does not complete either normally or abruptly.
*
- *
Invocations of this method are serialized such that only one
- * invocation will actually proceed with the shutdown sequence and
- * terminate the VM with the given status code. All other invocations
- * simply block indefinitely.
+ *
The argument serves as a status code. By convention, a nonzero status code
+ * indicates abnormal termination.
*
- *
Because this method always blocks indefinitely, if it is invoked from
- * a shutdown hook, it will prevent that shutdown hook from terminating.
- * Consequently, this will prevent the shutdown sequence from finishing.
+ *
Successful invocations of this method are serialized such that only one invocation
+ * initiates the shutdown sequence and terminates the VM with the given status code.
+ * All other invocations will perform no action and block indefinitely.
+ *
+ *
Because a successful invocation of this method blocks indefinitely, if it is invoked
+ * from a shutdown hook, it will prevent that shutdown hook from terminating. Consequently,
+ * this will prevent the shutdown sequence from finishing.
*
*
The {@link System#exit(int) System.exit} method is the
* conventional and convenient means of invoking this method.
@@ -190,7 +192,7 @@ public void exit(int status) {
* Registers a new virtual-machine shutdown hook.
*
*
A shutdown hook is simply an initialized but unstarted thread. Shutdown hooks
- * are started at the beginning of the shutdown sequence.
+ * are started at the beginning of the {@linkplain ##shutdown shutdown sequence}.
* Registration and de-registration of shutdown hooks is disallowed once the shutdown
* sequence has begun.
*
@@ -280,15 +282,17 @@ public boolean removeShutdownHook(Thread hook) {
}
/**
- * Immediately terminates the Java Virtual Machine. Termination
- * is unconditional and immediate. This method does not initiate the
- * shutdown sequence, nor does it wait for the shutdown sequence
- * to finish if it is already in progress. This method never returns normally.
+ * Immediately {@linkplain ##termination terminates} the Java Virtual Machine.
+ * If the security manager denies exiting, throws {@link SecurityException}.
+ * Otherwise, termination of the Java Virtual Machine is unconditional and immediate.
+ * This method does not initiate the {@linkplain ##shutdown shutdown sequence}, nor does
+ * it wait for the shutdown sequence to finish if it is already in progress. An
+ * invocation of this method never returns normally.
*
* @apiNote
* This method should be used with extreme caution. Using it may circumvent or disrupt
* any cleanup actions intended to be performed by shutdown hooks, possibly leading to
- * data corruption. See the termination section above
+ * data corruption. See the {@linkplain ##termination termination} section above
* for other possible consequences of halting the Java Virtual Machine.
*
* @param status
diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java
index 7723203fb29..fefea0bc0d0 100644
--- a/src/java.base/share/classes/java/lang/String.java
+++ b/src/java.base/share/classes/java/lang/String.java
@@ -3990,6 +3990,109 @@ public String replace(CharSequence target, CharSequence replacement) {
* @since 1.4
*/
public String[] split(String regex, int limit) {
+ return split(regex, limit, false);
+ }
+
+ /**
+ * Splits this string around matches of the given regular expression and
+ * returns both the strings and the matching delimiters.
+ *
+ *
The array returned by this method contains each substring of this
+ * string that is terminated by another substring that matches the given
+ * expression or is terminated by the end of the string.
+ * Each substring is immediately followed by the subsequence (the delimiter)
+ * that matches the given expression, except for the last
+ * substring, which is not followed by anything.
+ * The substrings in the array and the delimiters are in the order in which
+ * they occur in the input.
+ * If the expression does not match any part of the input then the resulting
+ * array has just one element, namely this string.
+ *
+ *
When there is a positive-width match at the beginning of this
+ * string then an empty leading substring is included at the beginning
+ * of the resulting array. A zero-width match at the beginning however
+ * never produces such empty leading substring nor the empty delimiter.
+ *
+ *
The {@code limit} parameter controls the number of times the
+ * pattern is applied and therefore affects the length of the resulting
+ * array.
+ *
+ *
If the limit is positive then the pattern will be applied
+ * at most limit - 1 times, the array's length will be
+ * no greater than 2 × limit - 1, and the array's last
+ * entry will contain all input beyond the last matched delimiter.
+ *
+ *
If the limit is zero then the pattern will be applied as
+ * many times as possible, the array can have any length, and trailing
+ * empty strings will be discarded.
+ *
+ *
If the limit is negative then the pattern will be applied
+ * as many times as possible and the array can have any length.
+ *
+ *
+ *
The input {@code "boo:::and::foo"}, for example, yields the following
+ * results with these parameters:
+ *
+ *
+ *
+ * @apiNote An invocation of this method of the form
+ * str.{@code splitWithDelimiters(}regex{@code ,} n{@code )}
+ * yields the same result as the expression
+ *
+ *
+ *
+ * @param regex
+ * the delimiting regular expression
+ *
+ * @param limit
+ * the result threshold, as described above
+ *
+ * @return the array of strings computed by splitting this string
+ * around matches of the given regular expression, alternating
+ * substrings and matching delimiters
+ *
+ * @since 21
+ */
+ public String[] splitWithDelimiters(String regex, int limit) {
+ return split(regex, limit, true);
+ }
+
+ private String[] split(String regex, int limit, boolean withDelimiters) {
/* fastpath if the regex is a
* (1) one-char String and this character is not one of the
* RegEx's meta characters ".$|()[{^?*+\\", or
@@ -3998,48 +4101,57 @@ public String[] split(String regex, int limit) {
*/
char ch = 0;
if (((regex.length() == 1 &&
- ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
- (regex.length() == 2 &&
- regex.charAt(0) == '\\' &&
- (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
- ((ch-'a')|('z'-ch)) < 0 &&
- ((ch-'A')|('Z'-ch)) < 0)) &&
- (ch < Character.MIN_HIGH_SURROGATE ||
- ch > Character.MAX_LOW_SURROGATE))
+ ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
+ (regex.length() == 2 &&
+ regex.charAt(0) == '\\' &&
+ (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
+ ((ch-'a')|('z'-ch)) < 0 &&
+ ((ch-'A')|('Z'-ch)) < 0)) &&
+ (ch < Character.MIN_HIGH_SURROGATE ||
+ ch > Character.MAX_LOW_SURROGATE))
{
// All the checks above can potentially be constant folded by
// a JIT/AOT compiler when the regex is a constant string.
// That requires method inlining of the checks, which is only
// possible when the actual split logic is in a separate method
// because the large split loop can usually not be inlined.
- return split(ch, limit);
+ return split(ch, limit, withDelimiters);
}
- return Pattern.compile(regex).split(this, limit);
+ Pattern pattern = Pattern.compile(regex);
+ return withDelimiters
+ ? pattern.splitWithDelimiters(this, limit)
+ : pattern.split(this, limit);
}
- private String[] split(char ch, int limit) {
+ private String[] split(char ch, int limit, boolean withDelimiters) {
+ int matchCount = 0;
int off = 0;
- int next = 0;
+ int next;
boolean limited = limit > 0;
ArrayList list = new ArrayList<>();
+ String del = withDelimiters ? String.valueOf(ch) : null;
while ((next = indexOf(ch, off)) != -1) {
- if (!limited || list.size() < limit - 1) {
+ if (!limited || matchCount < limit - 1) {
list.add(substring(off, next));
+ if (withDelimiters) {
+ list.add(del);
+ }
off = next + 1;
+ ++matchCount;
} else { // last one
- //assert (list.size() == limit - 1);
int last = length();
list.add(substring(off, last));
off = last;
+ ++matchCount;
break;
}
}
// If no match was found, return this
if (off == 0)
- return new String[]{this};
+ return new String[] {this};
// Add remaining segment
- if (!limited || list.size() < limit)
+ if (!limited || matchCount < limit)
list.add(substring(off, length()));
// Construct result
@@ -4096,7 +4208,7 @@ private String[] split(char ch, int limit) {
* @since 1.4
*/
public String[] split(String regex) {
- return split(regex, 0);
+ return split(regex, 0, false);
}
/**
diff --git a/src/java.base/share/classes/java/lang/StringConcatHelper.java b/src/java.base/share/classes/java/lang/StringConcatHelper.java
index cad34b98937..139181af096 100644
--- a/src/java.base/share/classes/java/lang/StringConcatHelper.java
+++ b/src/java.base/share/classes/java/lang/StringConcatHelper.java
@@ -26,6 +26,8 @@
package java.lang;
import jdk.internal.misc.Unsafe;
+import jdk.internal.javac.PreviewFeature;
+import jdk.internal.util.FormatConcatItem;
import jdk.internal.vm.annotation.ForceInline;
import java.lang.invoke.MethodHandle;
@@ -43,6 +45,15 @@ private StringConcatHelper() {
// no instantiation
}
+ /**
+ * Return the coder for the character.
+ * @param value character
+ * @return coder
+ */
+ static long coder(char value) {
+ return StringLatin1.canEncode(value) ? LATIN1 : UTF16;
+ }
+
/**
* Check for overflow, throw exception on overflow.
*
@@ -76,7 +87,7 @@ static long mix(long lengthCoder, boolean value) {
* @return new length and coder
*/
static long mix(long lengthCoder, char value) {
- return checkOverflow(lengthCoder + 1) | (StringLatin1.canEncode(value) ? 0 : UTF16);
+ return checkOverflow(lengthCoder + 1) | coder(value);
}
/**
@@ -116,6 +127,21 @@ static long mix(long lengthCoder, String value) {
return checkOverflow(lengthCoder);
}
+ /**
+ * Mix value length and coder into current length and coder.
+ * @param lengthCoder String length with coder packed into higher bits
+ * the upper word.
+ * @param value value to mix in
+ * @return new length and coder
+ * @since 21
+ */
+ @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES)
+ static long mix(long lengthCoder, FormatConcatItem value) {
+ lengthCoder = value.mix(lengthCoder);
+
+ return checkOverflow(lengthCoder);
+ }
+
/**
* Prepends the stringly representation of boolean value into buffer,
* given the coder and final index. Index is measured in chars, not in bytes!
@@ -319,6 +345,49 @@ static long prepend(long indexCoder, byte[] buf, String value, String prefix) {
return indexCoder;
}
+ /**
+ * Prepends the stringly representation of FormatConcatItem value into buffer,
+ * given the coder and final index. Index is measured in chars, not in bytes!
+ *
+ * @param indexCoder final char index in the buffer, along with coder packed
+ * into higher bits.
+ * @param buf buffer to append to
+ * @param value String value to encode
+ * @return updated index (coder value retained)
+ * @since 21
+ */
+ @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES)
+ private static long prepend(long indexCoder, byte[] buf,
+ FormatConcatItem value) {
+ try {
+ return value.prepend(indexCoder, buf);
+ } catch (Error ex) {
+ throw ex;
+ } catch (Throwable ex) {
+ throw new AssertionError("FormatConcatItem prepend error", ex);
+ }
+ }
+
+ /**
+ * Prepends constant and the stringly representation of value into buffer,
+ * given the coder and final index. Index is measured in chars, not in bytes!
+ *
+ * @param indexCoder final char index in the buffer, along with coder packed
+ * into higher bits.
+ * @param buf buffer to append to
+ * @param value boolean value to encode
+ * @param prefix a constant to prepend before value
+ * @return updated index (coder value retained)
+ * @since 21
+ */
+ @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES)
+ static long prepend(long indexCoder, byte[] buf,
+ FormatConcatItem value, String prefix) {
+ indexCoder = prepend(indexCoder, buf, value);
+ if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
+ return indexCoder;
+ }
+
/**
* Instantiates the String with given buffer and coder
* @param buf buffer to use
@@ -332,7 +401,8 @@ static String newString(byte[] buf, long indexCoder) {
} else if (indexCoder == UTF16) {
return new String(buf, String.UTF16);
} else {
- throw new InternalError("Storage is not completely initialized, " + (int)indexCoder + " bytes left");
+ throw new InternalError("Storage is not completely initialized, " +
+ (int)indexCoder + " bytes left");
}
}
@@ -449,6 +519,71 @@ static long initialCoder() {
return String.COMPACT_STRINGS ? LATIN1 : UTF16;
}
+ /*
+ * Initialize after phase1.
+ */
+ private static class LateInit {
+ static final MethodHandle GETCHAR_LATIN1_MH;
+
+ static final MethodHandle GETCHAR_UTF16_MH;
+
+ static final MethodHandle PUTCHAR_LATIN1_MH;
+
+ static final MethodHandle PUTCHAR_UTF16_MH;
+
+ static {
+ MethodType getCharMT =
+ MethodType.methodType(char.class,
+ byte[].class, int.class);
+ MethodType putCharMT =
+ MethodType.methodType(void.class,
+ byte[].class, int.class, int.class);
+ GETCHAR_LATIN1_MH = lookupStatic("getCharLatin1", getCharMT);
+ GETCHAR_UTF16_MH = lookupStatic("getCharUTF16", getCharMT);
+ PUTCHAR_LATIN1_MH = lookupStatic("putCharLatin1", putCharMT);
+ PUTCHAR_UTF16_MH = lookupStatic("putCharUTF16", putCharMT);
+ }
+
+ }
+
+ @ForceInline
+ @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES)
+ static char getCharLatin1(byte[] buffer, int index) {
+ return (char)buffer[index];
+ }
+
+ @ForceInline
+ @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES)
+ static char getCharUTF16(byte[] buffer, int index) {
+ return StringUTF16.getChar(buffer, index);
+ }
+
+ @ForceInline
+ @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES)
+ static void putCharLatin1(byte[] buffer, int index, int ch) {
+ buffer[index] = (byte)ch;
+ }
+
+ @ForceInline
+ @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES)
+ static void putCharUTF16(byte[] buffer, int index, int ch) {
+ StringUTF16.putChar(buffer, index, ch);
+ }
+
+ @ForceInline
+ @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES)
+ static MethodHandle selectGetChar(long indexCoder) {
+ return indexCoder < UTF16 ? LateInit.GETCHAR_LATIN1_MH :
+ LateInit.GETCHAR_UTF16_MH;
+ }
+
+ @ForceInline
+ @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES)
+ static MethodHandle selectPutChar(long indexCoder) {
+ return indexCoder < UTF16 ? LateInit.PUTCHAR_LATIN1_MH :
+ LateInit.PUTCHAR_UTF16_MH;
+ }
+
static MethodHandle lookupStatic(String name, MethodType methodType) {
try {
return MethodHandles.lookup().findStatic(StringConcatHelper.class, name, methodType);
diff --git a/src/java.base/share/classes/java/lang/StringTemplate.java b/src/java.base/share/classes/java/lang/StringTemplate.java
new file mode 100644
index 00000000000..8ba94667752
--- /dev/null
+++ b/src/java.base/share/classes/java/lang/StringTemplate.java
@@ -0,0 +1,621 @@
+/*
+ * Copyright (c) 2023, 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.
+ *
+ * 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 java.lang;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodType;
+import java.util.FormatProcessor;
+import java.util.function.Function;
+import java.util.List;
+import java.util.Objects;
+
+import jdk.internal.access.JavaTemplateAccess;
+import jdk.internal.access.SharedSecrets;
+import jdk.internal.javac.PreviewFeature;
+
+/**
+ * {@link StringTemplate} is the run-time representation of a string template or
+ * text block template in a template expression.
+ *
+ * In the source code of a Java program, a string template or text block template
+ * contains an interleaved succession of fragment literals and embedded
+ * expressions. The {@link StringTemplate#fragments()} method returns the
+ * fragment literals, and the {@link StringTemplate#values()} method returns the
+ * results of evaluating the embedded expressions. {@link StringTemplate} does not
+ * provide access to the source code of the embedded expressions themselves; it is
+ * not a compile-time representation of a string template or text block template.
+ *
+ * {@link StringTemplate} is primarily used in conjunction with a template processor
+ * to produce a string or other meaningful value. Evaluation of a template expression
+ * first produces an instance of {@link StringTemplate}, representing the right hand side
+ * of the template expression, and then passes the instance to the template processor
+ * given by the template expression.
+ *
+ * For example, the following code contains a template expression that uses the template
+ * processor {@code RAW}, which simply yields the {@link StringTemplate} passed to it:
+ * {@snippet :
+ * int x = 10;
+ * int y = 20;
+ * StringTemplate st = RAW."\{x} + \{y} = \{x + y}";
+ * List fragments = st.fragments();
+ * List
+ *
+ * All the native linker implementations limit the function descriptors that they support to those that contain
+ * only so-called canonical layouts. A canonical layout has the following characteristics:
+ *
If it is a {@linkplain ValueLayout value layout}, its {@linkplain ValueLayout#order() byte order} is
+ * the {@linkplain ByteOrder#nativeOrder() native byte order}.
+ *
If it is a {@linkplain GroupLayout group layout}, its size is a multiple of its alignment constraint, and
+ *
It does not contain padding other than what is strictly required to align its non-padding layout elements,
+ * or to satisfy constraint 3
- * This method is restricted.
- * Restricted methods are unsafe, and, if used incorrectly, their use might crash
- * the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
- * restricted methods, and use safe and supported functionalities, where possible.
*
* @apiNote It is not currently possible to obtain a linker for a different combination of OS and processor.
* @implNote The libraries exposed by the {@linkplain #defaultLookup() default lookup} associated with the returned
@@ -431,11 +444,8 @@ public sealed interface Linker permits AbstractLinker {
*
* @return a linker for the ABI associated with the underlying native platform.
* @throws UnsupportedOperationException if the underlying native platform is not supported.
- * @throws IllegalCallerException If the caller is in a module that does not have native access enabled.
*/
- @CallerSensitive
static Linker nativeLinker() {
- Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "nativeLinker");
return SharedUtils.getSystemLinker();
}
@@ -446,6 +456,11 @@ static Linker nativeLinker() {
* {@snippet lang=java :
* linker.downcallHandle(function).bindTo(symbol);
* }
+ *
+ * This method is restricted.
+ * Restricted methods are unsafe, and, if used incorrectly, their use might crash
+ * the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
+ * restricted methods, and use safe and supported functionalities, where possible.
*
* @param symbol the address of the target function.
* @param function the function descriptor of the target function.
@@ -454,11 +469,10 @@ static Linker nativeLinker() {
* @throws IllegalArgumentException if the provided function descriptor is not supported by this linker.
* or if the symbol is {@link MemorySegment#NULL}
* @throws IllegalArgumentException if an invalid combination of linker options is given.
+ * @throws IllegalCallerException If the caller is in a module that does not have native access enabled.
*/
- default MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor function, Option... options) {
- SharedUtils.checkSymbol(symbol);
- return downcallHandle(function, options).bindTo(symbol);
- }
+ @CallerSensitive
+ MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor function, Option... options);
/**
* Creates a method handle which is used to call a foreign function with the given signature.
@@ -490,6 +504,11 @@ default MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor fun
* The returned method handle will throw an {@link IllegalArgumentException} if the {@link MemorySegment}
* representing the target address of the foreign function is the {@link MemorySegment#NULL} address.
* The returned method handle will additionally throw {@link NullPointerException} if any argument passed to it is {@code null}.
+ *
+ * This method is restricted.
+ * Restricted methods are unsafe, and, if used incorrectly, their use might crash
+ * the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
+ * restricted methods, and use safe and supported functionalities, where possible.
*
* @param function the function descriptor of the target function.
* @param options any linker options.
@@ -497,7 +516,9 @@ default MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor fun
* from the provided function descriptor.
* @throws IllegalArgumentException if the provided function descriptor is not supported by this linker.
* @throws IllegalArgumentException if an invalid combination of linker options is given.
+ * @throws IllegalCallerException If the caller is in a module that does not have native access enabled.
*/
+ @CallerSensitive
MethodHandle downcallHandle(FunctionDescriptor function, Option... options);
/**
@@ -521,6 +542,11 @@ default MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor fun
* could wrap all code in the target method handle in a try/catch block that catches any {@link Throwable}, for
* instance by using the {@link java.lang.invoke.MethodHandles#catchException(MethodHandle, Class, MethodHandle)}
* method handle combinator, and handle exceptions as desired in the corresponding catch block.
+ *
+ * This method is restricted.
+ * Restricted methods are unsafe, and, if used incorrectly, their use might crash
+ * the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
+ * restricted methods, and use safe and supported functionalities, where possible.
*
* @param target the target method handle.
* @param function the upcall stub function descriptor.
@@ -533,7 +559,9 @@ default MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor fun
* @throws IllegalStateException if {@code arena.scope().isAlive() == false}
* @throws WrongThreadException if {@code arena} is a confined arena, and this method is called from a
* thread {@code T}, other than the arena's owner thread.
+ * @throws IllegalCallerException If the caller is in a module that does not have native access enabled.
*/
+ @CallerSensitive
MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function, Arena arena, Linker.Option... options);
/**
@@ -570,7 +598,7 @@ static Option firstVariadicArg(int index) {
}
/**
- * {@return A linker option used to save portions of the execution state immediately after
+ * {@return a linker option used to save portions of the execution state immediately after
* calling a foreign function associated with a downcall method handle,
* before it can be overwritten by the Java runtime, or read through conventional means}
*
@@ -594,12 +622,12 @@ static Option firstVariadicArg(int index) {
* Linker.Option ccs = Linker.Option.captureCallState("errno");
* MethodHandle handle = Linker.nativeLinker().downcallHandle(targetAddress, FunctionDescriptor.ofVoid(), ccs);
*
- * StructLayout capturedStateLayout = Linker.Option.capturedStateLayout();
+ * StructLayout capturedStateLayout = Linker.Option.captureStateLayout();
* VarHandle errnoHandle = capturedStateLayout.varHandle(PathElement.groupElement("errno"));
* try (Arena arena = Arena.ofConfined()) {
* MemorySegment capturedState = arena.allocate(capturedStateLayout);
* handle.invoke(capturedState);
- * int errno = errnoHandle.get(capturedState);
+ * int errno = (int) errnoHandle.get(capturedState);
* // use errno
* }
* }
@@ -618,7 +646,7 @@ static Option captureCallState(String... capturedState) {
}
/**
- * {@return A struct layout that represents the layout of the capture state segment that is passed
+ * {@return a struct layout that represents the layout of the capture state segment that is passed
* to a downcall handle linked with {@link #captureCallState(String...)}}.
*
* The capture state layout is platform dependent but is guaranteed to be
@@ -646,7 +674,7 @@ static StructLayout captureStateLayout() {
}
/**
- * {@return A linker option used to mark a foreign function as trivial}
+ * {@return a linker option used to mark a foreign function as trivial}
*
* A trivial function is a function that has an extremely short running time
* in all cases (similar to calling an empty function), and does not call back into Java (e.g. using an upcall stub).
diff --git a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
index ecef9f55a82..78f3e6758f6 100644
--- a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
@@ -75,7 +75,7 @@
* SequenceLayout taggedValues = MemoryLayout.sequenceLayout(5,
* MemoryLayout.structLayout(
* ValueLayout.JAVA_BYTE.withName("kind"),
- * MemoryLayout.paddingLayout(24),
+ * MemoryLayout.paddingLayout(3),
* ValueLayout.JAVA_INT.withName("value")
* )
* ).withName("TaggedValues");
@@ -84,7 +84,7 @@
*
Size, alignment and byte order
*
* All layouts have a size; layout size for value and padding layouts is always explicitly denoted; this means that a layout description
- * always has the same size in bits, regardless of the platform in which it is used. For derived layouts, the size is computed
+ * always has the same size in bytes, regardless of the platform in which it is used. For derived layouts, the size is computed
* as follows:
*
*
for a sequence layout S whose element layout is E and size is L,
@@ -104,7 +104,7 @@
*
for a group layout G with member layouts M1, M2, ... Mn whose alignments are
* A1, A2, ... An, respectively, the natural alignment of G is max(A1, A2 ... An)
*
- * A layout's natural alignment can be overridden if needed (see {@link MemoryLayout#withBitAlignment(long)}), which can be useful to describe
+ * A layout's natural alignment can be overridden if needed (see {@link MemoryLayout#withByteAlignment(long)}), which can be useful to describe
* hyper-aligned layouts.
*
* All value layouts have an explicit byte order (see {@link java.nio.ByteOrder}) which is set when the layout is created.
@@ -115,17 +115,17 @@
* at a layout nested within the root layout - this is the layout selected by the layout path.
* Layout paths are typically expressed as a sequence of one or more {@link PathElement} instances.
*
- * Layout paths are for example useful in order to obtain {@linkplain MemoryLayout#bitOffset(PathElement...) offsets} of
+ * Layout paths are for example useful in order to obtain {@linkplain MemoryLayout#byteOffset(PathElement...) offsets} of
* arbitrarily nested layouts inside another layout, to quickly obtain a {@linkplain #varHandle(PathElement...) memory access handle}
* corresponding to the selected layout, or to {@linkplain #select(PathElement...) select} an arbitrarily nested layout inside
* another layout.
*
* Such layout paths can be constructed programmatically using the methods in this class.
* For instance, given the {@code taggedValues} layout instance constructed as above, we can obtain the offset,
- * in bits, of the member layout named value in the first sequence element, as follows:
+ * in bytes, of the member layout named value in the first sequence element, as follows:
* {@snippet lang=java :
- * long valueOffset = taggedValues.bitOffset(PathElement.sequenceElement(0),
- * PathElement.groupElement("value")); // yields 32
+ * long valueOffset = taggedValues.byteOffset(PathElement.sequenceElement(0),
+ * PathElement.groupElement("value")); // yields 4
* }
*
* Similarly, we can select the member layout named {@code value}, as follows:
@@ -151,7 +151,7 @@
* access coordinate.
*
*
A layout path with free dimensions can also be used to create an offset-computing method handle, using the
- * {@link #bitOffset(PathElement...)} or {@link #byteOffsetHandle(PathElement...)} method. Again, free dimensions are
+ * {@link #byteOffset(PathElement...)} or {@link #byteOffsetHandle(PathElement...)} method. Again, free dimensions are
* translated into {@code long} parameters of the created method handle. The method handle can be used to compute the
* offsets of elements of a sequence at different indices, by supplying these indices when invoking the method handle.
* For instance:
@@ -172,14 +172,8 @@
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, PaddingLayout, ValueLayout {
- /**
- * {@return the layout size, in bits}
- */
- long bitSize();
-
/**
* {@return the layout size, in bytes}
- * @throws UnsupportedOperationException if {@code bitSize()} is not a multiple of 8.
*/
long byteSize();
@@ -210,24 +204,6 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
*/
MemoryLayout withoutName();
- /**
- * Returns the alignment constraint associated with this layout, expressed in bits. Layout alignment defines a power
- * of two {@code A} which is the bit-wise alignment of the layout. If {@code A <= 8} then {@code A/8} is the number of
- * bytes that must be aligned for any pointer that correctly points to this layout. Thus:
- *
- *
- *
{@code A=8} means unaligned (in the usual sense), which is common in packets.
- *
{@code A=64} means word aligned (on LP64), {@code A=32} int aligned, {@code A=16} short aligned, etc.
- *
{@code A=512} is the most strict alignment required by the x86/SV ABI (for AVX-512 data).
- *
- *
- * If no explicit alignment constraint was set on this layout (see {@link #withBitAlignment(long)}),
- * then this method returns the natural alignment constraint (in bits) associated with this layout.
- *
- * @return the layout alignment constraint, in bits.
- */
- long bitAlignment();
-
/**
* Returns the alignment constraint associated with this layout, expressed in bytes. Layout alignment defines a power
* of two {@code A} which is the byte-wise alignment of the layout, where {@code A} is the number of bytes that must be aligned
@@ -239,76 +215,24 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
*
{@code A=64} is the most strict alignment required by the x86/SV ABI (for AVX-512 data).
*
*
- * If no explicit alignment constraint was set on this layout (see {@link #withBitAlignment(long)}),
+ * If no explicit alignment constraint was set on this layout (see {@link #withByteAlignment(long)}),
* then this method returns the natural alignment constraint (in bytes) associated with this layout.
*
* @return the layout alignment constraint, in bytes.
- * @throws UnsupportedOperationException if {@code bitAlignment()} is not a multiple of 8.
*/
long byteAlignment();
+
/**
* Returns a memory layout of the same type with the same size and name as this layout,
- * but with the specified alignment constraint (in bits).
+ * but with the specified alignment constraint (in bytes).
*
- * @param bitAlignment the layout alignment constraint, expressed in bits.
+ * @param byteAlignment the layout alignment constraint, expressed in bytes.
* @return a memory layout with the given alignment constraint.
- * @throws IllegalArgumentException if {@code bitAlignment} is not a power of two, or if it's less than 8.
+ * @throws IllegalArgumentException if {@code byteAlignment} is not a power of two, or if it's less than 1.
*/
- MemoryLayout withBitAlignment(long bitAlignment);
+ MemoryLayout withByteAlignment(long byteAlignment);
- /**
- * Computes the offset, in bits, of the layout selected by the given layout path, where the path is considered rooted in this
- * layout.
- *
- * @param elements the layout path elements.
- * @return The offset, in bits, of the layout selected by the layout path in {@code elements}.
- * @throws IllegalArgumentException if the layout path does not select any layout nested in this layout, or if the
- * layout path contains one or more path elements that select multiple sequence element indices
- * (see {@link PathElement#sequenceElement()} and {@link PathElement#sequenceElement(long, long)}).
- * @throws IllegalArgumentException if the layout path contains one or more dereference path elements
- * (see {@link PathElement#dereferenceElement()}).
- * @throws NullPointerException if either {@code elements == null}, or if any of the elements
- * in {@code elements} is {@code null}.
- */
- default long bitOffset(PathElement... elements) {
- return computePathOp(LayoutPath.rootPath(this), LayoutPath::offset,
- EnumSet.of(PathKind.SEQUENCE_ELEMENT, PathKind.SEQUENCE_RANGE, PathKind.DEREF_ELEMENT), elements);
- }
-
- /**
- * Creates a method handle that can be used to compute the offset, in bits, of the layout selected
- * by the given layout path, where the path is considered rooted in this layout.
- *
- *
The returned method handle has a return type of {@code long}, and features as many {@code long}
- * parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()}),
- * where the order of the parameters corresponds to the order of the path elements.
- * The returned method handle can be used to compute a layout offset similar to {@link #bitOffset(PathElement...)},
- * but where some sequence indices are specified only when invoking the method handle.
- *
- *
The final offset returned by the method handle is computed as follows:
- *
- *
- *
- * where {@code x_1}, {@code x_2}, ... {@code x_n} are dynamic values provided as {@code long}
- * arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are static offset constants
- * and {@code s_0}, {@code s_1}, ... {@code s_n} are static stride constants which are derived from
- * the layout path.
- *
- * @param elements the layout path elements.
- * @return a method handle that can be used to compute the bit offset of the layout element
- * specified by the given layout path elements, when supplied with the missing sequence element indices.
- * @throws IllegalArgumentException if the layout path contains one or more path elements that select
- * multiple sequence element indices (see {@link PathElement#sequenceElement(long, long)}).
- * @throws IllegalArgumentException if the layout path contains one or more dereference path elements
- * (see {@link PathElement#dereferenceElement()}).
- */
- default MethodHandle bitOffsetHandle(PathElement... elements) {
- return computePathOp(LayoutPath.rootPath(this), LayoutPath::offsetHandle,
- EnumSet.of(PathKind.SEQUENCE_RANGE, PathKind.DEREF_ELEMENT), elements);
- }
/**
* Computes the offset, in bytes, of the layout selected by the given layout path, where the path is considered rooted in this
@@ -321,12 +245,12 @@ default MethodHandle bitOffsetHandle(PathElement... elements) {
* (see {@link PathElement#sequenceElement()} and {@link PathElement#sequenceElement(long, long)}).
* @throws IllegalArgumentException if the layout path contains one or more dereference path elements
* (see {@link PathElement#dereferenceElement()}).
- * @throws UnsupportedOperationException if {@code bitOffset(elements)} is not a multiple of 8.
* @throws NullPointerException if either {@code elements == null}, or if any of the elements
* in {@code elements} is {@code null}.
*/
default long byteOffset(PathElement... elements) {
- return Utils.bitsToBytes(bitOffset(elements));
+ return computePathOp(LayoutPath.rootPath(this), LayoutPath::offset,
+ EnumSet.of(PathKind.SEQUENCE_ELEMENT, PathKind.SEQUENCE_RANGE, PathKind.DEREF_ELEMENT), elements);
}
/**
@@ -342,8 +266,7 @@ default long byteOffset(PathElement... elements) {
*
The final offset returned by the method handle is computed as follows:
*
*
*
* where {@code x_1}, {@code x_2}, ... {@code x_n} are dynamic values provided as {@code long}
@@ -351,9 +274,6 @@ default long byteOffset(PathElement... elements) {
* and {@code s_0}, {@code s_1}, ... {@code s_n} are static stride constants which are derived from
* the layout path.
*
- *
The method handle will throw an {@link UnsupportedOperationException} if the computed
- * offset in bits is not a multiple of 8.
- *
* @param elements the layout path elements.
* @return a method handle that can be used to compute the byte offset of the layout element
* specified by the given layout path elements, when supplied with the missing sequence element indices.
@@ -363,9 +283,8 @@ default long byteOffset(PathElement... elements) {
* (see {@link PathElement#dereferenceElement()}).
*/
default MethodHandle byteOffsetHandle(PathElement... elements) {
- MethodHandle mh = bitOffsetHandle(elements);
- mh = MethodHandles.filterReturnValue(mh, Utils.BITS_TO_BYTES);
- return mh;
+ return computePathOp(LayoutPath.rootPath(this), LayoutPath::offsetHandle,
+ EnumSet.of(PathKind.SEQUENCE_RANGE, PathKind.DEREF_ELEMENT), elements);
}
/**
@@ -448,8 +367,7 @@ default VarHandle varHandle(PathElement... elements) {
*
The offset of the returned segment is computed as follows:
*
*
*
* where {@code x_1}, {@code x_2}, ... {@code x_n} are dynamic values provided as {@code long}
@@ -465,12 +383,8 @@ default VarHandle varHandle(PathElement... elements) {
* where {@code segment} is the segment to be sliced, and where {@code layout} is the layout selected by the given
* layout path, as per {@link MemoryLayout#select(PathElement...)}.
*
- *
The method handle will throw an {@link UnsupportedOperationException} if the computed
- * offset in bits is not a multiple of 8.
- *
* @param elements the layout path elements.
* @return a method handle which can be used to create a slice of the selected layout element, given a segment.
- * @throws UnsupportedOperationException if the size of the selected layout in bits is not a multiple of 8.
* @throws IllegalArgumentException if the layout path contains one or more dereference path elements
* (see {@link PathElement#dereferenceElement()}).
*/
@@ -687,14 +601,14 @@ static PathElement dereferenceElement() {
String toString();
/**
- * Creates a padding layout with the given bitSize and a bit-alignment of eight.
+ * Creates a padding layout with the given byte size and a byte-alignment of one.
*
- * @param bitSize the padding size in bits.
+ * @param byteSize the padding size (expressed in bytes).
* @return the new selector layout.
- * @throws IllegalArgumentException if {@code bitSize <= 0} or {@code bitSize % 8 != 0}
+ * @throws IllegalArgumentException if {@code byteSize <= 0}.
*/
- static PaddingLayout paddingLayout(long bitSize) {
- return PaddingLayoutImpl.of(MemoryLayoutUtil.requireBitSizeValid(bitSize, false));
+ static PaddingLayout paddingLayout(long byteSize) {
+ return PaddingLayoutImpl.of(MemoryLayoutUtil.requireByteSizeValid(byteSize, false));
}
/**
@@ -704,12 +618,12 @@ static PaddingLayout paddingLayout(long bitSize) {
* @param elementLayout the sequence element layout.
* @return the new sequence layout with the given element layout and size.
* @throws IllegalArgumentException if {@code elementCount } is negative.
- * @throws IllegalArgumentException if {@code elementLayout.bitAlignment() > elementLayout.bitSize()}.
+ * @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0}.
*/
static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout) {
MemoryLayoutUtil.requireNonNegative(elementCount);
Objects.requireNonNull(elementLayout);
- Utils.checkElementAlignment(elementLayout, "Element layout alignment greater than its size");
+ Utils.checkElementAlignment(elementLayout, "Element layout size is not multiple of alignment");
return wrapOverflow(() ->
SequenceLayoutImpl.of(elementCount, elementLayout));
}
@@ -720,16 +634,16 @@ static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayo
*
* This is equivalent to the following code:
* {@snippet lang = java:
- * sequenceLayout(Long.MAX_VALUE / elementLayout.bitSize(), elementLayout);
+ * sequenceLayout(Long.MAX_VALUE / elementLayout.byteSize(), elementLayout);
* }
*
* @param elementLayout the sequence element layout.
* @return a new sequence layout with the given element layout and maximum element count.
- * @throws IllegalArgumentException if {@code elementLayout.bitAlignment() > elementLayout.bitSize()}.
+ * @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0}.
*/
static SequenceLayout sequenceLayout(MemoryLayout elementLayout) {
Objects.requireNonNull(elementLayout);
- return sequenceLayout(Long.MAX_VALUE / elementLayout.bitSize(), elementLayout);
+ return sequenceLayout(Long.MAX_VALUE / elementLayout.byteSize(), elementLayout);
}
/**
@@ -737,8 +651,30 @@ static SequenceLayout sequenceLayout(MemoryLayout elementLayout) {
*
* @param elements The member layouts of the struct layout.
* @return a struct layout with the given member layouts.
- * @throws IllegalArgumentException if the sum of the {@linkplain #bitSize() bit sizes} of the member layouts
+ * @throws IllegalArgumentException if the sum of the {@linkplain #byteSize() byte sizes} of the member layouts
* overflows.
+ * @throws IllegalArgumentException if a member layout in {@code elements} occurs at an offset (relative to the start
+ * of the struct layout) which is not compatible with its alignment constraint.
+ *
+ * @apiNote This factory does not automatically align element layouts, by inserting additional {@linkplain PaddingLayout
+ * padding layout} elements. As such, the following struct layout creation will fail with an exception:
+ *
+ * {@snippet lang = java:
+ * structLayout(JAVA_SHORT, JAVA_INT);
+ * }
+ *
+ * To avoid the exception, clients can either insert additional padding layout elements:
+ *
+ * {@snippet lang = java:
+ * structLayout(JAVA_SHORT, MemoryLayout.paddingLayout(2), JAVA_INT);
+ * }
+ *
+ * Or, alternatively, they can use a member layout which features a smaller alignment constraint. This will result
+ * in a packed struct layout:
+ *
+ * {@snippet lang = java:
+ * structLayout(JAVA_SHORT, JAVA_INT.withByteAlignment(2));
+ * }
*/
static StructLayout structLayout(MemoryLayout... elements) {
Objects.requireNonNull(elements);
diff --git a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java
index 1580787431f..36e2decc4dd 100644
--- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java
+++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java
@@ -142,7 +142,7 @@
* MethodType.methodType(long.class, long.class, long.class));
* intHandle = MethodHandles.filterCoordinates(intHandle, 1,
* MethodHandles.insertArguments(multiplyExact, 0, 4L));
- * intHandle.get(segment, 3L); // get int element at offset 3 * 4 = 12
+ * int value = (int) intHandle.get(segment, 3L); // get int element at offset 3 * 4 = 12
* }
*
* Alternatively, complex var handles can can be obtained
@@ -152,7 +152,7 @@
* {@snippet lang=java :
* MemorySegment segment = ...
* VarHandle intHandle = ValueLayout.JAVA_INT.arrayElementVarHandle();
- * intHandle.get(segment, 3L); // get int element at offset 3 * 4 = 12
+ * int value = (int) intHandle.get(segment, 3L); // get int element at offset 3 * 4 = 12
* }
*
*
Slicing memory segments
@@ -264,12 +264,6 @@
* collection. Access operations rely on this invariant to determine if the specified offset in a heap segment refers
* to an aligned address in physical memory. For example:
*
- *
The starting physical address of a {@code long[]} array will be 8-byte aligned (e.g. 1000), so that successive long elements
- * occur at 8-byte aligned addresses (e.g., 1000, 1008, 1016, 1024, etc.) A heap segment backed by a {@code long[]} array
- * can be accessed at offsets 0, 8, 16, 24, etc under an 8-byte alignment constraint. In addition, the segment can be
- * accessed at offsets 0, 4, 8, 12, etc under a 4-byte alignment constraint, because the target addresses
- * (1000, 1004, 1008, 1012) are 4-byte aligned. And, the segment can be accessed at offsets 0, 2, 4, 6, etc under a
- * 2-byte alignment constraint, because the target addresses (e.g. 1000, 1002, 1004, 1006) are 2-byte aligned.
*
The starting physical address of a {@code short[]} array will be 2-byte aligned (e.g. 1006) so that successive
* short elements occur at 2-byte aligned addresses (e.g. 1006, 1008, 1010, 1012, etc). A heap segment backed by a
* {@code short[]} array can be accessed at offsets 0, 2, 4, 6, etc under a 2-byte alignment constraint. The segment cannot
@@ -278,10 +272,22 @@
* to physical address 1007. Similarly, the segment cannot be accessed at any offset under an 8-byte alignment constraint,
* because because there is no guarantee that the target address would be 8-byte aligned, e.g., offset 2 would correspond
* to physical address 1008 but offset 4 would correspond to physical address 1010.
+ *
The starting physical address of a {@code long[]} array will be 8-byte aligned (e.g. 1000) on 64-bit platforms,
+ * so that successive long elements occur at 8-byte aligned addresses (e.g., 1000, 1008, 1016, 1024, etc.) On 64-bit platforms,
+ * a heap segment backed by a {@code long[]} array can be accessed at offsets 0, 8, 16, 24, etc under an 8-byte alignment
+ * constraint. In addition, the segment can be accessed at offsets 0, 4, 8, 12, etc under a 4-byte alignment constraint,
+ * because the target addresses (1000, 1004, 1008, 1012) are 4-byte aligned. And, the segment can be accessed at offsets
+ * 0, 2, 4, 6, etc under a 2-byte alignment constraint, because the target addresses (e.g. 1000, 1002, 1004, 1006) are 2-byte aligned.
+ *
The starting physical address of a {@code long[]} array will be 4-byte aligned (e.g. 1000) on 32-bit platforms,
+ * so that successive long elements occur at 4-byte aligned addresses (e.g., 1004, 1008, 1012, 1016, etc.) On 32-bit
+ * platforms, a heap segment backed by a {@code long[]} array can be accessed at offsets 0, 4, 8, 12, etc under a 4-byte
+ * alignment constraint, because the target addresses (1000, 1004, 1008, 1012) are 4-byte aligned. And, the segment
+ * can be accessed at offsets 0, 2, 4, 6, etc under a 2-byte alignment constraint, because the target addresses
+ * (e.g. 1000, 1002, 1004, 1006) are 2-byte aligned.
*
*
- * In other words, heap segments feature a maximum alignment which is derived from the size of the elements of
- * the Java array backing the segment, as shown in the following table:
+ * In other words, heap segments feature a (platform-dependent) maximum alignment which is derived from the
+ * size of the elements of the Java array backing the segment, as shown in the following table:
*
*
*
Maximum alignment of heap segments
@@ -293,21 +299,21 @@
*
*
*
{@code boolean[]}
- *
{@code 1}
+ *
{@code ValueLayout.JAVA_BOOLEAN.byteAlignment()}
*
{@code byte[]}
- *
{@code 1}
+ *
{@code ValueLayout.JAVA_BYTE.byteAlignment()}
*
{@code char[]}
- *
{@code 2}
+ *
{@code ValueLayout.JAVA_CHAR.byteAlignment()}
*
{@code short[]}
- *
{@code 2}
+ *
{@code ValueLayout.JAVA_SHORT.byteAlignment()}
*
{@code int[]}
- *
{@code 4}
+ *
{@code ValueLayout.JAVA_INT.byteAlignment()}
*
{@code float[]}
- *
{@code 4}
+ *
{@code ValueLayout.JAVA_FLOAT.byteAlignment()}
*
{@code long[]}
- *
{@code 8}
+ *
{@code ValueLayout.JAVA_LONG.byteAlignment()}
*
{@code double[]}
- *
{@code 8}
+ *
{@code ValueLayout.JAVA_DOUBLE.byteAlignment()}
*
*
*
@@ -318,22 +324,25 @@
*
* {@snippet lang=java :
* MemorySegment byteSegment = MemorySegment.ofArray(new byte[10]);
- * byteSegment.get(ValueLayout.JAVA_INT, 0); // fails: layout alignment is 4, segment max alignment is 1
+ * byteSegment.get(ValueLayout.JAVA_INT, 0); // fails: ValueLayout.JAVA_INT.byteAlignment() > ValueLayout.JAVA_BYTE.byteAlignment()
* }
*
* In such circumstances, clients have two options. They can use a heap segment backed by a different array
- * type (e.g. {@code long[]}), capable of supporting greater maximum alignment:
+ * type (e.g. {@code long[]}), capable of supporting greater maximum alignment. More specifically, the maximum alignment
+ * associated with {@code long[]} is set to {@code ValueLayout.JAVA_LONG.byteAlignment()} which is a platform-dependent
+ * value (set to {@code ValueLayout.ADDRESS.byteSize()}). That is, {@code long[]}) is guaranteed to provide at least
+ * 8-byte alignment in 64-bit platforms, but only 4-byte alignment in 32-bit platforms:
*
* {@snippet lang=java :
* MemorySegment longSegment = MemorySegment.ofArray(new long[10]);
- * longSegment.get(ValueLayout.JAVA_INT, 0); // ok: layout alignment is 4, segment max alignment is 8
+ * longSegment.get(ValueLayout.JAVA_INT, 0); // ok: ValueLayout.JAVA_INT.byteAlignment() <= ValueLayout.JAVA_LONG.byteAlignment()
* }
*
* Alternatively, they can invoke the access operation with an unaligned layout.
* All unaligned layout constants (e.g. {@link ValueLayout#JAVA_INT_UNALIGNED}) have their alignment constraint set to 1:
* {@snippet lang=java :
* MemorySegment byteSegment = MemorySegment.ofArray(new byte[10]);
- * byteSegment.get(ValueLayout.JAVA_INT_UNALIGNED, 0); // ok: layout alignment is 1, segment max alignment is 1
+ * byteSegment.get(ValueLayout.JAVA_INT_UNALIGNED, 0); // ok: ValueLayout.JAVA_INT_UNALIGNED.byteAlignment() == ValueLayout.JAVA_BYTE.byteAlignment()
* }
*
*
Zero-length memory segments
@@ -370,7 +379,7 @@
* to read a pointer from some memory segment. This can be done via the
* {@linkplain MemorySegment#get(AddressLayout, long)} access method. This method accepts an
* {@linkplain AddressLayout address layout} (e.g. {@link ValueLayout#ADDRESS}), the layout of the pointer
- * to be read. For instance on a 64-bit platform, the size of an address layout is 64 bits. The access operation
+ * to be read. For instance on a 64-bit platform, the size of an address layout is 8 bytes. The access operation
* also accepts an offset, expressed in bytes, which indicates the position (relative to the start of the memory segment)
* at which the pointer is stored. The access operation returns a zero-length native memory segment, backed by a region
* of memory whose starting address is the 64-bit value read at the specified offset.
@@ -459,10 +468,11 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
*
* @param elementLayout the layout to be used for splitting.
* @return the element spliterator for this segment
- * @throws IllegalArgumentException if the {@code elementLayout} size is zero, or the segment size modulo the
- * {@code elementLayout} size is greater than zero, if this segment is
- * incompatible with the alignment constraint in the provided layout,
- * or if the {@code elementLayout} alignment is greater than its size.
+ * @throws IllegalArgumentException if {@code elementLayout.byteSize() == 0}.
+ * @throws IllegalArgumentException if {@code byteSize() % elementLayout.byteSize() != 0}.
+ * @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0}.
+ * @throws IllegalArgumentException if this segment is incompatible
+ * with the alignment constraint in the provided layout.
*/
Spliterator spliterator(MemoryLayout elementLayout);
@@ -475,10 +485,11 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
*
* @param elementLayout the layout to be used for splitting.
* @return a sequential {@code Stream} over disjoint slices in this segment.
- * @throws IllegalArgumentException if the {@code elementLayout} size is zero, or the segment size modulo the
- * {@code elementLayout} size is greater than zero, if this segment is
- * incompatible with the alignment constraint in the provided layout,
- * or if the {@code elementLayout} alignment is greater than its size.
+ * @throws IllegalArgumentException if {@code elementLayout.byteSize() == 0}.
+ * @throws IllegalArgumentException if {@code byteSize() % elementLayout.byteSize() != 0}.
+ * @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0}.
+ * @throws IllegalArgumentException if this segment is incompatible
+ * with the alignment constraint in the provided layout.
*/
Stream elements(MemoryLayout elementLayout);
@@ -616,11 +627,6 @@ default MemorySegment asSlice(long offset, MemoryLayout layout) {
* if the provided scope is the scope of an {@linkplain Arena#ofAuto() automatic arena}, the cleanup action
* must not prevent the scope from becoming unreachable.
* A failure to do so will permanently prevent the regions of memory allocated by the automatic arena from being deallocated.
- *
- * This method is restricted.
- * Restricted methods are unsafe, and, if used incorrectly, their use might crash
- * the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
- * restricted methods, and use safe and supported functionalities, where possible.
*
* @param arena the arena to be associated with the returned segment.
* @param cleanup the cleanup action that should be executed when the provided arena is closed (can be {@code null}).
@@ -750,8 +756,8 @@ default MemorySegment asSlice(long offset, MemoryLayout layout) {
* segment. Equivalent to (but likely more efficient than) the following code:
*
* {@snippet lang=java :
- * byteHandle = MemoryLayout.ofSequence(ValueLayout.JAVA_BYTE)
- * .varHandle(byte.class, MemoryLayout.PathElement.sequenceElement());
+ * var byteHandle = MemoryLayout.sequenceLayout(ValueLayout.JAVA_BYTE)
+ * .varHandle(MemoryLayout.PathElement.sequenceElement());
* for (long l = 0; l < segment.byteSize(); l++) {
* byteHandle.set(segment.address(), l, value);
* }
@@ -779,7 +785,7 @@ default MemorySegment asSlice(long offset, MemoryLayout layout) {
*
* Calling this method is equivalent to the following code:
* {@snippet lang=java :
- * MemorySegment.copy(src, 0, this, 0, src.byteSize);
+ * MemorySegment.copy(src, 0, this, 0, src.byteSize());
* }
* @param src the source segment.
* @throws IndexOutOfBoundsException if {@code src.byteSize() > this.byteSize()}.
diff --git a/src/java.base/share/classes/java/lang/foreign/PaddingLayout.java b/src/java.base/share/classes/java/lang/foreign/PaddingLayout.java
index a09689c874c..cd0cd44ed30 100644
--- a/src/java.base/share/classes/java/lang/foreign/PaddingLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/PaddingLayout.java
@@ -56,6 +56,5 @@ public sealed interface PaddingLayout extends MemoryLayout permits PaddingLayout
* {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
*/
- @Override
- PaddingLayout withBitAlignment(long bitAlignment);
+ PaddingLayout withByteAlignment(long byteAlignment);
}
diff --git a/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java b/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java
index 3d0a01631f8..95bde61f0bd 100644
--- a/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java
@@ -143,7 +143,7 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo
/**
* {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
- * @throws IllegalArgumentException if {@code bitAlignment < elementLayout().bitAlignment()}.
+ * @throws IllegalArgumentException if {@code byteAlignment < elementLayout().byteAlignment()}.
*/
- SequenceLayout withBitAlignment(long bitAlignment);
+ SequenceLayout withByteAlignment(long byteAlignment);
}
diff --git a/src/java.base/share/classes/java/lang/foreign/StructLayout.java b/src/java.base/share/classes/java/lang/foreign/StructLayout.java
index ad314ae3b36..57ddc00caee 100644
--- a/src/java.base/share/classes/java/lang/foreign/StructLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/StructLayout.java
@@ -56,5 +56,5 @@ public sealed interface StructLayout extends GroupLayout permits StructLayoutImp
* @throws IllegalArgumentException {@inheritDoc}
*/
@Override
- StructLayout withBitAlignment(long bitAlignment);
+ StructLayout withByteAlignment(long byteAlignment);
}
diff --git a/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java b/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java
index 573d884bdc1..f6ef8b23725 100644
--- a/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java
+++ b/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java
@@ -28,6 +28,7 @@
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.foreign.MemorySessionImpl;
+import jdk.internal.foreign.Utils;
import jdk.internal.javac.PreviewFeature;
import jdk.internal.loader.BuiltinClassLoader;
import jdk.internal.loader.NativeLibrary;
@@ -129,6 +130,28 @@ public interface SymbolLookup {
*/
Optional find(String name);
+ /**
+ * {@return a composed symbol lookup that returns result of finding the symbol with this lookup if found,
+ * otherwise returns the result of finding the symbol with the other lookup}
+ *
+ * @apiNote This method could be used to chain multiple symbol lookups together, e.g. so that symbols could
+ * be retrieved, in order, from multiple libraries:
+ * {@snippet lang = java:
+ * var lookup = SymbolLookup.libraryLookup("foo", arena)
+ * .or(SymbolLookup.libraryLookup("bar", arena))
+ * .or(SymbolLookup.loaderLookup());
+ *}
+ * The above code creates a symbol lookup that first searches for symbols in the "foo" library. If no symbol is found
+ * in "foo" then "bar" is searched. Finally, if a symbol is not found in neither "foo" nor "bar", the {@linkplain
+ * SymbolLookup#loaderLookup() loader lookup} is used.
+ *
+ * @param other the symbol lookup that should be used to look for symbols not found in this lookup.
+ */
+ default SymbolLookup or(SymbolLookup other) {
+ Objects.requireNonNull(other);
+ return name -> find(name).or(() -> other.find(name));
+ }
+
/**
* Returns a symbol lookup for symbols in the libraries associated with the caller's class loader.
*
@@ -170,6 +193,7 @@ static SymbolLookup loaderLookup() {
}
return name -> {
Objects.requireNonNull(name);
+ if (Utils.containsNullChars(name)) return Optional.empty();
JavaLangAccess javaLangAccess = SharedSecrets.getJavaLangAccess();
// note: ClassLoader::findNative supports a null loader
long addr = javaLangAccess.findNative(loader, name);
@@ -207,6 +231,9 @@ static SymbolLookup loaderLookup() {
@CallerSensitive
static SymbolLookup libraryLookup(String name, Arena arena) {
Reflection.ensureNativeAccess(Reflection.getCallerClass(), SymbolLookup.class, "libraryLookup");
+ if (Utils.containsNullChars(name)) {
+ throw new IllegalArgumentException("Cannot open library: " + name);
+ }
return libraryLookup(name, RawNativeLibraries::load, arena);
}
@@ -257,6 +284,7 @@ public void cleanup() {
});
return name -> {
Objects.requireNonNull(name);
+ if (Utils.containsNullChars(name)) return Optional.empty();
long addr = library.find(name);
return addr == 0L ?
Optional.empty() :
diff --git a/src/java.base/share/classes/java/lang/foreign/UnionLayout.java b/src/java.base/share/classes/java/lang/foreign/UnionLayout.java
index fa322f3cc74..f13d9274df1 100644
--- a/src/java.base/share/classes/java/lang/foreign/UnionLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/UnionLayout.java
@@ -56,5 +56,5 @@ public sealed interface UnionLayout extends GroupLayout permits UnionLayoutImpl
* @throws IllegalArgumentException {@inheritDoc}
*/
@Override
- UnionLayout withBitAlignment(long bitAlignment);
+ UnionLayout withByteAlignment(long byteAlignment);
}
diff --git a/src/java.base/share/classes/java/lang/foreign/ValueLayout.java b/src/java.base/share/classes/java/lang/foreign/ValueLayout.java
index 673c79c1a18..88163d61054 100644
--- a/src/java.base/share/classes/java/lang/foreign/ValueLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/ValueLayout.java
@@ -37,7 +37,7 @@
* integral values (either signed or unsigned), floating-point values and
* address values.
*
- * Each value layout has a size, an alignment (in bits),
+ * Each value layout has a size, an alignment (both expressed in bytes),
* a {@linkplain ByteOrder byte order}, and a carrier, that is, the Java type that should be used when
* {@linkplain MemorySegment#get(OfInt, long) accessing} a region of memory using the value layout.
*